1249259Sdim//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10249259Sdim// This file implements the MachO-specific dumper for llvm-readobj. 11249259Sdim// 12249259Sdim//===----------------------------------------------------------------------===// 13249259Sdim 14249259Sdim#include "llvm-readobj.h" 15249259Sdim#include "Error.h" 16249259Sdim#include "ObjDumper.h" 17288943Sdim#include "StackMapPrinter.h" 18249259Sdim#include "StreamWriter.h" 19249259Sdim#include "llvm/ADT/SmallString.h" 20276479Sdim#include "llvm/ADT/StringExtras.h" 21249259Sdim#include "llvm/Object/MachO.h" 22249259Sdim#include "llvm/Support/Casting.h" 23249259Sdim 24249259Sdimusing namespace llvm; 25249259Sdimusing namespace object; 26249259Sdim 27249259Sdimnamespace { 28249259Sdim 29249259Sdimclass MachODumper : public ObjDumper { 30249259Sdimpublic: 31251662Sdim MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer) 32249259Sdim : ObjDumper(Writer) 33249259Sdim , Obj(Obj) { } 34249259Sdim 35280031Sdim void printFileHeaders() override; 36280031Sdim void printSections() override; 37280031Sdim void printRelocations() override; 38280031Sdim void printSymbols() override; 39280031Sdim void printDynamicSymbols() override; 40280031Sdim void printUnwindInfo() override; 41288943Sdim void printStackMap() const override; 42249259Sdim 43296417Sdim // MachO-specific. 44296417Sdim void printMachODataInCode() override; 45296417Sdim void printMachOVersionMin() override; 46296417Sdim void printMachODysymtab() override; 47296417Sdim void printMachOSegment() override; 48296417Sdim void printMachOIndirectSymbols() override; 49296417Sdim void printMachOLinkerOptions () override; 50296417Sdim 51249259Sdimprivate: 52280031Sdim template<class MachHeader> 53280031Sdim void printFileHeaders(const MachHeader &Header); 54280031Sdim 55276479Sdim void printSymbol(const SymbolRef &Symbol); 56249259Sdim 57276479Sdim void printRelocation(const RelocationRef &Reloc); 58249259Sdim 59276479Sdim void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc); 60251662Sdim 61251662Sdim void printSections(const MachOObjectFile *Obj); 62251662Sdim 63251662Sdim const MachOObjectFile *Obj; 64249259Sdim}; 65249259Sdim 66249259Sdim} // namespace 67249259Sdim 68249259Sdim 69249259Sdimnamespace llvm { 70249259Sdim 71276479Sdimstd::error_code createMachODumper(const object::ObjectFile *Obj, 72276479Sdim StreamWriter &Writer, 73276479Sdim std::unique_ptr<ObjDumper> &Result) { 74249259Sdim const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); 75249259Sdim if (!MachOObj) 76249259Sdim return readobj_error::unsupported_obj_file_format; 77249259Sdim 78249259Sdim Result.reset(new MachODumper(MachOObj, Writer)); 79249259Sdim return readobj_error::success; 80249259Sdim} 81249259Sdim 82249259Sdim} // namespace llvm 83249259Sdim 84280031Sdimstatic const EnumEntry<uint32_t> MachOMagics[] = { 85280031Sdim { "Magic", MachO::MH_MAGIC }, 86280031Sdim { "Cigam", MachO::MH_CIGAM }, 87280031Sdim { "Magic64", MachO::MH_MAGIC_64 }, 88280031Sdim { "Cigam64", MachO::MH_CIGAM_64 }, 89280031Sdim { "FatMagic", MachO::FAT_MAGIC }, 90280031Sdim { "FatCigam", MachO::FAT_CIGAM }, 91280031Sdim}; 92249259Sdim 93280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderFileTypes[] = { 94280031Sdim { "Relocatable", MachO::MH_OBJECT }, 95280031Sdim { "Executable", MachO::MH_EXECUTE }, 96280031Sdim { "FixedVMLibrary", MachO::MH_FVMLIB }, 97280031Sdim { "Core", MachO::MH_CORE }, 98280031Sdim { "PreloadedExecutable", MachO::MH_PRELOAD }, 99280031Sdim { "DynamicLibrary", MachO::MH_DYLIB }, 100280031Sdim { "DynamicLinker", MachO::MH_DYLINKER }, 101280031Sdim { "Bundle", MachO::MH_BUNDLE }, 102280031Sdim { "DynamicLibraryStub", MachO::MH_DYLIB_STUB }, 103280031Sdim { "DWARFSymbol", MachO::MH_DSYM }, 104280031Sdim { "KextBundle", MachO::MH_KEXT_BUNDLE }, 105280031Sdim}; 106280031Sdim 107280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuTypes[] = { 108280031Sdim { "Any" , static_cast<uint32_t>(MachO::CPU_TYPE_ANY) }, 109280031Sdim { "X86" , MachO::CPU_TYPE_X86 }, 110280031Sdim { "X86-64" , MachO::CPU_TYPE_X86_64 }, 111280031Sdim { "Mc98000" , MachO::CPU_TYPE_MC98000 }, 112280031Sdim { "Arm" , MachO::CPU_TYPE_ARM }, 113280031Sdim { "Arm64" , MachO::CPU_TYPE_ARM64 }, 114280031Sdim { "Sparc" , MachO::CPU_TYPE_SPARC }, 115280031Sdim { "PowerPC" , MachO::CPU_TYPE_POWERPC }, 116280031Sdim { "PowerPC64" , MachO::CPU_TYPE_POWERPC64 }, 117280031Sdim}; 118280031Sdim 119280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX86[] = { 120280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL), 121280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386), 122280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486), 123280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX), 124280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586), 125280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO), 126280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3), 127280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5), 128280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON), 129280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE), 130280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3), 131280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M), 132280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON), 133280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M), 134280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4), 135280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M), 136280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM), 137280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2), 138280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON), 139280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP), 140280031Sdim}; 141280031Sdim 142280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX64[] = { 143280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL), 144280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1), 145280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H), 146280031Sdim}; 147280031Sdim 148280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = { 149280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL), 150280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T), 151280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6), 152280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5), 153280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ), 154280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE), 155280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7), 156280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S), 157280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K), 158280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M), 159280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M), 160280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM), 161280031Sdim}; 162280031Sdim 163280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = { 164280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL), 165280031Sdim}; 166280031Sdim 167280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = { 168280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL), 169280031Sdim}; 170280031Sdim 171280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderCpuSubtypesPPC[] = { 172280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL), 173280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601), 174280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602), 175280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603), 176280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e), 177280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev), 178280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604), 179280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e), 180280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620), 181280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750), 182280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400), 183280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450), 184280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970), 185280031Sdim}; 186280031Sdim 187280031Sdimstatic const EnumEntry<uint32_t> MachOHeaderFlags[] = { 188280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS), 189280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK), 190280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK), 191280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD), 192280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND), 193280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS), 194280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT), 195280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL), 196280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT), 197280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS), 198280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING), 199280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE), 200280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND), 201280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS), 202280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL), 203280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES), 204280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK), 205280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION), 206280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE), 207280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE), 208280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS), 209280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE), 210280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB), 211280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS), 212280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION), 213280031Sdim LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE), 214280031Sdim}; 215280031Sdim 216249259Sdimstatic const EnumEntry<unsigned> MachOSectionAttributes[] = { 217249259Sdim { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, 218249259Sdim { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, 219249259Sdim { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, 220249259Sdim { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, 221249259Sdim { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, 222249259Sdim { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, 223249259Sdim { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, 224249259Sdim { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, 225249259Sdim { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, 226249259Sdim { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, 227249259Sdim}; 228249259Sdim 229249259Sdimstatic const EnumEntry<unsigned> MachOSymbolRefTypes[] = { 230249259Sdim { "UndefinedNonLazy", 0 }, 231249259Sdim { "ReferenceFlagUndefinedLazy", 1 }, 232249259Sdim { "ReferenceFlagDefined", 2 }, 233249259Sdim { "ReferenceFlagPrivateDefined", 3 }, 234249259Sdim { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, 235249259Sdim { "ReferenceFlagPrivateUndefinedLazy", 5 } 236249259Sdim}; 237249259Sdim 238249259Sdimstatic const EnumEntry<unsigned> MachOSymbolFlags[] = { 239249259Sdim { "ReferencedDynamically", 0x10 }, 240249259Sdim { "NoDeadStrip", 0x20 }, 241249259Sdim { "WeakRef", 0x40 }, 242249259Sdim { "WeakDef", 0x80 } 243249259Sdim}; 244249259Sdim 245249259Sdimstatic const EnumEntry<unsigned> MachOSymbolTypes[] = { 246249259Sdim { "Undef", 0x0 }, 247249259Sdim { "Abs", 0x2 }, 248249259Sdim { "Indirect", 0xA }, 249249259Sdim { "PreboundUndef", 0xC }, 250276479Sdim { "Section", 0xE } 251249259Sdim}; 252249259Sdim 253249259Sdimnamespace { 254249259Sdim struct MachOSection { 255249259Sdim ArrayRef<char> Name; 256249259Sdim ArrayRef<char> SegmentName; 257249259Sdim uint64_t Address; 258249259Sdim uint64_t Size; 259249259Sdim uint32_t Offset; 260249259Sdim uint32_t Alignment; 261249259Sdim uint32_t RelocationTableOffset; 262249259Sdim uint32_t NumRelocationTableEntries; 263249259Sdim uint32_t Flags; 264249259Sdim uint32_t Reserved1; 265249259Sdim uint32_t Reserved2; 266296417Sdim uint32_t Reserved3; 267249259Sdim }; 268249259Sdim 269296417Sdim struct MachOSegment { 270296417Sdim std::string CmdName; 271296417Sdim std::string SegName; 272296417Sdim uint64_t cmdsize; 273296417Sdim uint64_t vmaddr; 274296417Sdim uint64_t vmsize; 275296417Sdim uint64_t fileoff; 276296417Sdim uint64_t filesize; 277296417Sdim uint32_t maxprot; 278296417Sdim uint32_t initprot; 279296417Sdim uint32_t nsects; 280296417Sdim uint32_t flags; 281296417Sdim }; 282296417Sdim 283249259Sdim struct MachOSymbol { 284249259Sdim uint32_t StringIndex; 285249259Sdim uint8_t Type; 286249259Sdim uint8_t SectionIndex; 287249259Sdim uint16_t Flags; 288249259Sdim uint64_t Value; 289249259Sdim }; 290249259Sdim} 291249259Sdim 292296417Sdimstatic std::string getMask(uint32_t prot) 293296417Sdim{ 294296417Sdim // TODO (davide): This always assumes prot is valid. 295296417Sdim // Catch mistakes and report if needed. 296296417Sdim std::string Prot; 297296417Sdim Prot = ""; 298296417Sdim Prot += (prot & MachO::VM_PROT_READ) ? "r" : "-"; 299296417Sdim Prot += (prot & MachO::VM_PROT_WRITE) ? "w" : "-"; 300296417Sdim Prot += (prot & MachO::VM_PROT_EXECUTE) ? "x" : "-"; 301296417Sdim return Prot; 302296417Sdim} 303296417Sdim 304251662Sdimstatic void getSection(const MachOObjectFile *Obj, 305251662Sdim DataRefImpl Sec, 306249259Sdim MachOSection &Section) { 307251662Sdim if (!Obj->is64Bit()) { 308261991Sdim MachO::section Sect = Obj->getSection(Sec); 309261991Sdim Section.Address = Sect.addr; 310261991Sdim Section.Size = Sect.size; 311261991Sdim Section.Offset = Sect.offset; 312261991Sdim Section.Alignment = Sect.align; 313261991Sdim Section.RelocationTableOffset = Sect.reloff; 314261991Sdim Section.NumRelocationTableEntries = Sect.nreloc; 315261991Sdim Section.Flags = Sect.flags; 316261991Sdim Section.Reserved1 = Sect.reserved1; 317261991Sdim Section.Reserved2 = Sect.reserved2; 318251662Sdim return; 319249259Sdim } 320261991Sdim MachO::section_64 Sect = Obj->getSection64(Sec); 321261991Sdim Section.Address = Sect.addr; 322261991Sdim Section.Size = Sect.size; 323261991Sdim Section.Offset = Sect.offset; 324261991Sdim Section.Alignment = Sect.align; 325261991Sdim Section.RelocationTableOffset = Sect.reloff; 326261991Sdim Section.NumRelocationTableEntries = Sect.nreloc; 327261991Sdim Section.Flags = Sect.flags; 328261991Sdim Section.Reserved1 = Sect.reserved1; 329261991Sdim Section.Reserved2 = Sect.reserved2; 330296417Sdim Section.Reserved3 = Sect.reserved3; 331249259Sdim} 332249259Sdim 333296417Sdimstatic void getSegment(const MachOObjectFile *Obj, 334296417Sdim const MachOObjectFile::LoadCommandInfo &L, 335296417Sdim MachOSegment &Segment) { 336296417Sdim if (!Obj->is64Bit()) { 337296417Sdim MachO::segment_command SC = Obj->getSegmentLoadCommand(L); 338296417Sdim Segment.CmdName = "LC_SEGMENT"; 339296417Sdim Segment.SegName = SC.segname; 340296417Sdim Segment.cmdsize = SC.cmdsize; 341296417Sdim Segment.vmaddr = SC.vmaddr; 342296417Sdim Segment.vmsize = SC.vmsize; 343296417Sdim Segment.fileoff = SC.fileoff; 344296417Sdim Segment.filesize = SC.filesize; 345296417Sdim Segment.maxprot = SC.maxprot; 346296417Sdim Segment.initprot = SC.initprot; 347296417Sdim Segment.nsects = SC.nsects; 348296417Sdim Segment.flags = SC.flags; 349296417Sdim return; 350296417Sdim } 351296417Sdim MachO::segment_command_64 SC = Obj->getSegment64LoadCommand(L); 352296417Sdim Segment.CmdName = "LC_SEGMENT_64"; 353296417Sdim Segment.SegName = SC.segname; 354296417Sdim Segment.cmdsize = SC.cmdsize; 355296417Sdim Segment.vmaddr = SC.vmaddr; 356296417Sdim Segment.vmsize = SC.vmsize; 357296417Sdim Segment.fileoff = SC.fileoff; 358296417Sdim Segment.filesize = SC.filesize; 359296417Sdim Segment.maxprot = SC.maxprot; 360296417Sdim Segment.initprot = SC.initprot; 361296417Sdim Segment.nsects = SC.nsects; 362296417Sdim Segment.flags = SC.flags; 363296417Sdim} 364249259Sdim 365251662Sdimstatic void getSymbol(const MachOObjectFile *Obj, 366249259Sdim DataRefImpl DRI, 367249259Sdim MachOSymbol &Symbol) { 368251662Sdim if (!Obj->is64Bit()) { 369261991Sdim MachO::nlist Entry = Obj->getSymbolTableEntry(DRI); 370261991Sdim Symbol.StringIndex = Entry.n_strx; 371261991Sdim Symbol.Type = Entry.n_type; 372261991Sdim Symbol.SectionIndex = Entry.n_sect; 373261991Sdim Symbol.Flags = Entry.n_desc; 374261991Sdim Symbol.Value = Entry.n_value; 375251662Sdim return; 376249259Sdim } 377261991Sdim MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); 378261991Sdim Symbol.StringIndex = Entry.n_strx; 379261991Sdim Symbol.Type = Entry.n_type; 380261991Sdim Symbol.SectionIndex = Entry.n_sect; 381261991Sdim Symbol.Flags = Entry.n_desc; 382261991Sdim Symbol.Value = Entry.n_value; 383249259Sdim} 384249259Sdim 385249259Sdimvoid MachODumper::printFileHeaders() { 386280031Sdim DictScope H(W, "MachHeader"); 387280031Sdim if (!Obj->is64Bit()) { 388280031Sdim printFileHeaders(Obj->getHeader()); 389280031Sdim } else { 390280031Sdim printFileHeaders(Obj->getHeader64()); 391280031Sdim W.printHex("Reserved", Obj->getHeader64().reserved); 392280031Sdim } 393249259Sdim} 394249259Sdim 395280031Sdimtemplate<class MachHeader> 396280031Sdimvoid MachODumper::printFileHeaders(const MachHeader &Header) { 397280031Sdim W.printEnum("Magic", Header.magic, makeArrayRef(MachOMagics)); 398280031Sdim W.printEnum("CpuType", Header.cputype, makeArrayRef(MachOHeaderCpuTypes)); 399280031Sdim uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK; 400280031Sdim switch (Header.cputype) { 401280031Sdim case MachO::CPU_TYPE_X86: 402280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX86)); 403280031Sdim break; 404280031Sdim case MachO::CPU_TYPE_X86_64: 405280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX64)); 406280031Sdim break; 407280031Sdim case MachO::CPU_TYPE_ARM: 408280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM)); 409280031Sdim break; 410280031Sdim case MachO::CPU_TYPE_POWERPC: 411280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesPPC)); 412280031Sdim break; 413280031Sdim case MachO::CPU_TYPE_SPARC: 414280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesSPARC)); 415280031Sdim break; 416280031Sdim case MachO::CPU_TYPE_ARM64: 417280031Sdim W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM64)); 418280031Sdim break; 419280031Sdim case MachO::CPU_TYPE_POWERPC64: 420280031Sdim default: 421280031Sdim W.printHex("CpuSubtype", subtype); 422280031Sdim } 423280031Sdim W.printEnum("FileType", Header.filetype, makeArrayRef(MachOHeaderFileTypes)); 424280031Sdim W.printNumber("NumOfLoadCommands", Header.ncmds); 425280031Sdim W.printNumber("SizeOfLoadCommands", Header.sizeofcmds); 426280031Sdim W.printFlags("Flags", Header.flags, makeArrayRef(MachOHeaderFlags)); 427280031Sdim} 428280031Sdim 429249259Sdimvoid MachODumper::printSections() { 430251662Sdim return printSections(Obj); 431251662Sdim} 432251662Sdim 433251662Sdimvoid MachODumper::printSections(const MachOObjectFile *Obj) { 434249259Sdim ListScope Group(W, "Sections"); 435249259Sdim 436249259Sdim int SectionIndex = -1; 437276479Sdim for (const SectionRef &Section : Obj->sections()) { 438249259Sdim ++SectionIndex; 439249259Sdim 440276479Sdim MachOSection MOSection; 441276479Sdim getSection(Obj, Section.getRawDataRefImpl(), MOSection); 442276479Sdim DataRefImpl DR = Section.getRawDataRefImpl(); 443249259Sdim 444249259Sdim StringRef Name; 445296417Sdim error(Section.getName(Name)); 446249259Sdim 447251662Sdim ArrayRef<char> RawName = Obj->getSectionRawName(DR); 448251662Sdim StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); 449251662Sdim ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); 450251662Sdim 451249259Sdim DictScope SectionD(W, "Section"); 452249259Sdim W.printNumber("Index", SectionIndex); 453251662Sdim W.printBinary("Name", Name, RawName); 454251662Sdim W.printBinary("Segment", SegmentName, RawSegmentName); 455276479Sdim W.printHex("Address", MOSection.Address); 456276479Sdim W.printHex("Size", MOSection.Size); 457276479Sdim W.printNumber("Offset", MOSection.Offset); 458276479Sdim W.printNumber("Alignment", MOSection.Alignment); 459276479Sdim W.printHex("RelocationOffset", MOSection.RelocationTableOffset); 460276479Sdim W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries); 461276479Sdim W.printEnum("Type", MOSection.Flags & 0xFF, 462276479Sdim makeArrayRef(MachOSectionAttributes)); 463276479Sdim W.printFlags("Attributes", MOSection.Flags >> 8, 464276479Sdim makeArrayRef(MachOSectionAttributes)); 465276479Sdim W.printHex("Reserved1", MOSection.Reserved1); 466276479Sdim W.printHex("Reserved2", MOSection.Reserved2); 467296417Sdim if (Obj->is64Bit()) 468296417Sdim W.printHex("Reserved3", MOSection.Reserved3); 469249259Sdim 470249259Sdim if (opts::SectionRelocations) { 471249259Sdim ListScope D(W, "Relocations"); 472276479Sdim for (const RelocationRef &Reloc : Section.relocations()) 473276479Sdim printRelocation(Reloc); 474249259Sdim } 475249259Sdim 476249259Sdim if (opts::SectionSymbols) { 477249259Sdim ListScope D(W, "Symbols"); 478276479Sdim for (const SymbolRef &Symbol : Obj->symbols()) { 479280031Sdim if (!Section.containsSymbol(Symbol)) 480249259Sdim continue; 481249259Sdim 482276479Sdim printSymbol(Symbol); 483249259Sdim } 484249259Sdim } 485249259Sdim 486249259Sdim if (opts::SectionData) { 487280031Sdim bool IsBSS = Section.isBSS(); 488280031Sdim if (!IsBSS) { 489280031Sdim StringRef Data; 490296417Sdim error(Section.getContents(Data)); 491249259Sdim 492280031Sdim W.printBinaryBlock("SectionData", Data); 493280031Sdim } 494249259Sdim } 495249259Sdim } 496249259Sdim} 497249259Sdim 498249259Sdimvoid MachODumper::printRelocations() { 499249259Sdim ListScope D(W, "Relocations"); 500249259Sdim 501276479Sdim std::error_code EC; 502276479Sdim for (const SectionRef &Section : Obj->sections()) { 503249259Sdim StringRef Name; 504296417Sdim error(Section.getName(Name)); 505249259Sdim 506249259Sdim bool PrintedGroup = false; 507276479Sdim for (const RelocationRef &Reloc : Section.relocations()) { 508249259Sdim if (!PrintedGroup) { 509249259Sdim W.startLine() << "Section " << Name << " {\n"; 510249259Sdim W.indent(); 511249259Sdim PrintedGroup = true; 512249259Sdim } 513249259Sdim 514276479Sdim printRelocation(Reloc); 515249259Sdim } 516249259Sdim 517249259Sdim if (PrintedGroup) { 518249259Sdim W.unindent(); 519249259Sdim W.startLine() << "}\n"; 520249259Sdim } 521249259Sdim } 522249259Sdim} 523249259Sdim 524276479Sdimvoid MachODumper::printRelocation(const RelocationRef &Reloc) { 525276479Sdim return printRelocation(Obj, Reloc); 526251662Sdim} 527251662Sdim 528251662Sdimvoid MachODumper::printRelocation(const MachOObjectFile *Obj, 529276479Sdim const RelocationRef &Reloc) { 530288943Sdim uint64_t Offset = Reloc.getOffset(); 531249259Sdim SmallString<32> RelocName; 532288943Sdim Reloc.getTypeName(RelocName); 533249259Sdim 534276479Sdim DataRefImpl DR = Reloc.getRawDataRefImpl(); 535261991Sdim MachO::any_relocation_info RE = Obj->getRelocation(DR); 536251662Sdim bool IsScattered = Obj->isRelocationScattered(RE); 537288943Sdim bool IsExtern = !IsScattered && Obj->getPlainRelocationExternal(RE); 538288943Sdim 539288943Sdim StringRef TargetName; 540288943Sdim if (IsExtern) { 541276479Sdim symbol_iterator Symbol = Reloc.getSymbol(); 542276479Sdim if (Symbol != Obj->symbol_end()) { 543288943Sdim ErrorOr<StringRef> TargetNameOrErr = Symbol->getName(); 544296417Sdim error(TargetNameOrErr.getError()); 545288943Sdim TargetName = *TargetNameOrErr; 546288943Sdim } 547288943Sdim } else if (!IsScattered) { 548288943Sdim section_iterator SecI = Obj->getRelocationSection(DR); 549288943Sdim if (SecI != Obj->section_end()) { 550296417Sdim error(SecI->getName(TargetName)); 551288943Sdim } 552276479Sdim } 553288943Sdim if (TargetName.empty()) 554288943Sdim TargetName = "-"; 555251662Sdim 556251662Sdim if (opts::ExpandRelocs) { 557251662Sdim DictScope Group(W, "Relocation"); 558251662Sdim W.printHex("Offset", Offset); 559251662Sdim W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE)); 560251662Sdim W.printNumber("Length", Obj->getAnyRelocationLength(RE)); 561251662Sdim W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); 562288943Sdim if (IsScattered) { 563288943Sdim W.printHex("Value", Obj->getScatteredRelocationValue(RE)); 564288943Sdim } else { 565288943Sdim const char *Kind = IsExtern ? "Symbol" : "Section"; 566288943Sdim W.printNumber(Kind, TargetName, Obj->getPlainRelocationSymbolNum(RE)); 567288943Sdim } 568251662Sdim } else { 569288943Sdim SmallString<32> SymbolNameOrOffset("0x"); 570288943Sdim if (IsScattered) { 571288943Sdim // Scattered relocations don't really have an associated symbol for some 572288943Sdim // reason, even if one exists in the symtab at the correct address. 573288943Sdim SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE)); 574288943Sdim } else { 575288943Sdim SymbolNameOrOffset = TargetName; 576288943Sdim } 577288943Sdim 578251662Sdim raw_ostream& OS = W.startLine(); 579251662Sdim OS << W.hex(Offset) 580251662Sdim << " " << Obj->getAnyRelocationPCRel(RE) 581251662Sdim << " " << Obj->getAnyRelocationLength(RE); 582251662Sdim if (IsScattered) 583251662Sdim OS << " n/a"; 584251662Sdim else 585251662Sdim OS << " " << Obj->getPlainRelocationExternal(RE); 586251662Sdim OS << " " << RelocName 587251662Sdim << " " << IsScattered 588276479Sdim << " " << SymbolNameOrOffset 589251662Sdim << "\n"; 590251662Sdim } 591249259Sdim} 592249259Sdim 593249259Sdimvoid MachODumper::printSymbols() { 594249259Sdim ListScope Group(W, "Symbols"); 595249259Sdim 596276479Sdim for (const SymbolRef &Symbol : Obj->symbols()) { 597276479Sdim printSymbol(Symbol); 598249259Sdim } 599249259Sdim} 600249259Sdim 601249259Sdimvoid MachODumper::printDynamicSymbols() { 602249259Sdim ListScope Group(W, "DynamicSymbols"); 603249259Sdim} 604249259Sdim 605276479Sdimvoid MachODumper::printSymbol(const SymbolRef &Symbol) { 606249259Sdim StringRef SymbolName; 607288943Sdim if (ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName()) 608288943Sdim SymbolName = *SymbolNameOrErr; 609249259Sdim 610276479Sdim MachOSymbol MOSymbol; 611276479Sdim getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); 612249259Sdim 613251662Sdim StringRef SectionName = ""; 614296417Sdim ErrorOr<section_iterator> SecIOrErr = Symbol.getSection(); 615296417Sdim error(SecIOrErr.getError()); 616296417Sdim section_iterator SecI = *SecIOrErr; 617296417Sdim if (SecI != Obj->section_end()) 618276479Sdim error(SecI->getName(SectionName)); 619249259Sdim 620249259Sdim DictScope D(W, "Symbol"); 621276479Sdim W.printNumber("Name", SymbolName, MOSymbol.StringIndex); 622276479Sdim if (MOSymbol.Type & MachO::N_STAB) { 623276479Sdim W.printHex("Type", "SymDebugTable", MOSymbol.Type); 624249259Sdim } else { 625276479Sdim if (MOSymbol.Type & MachO::N_PEXT) 626276479Sdim W.startLine() << "PrivateExtern\n"; 627276479Sdim if (MOSymbol.Type & MachO::N_EXT) 628276479Sdim W.startLine() << "Extern\n"; 629276479Sdim W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE), 630276479Sdim makeArrayRef(MachOSymbolTypes)); 631249259Sdim } 632276479Sdim W.printHex("Section", SectionName, MOSymbol.SectionIndex); 633276479Sdim W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0xF), 634276479Sdim makeArrayRef(MachOSymbolRefTypes)); 635276479Sdim W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0xF), 636276479Sdim makeArrayRef(MachOSymbolFlags)); 637276479Sdim W.printHex("Value", MOSymbol.Value); 638249259Sdim} 639249259Sdim 640249259Sdimvoid MachODumper::printUnwindInfo() { 641249259Sdim W.startLine() << "UnwindInfo not implemented.\n"; 642249259Sdim} 643288943Sdim 644288943Sdimvoid MachODumper::printStackMap() const { 645288943Sdim object::SectionRef StackMapSection; 646288943Sdim for (auto Sec : Obj->sections()) { 647288943Sdim StringRef Name; 648288943Sdim Sec.getName(Name); 649288943Sdim if (Name == "__llvm_stackmaps") { 650288943Sdim StackMapSection = Sec; 651288943Sdim break; 652288943Sdim } 653288943Sdim } 654288943Sdim 655288943Sdim if (StackMapSection == object::SectionRef()) 656288943Sdim return; 657288943Sdim 658288943Sdim StringRef StackMapContents; 659288943Sdim StackMapSection.getContents(StackMapContents); 660288943Sdim ArrayRef<uint8_t> StackMapContentsArray( 661288943Sdim reinterpret_cast<const uint8_t*>(StackMapContents.data()), 662288943Sdim StackMapContents.size()); 663288943Sdim 664288943Sdim if (Obj->isLittleEndian()) 665288943Sdim prettyPrintStackMap( 666288943Sdim llvm::outs(), 667288943Sdim StackMapV1Parser<support::little>(StackMapContentsArray)); 668288943Sdim else 669288943Sdim prettyPrintStackMap(llvm::outs(), 670288943Sdim StackMapV1Parser<support::big>(StackMapContentsArray)); 671288943Sdim} 672296417Sdim 673296417Sdimvoid MachODumper::printMachODataInCode() { 674296417Sdim for (const auto &Load : Obj->load_commands()) { 675296417Sdim if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { 676296417Sdim MachO::linkedit_data_command LLC = Obj->getLinkeditDataLoadCommand(Load); 677296417Sdim DictScope Group(W, "DataInCode"); 678296417Sdim W.printNumber("Data offset", LLC.dataoff); 679296417Sdim W.printNumber("Data size", LLC.datasize); 680296417Sdim ListScope D(W, "Data entries"); 681296417Sdim unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); 682296417Sdim for (unsigned i = 0; i < NumRegions; ++i) { 683296417Sdim MachO::data_in_code_entry DICE = Obj->getDataInCodeTableEntry( 684296417Sdim LLC.dataoff, i); 685296417Sdim DictScope Group(W, "Entry"); 686296417Sdim W.printNumber("Index", i); 687296417Sdim W.printNumber("Offset", DICE.offset); 688296417Sdim W.printNumber("Length", DICE.length); 689296417Sdim W.printNumber("Kind", DICE.kind); 690296417Sdim } 691296417Sdim } 692296417Sdim } 693296417Sdim} 694296417Sdim 695296417Sdimvoid MachODumper::printMachOVersionMin() { 696296417Sdim for (const auto &Load : Obj->load_commands()) { 697296417Sdim StringRef Cmd; 698296417Sdim switch (Load.C.cmd) { 699296417Sdim case MachO::LC_VERSION_MIN_MACOSX: 700296417Sdim Cmd = "LC_VERSION_MIN_MACOSX"; 701296417Sdim break; 702296417Sdim case MachO::LC_VERSION_MIN_IPHONEOS: 703296417Sdim Cmd = "LC_VERSION_MIN_IPHONEOS"; 704296417Sdim break; 705296417Sdim case MachO::LC_VERSION_MIN_TVOS: 706296417Sdim Cmd = "LC_VERSION_MIN_TVOS"; 707296417Sdim break; 708296417Sdim case MachO::LC_VERSION_MIN_WATCHOS: 709296417Sdim Cmd = "LC_VERSION_MIN_WATCHOS"; 710296417Sdim break; 711296417Sdim default: 712296417Sdim continue; 713296417Sdim } 714296417Sdim 715296417Sdim MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load); 716296417Sdim DictScope Group(W, "MinVersion"); 717296417Sdim W.printString("Cmd", Cmd); 718296417Sdim W.printNumber("Size", VMC.cmdsize); 719296417Sdim SmallString<32> Version; 720296417Sdim Version = utostr(MachOObjectFile::getVersionMinMajor(VMC, false)) + "." + 721296417Sdim utostr(MachOObjectFile::getVersionMinMinor(VMC, false)); 722296417Sdim uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, false); 723296417Sdim if (Update != 0) 724296417Sdim Version += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, false)); 725296417Sdim W.printString("Version", Version); 726296417Sdim SmallString<32> SDK; 727296417Sdim if (VMC.sdk == 0) 728296417Sdim SDK = "n/a"; 729296417Sdim else { 730296417Sdim SDK = utostr(MachOObjectFile::getVersionMinMajor(VMC, true)) + "." + 731296417Sdim utostr(MachOObjectFile::getVersionMinMinor(VMC, true)); 732296417Sdim uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, true); 733296417Sdim if (Update != 0) 734296417Sdim SDK += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, true)); 735296417Sdim } 736296417Sdim W.printString("SDK", SDK); 737296417Sdim } 738296417Sdim} 739296417Sdim 740296417Sdimvoid MachODumper::printMachODysymtab() { 741296417Sdim for (const auto &Load : Obj->load_commands()) { 742296417Sdim if (Load.C.cmd == MachO::LC_DYSYMTAB) { 743296417Sdim MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); 744296417Sdim DictScope Group(W, "Dysymtab"); 745296417Sdim W.printNumber("ilocalsym", DLC.ilocalsym); 746296417Sdim W.printNumber("nlocalsym", DLC.nlocalsym); 747296417Sdim W.printNumber("iextdefsym", DLC.iextdefsym); 748296417Sdim W.printNumber("nextdefsym", DLC.nextdefsym); 749296417Sdim W.printNumber("iundefsym", DLC.iundefsym); 750296417Sdim W.printNumber("nundefsym", DLC.nundefsym); 751296417Sdim W.printNumber("tocoff", DLC.tocoff); 752296417Sdim W.printNumber("ntoc", DLC.ntoc); 753296417Sdim W.printNumber("modtaboff", DLC.modtaboff); 754296417Sdim W.printNumber("nmodtab", DLC.nmodtab); 755296417Sdim W.printNumber("extrefsymoff", DLC.extrefsymoff); 756296417Sdim W.printNumber("nextrefsyms", DLC.nextrefsyms); 757296417Sdim W.printNumber("indirectsymoff", DLC.indirectsymoff); 758296417Sdim W.printNumber("nindirectsyms", DLC.nindirectsyms); 759296417Sdim W.printNumber("extreloff", DLC.extreloff); 760296417Sdim W.printNumber("nextrel", DLC.nextrel); 761296417Sdim W.printNumber("locreloff", DLC.locreloff); 762296417Sdim W.printNumber("nlocrel", DLC.nlocrel); 763296417Sdim } 764296417Sdim } 765296417Sdim} 766296417Sdim 767296417Sdimvoid MachODumper::printMachOSegment() { 768296417Sdim for (const auto &Load : Obj->load_commands()) { 769296417Sdim if (Load.C.cmd == MachO::LC_SEGMENT || Load.C.cmd == MachO::LC_SEGMENT_64) { 770296417Sdim MachOSegment MOSegment; 771296417Sdim getSegment(Obj, Load, MOSegment); 772296417Sdim DictScope Group(W, "Segment"); 773296417Sdim W.printString("Cmd", MOSegment.CmdName); 774296417Sdim W.printString("Name", MOSegment.SegName); 775296417Sdim W.printNumber("Size", MOSegment.cmdsize); 776296417Sdim W.printHex("vmaddr", MOSegment.vmaddr); 777296417Sdim W.printHex("vmsize", MOSegment.vmsize); 778296417Sdim W.printNumber("fileoff", MOSegment.fileoff); 779296417Sdim W.printNumber("filesize", MOSegment.filesize); 780296417Sdim W.printString("maxprot", getMask(MOSegment.maxprot)); 781296417Sdim W.printString("initprot", getMask(MOSegment.initprot)); 782296417Sdim W.printNumber("nsects", MOSegment.nsects); 783296417Sdim W.printHex("flags", MOSegment.flags); 784296417Sdim } 785296417Sdim } 786296417Sdim} 787296417Sdim 788296417Sdimvoid MachODumper::printMachOIndirectSymbols() { 789296417Sdim for (const auto &Load : Obj->load_commands()) { 790296417Sdim if (Load.C.cmd == MachO::LC_DYSYMTAB) { 791296417Sdim MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); 792296417Sdim DictScope Group(W, "Indirect Symbols"); 793296417Sdim W.printNumber("Number", DLC.nindirectsyms); 794296417Sdim ListScope D(W, "Symbols"); 795296417Sdim for (unsigned i = 0; i < DLC.nindirectsyms; ++i) { 796296417Sdim DictScope Group(W, "Entry"); 797296417Sdim W.printNumber("Entry Index", i); 798296417Sdim W.printHex("Symbol Index", Obj->getIndirectSymbolTableEntry(DLC, i)); 799296417Sdim } 800296417Sdim } 801296417Sdim } 802296417Sdim} 803296417Sdim 804296417Sdimvoid MachODumper::printMachOLinkerOptions() { 805296417Sdim for (const auto &Load : Obj->load_commands()) { 806296417Sdim if (Load.C.cmd == MachO::LC_LINKER_OPTION) { 807296417Sdim MachO::linker_option_command LOLC = Obj->getLinkerOptionLoadCommand(Load); 808296417Sdim DictScope Group(W, "Linker Options"); 809296417Sdim W.printNumber("Size", LOLC.cmdsize); 810296417Sdim ListScope D(W, "Strings"); 811296417Sdim uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command); 812296417Sdim const char *P = Load.Ptr + sizeof(MachO::linker_option_command); 813296417Sdim StringRef Data(P, DataSize); 814296417Sdim for (unsigned i = 0; i < LOLC.count; ++i) { 815296417Sdim std::pair<StringRef,StringRef> Split = Data.split('\0'); 816296417Sdim W.printString("Value", Split.first); 817296417Sdim Data = Split.second; 818296417Sdim } 819296417Sdim } 820296417Sdim } 821296417Sdim} 822