brintos

brintos / llvm-project-archived public Read only

0
0
Text · 386.7 KiB · f633ed5 Raw
10585 lines · cpp
1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the MachO-specific dumper for llvm-objdump.10//11//===----------------------------------------------------------------------===//12 13#include "MachODump.h"14 15#include "ObjdumpOptID.h"16#include "SourcePrinter.h"17#include "llvm-objdump.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/BinaryFormat/MachO.h"21#include "llvm/Config/config.h"22#include "llvm/DebugInfo/DIContext.h"23#include "llvm/DebugInfo/DWARF/DWARFContext.h"24#include "llvm/Demangle/Demangle.h"25#include "llvm/MC/MCAsmInfo.h"26#include "llvm/MC/MCContext.h"27#include "llvm/MC/MCDisassembler/MCDisassembler.h"28#include "llvm/MC/MCInst.h"29#include "llvm/MC/MCInstPrinter.h"30#include "llvm/MC/MCInstrDesc.h"31#include "llvm/MC/MCInstrInfo.h"32#include "llvm/MC/MCRegisterInfo.h"33#include "llvm/MC/MCSubtargetInfo.h"34#include "llvm/MC/MCTargetOptions.h"35#include "llvm/MC/TargetRegistry.h"36#include "llvm/Object/MachO.h"37#include "llvm/Object/MachOUniversal.h"38#include "llvm/Option/ArgList.h"39#include "llvm/Support/Casting.h"40#include "llvm/Support/Debug.h"41#include "llvm/Support/Endian.h"42#include "llvm/Support/Format.h"43#include "llvm/Support/FormattedStream.h"44#include "llvm/Support/LEB128.h"45#include "llvm/Support/MemoryBuffer.h"46#include "llvm/Support/WithColor.h"47#include "llvm/Support/raw_ostream.h"48#include "llvm/TargetParser/Triple.h"49#include <algorithm>50#include <cstring>51#include <system_error>52 53using namespace llvm;54using namespace llvm::object;55using namespace llvm::objdump;56 57bool objdump::FirstPrivateHeader;58bool objdump::ExportsTrie;59bool objdump::Rebase;60bool objdump::Rpaths;61bool objdump::Bind;62bool objdump::LazyBind;63bool objdump::WeakBind;64static bool UseDbg;65static std::string DSYMFile;66bool objdump::FullLeadingAddr;67bool objdump::LeadingHeaders;68bool objdump::UniversalHeaders;69static bool ArchiveMemberOffsets;70bool objdump::IndirectSymbols;71bool objdump::DataInCode;72FunctionStartsMode objdump::FunctionStartsType =73    objdump::FunctionStartsMode::None;74bool objdump::LinkOptHints;75bool objdump::InfoPlist;76bool objdump::ChainedFixups;77bool objdump::DyldInfo;78bool objdump::DylibsUsed;79bool objdump::DylibId;80bool objdump::Verbose;81bool objdump::ObjcMetaData;82std::string objdump::DisSymName;83bool objdump::SymbolicOperands;84static std::vector<std::string> ArchFlags;85 86static bool ArchAll = false;87static std::string ThumbTripleName;88 89static StringRef ordinalName(const object::MachOObjectFile *, int);90 91void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {92  FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);93  ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);94  Rebase = InputArgs.hasArg(OBJDUMP_rebase);95  Rpaths = InputArgs.hasArg(OBJDUMP_rpaths);96  Bind = InputArgs.hasArg(OBJDUMP_bind);97  LazyBind = InputArgs.hasArg(OBJDUMP_lazy_bind);98  WeakBind = InputArgs.hasArg(OBJDUMP_weak_bind);99  UseDbg = InputArgs.hasArg(OBJDUMP_g);100  DSYMFile = InputArgs.getLastArgValue(OBJDUMP_dsym_EQ).str();101  FullLeadingAddr = InputArgs.hasArg(OBJDUMP_full_leading_addr);102  LeadingHeaders = !InputArgs.hasArg(OBJDUMP_no_leading_headers);103  UniversalHeaders = InputArgs.hasArg(OBJDUMP_universal_headers);104  ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);105  IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);106  DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);107  if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {108    FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())109                             .Case("addrs", FunctionStartsMode::Addrs)110                             .Case("names", FunctionStartsMode::Names)111                             .Case("both", FunctionStartsMode::Both)112                             .Default(FunctionStartsMode::None);113    if (FunctionStartsType == FunctionStartsMode::None)114      invalidArgValue(A);115  }116  LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);117  InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);118  ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);119  DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);120  DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);121  DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);122  Verbose = !InputArgs.hasArg(OBJDUMP_non_verbose);123  ObjcMetaData = InputArgs.hasArg(OBJDUMP_objc_meta_data);124  DisSymName = InputArgs.getLastArgValue(OBJDUMP_dis_symname).str();125  SymbolicOperands = !InputArgs.hasArg(OBJDUMP_no_symbolic_operands);126  ArchFlags = InputArgs.getAllArgValues(OBJDUMP_arch_EQ);127}128 129static const Target *GetTarget(const MachOObjectFile *MachOObj,130                               const char **McpuDefault,131                               const Target **ThumbTarget,132                               Triple &ThumbTriple) {133  // Figure out the target triple.134  Triple TT(TripleName);135  if (TripleName.empty()) {136    TT = MachOObj->getArchTriple(McpuDefault);137    TripleName = TT.str();138  }139 140  if (TT.getArch() == Triple::arm) {141    // We've inferred a 32-bit ARM target from the object file. All MachO CPUs142    // that support ARM are also capable of Thumb mode.143    std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();144    ThumbTriple = TT;145    ThumbTriple.setArchName(ThumbName);146    ThumbTripleName = ThumbTriple.str();147  }148 149  // Get the target specific parser.150  std::string Error;151  const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);152  if (TheTarget && ThumbTripleName.empty())153    return TheTarget;154 155  *ThumbTarget = TargetRegistry::lookupTarget(ThumbTriple, Error);156  if (*ThumbTarget)157    return TheTarget;158 159  WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";160  if (!TheTarget)161    errs() << TripleName;162  else163    errs() << ThumbTripleName;164  errs() << "', see --version and --triple.\n";165  return nullptr;166}167 168namespace {169struct SymbolSorter {170  bool operator()(const SymbolRef &A, const SymbolRef &B) {171    Expected<SymbolRef::Type> ATypeOrErr = A.getType();172    if (!ATypeOrErr)173      reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());174    SymbolRef::Type AType = *ATypeOrErr;175    Expected<SymbolRef::Type> BTypeOrErr = B.getType();176    if (!BTypeOrErr)177      reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());178    SymbolRef::Type BType = *BTypeOrErr;179    uint64_t AAddr =180        (AType != SymbolRef::ST_Function) ? 0 : cantFail(A.getValue());181    uint64_t BAddr =182        (BType != SymbolRef::ST_Function) ? 0 : cantFail(B.getValue());183    return AAddr < BAddr;184  }185};186 187class MachODumper : public Dumper {188  const object::MachOObjectFile &Obj;189 190public:191  MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}192  void printPrivateHeaders() override;193};194} // namespace195 196std::unique_ptr<Dumper>197objdump::createMachODumper(const object::MachOObjectFile &Obj) {198  return std::make_unique<MachODumper>(Obj);199}200 201// Types for the storted data in code table that is built before disassembly202// and the predicate function to sort them.203typedef std::pair<uint64_t, DiceRef> DiceTableEntry;204typedef std::vector<DiceTableEntry> DiceTable;205typedef DiceTable::iterator dice_table_iterator;206 207// This is used to search for a data in code table entry for the PC being208// disassembled.  The j parameter has the PC in j.first.  A single data in code209// table entry can cover many bytes for each of its Kind's.  So if the offset,210// aka the i.first value, of the data in code table entry plus its Length211// covers the PC being searched for this will return true.  If not it will212// return false.213static bool compareDiceTableEntries(const DiceTableEntry &i,214                                    const DiceTableEntry &j) {215  uint16_t Length;216  i.second.getLength(Length);217 218  return j.first >= i.first && j.first < i.first + Length;219}220 221static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,222                               unsigned short Kind) {223  uint32_t Value, Size = 1;224 225  switch (Kind) {226  default:227  case MachO::DICE_KIND_DATA:228    if (Length >= 4) {229      if (ShowRawInsn)230        dumpBytes(ArrayRef(bytes, 4), outs());231      Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];232      outs() << "\t.long " << Value;233      Size = 4;234    } else if (Length >= 2) {235      if (ShowRawInsn)236        dumpBytes(ArrayRef(bytes, 2), outs());237      Value = bytes[1] << 8 | bytes[0];238      outs() << "\t.short " << Value;239      Size = 2;240    } else {241      if (ShowRawInsn)242        dumpBytes(ArrayRef(bytes, 2), outs());243      Value = bytes[0];244      outs() << "\t.byte " << Value;245      Size = 1;246    }247    if (Kind == MachO::DICE_KIND_DATA)248      outs() << "\t@ KIND_DATA\n";249    else250      outs() << "\t@ data in code kind = " << Kind << "\n";251    break;252  case MachO::DICE_KIND_JUMP_TABLE8:253    if (ShowRawInsn)254      dumpBytes(ArrayRef(bytes, 1), outs());255    Value = bytes[0];256    outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";257    Size = 1;258    break;259  case MachO::DICE_KIND_JUMP_TABLE16:260    if (ShowRawInsn)261      dumpBytes(ArrayRef(bytes, 2), outs());262    Value = bytes[1] << 8 | bytes[0];263    outs() << "\t.short " << format("%5u", Value & 0xffff)264           << "\t@ KIND_JUMP_TABLE16\n";265    Size = 2;266    break;267  case MachO::DICE_KIND_JUMP_TABLE32:268  case MachO::DICE_KIND_ABS_JUMP_TABLE32:269    if (ShowRawInsn)270      dumpBytes(ArrayRef(bytes, 4), outs());271    Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];272    outs() << "\t.long " << Value;273    if (Kind == MachO::DICE_KIND_JUMP_TABLE32)274      outs() << "\t@ KIND_JUMP_TABLE32\n";275    else276      outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";277    Size = 4;278    break;279  }280  return Size;281}282 283static void getSectionsAndSymbols(MachOObjectFile *MachOObj,284                                  std::vector<SectionRef> &Sections,285                                  std::vector<SymbolRef> &Symbols,286                                  SmallVectorImpl<uint64_t> &FoundFns,287                                  uint64_t &BaseSegmentAddress) {288  const StringRef FileName = MachOObj->getFileName();289  for (const SymbolRef &Symbol : MachOObj->symbols()) {290    StringRef SymName = unwrapOrError(Symbol.getName(), FileName);291    if (!SymName.starts_with("ltmp"))292      Symbols.push_back(Symbol);293  }294 295  append_range(Sections, MachOObj->sections());296 297  bool BaseSegmentAddressSet = false;298  for (const auto &Command : MachOObj->load_commands()) {299    if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {300      // We found a function starts segment, parse the addresses for later301      // consumption.302      MachO::linkedit_data_command LLC =303          MachOObj->getLinkeditDataLoadCommand(Command);304 305      MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);306    } else if (Command.C.cmd == MachO::LC_SEGMENT) {307      MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);308      StringRef SegName = SLC.segname;309      if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {310        BaseSegmentAddressSet = true;311        BaseSegmentAddress = SLC.vmaddr;312      }313    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {314      MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command);315      StringRef SegName = SLC.segname;316      if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {317        BaseSegmentAddressSet = true;318        BaseSegmentAddress = SLC.vmaddr;319      }320    }321  }322}323 324static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,325                                 DiceTable &Dices, uint64_t &InstSize) {326  // Check the data in code table here to see if this is data not an327  // instruction to be disassembled.328  DiceTable Dice;329  Dice.push_back(std::make_pair(PC, DiceRef()));330  dice_table_iterator DTI =331      std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),332                  compareDiceTableEntries);333  if (DTI != Dices.end()) {334    uint16_t Length;335    DTI->second.getLength(Length);336    uint16_t Kind;337    DTI->second.getKind(Kind);338    InstSize = DumpDataInCode(bytes, Length, Kind);339    if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&340        (PC == (DTI->first + Length - 1)) && (Length & 1))341      InstSize++;342    return true;343  }344  return false;345}346 347static void printRelocationTargetName(const MachOObjectFile *O,348                                      const MachO::any_relocation_info &RE,349                                      raw_string_ostream &Fmt) {350  // Target of a scattered relocation is an address.  In the interest of351  // generating pretty output, scan through the symbol table looking for a352  // symbol that aligns with that address.  If we find one, print it.353  // Otherwise, we just print the hex address of the target.354  const StringRef FileName = O->getFileName();355  if (O->isRelocationScattered(RE)) {356    uint32_t Val = O->getPlainRelocationSymbolNum(RE);357 358    for (const SymbolRef &Symbol : O->symbols()) {359      uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);360      if (Addr != Val)361        continue;362      Fmt << unwrapOrError(Symbol.getName(), FileName);363      return;364    }365 366    // If we couldn't find a symbol that this relocation refers to, try367    // to find a section beginning instead.368    for (const SectionRef &Section : ToolSectionFilter(*O)) {369      uint64_t Addr = Section.getAddress();370      if (Addr != Val)371        continue;372      StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName());373      Fmt << NameOrErr;374      return;375    }376 377    Fmt << format("0x%x", Val);378    return;379  }380 381  StringRef S;382  bool isExtern = O->getPlainRelocationExternal(RE);383  uint64_t Val = O->getPlainRelocationSymbolNum(RE);384 385  if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&386      (O->getArch() == Triple::aarch64 || O->getArch() == Triple::aarch64_be)) {387    Fmt << format("0x%0" PRIx64, Val);388    return;389  }390 391  if (isExtern) {392    symbol_iterator SI = O->symbol_begin();393    std::advance(SI, Val);394    S = unwrapOrError(SI->getName(), FileName);395  } else {396    section_iterator SI = O->section_begin();397    // Adjust for the fact that sections are 1-indexed.398    if (Val == 0) {399      Fmt << "0 (?,?)";400      return;401    }402    uint32_t I = Val - 1;403    while (I != 0 && SI != O->section_end()) {404      --I;405      std::advance(SI, 1);406    }407    if (SI == O->section_end()) {408      Fmt << Val << " (?,?)";409    } else {410      if (Expected<StringRef> NameOrErr = SI->getName())411        S = *NameOrErr;412      else413        consumeError(NameOrErr.takeError());414    }415  }416 417  Fmt << S;418}419 420Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,421                                             const RelocationRef &RelRef,422                                             SmallVectorImpl<char> &Result) {423  DataRefImpl Rel = RelRef.getRawDataRefImpl();424  MachO::any_relocation_info RE = Obj->getRelocation(Rel);425 426  unsigned Arch = Obj->getArch();427 428  std::string FmtBuf;429  raw_string_ostream Fmt(FmtBuf);430  unsigned Type = Obj->getAnyRelocationType(RE);431  bool IsPCRel = Obj->getAnyRelocationPCRel(RE);432 433  // Determine any addends that should be displayed with the relocation.434  // These require decoding the relocation type, which is triple-specific.435 436  // X86_64 has entirely custom relocation types.437  if (Arch == Triple::x86_64) {438    switch (Type) {439    case MachO::X86_64_RELOC_GOT_LOAD:440    case MachO::X86_64_RELOC_GOT: {441      printRelocationTargetName(Obj, RE, Fmt);442      Fmt << "@GOT";443      if (IsPCRel)444        Fmt << "PCREL";445      break;446    }447    case MachO::X86_64_RELOC_SUBTRACTOR: {448      DataRefImpl RelNext = Rel;449      Obj->moveRelocationNext(RelNext);450      MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);451 452      // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type453      // X86_64_RELOC_UNSIGNED.454      // NOTE: Scattered relocations don't exist on x86_64.455      unsigned RType = Obj->getAnyRelocationType(RENext);456      if (RType != MachO::X86_64_RELOC_UNSIGNED)457        reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "458                                        "X86_64_RELOC_SUBTRACTOR.");459 460      // The X86_64_RELOC_UNSIGNED contains the minuend symbol;461      // X86_64_RELOC_SUBTRACTOR contains the subtrahend.462      printRelocationTargetName(Obj, RENext, Fmt);463      Fmt << "-";464      printRelocationTargetName(Obj, RE, Fmt);465      break;466    }467    case MachO::X86_64_RELOC_TLV:468      printRelocationTargetName(Obj, RE, Fmt);469      Fmt << "@TLV";470      if (IsPCRel)471        Fmt << "P";472      break;473    case MachO::X86_64_RELOC_SIGNED_1:474      printRelocationTargetName(Obj, RE, Fmt);475      Fmt << "-1";476      break;477    case MachO::X86_64_RELOC_SIGNED_2:478      printRelocationTargetName(Obj, RE, Fmt);479      Fmt << "-2";480      break;481    case MachO::X86_64_RELOC_SIGNED_4:482      printRelocationTargetName(Obj, RE, Fmt);483      Fmt << "-4";484      break;485    default:486      printRelocationTargetName(Obj, RE, Fmt);487      break;488    }489    // X86 and ARM share some relocation types in common.490  } else if (Arch == Triple::x86 || Arch == Triple::arm ||491             Arch == Triple::ppc) {492    // Generic relocation types...493    switch (Type) {494    case MachO::GENERIC_RELOC_PAIR: // prints no info495      return Error::success();496    case MachO::GENERIC_RELOC_SECTDIFF: {497      DataRefImpl RelNext = Rel;498      Obj->moveRelocationNext(RelNext);499      MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);500 501      // X86 sect diff's must be followed by a relocation of type502      // GENERIC_RELOC_PAIR.503      unsigned RType = Obj->getAnyRelocationType(RENext);504 505      if (RType != MachO::GENERIC_RELOC_PAIR)506        reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "507                                        "GENERIC_RELOC_SECTDIFF.");508 509      printRelocationTargetName(Obj, RE, Fmt);510      Fmt << "-";511      printRelocationTargetName(Obj, RENext, Fmt);512      break;513    }514    }515 516    if (Arch == Triple::x86 || Arch == Triple::ppc) {517      switch (Type) {518      case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {519        DataRefImpl RelNext = Rel;520        Obj->moveRelocationNext(RelNext);521        MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);522 523        // X86 sect diff's must be followed by a relocation of type524        // GENERIC_RELOC_PAIR.525        unsigned RType = Obj->getAnyRelocationType(RENext);526        if (RType != MachO::GENERIC_RELOC_PAIR)527          reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "528                                          "GENERIC_RELOC_LOCAL_SECTDIFF.");529 530        printRelocationTargetName(Obj, RE, Fmt);531        Fmt << "-";532        printRelocationTargetName(Obj, RENext, Fmt);533        break;534      }535      case MachO::GENERIC_RELOC_TLV: {536        printRelocationTargetName(Obj, RE, Fmt);537        Fmt << "@TLV";538        if (IsPCRel)539          Fmt << "P";540        break;541      }542      default:543        printRelocationTargetName(Obj, RE, Fmt);544      }545    } else { // ARM-specific relocations546      switch (Type) {547      case MachO::ARM_RELOC_HALF:548      case MachO::ARM_RELOC_HALF_SECTDIFF: {549        // Half relocations steal a bit from the length field to encode550        // whether this is an upper16 or a lower16 relocation.551        bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;552 553        if (isUpper)554          Fmt << ":upper16:(";555        else556          Fmt << ":lower16:(";557        printRelocationTargetName(Obj, RE, Fmt);558 559        DataRefImpl RelNext = Rel;560        Obj->moveRelocationNext(RelNext);561        MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);562 563        // ARM half relocs must be followed by a relocation of type564        // ARM_RELOC_PAIR.565        unsigned RType = Obj->getAnyRelocationType(RENext);566        if (RType != MachO::ARM_RELOC_PAIR)567          reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "568                                          "ARM_RELOC_HALF");569 570        // NOTE: The half of the target virtual address is stashed in the571        // address field of the secondary relocation, but we can't reverse572        // engineer the constant offset from it without decoding the movw/movt573        // instruction to find the other half in its immediate field.574 575        // ARM_RELOC_HALF_SECTDIFF encodes the second section in the576        // symbol/section pointer of the follow-on relocation.577        if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {578          Fmt << "-";579          printRelocationTargetName(Obj, RENext, Fmt);580        }581 582        Fmt << ")";583        break;584      }585      default: {586        printRelocationTargetName(Obj, RE, Fmt);587      }588      }589    }590  } else591    printRelocationTargetName(Obj, RE, Fmt);592 593  Fmt.flush();594  Result.append(FmtBuf.begin(), FmtBuf.end());595  return Error::success();596}597 598static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,599                                     uint32_t n, uint32_t count,600                                     uint32_t stride, uint64_t addr) {601  MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();602  uint32_t nindirectsyms = Dysymtab.nindirectsyms;603  if (n > nindirectsyms)604    outs() << " (entries start past the end of the indirect symbol "605              "table) (reserved1 field greater than the table size)";606  else if (n + count > nindirectsyms)607    outs() << " (entries extends past the end of the indirect symbol "608              "table)";609  outs() << "\n";610  uint32_t cputype = O->getHeader().cputype;611  if (cputype & MachO::CPU_ARCH_ABI64)612    outs() << "address            index";613  else614    outs() << "address    index";615  if (verbose)616    outs() << " name\n";617  else618    outs() << "\n";619  for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {620    if (cputype & MachO::CPU_ARCH_ABI64)621      outs() << format("0x%016" PRIx64, addr + j * stride) << " ";622    else623      outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";624    MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();625    uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);626    if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {627      outs() << "LOCAL\n";628      continue;629    }630    if (indirect_symbol ==631        (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {632      outs() << "LOCAL ABSOLUTE\n";633      continue;634    }635    if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {636      outs() << "ABSOLUTE\n";637      continue;638    }639    outs() << format("%5u ", indirect_symbol);640    if (verbose) {641      MachO::symtab_command Symtab = O->getSymtabLoadCommand();642      if (indirect_symbol < Symtab.nsyms) {643        symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);644        SymbolRef Symbol = *Sym;645        outs() << unwrapOrError(Symbol.getName(), O->getFileName());646      } else {647        outs() << "?";648      }649    }650    outs() << "\n";651  }652}653 654static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {655  for (const auto &Load : O->load_commands()) {656    if (Load.C.cmd == MachO::LC_SEGMENT_64) {657      MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);658      for (unsigned J = 0; J < Seg.nsects; ++J) {659        MachO::section_64 Sec = O->getSection64(Load, J);660        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;661        if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||662            section_type == MachO::S_LAZY_SYMBOL_POINTERS ||663            section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||664            section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||665            section_type == MachO::S_SYMBOL_STUBS) {666          uint32_t stride;667          if (section_type == MachO::S_SYMBOL_STUBS)668            stride = Sec.reserved2;669          else670            stride = 8;671          if (stride == 0) {672            outs() << "Can't print indirect symbols for (" << Sec.segname << ","673                   << Sec.sectname << ") "674                   << "(size of stubs in reserved2 field is zero)\n";675            continue;676          }677          uint32_t count = Sec.size / stride;678          outs() << "Indirect symbols for (" << Sec.segname << ","679                 << Sec.sectname << ") " << count << " entries";680          uint32_t n = Sec.reserved1;681          PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);682        }683      }684    } else if (Load.C.cmd == MachO::LC_SEGMENT) {685      MachO::segment_command Seg = O->getSegmentLoadCommand(Load);686      for (unsigned J = 0; J < Seg.nsects; ++J) {687        MachO::section Sec = O->getSection(Load, J);688        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;689        if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||690            section_type == MachO::S_LAZY_SYMBOL_POINTERS ||691            section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||692            section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||693            section_type == MachO::S_SYMBOL_STUBS) {694          uint32_t stride;695          if (section_type == MachO::S_SYMBOL_STUBS)696            stride = Sec.reserved2;697          else698            stride = 4;699          if (stride == 0) {700            outs() << "Can't print indirect symbols for (" << Sec.segname << ","701                   << Sec.sectname << ") "702                   << "(size of stubs in reserved2 field is zero)\n";703            continue;704          }705          uint32_t count = Sec.size / stride;706          outs() << "Indirect symbols for (" << Sec.segname << ","707                 << Sec.sectname << ") " << count << " entries";708          uint32_t n = Sec.reserved1;709          PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);710        }711      }712    }713  }714}715 716static void PrintRType(const uint64_t cputype, const unsigned r_type) {717  static char const *generic_r_types[] = {718    "VANILLA ", "PAIR    ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV     ",719    "  6 (?) ", "  7 (?) ", "  8 (?) ", "  9 (?) ", " 10 (?) ", " 11 (?) ",720    " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "721  };722  static char const *x86_64_r_types[] = {723    "UNSIGND ", "SIGNED  ", "BRANCH  ", "GOT_LD  ", "GOT     ", "SUB     ",724    "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV     ", " 10 (?) ", " 11 (?) ",725    " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "726  };727  static char const *arm_r_types[] = {728    "VANILLA ", "PAIR    ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",729    "BR24    ", "T_BR22  ", "T_BR32  ", "HALF    ", "HALFDIF ",730    " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "731  };732  static char const *arm64_r_types[] = {733    "UNSIGND ", "SUB     ", "BR26    ", "PAGE21  ", "PAGOF12 ",734    "GOTLDP  ", "GOTLDPOF", "PTRTGOT ", "TLVLDP  ", "TLVLDPOF",735    "ADDEND  ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "736  };737 738  if (r_type > 0xf){739    outs() << format("%-7u", r_type) << " ";740    return;741  }742  switch (cputype) {743    case MachO::CPU_TYPE_I386:744      outs() << generic_r_types[r_type];745      break;746    case MachO::CPU_TYPE_X86_64:747      outs() << x86_64_r_types[r_type];748      break;749    case MachO::CPU_TYPE_ARM:750      outs() << arm_r_types[r_type];751      break;752    case MachO::CPU_TYPE_ARM64:753    case MachO::CPU_TYPE_ARM64_32:754      outs() << arm64_r_types[r_type];755      break;756    default:757      outs() << format("%-7u ", r_type);758  }759}760 761static void PrintRLength(const uint64_t cputype, const unsigned r_type,762                         const unsigned r_length, const bool previous_arm_half){763  if (cputype == MachO::CPU_TYPE_ARM &&764      (r_type == MachO::ARM_RELOC_HALF ||765       r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {766    if ((r_length & 0x1) == 0)767      outs() << "lo/";768    else769      outs() << "hi/";770    if ((r_length & 0x1) == 0)771      outs() << "arm ";772    else773      outs() << "thm ";774  } else {775    switch (r_length) {776      case 0:777        outs() << "byte   ";778        break;779      case 1:780        outs() << "word   ";781        break;782      case 2:783        outs() << "long   ";784        break;785      case 3:786        if (cputype == MachO::CPU_TYPE_X86_64)787          outs() << "quad   ";788        else789          outs() << format("?(%2d)  ", r_length);790        break;791      default:792        outs() << format("?(%2d)  ", r_length);793    }794  }795}796 797static void PrintRelocationEntries(const MachOObjectFile *O,798                                   const relocation_iterator Begin,799                                   const relocation_iterator End,800                                   const uint64_t cputype,801                                   const bool verbose) {802  const MachO::symtab_command Symtab = O->getSymtabLoadCommand();803  bool previous_arm_half = false;804  bool previous_sectdiff = false;805  uint32_t sectdiff_r_type = 0;806 807  for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {808    const DataRefImpl Rel = Reloc->getRawDataRefImpl();809    const MachO::any_relocation_info RE = O->getRelocation(Rel);810    const unsigned r_type = O->getAnyRelocationType(RE);811    const bool r_scattered = O->isRelocationScattered(RE);812    const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);813    const unsigned r_length = O->getAnyRelocationLength(RE);814    const unsigned r_address = O->getAnyRelocationAddress(RE);815    const bool r_extern = (r_scattered ? false :816                           O->getPlainRelocationExternal(RE));817    const uint32_t r_value = (r_scattered ?818                              O->getScatteredRelocationValue(RE) : 0);819    const unsigned r_symbolnum = (r_scattered ? 0 :820                                  O->getPlainRelocationSymbolNum(RE));821 822    if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {823      if (verbose) {824        // scattered: address825        if ((cputype == MachO::CPU_TYPE_I386 &&826             r_type == MachO::GENERIC_RELOC_PAIR) ||827            (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))828          outs() << "         ";829        else830          outs() << format("%08x ", (unsigned int)r_address);831 832        // scattered: pcrel833        if (r_pcrel)834          outs() << "True  ";835        else836          outs() << "False ";837 838        // scattered: length839        PrintRLength(cputype, r_type, r_length, previous_arm_half);840 841        // scattered: extern & type842        outs() << "n/a    ";843        PrintRType(cputype, r_type);844 845        // scattered: scattered & value846        outs() << format("True      0x%08x", (unsigned int)r_value);847        if (previous_sectdiff == false) {848          if ((cputype == MachO::CPU_TYPE_ARM &&849               r_type == MachO::ARM_RELOC_PAIR))850            outs() << format(" half = 0x%04x ", (unsigned int)r_address);851        } else if (cputype == MachO::CPU_TYPE_ARM &&852                   sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)853          outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);854        if ((cputype == MachO::CPU_TYPE_I386 &&855             (r_type == MachO::GENERIC_RELOC_SECTDIFF ||856              r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||857            (cputype == MachO::CPU_TYPE_ARM &&858             (sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||859              sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||860              sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {861          previous_sectdiff = true;862          sectdiff_r_type = r_type;863        } else {864          previous_sectdiff = false;865          sectdiff_r_type = 0;866        }867        if (cputype == MachO::CPU_TYPE_ARM &&868            (r_type == MachO::ARM_RELOC_HALF ||869             r_type == MachO::ARM_RELOC_HALF_SECTDIFF))870          previous_arm_half = true;871        else872          previous_arm_half = false;873        outs() << "\n";874      }875      else {876        // scattered: address pcrel length extern type scattered value877        outs() << format("%08x %1d     %-2d     n/a    %-7d 1         0x%08x\n",878                         (unsigned int)r_address, r_pcrel, r_length, r_type,879                         (unsigned int)r_value);880      }881    }882    else {883      if (verbose) {884        // plain: address885        if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)886          outs() << "         ";887        else888          outs() << format("%08x ", (unsigned int)r_address);889 890        // plain: pcrel891        if (r_pcrel)892          outs() << "True  ";893        else894          outs() << "False ";895 896        // plain: length897        PrintRLength(cputype, r_type, r_length, previous_arm_half);898 899        if (r_extern) {900          // plain: extern & type & scattered901          outs() << "True   ";902          PrintRType(cputype, r_type);903          outs() << "False     ";904 905          // plain: symbolnum/value906          if (r_symbolnum > Symtab.nsyms)907            outs() << format("?(%d)\n", r_symbolnum);908          else {909            SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);910            Expected<StringRef> SymNameNext = Symbol.getName();911            const char *name = nullptr;912            if (SymNameNext)913              name = SymNameNext->data();914            if (name == nullptr)915              outs() << format("?(%d)\n", r_symbolnum);916            else917              outs() << name << "\n";918          }919        }920        else {921          // plain: extern & type & scattered922          outs() << "False  ";923          PrintRType(cputype, r_type);924          outs() << "False     ";925 926          // plain: symbolnum/value927          if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)928            outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);929          else if ((cputype == MachO::CPU_TYPE_ARM64 ||930                    cputype == MachO::CPU_TYPE_ARM64_32) &&931                   r_type == MachO::ARM64_RELOC_ADDEND)932            outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);933          else {934            outs() << format("%d ", r_symbolnum);935            if (r_symbolnum == MachO::R_ABS)936              outs() << "R_ABS\n";937            else {938              // in this case, r_symbolnum is actually a 1-based section number939              uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;940              if (r_symbolnum > 0 && r_symbolnum <= nsects) {941                object::DataRefImpl DRI;942                DRI.d.a = r_symbolnum-1;943                StringRef SegName = O->getSectionFinalSegmentName(DRI);944                if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))945                  outs() << "(" << SegName << "," << *NameOrErr << ")\n";946                else947                  outs() << "(?,?)\n";948              }949              else {950                outs() << "(?,?)\n";951              }952            }953          }954        }955        if (cputype == MachO::CPU_TYPE_ARM &&956            (r_type == MachO::ARM_RELOC_HALF ||957             r_type == MachO::ARM_RELOC_HALF_SECTDIFF))958          previous_arm_half = true;959        else960          previous_arm_half = false;961      }962      else {963        // plain: address pcrel length extern type scattered symbolnum/section964        outs() << format("%08x %1d     %-2d     %1d      %-7d 0         %d\n",965                         (unsigned int)r_address, r_pcrel, r_length, r_extern,966                         r_type, r_symbolnum);967      }968    }969  }970}971 972static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {973  const uint64_t cputype = O->getHeader().cputype;974  const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();975  if (Dysymtab.nextrel != 0) {976    outs() << "External relocation information " << Dysymtab.nextrel977           << " entries";978    outs() << "\naddress  pcrel length extern type    scattered "979              "symbolnum/value\n";980    PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,981                           verbose);982  }983  if (Dysymtab.nlocrel != 0) {984    outs() << format("Local relocation information %u entries",985                     Dysymtab.nlocrel);986    outs() << "\naddress  pcrel length extern type    scattered "987              "symbolnum/value\n";988    PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,989                           verbose);990  }991  for (const auto &Load : O->load_commands()) {992    if (Load.C.cmd == MachO::LC_SEGMENT_64) {993      const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);994      for (unsigned J = 0; J < Seg.nsects; ++J) {995        const MachO::section_64 Sec = O->getSection64(Load, J);996        if (Sec.nreloc != 0) {997          DataRefImpl DRI;998          DRI.d.a = J;999          const StringRef SegName = O->getSectionFinalSegmentName(DRI);1000          if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1001            outs() << "Relocation information (" << SegName << "," << *NameOrErr1002                   << format(") %u entries", Sec.nreloc);1003          else1004            outs() << "Relocation information (" << SegName << ",?) "1005                   << format("%u entries", Sec.nreloc);1006          outs() << "\naddress  pcrel length extern type    scattered "1007                    "symbolnum/value\n";1008          PrintRelocationEntries(O, O->section_rel_begin(DRI),1009                                 O->section_rel_end(DRI), cputype, verbose);1010        }1011      }1012    } else if (Load.C.cmd == MachO::LC_SEGMENT) {1013      const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);1014      for (unsigned J = 0; J < Seg.nsects; ++J) {1015        const MachO::section Sec = O->getSection(Load, J);1016        if (Sec.nreloc != 0) {1017          DataRefImpl DRI;1018          DRI.d.a = J;1019          const StringRef SegName = O->getSectionFinalSegmentName(DRI);1020          if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1021            outs() << "Relocation information (" << SegName << "," << *NameOrErr1022                   << format(") %u entries", Sec.nreloc);1023          else1024            outs() << "Relocation information (" << SegName << ",?) "1025                   << format("%u entries", Sec.nreloc);1026          outs() << "\naddress  pcrel length extern type    scattered "1027                    "symbolnum/value\n";1028          PrintRelocationEntries(O, O->section_rel_begin(DRI),1029                                 O->section_rel_end(DRI), cputype, verbose);1030        }1031      }1032    }1033  }1034}1035 1036static void PrintFunctionStarts(MachOObjectFile *O) {1037  uint64_t BaseSegmentAddress = 0;1038  for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1039    if (Command.C.cmd == MachO::LC_SEGMENT) {1040      MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1041      if (StringRef(SLC.segname) == "__TEXT") {1042        BaseSegmentAddress = SLC.vmaddr;1043        break;1044      }1045    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1046      MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1047      if (StringRef(SLC.segname) == "__TEXT") {1048        BaseSegmentAddress = SLC.vmaddr;1049        break;1050      }1051    }1052  }1053 1054  SmallVector<uint64_t, 8> FunctionStarts;1055  for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {1056    if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {1057      MachO::linkedit_data_command FunctionStartsLC =1058          O->getLinkeditDataLoadCommand(LC);1059      O->ReadULEB128s(FunctionStartsLC.dataoff, FunctionStarts);1060      break;1061    }1062  }1063 1064  DenseMap<uint64_t, StringRef> SymbolNames;1065  if (FunctionStartsType == FunctionStartsMode::Names ||1066      FunctionStartsType == FunctionStartsMode::Both) {1067    for (SymbolRef Sym : O->symbols()) {1068      if (Expected<uint64_t> Addr = Sym.getAddress()) {1069        if (Expected<StringRef> Name = Sym.getName()) {1070          SymbolNames[*Addr] = *Name;1071        }1072      }1073    }1074  }1075 1076  for (uint64_t S : FunctionStarts) {1077    uint64_t Addr = BaseSegmentAddress + S;1078    if (FunctionStartsType == FunctionStartsMode::Names) {1079      auto It = SymbolNames.find(Addr);1080      if (It != SymbolNames.end())1081        outs() << It->second << "\n";1082    } else {1083      if (O->is64Bit())1084        outs() << format("%016" PRIx64, Addr);1085      else1086        outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));1087 1088      if (FunctionStartsType == FunctionStartsMode::Both) {1089        auto It = SymbolNames.find(Addr);1090        if (It != SymbolNames.end())1091          outs() << " " << It->second;1092        else1093          outs() << " ?";1094      }1095      outs() << "\n";1096    }1097  }1098}1099 1100static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {1101  MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();1102  uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);1103  outs() << "Data in code table (" << nentries << " entries)\n";1104  outs() << "offset     length kind\n";1105  for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;1106       ++DI) {1107    uint32_t Offset;1108    DI->getOffset(Offset);1109    outs() << format("0x%08" PRIx32, Offset) << " ";1110    uint16_t Length;1111    DI->getLength(Length);1112    outs() << format("%6u", Length) << " ";1113    uint16_t Kind;1114    DI->getKind(Kind);1115    if (verbose) {1116      switch (Kind) {1117      case MachO::DICE_KIND_DATA:1118        outs() << "DATA";1119        break;1120      case MachO::DICE_KIND_JUMP_TABLE8:1121        outs() << "JUMP_TABLE8";1122        break;1123      case MachO::DICE_KIND_JUMP_TABLE16:1124        outs() << "JUMP_TABLE16";1125        break;1126      case MachO::DICE_KIND_JUMP_TABLE32:1127        outs() << "JUMP_TABLE32";1128        break;1129      case MachO::DICE_KIND_ABS_JUMP_TABLE32:1130        outs() << "ABS_JUMP_TABLE32";1131        break;1132      default:1133        outs() << format("0x%04" PRIx32, Kind);1134        break;1135      }1136    } else1137      outs() << format("0x%04" PRIx32, Kind);1138    outs() << "\n";1139  }1140}1141 1142static void PrintLinkOptHints(MachOObjectFile *O) {1143  MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();1144  const char *loh = O->getData().substr(LohLC.dataoff, 1).data();1145  uint32_t nloh = LohLC.datasize;1146  outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";1147  for (uint32_t i = 0; i < nloh;) {1148    unsigned n;1149    uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);1150    i += n;1151    outs() << "    identifier " << identifier << " ";1152    if (i >= nloh)1153      return;1154    switch (identifier) {1155    case 1:1156      outs() << "AdrpAdrp\n";1157      break;1158    case 2:1159      outs() << "AdrpLdr\n";1160      break;1161    case 3:1162      outs() << "AdrpAddLdr\n";1163      break;1164    case 4:1165      outs() << "AdrpLdrGotLdr\n";1166      break;1167    case 5:1168      outs() << "AdrpAddStr\n";1169      break;1170    case 6:1171      outs() << "AdrpLdrGotStr\n";1172      break;1173    case 7:1174      outs() << "AdrpAdd\n";1175      break;1176    case 8:1177      outs() << "AdrpLdrGot\n";1178      break;1179    default:1180      outs() << "Unknown identifier value\n";1181      break;1182    }1183    uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);1184    i += n;1185    outs() << "    narguments " << narguments << "\n";1186    if (i >= nloh)1187      return;1188 1189    for (uint32_t j = 0; j < narguments; j++) {1190      uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);1191      i += n;1192      outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";1193      if (i >= nloh)1194        return;1195    }1196  }1197}1198 1199static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {1200  SmallVector<std::string> Ret;1201  for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1202    if (Command.C.cmd == MachO::LC_SEGMENT) {1203      MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1204      Ret.push_back(SLC.segname);1205    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1206      MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1207      Ret.push_back(SLC.segname);1208    }1209  }1210  return Ret;1211}1212 1213static void1214PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {1215  outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";1216  outs() << "  fixups_version = " << H.fixups_version << '\n';1217  outs() << "  starts_offset  = " << H.starts_offset << '\n';1218  outs() << "  imports_offset = " << H.imports_offset << '\n';1219  outs() << "  symbols_offset = " << H.symbols_offset << '\n';1220  outs() << "  imports_count  = " << H.imports_count << '\n';1221 1222  outs() << "  imports_format = " << H.imports_format;1223  switch (H.imports_format) {1224  case llvm::MachO::DYLD_CHAINED_IMPORT:1225    outs() << " (DYLD_CHAINED_IMPORT)";1226    break;1227  case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:1228    outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";1229    break;1230  case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:1231    outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";1232    break;1233  }1234  outs() << '\n';1235 1236  outs() << "  symbols_format = " << H.symbols_format;1237  if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)1238    outs() << " (zlib compressed)";1239  outs() << '\n';1240}1241 1242static constexpr std::array<StringRef, 13> PointerFormats{1243    "DYLD_CHAINED_PTR_ARM64E",1244    "DYLD_CHAINED_PTR_64",1245    "DYLD_CHAINED_PTR_32",1246    "DYLD_CHAINED_PTR_32_CACHE",1247    "DYLD_CHAINED_PTR_32_FIRMWARE",1248    "DYLD_CHAINED_PTR_64_OFFSET",1249    "DYLD_CHAINED_PTR_ARM64E_KERNEL",1250    "DYLD_CHAINED_PTR_64_KERNEL_CACHE",1251    "DYLD_CHAINED_PTR_ARM64E_USERLAND",1252    "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",1253    "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",1254    "DYLD_CHAINED_PTR_ARM64E_USERLAND24",1255};1256 1257static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,1258                                      StringRef SegName) {1259  outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName1260         << ")\n";1261  outs() << "  size = " << Segment.Header.size << '\n';1262  outs() << "  page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)1263         << '\n';1264 1265  outs() << "  pointer_format = " << Segment.Header.pointer_format;1266  if ((Segment.Header.pointer_format - 1) <1267      MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)1268    outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";1269  outs() << '\n';1270 1271  outs() << "  segment_offset = "1272         << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';1273  outs() << "  max_valid_pointer = " << Segment.Header.max_valid_pointer1274         << '\n';1275  outs() << "  page_count = " << Segment.Header.page_count << '\n';1276  for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {1277    outs() << "    page_start[" << Index << "] = " << PageStart;1278    // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)1279    if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)1280      outs() << " (DYLD_CHAINED_PTR_START_NONE)";1281    outs() << '\n';1282  }1283}1284 1285static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,1286                                    int Format, MachOObjectFile *O) {1287  if (Format == MachO::DYLD_CHAINED_IMPORT)1288    outs() << "dyld chained import";1289  else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)1290    outs() << "dyld chained import addend";1291  else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)1292    outs() << "dyld chained import addend64";1293  // FIXME: otool prints the encoded value as well.1294  outs() << '[' << Idx << "]\n";1295 1296  outs() << "  lib_ordinal = " << Target.libOrdinal() << " ("1297         << ordinalName(O, Target.libOrdinal()) << ")\n";1298  outs() << "  weak_import = " << Target.weakImport() << '\n';1299  outs() << "  name_offset = " << Target.nameOffset() << " ("1300         << Target.symbolName() << ")\n";1301  if (Format != MachO::DYLD_CHAINED_IMPORT)1302    outs() << "  addend      = " << (int64_t)Target.addend() << '\n';1303}1304 1305static void PrintChainedFixups(MachOObjectFile *O) {1306  // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.1307  // FIXME: Support chained fixups in __TEXT,__chain_starts section too.1308  auto ChainedFixupHeader =1309      unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());1310  if (!ChainedFixupHeader)1311    return;1312 1313  PrintChainedFixupsHeader(*ChainedFixupHeader);1314 1315  auto [SegCount, Segments] =1316      unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());1317 1318  auto SegNames = GetSegmentNames(O);1319 1320  size_t StartsIdx = 0;1321  outs() << "chained starts in image\n";1322  outs() << "  seg_count = " << SegCount << '\n';1323  for (size_t I = 0; I < SegCount; ++I) {1324    uint64_t SegOffset = 0;1325    if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {1326      SegOffset = Segments[StartsIdx].Offset;1327      ++StartsIdx;1328    }1329 1330    outs() << "    seg_offset[" << I << "] = " << SegOffset << " ("1331           << SegNames[I] << ")\n";1332  }1333 1334  for (const ChainedFixupsSegment &S : Segments)1335    PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);1336 1337  auto FixupTargets =1338      unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());1339 1340  uint32_t ImportsFormat = ChainedFixupHeader->imports_format;1341  for (auto [Idx, Target] : enumerate(FixupTargets))1342    PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);1343}1344 1345static void PrintDyldInfo(MachOObjectFile *O) {1346  Error Err = Error::success();1347 1348  size_t SegmentWidth = strlen("segment");1349  size_t SectionWidth = strlen("section");1350  size_t AddressWidth = strlen("address");1351  size_t AddendWidth = strlen("addend");1352  size_t DylibWidth = strlen("dylib");1353  const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;1354 1355  auto HexLength = [](uint64_t Num) {1356    return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;1357  };1358  for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1359    SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());1360    SectionWidth = std::max(SectionWidth, Entry.sectionName().size());1361    AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);1362    if (Entry.isBind()) {1363      AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);1364      DylibWidth = std::max(DylibWidth, Entry.symbolName().size());1365    }1366  }1367  // Errors will be handled when printing the table.1368  if (Err)1369    consumeError(std::move(Err));1370 1371  outs() << "dyld information:\n";1372  outs() << left_justify("segment", SegmentWidth) << ' '1373         << left_justify("section", SectionWidth) << ' '1374         << left_justify("address", AddressWidth) << ' '1375         << left_justify("pointer", PointerWidth) << " type   "1376         << left_justify("addend", AddendWidth) << ' '1377         << left_justify("dylib", DylibWidth) << " symbol/vm address\n";1378  for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1379    outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '1380           << left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"1381           << left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '1382           << format_hex(Entry.rawValue(), PointerWidth, true) << ' ';1383    if (Entry.isBind()) {1384      outs() << "bind   "1385             << "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)1386             << ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)1387             << ' ' << Entry.symbolName();1388      if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)1389        outs() << " (weak import)";1390      outs() << '\n';1391    } else {1392      assert(Entry.isRebase());1393      outs() << "rebase";1394      outs().indent(AddendWidth + DylibWidth + 2);1395      outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';1396    }1397  }1398  if (Err)1399    reportError(std::move(Err), O->getFileName());1400 1401  // TODO: Print opcode-based fixups if the object uses those.1402}1403 1404static void PrintDylibs(MachOObjectFile *O, bool JustId) {1405  unsigned Index = 0;1406  for (const auto &Load : O->load_commands()) {1407    if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||1408        (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||1409                     Load.C.cmd == MachO::LC_LOAD_DYLIB ||1410                     Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||1411                     Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||1412                     Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||1413                     Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {1414      MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);1415      if (dl.dylib.name < dl.cmdsize) {1416        const char *p = (const char *)(Load.Ptr) + dl.dylib.name;1417        if (JustId)1418          outs() << p << "\n";1419        else {1420          outs() << "\t" << p;1421          outs() << " (compatibility version "1422                 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."1423                 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."1424                 << (dl.dylib.compatibility_version & 0xff) << ",";1425          outs() << " current version "1426                 << ((dl.dylib.current_version >> 16) & 0xffff) << "."1427                 << ((dl.dylib.current_version >> 8) & 0xff) << "."1428                 << (dl.dylib.current_version & 0xff);1429          if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1430            outs() << ", weak";1431          if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1432            outs() << ", reexport";1433          if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1434            outs() << ", upward";1435          if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1436            outs() << ", lazy";1437          outs() << ")\n";1438        }1439      } else {1440        outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";1441        if (Load.C.cmd == MachO::LC_ID_DYLIB)1442          outs() << "LC_ID_DYLIB ";1443        else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)1444          outs() << "LC_LOAD_DYLIB ";1445        else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1446          outs() << "LC_LOAD_WEAK_DYLIB ";1447        else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1448          outs() << "LC_LAZY_LOAD_DYLIB ";1449        else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1450          outs() << "LC_REEXPORT_DYLIB ";1451        else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1452          outs() << "LC_LOAD_UPWARD_DYLIB ";1453        else1454          outs() << "LC_??? ";1455        outs() << "command " << Index++ << "\n";1456      }1457    }1458  }1459}1460 1461static void printRpaths(MachOObjectFile *O) {1462  for (const auto &Command : O->load_commands()) {1463    if (Command.C.cmd == MachO::LC_RPATH) {1464      auto Rpath = O->getRpathCommand(Command);1465      const char *P = (const char *)(Command.Ptr) + Rpath.path;1466      outs() << P << "\n";1467    }1468  }1469}1470 1471typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;1472 1473static void CreateSymbolAddressMap(MachOObjectFile *O,1474                                   SymbolAddressMap *AddrMap) {1475  // Create a map of symbol addresses to symbol names.1476  const StringRef FileName = O->getFileName();1477  for (const SymbolRef &Symbol : O->symbols()) {1478    SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);1479    if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||1480        ST == SymbolRef::ST_Other) {1481      uint64_t Address = cantFail(Symbol.getValue());1482      StringRef SymName = unwrapOrError(Symbol.getName(), FileName);1483      if (!SymName.starts_with(".objc"))1484        (*AddrMap)[Address] = SymName;1485    }1486  }1487}1488 1489// GuessSymbolName is passed the address of what might be a symbol and a1490// pointer to the SymbolAddressMap.  It returns the name of a symbol1491// with that address or nullptr if no symbol is found with that address.1492static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {1493  const char *SymbolName = nullptr;1494  // A DenseMap can't lookup up some values.1495  if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {1496    StringRef name = AddrMap->lookup(value);1497    if (!name.empty())1498      SymbolName = name.data();1499  }1500  return SymbolName;1501}1502 1503static void DumpCstringChar(const char c) {1504  char p[2];1505  p[0] = c;1506  p[1] = '\0';1507  outs().write_escaped(p);1508}1509 1510static void DumpCstringSection(MachOObjectFile *O, const char *sect,1511                               uint32_t sect_size, uint64_t sect_addr,1512                               bool print_addresses) {1513  for (uint32_t i = 0; i < sect_size; i++) {1514    if (print_addresses) {1515      if (O->is64Bit())1516        outs() << format("%016" PRIx64, sect_addr + i) << "  ";1517      else1518        outs() << format("%08" PRIx64, sect_addr + i) << "  ";1519    }1520    for (; i < sect_size && sect[i] != '\0'; i++)1521      DumpCstringChar(sect[i]);1522    if (i < sect_size && sect[i] == '\0')1523      outs() << "\n";1524  }1525}1526 1527static void DumpLiteral4(uint32_t l, float f) {1528  outs() << format("0x%08" PRIx32, l);1529  if ((l & 0x7f800000) != 0x7f800000)1530    outs() << format(" (%.16e)\n", f);1531  else {1532    if (l == 0x7f800000)1533      outs() << " (+Infinity)\n";1534    else if (l == 0xff800000)1535      outs() << " (-Infinity)\n";1536    else if ((l & 0x00400000) == 0x00400000)1537      outs() << " (non-signaling Not-a-Number)\n";1538    else1539      outs() << " (signaling Not-a-Number)\n";1540  }1541}1542 1543static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,1544                                uint32_t sect_size, uint64_t sect_addr,1545                                bool print_addresses) {1546  for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {1547    if (print_addresses) {1548      if (O->is64Bit())1549        outs() << format("%016" PRIx64, sect_addr + i) << "  ";1550      else1551        outs() << format("%08" PRIx64, sect_addr + i) << "  ";1552    }1553    float f;1554    memcpy(&f, sect + i, sizeof(float));1555    if (O->isLittleEndian() != sys::IsLittleEndianHost)1556      sys::swapByteOrder(f);1557    uint32_t l;1558    memcpy(&l, sect + i, sizeof(uint32_t));1559    if (O->isLittleEndian() != sys::IsLittleEndianHost)1560      sys::swapByteOrder(l);1561    DumpLiteral4(l, f);1562  }1563}1564 1565static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,1566                         double d) {1567  outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);1568  uint32_t Hi, Lo;1569  Hi = (O->isLittleEndian()) ? l1 : l0;1570  Lo = (O->isLittleEndian()) ? l0 : l1;1571 1572  // Hi is the high word, so this is equivalent to if(isfinite(d))1573  if ((Hi & 0x7ff00000) != 0x7ff00000)1574    outs() << format(" (%.16e)\n", d);1575  else {1576    if (Hi == 0x7ff00000 && Lo == 0)1577      outs() << " (+Infinity)\n";1578    else if (Hi == 0xfff00000 && Lo == 0)1579      outs() << " (-Infinity)\n";1580    else if ((Hi & 0x00080000) == 0x00080000)1581      outs() << " (non-signaling Not-a-Number)\n";1582    else1583      outs() << " (signaling Not-a-Number)\n";1584  }1585}1586 1587static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,1588                                uint32_t sect_size, uint64_t sect_addr,1589                                bool print_addresses) {1590  for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {1591    if (print_addresses) {1592      if (O->is64Bit())1593        outs() << format("%016" PRIx64, sect_addr + i) << "  ";1594      else1595        outs() << format("%08" PRIx64, sect_addr + i) << "  ";1596    }1597    double d;1598    memcpy(&d, sect + i, sizeof(double));1599    if (O->isLittleEndian() != sys::IsLittleEndianHost)1600      sys::swapByteOrder(d);1601    uint32_t l0, l1;1602    memcpy(&l0, sect + i, sizeof(uint32_t));1603    memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1604    if (O->isLittleEndian() != sys::IsLittleEndianHost) {1605      sys::swapByteOrder(l0);1606      sys::swapByteOrder(l1);1607    }1608    DumpLiteral8(O, l0, l1, d);1609  }1610}1611 1612static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {1613  outs() << format("0x%08" PRIx32, l0) << " ";1614  outs() << format("0x%08" PRIx32, l1) << " ";1615  outs() << format("0x%08" PRIx32, l2) << " ";1616  outs() << format("0x%08" PRIx32, l3) << "\n";1617}1618 1619static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,1620                                 uint32_t sect_size, uint64_t sect_addr,1621                                 bool print_addresses) {1622  for (uint32_t i = 0; i < sect_size; i += 16) {1623    if (print_addresses) {1624      if (O->is64Bit())1625        outs() << format("%016" PRIx64, sect_addr + i) << "  ";1626      else1627        outs() << format("%08" PRIx64, sect_addr + i) << "  ";1628    }1629    uint32_t l0, l1, l2, l3;1630    memcpy(&l0, sect + i, sizeof(uint32_t));1631    memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1632    memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));1633    memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));1634    if (O->isLittleEndian() != sys::IsLittleEndianHost) {1635      sys::swapByteOrder(l0);1636      sys::swapByteOrder(l1);1637      sys::swapByteOrder(l2);1638      sys::swapByteOrder(l3);1639    }1640    DumpLiteral16(l0, l1, l2, l3);1641  }1642}1643 1644static void DumpLiteralPointerSection(MachOObjectFile *O,1645                                      const SectionRef &Section,1646                                      const char *sect, uint32_t sect_size,1647                                      uint64_t sect_addr,1648                                      bool print_addresses) {1649  // Collect the literal sections in this Mach-O file.1650  std::vector<SectionRef> LiteralSections;1651  for (const SectionRef &Section : O->sections()) {1652    DataRefImpl Ref = Section.getRawDataRefImpl();1653    uint32_t section_type;1654    if (O->is64Bit()) {1655      const MachO::section_64 Sec = O->getSection64(Ref);1656      section_type = Sec.flags & MachO::SECTION_TYPE;1657    } else {1658      const MachO::section Sec = O->getSection(Ref);1659      section_type = Sec.flags & MachO::SECTION_TYPE;1660    }1661    if (section_type == MachO::S_CSTRING_LITERALS ||1662        section_type == MachO::S_4BYTE_LITERALS ||1663        section_type == MachO::S_8BYTE_LITERALS ||1664        section_type == MachO::S_16BYTE_LITERALS)1665      LiteralSections.push_back(Section);1666  }1667 1668  // Set the size of the literal pointer.1669  uint32_t lp_size = O->is64Bit() ? 8 : 4;1670 1671  // Collect the external relocation symbols for the literal pointers.1672  std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1673  for (const RelocationRef &Reloc : Section.relocations()) {1674    DataRefImpl Rel;1675    MachO::any_relocation_info RE;1676    bool isExtern = false;1677    Rel = Reloc.getRawDataRefImpl();1678    RE = O->getRelocation(Rel);1679    isExtern = O->getPlainRelocationExternal(RE);1680    if (isExtern) {1681      uint64_t RelocOffset = Reloc.getOffset();1682      symbol_iterator RelocSym = Reloc.getSymbol();1683      Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1684    }1685  }1686  array_pod_sort(Relocs.begin(), Relocs.end());1687 1688  // Dump each literal pointer.1689  for (uint32_t i = 0; i < sect_size; i += lp_size) {1690    if (print_addresses) {1691      if (O->is64Bit())1692        outs() << format("%016" PRIx64, sect_addr + i) << "  ";1693      else1694        outs() << format("%08" PRIx64, sect_addr + i) << "  ";1695    }1696    uint64_t lp;1697    if (O->is64Bit()) {1698      memcpy(&lp, sect + i, sizeof(uint64_t));1699      if (O->isLittleEndian() != sys::IsLittleEndianHost)1700        sys::swapByteOrder(lp);1701    } else {1702      uint32_t li;1703      memcpy(&li, sect + i, sizeof(uint32_t));1704      if (O->isLittleEndian() != sys::IsLittleEndianHost)1705        sys::swapByteOrder(li);1706      lp = li;1707    }1708 1709    // First look for an external relocation entry for this literal pointer.1710    auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1711      return P.first == i;1712    });1713    if (Reloc != Relocs.end()) {1714      symbol_iterator RelocSym = Reloc->second;1715      StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());1716      outs() << "external relocation entry for symbol:" << SymName << "\n";1717      continue;1718    }1719 1720    // For local references see what the section the literal pointer points to.1721    auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {1722      return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();1723    });1724    if (Sect == LiteralSections.end()) {1725      outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";1726      continue;1727    }1728 1729    uint64_t SectAddress = Sect->getAddress();1730    uint64_t SectSize = Sect->getSize();1731 1732    StringRef SectName;1733    Expected<StringRef> SectNameOrErr = Sect->getName();1734    if (SectNameOrErr)1735      SectName = *SectNameOrErr;1736    else1737      consumeError(SectNameOrErr.takeError());1738 1739    DataRefImpl Ref = Sect->getRawDataRefImpl();1740    StringRef SegmentName = O->getSectionFinalSegmentName(Ref);1741    outs() << SegmentName << ":" << SectName << ":";1742 1743    uint32_t section_type;1744    if (O->is64Bit()) {1745      const MachO::section_64 Sec = O->getSection64(Ref);1746      section_type = Sec.flags & MachO::SECTION_TYPE;1747    } else {1748      const MachO::section Sec = O->getSection(Ref);1749      section_type = Sec.flags & MachO::SECTION_TYPE;1750    }1751 1752    StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());1753 1754    const char *Contents = BytesStr.data();1755 1756    switch (section_type) {1757    case MachO::S_CSTRING_LITERALS:1758      for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';1759           i++) {1760        DumpCstringChar(Contents[i]);1761      }1762      outs() << "\n";1763      break;1764    case MachO::S_4BYTE_LITERALS:1765      float f;1766      memcpy(&f, Contents + (lp - SectAddress), sizeof(float));1767      uint32_t l;1768      memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));1769      if (O->isLittleEndian() != sys::IsLittleEndianHost) {1770        sys::swapByteOrder(f);1771        sys::swapByteOrder(l);1772      }1773      DumpLiteral4(l, f);1774      break;1775    case MachO::S_8BYTE_LITERALS: {1776      double d;1777      memcpy(&d, Contents + (lp - SectAddress), sizeof(double));1778      uint32_t l0, l1;1779      memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1780      memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1781             sizeof(uint32_t));1782      if (O->isLittleEndian() != sys::IsLittleEndianHost) {1783        sys::swapByteOrder(f);1784        sys::swapByteOrder(l0);1785        sys::swapByteOrder(l1);1786      }1787      DumpLiteral8(O, l0, l1, d);1788      break;1789    }1790    case MachO::S_16BYTE_LITERALS: {1791      uint32_t l0, l1, l2, l3;1792      memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1793      memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1794             sizeof(uint32_t));1795      memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),1796             sizeof(uint32_t));1797      memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),1798             sizeof(uint32_t));1799      if (O->isLittleEndian() != sys::IsLittleEndianHost) {1800        sys::swapByteOrder(l0);1801        sys::swapByteOrder(l1);1802        sys::swapByteOrder(l2);1803        sys::swapByteOrder(l3);1804      }1805      DumpLiteral16(l0, l1, l2, l3);1806      break;1807    }1808    }1809  }1810}1811 1812static void DumpInitTermPointerSection(MachOObjectFile *O,1813                                       const SectionRef &Section,1814                                       const char *sect,1815                                       uint32_t sect_size, uint64_t sect_addr,1816                                       SymbolAddressMap *AddrMap,1817                                       bool verbose) {1818  uint32_t stride;1819  stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);1820 1821  // Collect the external relocation symbols for the pointers.1822  std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1823  for (const RelocationRef &Reloc : Section.relocations()) {1824    DataRefImpl Rel;1825    MachO::any_relocation_info RE;1826    bool isExtern = false;1827    Rel = Reloc.getRawDataRefImpl();1828    RE = O->getRelocation(Rel);1829    isExtern = O->getPlainRelocationExternal(RE);1830    if (isExtern) {1831      uint64_t RelocOffset = Reloc.getOffset();1832      symbol_iterator RelocSym = Reloc.getSymbol();1833      Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1834    }1835  }1836  array_pod_sort(Relocs.begin(), Relocs.end());1837 1838  for (uint32_t i = 0; i < sect_size; i += stride) {1839    const char *SymbolName = nullptr;1840    uint64_t p;1841    if (O->is64Bit()) {1842      outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";1843      uint64_t pointer_value;1844      memcpy(&pointer_value, sect + i, stride);1845      if (O->isLittleEndian() != sys::IsLittleEndianHost)1846        sys::swapByteOrder(pointer_value);1847      outs() << format("0x%016" PRIx64, pointer_value);1848      p = pointer_value;1849    } else {1850      outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";1851      uint32_t pointer_value;1852      memcpy(&pointer_value, sect + i, stride);1853      if (O->isLittleEndian() != sys::IsLittleEndianHost)1854        sys::swapByteOrder(pointer_value);1855      outs() << format("0x%08" PRIx32, pointer_value);1856      p = pointer_value;1857    }1858    if (verbose) {1859      // First look for an external relocation entry for this pointer.1860      auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1861        return P.first == i;1862      });1863      if (Reloc != Relocs.end()) {1864        symbol_iterator RelocSym = Reloc->second;1865        outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());1866      } else {1867        SymbolName = GuessSymbolName(p, AddrMap);1868        if (SymbolName)1869          outs() << " " << SymbolName;1870      }1871    }1872    outs() << "\n";1873  }1874}1875 1876static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,1877                                   uint32_t size, uint64_t addr) {1878  uint32_t cputype = O->getHeader().cputype;1879  if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {1880    uint32_t j;1881    for (uint32_t i = 0; i < size; i += j, addr += j) {1882      if (O->is64Bit())1883        outs() << format("%016" PRIx64, addr) << "\t";1884      else1885        outs() << format("%08" PRIx64, addr) << "\t";1886      for (j = 0; j < 16 && i + j < size; j++) {1887        uint8_t byte_word = *(sect + i + j);1888        outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1889      }1890      outs() << "\n";1891    }1892  } else {1893    uint32_t j;1894    for (uint32_t i = 0; i < size; i += j, addr += j) {1895      if (O->is64Bit())1896        outs() << format("%016" PRIx64, addr) << "\t";1897      else1898        outs() << format("%08" PRIx64, addr) << "\t";1899      for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;1900           j += sizeof(int32_t)) {1901        if (i + j + sizeof(int32_t) <= size) {1902          uint32_t long_word;1903          memcpy(&long_word, sect + i + j, sizeof(int32_t));1904          if (O->isLittleEndian() != sys::IsLittleEndianHost)1905            sys::swapByteOrder(long_word);1906          outs() << format("%08" PRIx32, long_word) << " ";1907        } else {1908          for (uint32_t k = 0; i + j + k < size; k++) {1909            uint8_t byte_word = *(sect + i + j + k);1910            outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1911          }1912        }1913      }1914      outs() << "\n";1915    }1916  }1917}1918 1919static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,1920                             StringRef DisSegName, StringRef DisSectName);1921static void DumpProtocolSection(MachOObjectFile *O, const char *sect,1922                                uint32_t size, uint32_t addr);1923static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,1924                                bool verbose) {1925  SymbolAddressMap AddrMap;1926  if (verbose)1927    CreateSymbolAddressMap(O, &AddrMap);1928 1929  for (unsigned i = 0; i < FilterSections.size(); ++i) {1930    StringRef DumpSection = FilterSections[i];1931    std::pair<StringRef, StringRef> DumpSegSectName;1932    DumpSegSectName = DumpSection.split(',');1933    StringRef DumpSegName, DumpSectName;1934    if (!DumpSegSectName.second.empty()) {1935      DumpSegName = DumpSegSectName.first;1936      DumpSectName = DumpSegSectName.second;1937    } else {1938      DumpSegName = "";1939      DumpSectName = DumpSegSectName.first;1940    }1941    for (const SectionRef &Section : O->sections()) {1942      StringRef SectName;1943      Expected<StringRef> SecNameOrErr = Section.getName();1944      if (SecNameOrErr)1945        SectName = *SecNameOrErr;1946      else1947        consumeError(SecNameOrErr.takeError());1948 1949      if (!DumpSection.empty())1950        FoundSectionSet.insert(DumpSection);1951 1952      DataRefImpl Ref = Section.getRawDataRefImpl();1953      StringRef SegName = O->getSectionFinalSegmentName(Ref);1954      if ((DumpSegName.empty() || SegName == DumpSegName) &&1955          (SectName == DumpSectName)) {1956 1957        uint32_t section_flags;1958        if (O->is64Bit()) {1959          const MachO::section_64 Sec = O->getSection64(Ref);1960          section_flags = Sec.flags;1961 1962        } else {1963          const MachO::section Sec = O->getSection(Ref);1964          section_flags = Sec.flags;1965        }1966        uint32_t section_type = section_flags & MachO::SECTION_TYPE;1967 1968        StringRef BytesStr =1969            unwrapOrError(Section.getContents(), O->getFileName());1970        const char *sect = BytesStr.data();1971        uint32_t sect_size = BytesStr.size();1972        uint64_t sect_addr = Section.getAddress();1973 1974        if (LeadingHeaders)1975          outs() << "Contents of (" << SegName << "," << SectName1976                 << ") section\n";1977 1978        if (verbose) {1979          if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||1980              (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {1981            DisassembleMachO(Filename, O, SegName, SectName);1982            continue;1983          }1984          if (SegName == "__TEXT" && SectName == "__info_plist") {1985            outs() << sect;1986            continue;1987          }1988          if (SegName == "__OBJC" && SectName == "__protocol") {1989            DumpProtocolSection(O, sect, sect_size, sect_addr);1990            continue;1991          }1992          switch (section_type) {1993          case MachO::S_REGULAR:1994            DumpRawSectionContents(O, sect, sect_size, sect_addr);1995            break;1996          case MachO::S_ZEROFILL:1997            outs() << "zerofill section and has no contents in the file\n";1998            break;1999          case MachO::S_CSTRING_LITERALS:2000            DumpCstringSection(O, sect, sect_size, sect_addr, LeadingAddr);2001            break;2002          case MachO::S_4BYTE_LITERALS:2003            DumpLiteral4Section(O, sect, sect_size, sect_addr, LeadingAddr);2004            break;2005          case MachO::S_8BYTE_LITERALS:2006            DumpLiteral8Section(O, sect, sect_size, sect_addr, LeadingAddr);2007            break;2008          case MachO::S_16BYTE_LITERALS:2009            DumpLiteral16Section(O, sect, sect_size, sect_addr, LeadingAddr);2010            break;2011          case MachO::S_LITERAL_POINTERS:2012            DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,2013                                      LeadingAddr);2014            break;2015          case MachO::S_MOD_INIT_FUNC_POINTERS:2016          case MachO::S_MOD_TERM_FUNC_POINTERS:2017            DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,2018                                       &AddrMap, verbose);2019            break;2020          default:2021            outs() << "Unknown section type ("2022                   << format("0x%08" PRIx32, section_type) << ")\n";2023            DumpRawSectionContents(O, sect, sect_size, sect_addr);2024            break;2025          }2026        } else {2027          if (section_type == MachO::S_ZEROFILL)2028            outs() << "zerofill section and has no contents in the file\n";2029          else2030            DumpRawSectionContents(O, sect, sect_size, sect_addr);2031        }2032      }2033    }2034  }2035}2036 2037static void DumpInfoPlistSectionContents(StringRef Filename,2038                                         MachOObjectFile *O) {2039  for (const SectionRef &Section : O->sections()) {2040    StringRef SectName;2041    Expected<StringRef> SecNameOrErr = Section.getName();2042    if (SecNameOrErr)2043      SectName = *SecNameOrErr;2044    else2045      consumeError(SecNameOrErr.takeError());2046 2047    DataRefImpl Ref = Section.getRawDataRefImpl();2048    StringRef SegName = O->getSectionFinalSegmentName(Ref);2049    if (SegName == "__TEXT" && SectName == "__info_plist") {2050      if (LeadingHeaders)2051        outs() << "Contents of (" << SegName << "," << SectName << ") section\n";2052      StringRef BytesStr =2053          unwrapOrError(Section.getContents(), O->getFileName());2054      const char *sect = BytesStr.data();2055      outs() << format("%.*s", BytesStr.size(), sect) << "\n";2056      return;2057    }2058  }2059}2060 2061// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file2062// and if it is and there is a list of architecture flags is specified then2063// check to make sure this Mach-O file is one of those architectures or all2064// architectures were specified.  If not then an error is generated and this2065// routine returns false.  Else it returns true.2066static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {2067  auto *MachO = dyn_cast<MachOObjectFile>(O);2068 2069  if (!MachO || ArchAll || ArchFlags.empty())2070    return true;2071 2072  MachO::mach_header H;2073  MachO::mach_header_64 H_64;2074  Triple T;2075  const char *McpuDefault, *ArchFlag;2076  if (MachO->is64Bit()) {2077    H_64 = MachO->MachOObjectFile::getHeader64();2078    T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,2079                                       &McpuDefault, &ArchFlag);2080  } else {2081    H = MachO->MachOObjectFile::getHeader();2082    T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,2083                                       &McpuDefault, &ArchFlag);2084  }2085  const std::string ArchFlagName(ArchFlag);2086  if (!llvm::is_contained(ArchFlags, ArchFlagName)) {2087    WithColor::error(errs(), "llvm-objdump")2088        << Filename << ": no architecture specified.\n";2089    return false;2090  }2091  return true;2092}2093 2094static void printObjcMetaData(MachOObjectFile *O, bool verbose);2095 2096// ProcessMachO() is passed a single opened Mach-O file, which may be an2097// archive member and or in a slice of a universal file.  It prints the2098// the file name and header info and then processes it according to the2099// command line options.2100static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,2101                         StringRef ArchiveMemberName = StringRef(),2102                         StringRef ArchitectureName = StringRef()) {2103  std::unique_ptr<Dumper> D = createMachODumper(*MachOOF);2104 2105  // If we are doing some processing here on the Mach-O file print the header2106  // info.  And don't print it otherwise like in the case of printing the2107  // UniversalHeaders or ArchiveHeaders.2108  if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||2109      Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||2110      DataInCode || FunctionStartsType != FunctionStartsMode::None ||2111      LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||2112      Rpaths || ObjcMetaData || (!FilterSections.empty())) {2113    if (LeadingHeaders) {2114      outs() << Name;2115      if (!ArchiveMemberName.empty())2116        outs() << '(' << ArchiveMemberName << ')';2117      if (!ArchitectureName.empty())2118        outs() << " (architecture " << ArchitectureName << ")";2119      outs() << ":\n";2120    }2121  }2122  // To use the report_error() form with an ArchiveName and FileName set2123  // these up based on what is passed for Name and ArchiveMemberName.2124  StringRef ArchiveName;2125  StringRef FileName;2126  if (!ArchiveMemberName.empty()) {2127    ArchiveName = Name;2128    FileName = ArchiveMemberName;2129  } else {2130    ArchiveName = StringRef();2131    FileName = Name;2132  }2133 2134  // If we need the symbol table to do the operation then check it here to2135  // produce a good error message as to where the Mach-O file comes from in2136  // the error message.2137  if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)2138    if (Error Err = MachOOF->checkSymbolTable())2139      reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);2140 2141  if (DisassembleAll) {2142    for (const SectionRef &Section : MachOOF->sections()) {2143      StringRef SectName;2144      if (Expected<StringRef> NameOrErr = Section.getName())2145        SectName = *NameOrErr;2146      else2147        consumeError(NameOrErr.takeError());2148 2149      if (SectName == "__text") {2150        DataRefImpl Ref = Section.getRawDataRefImpl();2151        StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);2152        DisassembleMachO(FileName, MachOOF, SegName, SectName);2153      }2154    }2155  }2156  else if (Disassemble) {2157    if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&2158        MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)2159      DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");2160    else2161      DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");2162  }2163  if (IndirectSymbols)2164    PrintIndirectSymbols(MachOOF, Verbose);2165  if (DataInCode)2166    PrintDataInCodeTable(MachOOF, Verbose);2167  if (FunctionStartsType != FunctionStartsMode::None)2168    PrintFunctionStarts(MachOOF);2169  if (LinkOptHints)2170    PrintLinkOptHints(MachOOF);2171  if (Relocations)2172    PrintRelocations(MachOOF, Verbose);2173  if (SectionHeaders)2174    printSectionHeaders(*MachOOF);2175  if (SectionContents)2176    printSectionContents(MachOOF);2177  if (!FilterSections.empty())2178    DumpSectionContents(FileName, MachOOF, Verbose);2179  if (InfoPlist)2180    DumpInfoPlistSectionContents(FileName, MachOOF);2181  if (DyldInfo)2182    PrintDyldInfo(MachOOF);2183  if (ChainedFixups)2184    PrintChainedFixups(MachOOF);2185  if (DylibsUsed)2186    PrintDylibs(MachOOF, false);2187  if (DylibId)2188    PrintDylibs(MachOOF, true);2189  if (SymbolTable)2190    D->printSymbolTable(ArchiveName, ArchitectureName);2191  if (UnwindInfo)2192    printMachOUnwindInfo(MachOOF);2193  if (PrivateHeaders) {2194    printMachOFileHeader(MachOOF);2195    printMachOLoadCommands(MachOOF);2196  }2197  if (FirstPrivateHeader)2198    printMachOFileHeader(MachOOF);2199  if (ObjcMetaData)2200    printObjcMetaData(MachOOF, Verbose);2201  if (ExportsTrie)2202    printExportsTrie(MachOOF);2203  if (Rebase)2204    printRebaseTable(MachOOF);2205  if (Rpaths)2206    printRpaths(MachOOF);2207  if (Bind)2208    printBindTable(MachOOF);2209  if (LazyBind)2210    printLazyBindTable(MachOOF);2211  if (WeakBind)2212    printWeakBindTable(MachOOF);2213 2214  if (DwarfDumpType != DIDT_Null) {2215    std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);2216    // Dump the complete DWARF structure.2217    DIDumpOptions DumpOpts;2218    DumpOpts.DumpType = DwarfDumpType;2219    DICtx->dump(outs(), DumpOpts);2220  }2221}2222 2223// printUnknownCPUType() helps print_fat_headers for unknown CPU's.2224static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {2225  outs() << "    cputype (" << cputype << ")\n";2226  outs() << "    cpusubtype (" << cpusubtype << ")\n";2227}2228 2229// printCPUType() helps print_fat_headers by printing the cputype and2230// pusubtype (symbolically for the one's it knows about).2231static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {2232  switch (cputype) {2233  case MachO::CPU_TYPE_I386:2234    switch (cpusubtype) {2235    case MachO::CPU_SUBTYPE_I386_ALL:2236      outs() << "    cputype CPU_TYPE_I386\n";2237      outs() << "    cpusubtype CPU_SUBTYPE_I386_ALL\n";2238      break;2239    default:2240      printUnknownCPUType(cputype, cpusubtype);2241      break;2242    }2243    break;2244  case MachO::CPU_TYPE_X86_64:2245    switch (cpusubtype) {2246    case MachO::CPU_SUBTYPE_X86_64_ALL:2247      outs() << "    cputype CPU_TYPE_X86_64\n";2248      outs() << "    cpusubtype CPU_SUBTYPE_X86_64_ALL\n";2249      break;2250    case MachO::CPU_SUBTYPE_X86_64_H:2251      outs() << "    cputype CPU_TYPE_X86_64\n";2252      outs() << "    cpusubtype CPU_SUBTYPE_X86_64_H\n";2253      break;2254    default:2255      printUnknownCPUType(cputype, cpusubtype);2256      break;2257    }2258    break;2259  case MachO::CPU_TYPE_ARM:2260    switch (cpusubtype) {2261    case MachO::CPU_SUBTYPE_ARM_ALL:2262      outs() << "    cputype CPU_TYPE_ARM\n";2263      outs() << "    cpusubtype CPU_SUBTYPE_ARM_ALL\n";2264      break;2265    case MachO::CPU_SUBTYPE_ARM_V4T:2266      outs() << "    cputype CPU_TYPE_ARM\n";2267      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V4T\n";2268      break;2269    case MachO::CPU_SUBTYPE_ARM_V5TEJ:2270      outs() << "    cputype CPU_TYPE_ARM\n";2271      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";2272      break;2273    case MachO::CPU_SUBTYPE_ARM_XSCALE:2274      outs() << "    cputype CPU_TYPE_ARM\n";2275      outs() << "    cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";2276      break;2277    case MachO::CPU_SUBTYPE_ARM_V6:2278      outs() << "    cputype CPU_TYPE_ARM\n";2279      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V6\n";2280      break;2281    case MachO::CPU_SUBTYPE_ARM_V6M:2282      outs() << "    cputype CPU_TYPE_ARM\n";2283      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V6M\n";2284      break;2285    case MachO::CPU_SUBTYPE_ARM_V7:2286      outs() << "    cputype CPU_TYPE_ARM\n";2287      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V7\n";2288      break;2289    case MachO::CPU_SUBTYPE_ARM_V7EM:2290      outs() << "    cputype CPU_TYPE_ARM\n";2291      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V7EM\n";2292      break;2293    case MachO::CPU_SUBTYPE_ARM_V7K:2294      outs() << "    cputype CPU_TYPE_ARM\n";2295      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V7K\n";2296      break;2297    case MachO::CPU_SUBTYPE_ARM_V7M:2298      outs() << "    cputype CPU_TYPE_ARM\n";2299      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V7M\n";2300      break;2301    case MachO::CPU_SUBTYPE_ARM_V7S:2302      outs() << "    cputype CPU_TYPE_ARM\n";2303      outs() << "    cpusubtype CPU_SUBTYPE_ARM_V7S\n";2304      break;2305    default:2306      printUnknownCPUType(cputype, cpusubtype);2307      break;2308    }2309    break;2310  case MachO::CPU_TYPE_ARM64:2311    switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2312    case MachO::CPU_SUBTYPE_ARM64_ALL:2313      outs() << "    cputype CPU_TYPE_ARM64\n";2314      outs() << "    cpusubtype CPU_SUBTYPE_ARM64_ALL\n";2315      break;2316    case MachO::CPU_SUBTYPE_ARM64_V8:2317      outs() << "    cputype CPU_TYPE_ARM64\n";2318      outs() << "    cpusubtype CPU_SUBTYPE_ARM64_V8\n";2319      break;2320    case MachO::CPU_SUBTYPE_ARM64E:2321      outs() << "    cputype CPU_TYPE_ARM64\n";2322      outs() << "    cpusubtype CPU_SUBTYPE_ARM64E\n";2323      break;2324    default:2325      printUnknownCPUType(cputype, cpusubtype);2326      break;2327    }2328    break;2329  case MachO::CPU_TYPE_ARM64_32:2330    switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2331    case MachO::CPU_SUBTYPE_ARM64_32_V8:2332      outs() << "    cputype CPU_TYPE_ARM64_32\n";2333      outs() << "    cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";2334      break;2335    default:2336      printUnknownCPUType(cputype, cpusubtype);2337      break;2338    }2339    break;2340  default:2341    printUnknownCPUType(cputype, cpusubtype);2342    break;2343  }2344}2345 2346static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,2347                                       bool verbose) {2348  outs() << "Fat headers\n";2349  if (verbose) {2350    if (UB->getMagic() == MachO::FAT_MAGIC)2351      outs() << "fat_magic FAT_MAGIC\n";2352    else // UB->getMagic() == MachO::FAT_MAGIC_642353      outs() << "fat_magic FAT_MAGIC_64\n";2354  } else2355    outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";2356 2357  uint32_t nfat_arch = UB->getNumberOfObjects();2358  StringRef Buf = UB->getData();2359  uint64_t size = Buf.size();2360  uint64_t big_size = sizeof(struct MachO::fat_header) +2361                      nfat_arch * sizeof(struct MachO::fat_arch);2362  outs() << "nfat_arch " << UB->getNumberOfObjects();2363  if (nfat_arch == 0)2364    outs() << " (malformed, contains zero architecture types)\n";2365  else if (big_size > size)2366    outs() << " (malformed, architectures past end of file)\n";2367  else2368    outs() << "\n";2369 2370  for (uint32_t i = 0; i < nfat_arch; ++i) {2371    MachOUniversalBinary::ObjectForArch OFA(UB, i);2372    uint32_t cputype = OFA.getCPUType();2373    uint32_t cpusubtype = OFA.getCPUSubType();2374    outs() << "architecture ";2375    for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {2376      MachOUniversalBinary::ObjectForArch other_OFA(UB, j);2377      uint32_t other_cputype = other_OFA.getCPUType();2378      uint32_t other_cpusubtype = other_OFA.getCPUSubType();2379      if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&2380          (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==2381              (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {2382        outs() << "(illegal duplicate architecture) ";2383        break;2384      }2385    }2386    if (verbose) {2387      outs() << OFA.getArchFlagName() << "\n";2388      printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);2389    } else {2390      outs() << i << "\n";2391      outs() << "    cputype " << cputype << "\n";2392      outs() << "    cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)2393             << "\n";2394    }2395    if (verbose && cputype == MachO::CPU_TYPE_ARM64 &&2396        MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {2397      outs() << "    capabilities CPU_SUBTYPE_ARM64E_";2398      if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype))2399        outs() << "KERNEL_";2400      outs() << format("PTRAUTH_VERSION %d",2401                       MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype))2402             << "\n";2403    } else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) ==2404                              MachO::CPU_SUBTYPE_LIB64)2405      outs() << "    capabilities CPU_SUBTYPE_LIB64\n";2406    else2407      outs() << "    capabilities "2408             << format("0x%" PRIx32,2409                       (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";2410    outs() << "    offset " << OFA.getOffset();2411    if (OFA.getOffset() > size)2412      outs() << " (past end of file)";2413    if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)2414      outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";2415    outs() << "\n";2416    outs() << "    size " << OFA.getSize();2417    big_size = OFA.getOffset() + OFA.getSize();2418    if (big_size > size)2419      outs() << " (past end of file)";2420    outs() << "\n";2421    outs() << "    align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())2422           << ")\n";2423  }2424}2425 2426static void printArchiveChild(StringRef Filename, const Archive::Child &C,2427                              size_t ChildIndex, bool verbose,2428                              bool print_offset,2429                              StringRef ArchitectureName = StringRef()) {2430  if (print_offset)2431    outs() << C.getChildOffset() << "\t";2432  sys::fs::perms Mode =2433      unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex),2434                    Filename, ArchitectureName);2435  if (verbose) {2436    // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.2437    // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.2438    outs() << "-";2439    outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");2440    outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");2441    outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");2442    outs() << ((Mode & sys::fs::group_read) ? "r" : "-");2443    outs() << ((Mode & sys::fs::group_write) ? "w" : "-");2444    outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");2445    outs() << ((Mode & sys::fs::others_read) ? "r" : "-");2446    outs() << ((Mode & sys::fs::others_write) ? "w" : "-");2447    outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");2448  } else {2449    outs() << format("0%o ", Mode);2450  }2451 2452  outs() << format("%3d/%-3d %5" PRId64 " ",2453                   unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex),2454                                 Filename, ArchitectureName),2455                   unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex),2456                                 Filename, ArchitectureName),2457                   unwrapOrError(C.getRawSize(),2458                                 getFileNameForError(C, ChildIndex), Filename,2459                                 ArchitectureName));2460 2461  StringRef RawLastModified = C.getRawLastModified();2462  if (verbose) {2463    unsigned Seconds;2464    if (RawLastModified.getAsInteger(10, Seconds))2465      outs() << "(date: \"" << RawLastModified2466             << "\" contains non-decimal chars) ";2467    else {2468      // Since cime(3) returns a 26 character string of the form:2469      // "Sun Sep 16 01:03:52 1973\n\0"2470      // just print 24 characters.2471      time_t t = Seconds;2472      outs() << format("%.24s ", ctime(&t));2473    }2474  } else {2475    outs() << RawLastModified << " ";2476  }2477 2478  if (verbose) {2479    Expected<StringRef> NameOrErr = C.getName();2480    if (!NameOrErr) {2481      consumeError(NameOrErr.takeError());2482      outs() << unwrapOrError(C.getRawName(),2483                              getFileNameForError(C, ChildIndex), Filename,2484                              ArchitectureName)2485             << "\n";2486    } else {2487      StringRef Name = NameOrErr.get();2488      outs() << Name << "\n";2489    }2490  } else {2491    outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex),2492                            Filename, ArchitectureName)2493           << "\n";2494  }2495}2496 2497static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,2498                                bool print_offset,2499                                StringRef ArchitectureName = StringRef()) {2500  Error Err = Error::success();2501  size_t I = 0;2502  for (const auto &C : A->children(Err, false))2503    printArchiveChild(Filename, C, I++, verbose, print_offset,2504                      ArchitectureName);2505 2506  if (Err)2507    reportError(std::move(Err), Filename, "", ArchitectureName);2508}2509 2510static bool ValidateArchFlags() {2511  // Check for -arch all and verifiy the -arch flags are valid.2512  for (unsigned i = 0; i < ArchFlags.size(); ++i) {2513    if (ArchFlags[i] == "all") {2514      ArchAll = true;2515    } else {2516      if (!MachOObjectFile::isValidArch(ArchFlags[i])) {2517        WithColor::error(errs(), "llvm-objdump")2518            << "unknown architecture named '" + ArchFlags[i] +2519                   "'for the -arch option\n";2520        return false;2521      }2522    }2523  }2524  return true;2525}2526 2527// ParseInputMachO() parses the named Mach-O file in Filename and handles the2528// -arch flags selecting just those slices as specified by them and also parses2529// archive files.  Then for each individual Mach-O file ProcessMachO() is2530// called to process the file based on the command line options.2531void objdump::parseInputMachO(StringRef Filename) {2532  if (!ValidateArchFlags())2533    return;2534 2535  // Attempt to open the binary.2536  Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);2537  if (!BinaryOrErr) {2538    if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))2539      reportError(std::move(E), Filename);2540    else2541      outs() << Filename << ": is not an object file\n";2542    return;2543  }2544  Binary &Bin = *BinaryOrErr.get().getBinary();2545 2546  if (Archive *A = dyn_cast<Archive>(&Bin)) {2547    outs() << "Archive : " << Filename << "\n";2548    if (ArchiveHeaders)2549      printArchiveHeaders(Filename, A, Verbose, ArchiveMemberOffsets);2550 2551    Error Err = Error::success();2552    unsigned I = -1;2553    for (auto &C : A->children(Err)) {2554      ++I;2555      Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2556      if (!ChildOrErr) {2557        if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2558          reportError(std::move(E), getFileNameForError(C, I), Filename);2559        continue;2560      }2561      if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2562        if (!checkMachOAndArchFlags(O, Filename))2563          return;2564        ProcessMachO(Filename, O, O->getFileName());2565      }2566    }2567    if (Err)2568      reportError(std::move(Err), Filename);2569    return;2570  }2571  if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {2572    parseInputMachO(UB);2573    return;2574  }2575  if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {2576    if (!checkMachOAndArchFlags(O, Filename))2577      return;2578    if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))2579      ProcessMachO(Filename, MachOOF);2580    else2581      WithColor::error(errs(), "llvm-objdump")2582          << Filename << "': "2583          << "object is not a Mach-O file type.\n";2584    return;2585  }2586  llvm_unreachable("Input object can't be invalid at this point");2587}2588 2589void objdump::parseInputMachO(MachOUniversalBinary *UB) {2590  if (!ValidateArchFlags())2591    return;2592 2593  auto Filename = UB->getFileName();2594 2595  if (UniversalHeaders)2596    printMachOUniversalHeaders(UB, Verbose);2597 2598  // If we have a list of architecture flags specified dump only those.2599  if (!ArchAll && !ArchFlags.empty()) {2600    // Look for a slice in the universal binary that matches each ArchFlag.2601    bool ArchFound;2602    for (unsigned i = 0; i < ArchFlags.size(); ++i) {2603      ArchFound = false;2604      for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2605                                                  E = UB->end_objects();2606            I != E; ++I) {2607        if (ArchFlags[i] == I->getArchFlagName()) {2608          ArchFound = true;2609          Expected<std::unique_ptr<ObjectFile>> ObjOrErr =2610              I->getAsObjectFile();2611          std::string ArchitectureName;2612          if (ArchFlags.size() > 1)2613            ArchitectureName = I->getArchFlagName();2614          if (ObjOrErr) {2615            ObjectFile &O = *ObjOrErr.get();2616            if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2617              ProcessMachO(Filename, MachOOF, "", ArchitectureName);2618          } else if (Error E = isNotObjectErrorInvalidFileType(2619                         ObjOrErr.takeError())) {2620            reportError(std::move(E), "", Filename, ArchitectureName);2621            continue;2622          } else if (Expected<std::unique_ptr<Archive>> AOrErr =2623                         I->getAsArchive()) {2624            std::unique_ptr<Archive> &A = *AOrErr;2625            outs() << "Archive : " << Filename;2626            if (!ArchitectureName.empty())2627              outs() << " (architecture " << ArchitectureName << ")";2628            outs() << "\n";2629            if (ArchiveHeaders)2630              printArchiveHeaders(Filename, A.get(), Verbose,2631                                  ArchiveMemberOffsets, ArchitectureName);2632            Error Err = Error::success();2633            unsigned I = -1;2634            for (auto &C : A->children(Err)) {2635              ++I;2636              Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2637              if (!ChildOrErr) {2638                if (Error E =2639                        isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2640                  reportError(std::move(E), getFileNameForError(C, I), Filename,2641                              ArchitectureName);2642                continue;2643              }2644              if (MachOObjectFile *O =2645                      dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2646                ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);2647            }2648            if (Err)2649              reportError(std::move(Err), Filename);2650          } else {2651            consumeError(AOrErr.takeError());2652            reportError(Filename,2653                        "Mach-O universal file for architecture " +2654                            StringRef(I->getArchFlagName()) +2655                            " is not a Mach-O file or an archive file");2656          }2657        }2658      }2659      if (!ArchFound) {2660        WithColor::error(errs(), "llvm-objdump")2661            << "file: " + Filename + " does not contain "2662            << "architecture: " + ArchFlags[i] + "\n";2663        return;2664      }2665    }2666    return;2667  }2668  // No architecture flags were specified so if this contains a slice that2669  // matches the host architecture dump only that.2670  if (!ArchAll) {2671    for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2672                                                E = UB->end_objects();2673          I != E; ++I) {2674      if (MachOObjectFile::getHostArch().getArchName() ==2675          I->getArchFlagName()) {2676        Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2677        std::string ArchiveName;2678        ArchiveName.clear();2679        if (ObjOrErr) {2680          ObjectFile &O = *ObjOrErr.get();2681          if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2682            ProcessMachO(Filename, MachOOF);2683        } else if (Error E =2684                       isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2685          reportError(std::move(E), Filename);2686        } else if (Expected<std::unique_ptr<Archive>> AOrErr =2687                       I->getAsArchive()) {2688          std::unique_ptr<Archive> &A = *AOrErr;2689          outs() << "Archive : " << Filename << "\n";2690          if (ArchiveHeaders)2691            printArchiveHeaders(Filename, A.get(), Verbose,2692                                ArchiveMemberOffsets);2693          Error Err = Error::success();2694          unsigned I = -1;2695          for (auto &C : A->children(Err)) {2696            ++I;2697            Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2698            if (!ChildOrErr) {2699              if (Error E =2700                      isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2701                reportError(std::move(E), getFileNameForError(C, I), Filename);2702              continue;2703            }2704            if (MachOObjectFile *O =2705                    dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2706              ProcessMachO(Filename, O, O->getFileName());2707          }2708          if (Err)2709            reportError(std::move(Err), Filename);2710        } else {2711          consumeError(AOrErr.takeError());2712          reportError(Filename, "Mach-O universal file for architecture " +2713                                    StringRef(I->getArchFlagName()) +2714                                    " is not a Mach-O file or an archive file");2715        }2716        return;2717      }2718    }2719  }2720  // Either all architectures have been specified or none have been specified2721  // and this does not contain the host architecture so dump all the slices.2722  bool moreThanOneArch = UB->getNumberOfObjects() > 1;2723  for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2724                                              E = UB->end_objects();2725        I != E; ++I) {2726    Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2727    std::string ArchitectureName;2728    if (moreThanOneArch)2729      ArchitectureName = I->getArchFlagName();2730    if (ObjOrErr) {2731      ObjectFile &Obj = *ObjOrErr.get();2732      if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))2733        ProcessMachO(Filename, MachOOF, "", ArchitectureName);2734    } else if (Error E =2735                   isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2736      reportError(std::move(E), Filename, "", ArchitectureName);2737    } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {2738      std::unique_ptr<Archive> &A = *AOrErr;2739      outs() << "Archive : " << Filename;2740      if (!ArchitectureName.empty())2741        outs() << " (architecture " << ArchitectureName << ")";2742      outs() << "\n";2743      if (ArchiveHeaders)2744        printArchiveHeaders(Filename, A.get(), Verbose, ArchiveMemberOffsets,2745                            ArchitectureName);2746      Error Err = Error::success();2747      unsigned I = -1;2748      for (auto &C : A->children(Err)) {2749        ++I;2750        Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2751        if (!ChildOrErr) {2752          if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2753            reportError(std::move(E), getFileNameForError(C, I), Filename,2754                        ArchitectureName);2755          continue;2756        }2757        if (MachOObjectFile *O =2758                dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2759          if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))2760            ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),2761                          ArchitectureName);2762        }2763      }2764      if (Err)2765        reportError(std::move(Err), Filename);2766    } else {2767      consumeError(AOrErr.takeError());2768      reportError(Filename, "Mach-O universal file for architecture " +2769                                StringRef(I->getArchFlagName()) +2770                                " is not a Mach-O file or an archive file");2771    }2772  }2773}2774 2775namespace {2776// The block of info used by the Symbolizer call backs.2777struct DisassembleInfo {2778  DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,2779                  std::vector<SectionRef> *Sections, bool verbose)2780    : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}2781  bool verbose;2782  MachOObjectFile *O;2783  SectionRef S;2784  SymbolAddressMap *AddrMap;2785  std::vector<SectionRef> *Sections;2786  const char *class_name = nullptr;2787  const char *selector_name = nullptr;2788  std::unique_ptr<char[]> method = nullptr;2789  char *demangled_name = nullptr;2790  uint64_t adrp_addr = 0;2791  uint32_t adrp_inst = 0;2792  std::unique_ptr<SymbolAddressMap> bindtable;2793  uint32_t depth = 0;2794};2795} // namespace2796 2797// SymbolizerGetOpInfo() is the operand information call back function.2798// This is called to get the symbolic information for operand(s) of an2799// instruction when it is being done.  This routine does this from2800// the relocation information, symbol table, etc. That block of information2801// is a pointer to the struct DisassembleInfo that was passed when the2802// disassembler context was created and passed to back to here when2803// called back by the disassembler for instruction operands that could have2804// relocation information. The address of the instruction containing operand is2805// at the Pc parameter.  The immediate value the operand has is passed in2806// op_info->Value and is at Offset past the start of the instruction and has a2807// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the2808// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol2809// names and addends of the symbolic expression to add for the operand.  The2810// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic2811// information is returned then this function returns 1 else it returns 0.2812static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,2813                               uint64_t OpSize, uint64_t InstSize, int TagType,2814                               void *TagBuf) {2815  struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;2816  struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;2817  uint64_t value = op_info->Value;2818 2819  // Make sure all fields returned are zero if we don't set them.2820  memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));2821  op_info->Value = value;2822 2823  // If the TagType is not the value 1 which it code knows about or if no2824  // verbose symbolic information is wanted then just return 0, indicating no2825  // information is being returned.2826  if (TagType != 1 || !info->verbose)2827    return 0;2828 2829  unsigned int Arch = info->O->getArch();2830  if (Arch == Triple::x86) {2831    if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2832      return 0;2833    if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2834      // TODO:2835      // Search the external relocation entries of a fully linked image2836      // (if any) for an entry that matches this segment offset.2837      // uint32_t seg_offset = (Pc + Offset);2838      return 0;2839    }2840    // In MH_OBJECT filetypes search the section's relocation entries (if any)2841    // for an entry for this section offset.2842    uint32_t sect_addr = info->S.getAddress();2843    uint32_t sect_offset = (Pc + Offset) - sect_addr;2844    bool reloc_found = false;2845    DataRefImpl Rel;2846    MachO::any_relocation_info RE;2847    bool isExtern = false;2848    SymbolRef Symbol;2849    bool r_scattered = false;2850    uint32_t r_value, pair_r_value, r_type;2851    for (const RelocationRef &Reloc : info->S.relocations()) {2852      uint64_t RelocOffset = Reloc.getOffset();2853      if (RelocOffset == sect_offset) {2854        Rel = Reloc.getRawDataRefImpl();2855        RE = info->O->getRelocation(Rel);2856        r_type = info->O->getAnyRelocationType(RE);2857        r_scattered = info->O->isRelocationScattered(RE);2858        if (r_scattered) {2859          r_value = info->O->getScatteredRelocationValue(RE);2860          if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2861              r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {2862            DataRefImpl RelNext = Rel;2863            info->O->moveRelocationNext(RelNext);2864            MachO::any_relocation_info RENext;2865            RENext = info->O->getRelocation(RelNext);2866            if (info->O->isRelocationScattered(RENext))2867              pair_r_value = info->O->getScatteredRelocationValue(RENext);2868            else2869              return 0;2870          }2871        } else {2872          isExtern = info->O->getPlainRelocationExternal(RE);2873          if (isExtern) {2874            symbol_iterator RelocSym = Reloc.getSymbol();2875            Symbol = *RelocSym;2876          }2877        }2878        reloc_found = true;2879        break;2880      }2881    }2882    if (reloc_found && isExtern) {2883      op_info->AddSymbol.Present = 1;2884      op_info->AddSymbol.Name =2885          unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2886      // For i386 extern relocation entries the value in the instruction is2887      // the offset from the symbol, and value is already set in op_info->Value.2888      return 1;2889    }2890    if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2891                        r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {2892      const char *add = GuessSymbolName(r_value, info->AddrMap);2893      const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);2894      uint32_t offset = value - (r_value - pair_r_value);2895      op_info->AddSymbol.Present = 1;2896      if (add != nullptr)2897        op_info->AddSymbol.Name = add;2898      else2899        op_info->AddSymbol.Value = r_value;2900      op_info->SubtractSymbol.Present = 1;2901      if (sub != nullptr)2902        op_info->SubtractSymbol.Name = sub;2903      else2904        op_info->SubtractSymbol.Value = pair_r_value;2905      op_info->Value = offset;2906      return 1;2907    }2908    return 0;2909  }2910  if (Arch == Triple::x86_64) {2911    if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2912      return 0;2913    // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external2914    // relocation entries of a linked image (if any) for an entry that matches2915    // this segment offset.2916    if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2917      uint64_t seg_offset = Pc + Offset;2918      bool reloc_found = false;2919      DataRefImpl Rel;2920      MachO::any_relocation_info RE;2921      bool isExtern = false;2922      SymbolRef Symbol;2923      for (const RelocationRef &Reloc : info->O->external_relocations()) {2924        uint64_t RelocOffset = Reloc.getOffset();2925        if (RelocOffset == seg_offset) {2926          Rel = Reloc.getRawDataRefImpl();2927          RE = info->O->getRelocation(Rel);2928          // external relocation entries should always be external.2929          isExtern = info->O->getPlainRelocationExternal(RE);2930          if (isExtern) {2931            symbol_iterator RelocSym = Reloc.getSymbol();2932            Symbol = *RelocSym;2933          }2934          reloc_found = true;2935          break;2936        }2937      }2938      if (reloc_found && isExtern) {2939        // The Value passed in will be adjusted by the Pc if the instruction2940        // adds the Pc.  But for x86_64 external relocation entries the Value2941        // is the offset from the external symbol.2942        if (info->O->getAnyRelocationPCRel(RE))2943          op_info->Value -= Pc + InstSize;2944        const char *name =2945            unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2946        op_info->AddSymbol.Present = 1;2947        op_info->AddSymbol.Name = name;2948        return 1;2949      }2950      return 0;2951    }2952    // In MH_OBJECT filetypes search the section's relocation entries (if any)2953    // for an entry for this section offset.2954    uint64_t sect_addr = info->S.getAddress();2955    uint64_t sect_offset = (Pc + Offset) - sect_addr;2956    bool reloc_found = false;2957    DataRefImpl Rel;2958    MachO::any_relocation_info RE;2959    bool isExtern = false;2960    SymbolRef Symbol;2961    for (const RelocationRef &Reloc : info->S.relocations()) {2962      uint64_t RelocOffset = Reloc.getOffset();2963      if (RelocOffset == sect_offset) {2964        Rel = Reloc.getRawDataRefImpl();2965        RE = info->O->getRelocation(Rel);2966        // NOTE: Scattered relocations don't exist on x86_64.2967        isExtern = info->O->getPlainRelocationExternal(RE);2968        if (isExtern) {2969          symbol_iterator RelocSym = Reloc.getSymbol();2970          Symbol = *RelocSym;2971        }2972        reloc_found = true;2973        break;2974      }2975    }2976    if (reloc_found && isExtern) {2977      // The Value passed in will be adjusted by the Pc if the instruction2978      // adds the Pc.  But for x86_64 external relocation entries the Value2979      // is the offset from the external symbol.2980      if (info->O->getAnyRelocationPCRel(RE))2981        op_info->Value -= Pc + InstSize;2982      const char *name =2983          unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2984      unsigned Type = info->O->getAnyRelocationType(RE);2985      if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {2986        DataRefImpl RelNext = Rel;2987        info->O->moveRelocationNext(RelNext);2988        MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);2989        unsigned TypeNext = info->O->getAnyRelocationType(RENext);2990        bool isExternNext = info->O->getPlainRelocationExternal(RENext);2991        unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);2992        if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {2993          op_info->SubtractSymbol.Present = 1;2994          op_info->SubtractSymbol.Name = name;2995          symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);2996          Symbol = *RelocSymNext;2997          name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2998        }2999      }3000      // TODO: add the VariantKinds to op_info->VariantKind for relocation types3001      // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.3002      op_info->AddSymbol.Present = 1;3003      op_info->AddSymbol.Name = name;3004      return 1;3005    }3006    return 0;3007  }3008  if (Arch == Triple::arm) {3009    if (Offset != 0 || (InstSize != 4 && InstSize != 2))3010      return 0;3011    if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3012      // TODO:3013      // Search the external relocation entries of a fully linked image3014      // (if any) for an entry that matches this segment offset.3015      // uint32_t seg_offset = (Pc + Offset);3016      return 0;3017    }3018    // In MH_OBJECT filetypes search the section's relocation entries (if any)3019    // for an entry for this section offset.3020    uint32_t sect_addr = info->S.getAddress();3021    uint32_t sect_offset = (Pc + Offset) - sect_addr;3022    DataRefImpl Rel;3023    MachO::any_relocation_info RE;3024    bool isExtern = false;3025    SymbolRef Symbol;3026    bool r_scattered = false;3027    uint32_t r_value, pair_r_value, r_type, r_length, other_half;3028    auto Reloc =3029        find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3030          uint64_t RelocOffset = Reloc.getOffset();3031          return RelocOffset == sect_offset;3032        });3033 3034    if (Reloc == info->S.relocations().end())3035      return 0;3036 3037    Rel = Reloc->getRawDataRefImpl();3038    RE = info->O->getRelocation(Rel);3039    r_length = info->O->getAnyRelocationLength(RE);3040    r_scattered = info->O->isRelocationScattered(RE);3041    if (r_scattered) {3042      r_value = info->O->getScatteredRelocationValue(RE);3043      r_type = info->O->getScatteredRelocationType(RE);3044    } else {3045      r_type = info->O->getAnyRelocationType(RE);3046      isExtern = info->O->getPlainRelocationExternal(RE);3047      if (isExtern) {3048        symbol_iterator RelocSym = Reloc->getSymbol();3049        Symbol = *RelocSym;3050      }3051    }3052    if (r_type == MachO::ARM_RELOC_HALF ||3053        r_type == MachO::ARM_RELOC_SECTDIFF ||3054        r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||3055        r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3056      DataRefImpl RelNext = Rel;3057      info->O->moveRelocationNext(RelNext);3058      MachO::any_relocation_info RENext;3059      RENext = info->O->getRelocation(RelNext);3060      other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;3061      if (info->O->isRelocationScattered(RENext))3062        pair_r_value = info->O->getScatteredRelocationValue(RENext);3063    }3064 3065    if (isExtern) {3066      const char *name =3067          unwrapOrError(Symbol.getName(), info->O->getFileName()).data();3068      op_info->AddSymbol.Present = 1;3069      op_info->AddSymbol.Name = name;3070      switch (r_type) {3071      case MachO::ARM_RELOC_HALF:3072        if ((r_length & 0x1) == 1) {3073          op_info->Value = value << 16 | other_half;3074          op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3075        } else {3076          op_info->Value = other_half << 16 | value;3077          op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3078        }3079        break;3080      default:3081        break;3082      }3083      return 1;3084    }3085    // If we have a branch that is not an external relocation entry then3086    // return 0 so the code in tryAddingSymbolicOperand() can use the3087    // SymbolLookUp call back with the branch target address to look up the3088    // symbol and possibility add an annotation for a symbol stub.3089    if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||3090                          r_type == MachO::ARM_THUMB_RELOC_BR22))3091      return 0;3092 3093    uint32_t offset = 0;3094    if (r_type == MachO::ARM_RELOC_HALF ||3095        r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3096      if ((r_length & 0x1) == 1)3097        value = value << 16 | other_half;3098      else3099        value = other_half << 16 | value;3100    }3101    if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&3102                        r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {3103      offset = value - r_value;3104      value = r_value;3105    }3106 3107    if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3108      if ((r_length & 0x1) == 1)3109        op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3110      else3111        op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3112      const char *add = GuessSymbolName(r_value, info->AddrMap);3113      const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);3114      int32_t offset = value - (r_value - pair_r_value);3115      op_info->AddSymbol.Present = 1;3116      if (add != nullptr)3117        op_info->AddSymbol.Name = add;3118      else3119        op_info->AddSymbol.Value = r_value;3120      op_info->SubtractSymbol.Present = 1;3121      if (sub != nullptr)3122        op_info->SubtractSymbol.Name = sub;3123      else3124        op_info->SubtractSymbol.Value = pair_r_value;3125      op_info->Value = offset;3126      return 1;3127    }3128 3129    op_info->AddSymbol.Present = 1;3130    op_info->Value = offset;3131    if (r_type == MachO::ARM_RELOC_HALF) {3132      if ((r_length & 0x1) == 1)3133        op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3134      else3135        op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3136    }3137    const char *add = GuessSymbolName(value, info->AddrMap);3138    if (add != nullptr) {3139      op_info->AddSymbol.Name = add;3140      return 1;3141    }3142    op_info->AddSymbol.Value = value;3143    return 1;3144  }3145  if (Arch == Triple::aarch64) {3146    if (Offset != 0 || InstSize != 4)3147      return 0;3148    if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3149      // TODO:3150      // Search the external relocation entries of a fully linked image3151      // (if any) for an entry that matches this segment offset.3152      // uint64_t seg_offset = (Pc + Offset);3153      return 0;3154    }3155    // In MH_OBJECT filetypes search the section's relocation entries (if any)3156    // for an entry for this section offset.3157    uint64_t sect_addr = info->S.getAddress();3158    uint64_t sect_offset = (Pc + Offset) - sect_addr;3159    auto Reloc =3160        find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3161          uint64_t RelocOffset = Reloc.getOffset();3162          return RelocOffset == sect_offset;3163        });3164 3165    if (Reloc == info->S.relocations().end())3166      return 0;3167 3168    DataRefImpl Rel = Reloc->getRawDataRefImpl();3169    MachO::any_relocation_info RE = info->O->getRelocation(Rel);3170    uint32_t r_type = info->O->getAnyRelocationType(RE);3171    if (r_type == MachO::ARM64_RELOC_ADDEND) {3172      DataRefImpl RelNext = Rel;3173      info->O->moveRelocationNext(RelNext);3174      MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);3175      if (value == 0) {3176        value = info->O->getPlainRelocationSymbolNum(RENext);3177        op_info->Value = value;3178      }3179    }3180    // NOTE: Scattered relocations don't exist on arm64.3181    if (!info->O->getPlainRelocationExternal(RE))3182      return 0;3183    const char *name =3184        unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())3185            .data();3186    op_info->AddSymbol.Present = 1;3187    op_info->AddSymbol.Name = name;3188 3189    switch (r_type) {3190    case MachO::ARM64_RELOC_PAGE21:3191      /* @page */3192      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;3193      break;3194    case MachO::ARM64_RELOC_PAGEOFF12:3195      /* @pageoff */3196      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;3197      break;3198    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:3199      /* @gotpage */3200      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;3201      break;3202    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:3203      /* @gotpageoff */3204      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;3205      break;3206    case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:3207      /* @tvlppage is not implemented in llvm-mc */3208      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;3209      break;3210    case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:3211      /* @tvlppageoff is not implemented in llvm-mc */3212      op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;3213      break;3214    default:3215    case MachO::ARM64_RELOC_BRANCH26:3216      op_info->VariantKind = LLVMDisassembler_VariantKind_None;3217      break;3218    }3219    return 1;3220  }3221  return 0;3222}3223 3224// GuessCstringPointer is passed the address of what might be a pointer to a3225// literal string in a cstring section.  If that address is in a cstring section3226// it returns a pointer to that string.  Else it returns nullptr.3227static const char *GuessCstringPointer(uint64_t ReferenceValue,3228                                       struct DisassembleInfo *info) {3229  for (const auto &Load : info->O->load_commands()) {3230    if (Load.C.cmd == MachO::LC_SEGMENT_64) {3231      MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3232      for (unsigned J = 0; J < Seg.nsects; ++J) {3233        MachO::section_64 Sec = info->O->getSection64(Load, J);3234        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3235        if (section_type == MachO::S_CSTRING_LITERALS &&3236            ReferenceValue >= Sec.addr &&3237            ReferenceValue < Sec.addr + Sec.size) {3238          uint64_t sect_offset = ReferenceValue - Sec.addr;3239          uint64_t object_offset = Sec.offset + sect_offset;3240          StringRef MachOContents = info->O->getData();3241          uint64_t object_size = MachOContents.size();3242          const char *object_addr = MachOContents.data();3243          if (object_offset < object_size) {3244            const char *name = object_addr + object_offset;3245            return name;3246          } else {3247            return nullptr;3248          }3249        }3250      }3251    } else if (Load.C.cmd == MachO::LC_SEGMENT) {3252      MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3253      for (unsigned J = 0; J < Seg.nsects; ++J) {3254        MachO::section Sec = info->O->getSection(Load, J);3255        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3256        if (section_type == MachO::S_CSTRING_LITERALS &&3257            ReferenceValue >= Sec.addr &&3258            ReferenceValue < Sec.addr + Sec.size) {3259          uint64_t sect_offset = ReferenceValue - Sec.addr;3260          uint64_t object_offset = Sec.offset + sect_offset;3261          StringRef MachOContents = info->O->getData();3262          uint64_t object_size = MachOContents.size();3263          const char *object_addr = MachOContents.data();3264          if (object_offset < object_size) {3265            const char *name = object_addr + object_offset;3266            return name;3267          } else {3268            return nullptr;3269          }3270        }3271      }3272    }3273  }3274  return nullptr;3275}3276 3277// GuessIndirectSymbol returns the name of the indirect symbol for the3278// ReferenceValue passed in or nullptr.  This is used when ReferenceValue maybe3279// an address of a symbol stub or a lazy or non-lazy pointer to associate the3280// symbol name being referenced by the stub or pointer.3281static const char *GuessIndirectSymbol(uint64_t ReferenceValue,3282                                       struct DisassembleInfo *info) {3283  MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();3284  MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();3285  for (const auto &Load : info->O->load_commands()) {3286    if (Load.C.cmd == MachO::LC_SEGMENT_64) {3287      MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3288      for (unsigned J = 0; J < Seg.nsects; ++J) {3289        MachO::section_64 Sec = info->O->getSection64(Load, J);3290        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3291        if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3292             section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3293             section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3294             section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3295             section_type == MachO::S_SYMBOL_STUBS) &&3296            ReferenceValue >= Sec.addr &&3297            ReferenceValue < Sec.addr + Sec.size) {3298          uint32_t stride;3299          if (section_type == MachO::S_SYMBOL_STUBS)3300            stride = Sec.reserved2;3301          else3302            stride = 8;3303          if (stride == 0)3304            return nullptr;3305          uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3306          if (index < Dysymtab.nindirectsyms) {3307            uint32_t indirect_symbol =3308                info->O->getIndirectSymbolTableEntry(Dysymtab, index);3309            if (indirect_symbol < Symtab.nsyms) {3310              symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3311              return unwrapOrError(Sym->getName(), info->O->getFileName())3312                  .data();3313            }3314          }3315        }3316      }3317    } else if (Load.C.cmd == MachO::LC_SEGMENT) {3318      MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3319      for (unsigned J = 0; J < Seg.nsects; ++J) {3320        MachO::section Sec = info->O->getSection(Load, J);3321        uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3322        if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3323             section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3324             section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3325             section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3326             section_type == MachO::S_SYMBOL_STUBS) &&3327            ReferenceValue >= Sec.addr &&3328            ReferenceValue < Sec.addr + Sec.size) {3329          uint32_t stride;3330          if (section_type == MachO::S_SYMBOL_STUBS)3331            stride = Sec.reserved2;3332          else3333            stride = 4;3334          if (stride == 0)3335            return nullptr;3336          uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3337          if (index < Dysymtab.nindirectsyms) {3338            uint32_t indirect_symbol =3339                info->O->getIndirectSymbolTableEntry(Dysymtab, index);3340            if (indirect_symbol < Symtab.nsyms) {3341              symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3342              return unwrapOrError(Sym->getName(), info->O->getFileName())3343                  .data();3344            }3345          }3346        }3347      }3348    }3349  }3350  return nullptr;3351}3352 3353// method_reference() is called passing it the ReferenceName that might be3354// a reference it to an Objective-C method call.  If so then it allocates and3355// assembles a method call string with the values last seen and saved in3356// the DisassembleInfo's class_name and selector_name fields.  This is saved3357// into the method field of the info and any previous string is free'ed.3358// Then the class_name field in the info is set to nullptr.  The method call3359// string is set into ReferenceName and ReferenceType is set to3360// LLVMDisassembler_ReferenceType_Out_Objc_Message.  If this not a method call3361// then both ReferenceType and ReferenceName are left unchanged.3362static void method_reference(struct DisassembleInfo *info,3363                             uint64_t *ReferenceType,3364                             const char **ReferenceName) {3365  unsigned int Arch = info->O->getArch();3366  if (*ReferenceName != nullptr) {3367    if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {3368      if (info->selector_name != nullptr) {3369        if (info->class_name != nullptr) {3370          info->method = std::make_unique<char[]>(3371              5 + strlen(info->class_name) + strlen(info->selector_name));3372          char *method = info->method.get();3373          if (method != nullptr) {3374            strcpy(method, "+[");3375            strcat(method, info->class_name);3376            strcat(method, " ");3377            strcat(method, info->selector_name);3378            strcat(method, "]");3379            *ReferenceName = method;3380            *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3381          }3382        } else {3383          info->method =3384              std::make_unique<char[]>(9 + strlen(info->selector_name));3385          char *method = info->method.get();3386          if (method != nullptr) {3387            if (Arch == Triple::x86_64)3388              strcpy(method, "-[%rdi ");3389            else if (Arch == Triple::aarch64)3390              strcpy(method, "-[x0 ");3391            else3392              strcpy(method, "-[r? ");3393            strcat(method, info->selector_name);3394            strcat(method, "]");3395            *ReferenceName = method;3396            *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3397          }3398        }3399        info->class_name = nullptr;3400      }3401    } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {3402      if (info->selector_name != nullptr) {3403        info->method =3404            std::make_unique<char[]>(17 + strlen(info->selector_name));3405        char *method = info->method.get();3406        if (method != nullptr) {3407          if (Arch == Triple::x86_64)3408            strcpy(method, "-[[%rdi super] ");3409          else if (Arch == Triple::aarch64)3410            strcpy(method, "-[[x0 super] ");3411          else3412            strcpy(method, "-[[r? super] ");3413          strcat(method, info->selector_name);3414          strcat(method, "]");3415          *ReferenceName = method;3416          *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3417        }3418        info->class_name = nullptr;3419      }3420    }3421  }3422}3423 3424// GuessPointerPointer() is passed the address of what might be a pointer to3425// a reference to an Objective-C class, selector, message ref or cfstring.3426// If so the value of the pointer is returned and one of the booleans are set3427// to true.  If not zero is returned and all the booleans are set to false.3428static uint64_t GuessPointerPointer(uint64_t ReferenceValue,3429                                    struct DisassembleInfo *info,3430                                    bool &classref, bool &selref, bool &msgref,3431                                    bool &cfstring) {3432  classref = false;3433  selref = false;3434  msgref = false;3435  cfstring = false;3436  for (const auto &Load : info->O->load_commands()) {3437    if (Load.C.cmd == MachO::LC_SEGMENT_64) {3438      MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3439      for (unsigned J = 0; J < Seg.nsects; ++J) {3440        MachO::section_64 Sec = info->O->getSection64(Load, J);3441        if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||3442             strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3443             strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||3444             strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||3445             strncmp(Sec.sectname, "__cfstring", 16) == 0) &&3446            ReferenceValue >= Sec.addr &&3447            ReferenceValue < Sec.addr + Sec.size) {3448          uint64_t sect_offset = ReferenceValue - Sec.addr;3449          uint64_t object_offset = Sec.offset + sect_offset;3450          StringRef MachOContents = info->O->getData();3451          uint64_t object_size = MachOContents.size();3452          const char *object_addr = MachOContents.data();3453          if (object_offset < object_size) {3454            uint64_t pointer_value;3455            memcpy(&pointer_value, object_addr + object_offset,3456                   sizeof(uint64_t));3457            if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3458              sys::swapByteOrder(pointer_value);3459            if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)3460              selref = true;3461            else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3462                     strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)3463              classref = true;3464            else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&3465                     ReferenceValue + 8 < Sec.addr + Sec.size) {3466              msgref = true;3467              memcpy(&pointer_value, object_addr + object_offset + 8,3468                     sizeof(uint64_t));3469              if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3470                sys::swapByteOrder(pointer_value);3471            } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)3472              cfstring = true;3473            return pointer_value;3474          } else {3475            return 0;3476          }3477        }3478      }3479    }3480    // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.3481  }3482  return 0;3483}3484 3485// get_pointer_64 returns a pointer to the bytes in the object file at the3486// Address from a section in the Mach-O file.  And indirectly returns the3487// offset into the section, number of bytes left in the section past the offset3488// and which section is was being referenced.  If the Address is not in a3489// section nullptr is returned.3490static const char *get_pointer_64(uint64_t Address, uint32_t &offset,3491                                  uint32_t &left, SectionRef &S,3492                                  DisassembleInfo *info,3493                                  bool objc_only = false) {3494  offset = 0;3495  left = 0;3496  S = SectionRef();3497  for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {3498    uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();3499    uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();3500    if (SectSize == 0)3501      continue;3502    if (objc_only) {3503      StringRef SectName;3504      Expected<StringRef> SecNameOrErr =3505          ((*(info->Sections))[SectIdx]).getName();3506      if (SecNameOrErr)3507        SectName = *SecNameOrErr;3508      else3509        consumeError(SecNameOrErr.takeError());3510 3511      DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();3512      StringRef SegName = info->O->getSectionFinalSegmentName(Ref);3513      if (SegName != "__OBJC" && SectName != "__cstring")3514        continue;3515    }3516    if (Address >= SectAddress && Address < SectAddress + SectSize) {3517      S = (*(info->Sections))[SectIdx];3518      offset = Address - SectAddress;3519      left = SectSize - offset;3520      StringRef SectContents = unwrapOrError(3521          ((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());3522      return SectContents.data() + offset;3523    }3524  }3525  return nullptr;3526}3527 3528static const char *get_pointer_32(uint32_t Address, uint32_t &offset,3529                                  uint32_t &left, SectionRef &S,3530                                  DisassembleInfo *info,3531                                  bool objc_only = false) {3532  return get_pointer_64(Address, offset, left, S, info, objc_only);3533}3534 3535// get_symbol_64() returns the name of a symbol (or nullptr) and the address of3536// the symbol indirectly through n_value. Based on the relocation information3537// for the specified section offset in the specified section reference.3538// If no relocation information is found and a non-zero ReferenceValue for the3539// symbol is passed, look up that address in the info's AddrMap.3540static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,3541                                 DisassembleInfo *info, uint64_t &n_value,3542                                 uint64_t ReferenceValue = 0) {3543  n_value = 0;3544  if (!info->verbose)3545    return nullptr;3546 3547  // See if there is an external relocation entry at the sect_offset.3548  bool reloc_found = false;3549  DataRefImpl Rel;3550  MachO::any_relocation_info RE;3551  bool isExtern = false;3552  SymbolRef Symbol;3553  for (const RelocationRef &Reloc : S.relocations()) {3554    uint64_t RelocOffset = Reloc.getOffset();3555    if (RelocOffset == sect_offset) {3556      Rel = Reloc.getRawDataRefImpl();3557      RE = info->O->getRelocation(Rel);3558      if (info->O->isRelocationScattered(RE))3559        continue;3560      isExtern = info->O->getPlainRelocationExternal(RE);3561      if (isExtern) {3562        symbol_iterator RelocSym = Reloc.getSymbol();3563        Symbol = *RelocSym;3564      }3565      reloc_found = true;3566      break;3567    }3568  }3569  // If there is an external relocation entry for a symbol in this section3570  // at this section_offset then use that symbol's value for the n_value3571  // and return its name.3572  const char *SymbolName = nullptr;3573  if (reloc_found && isExtern) {3574    n_value = cantFail(Symbol.getValue());3575    StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());3576    if (!Name.empty()) {3577      SymbolName = Name.data();3578      return SymbolName;3579    }3580  }3581 3582  // TODO: For fully linked images, look through the external relocation3583  // entries off the dynamic symtab command. For these the r_offset is from the3584  // start of the first writeable segment in the Mach-O file.  So the offset3585  // to this section from that segment is passed to this routine by the caller,3586  // as the database_offset. Which is the difference of the section's starting3587  // address and the first writable segment.3588  //3589  // NOTE: need add passing the database_offset to this routine.3590 3591  // We did not find an external relocation entry so look up the ReferenceValue3592  // as an address of a symbol and if found return that symbol's name.3593  SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);3594 3595  return SymbolName;3596}3597 3598static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,3599                                 DisassembleInfo *info,3600                                 uint32_t ReferenceValue) {3601  uint64_t n_value64;3602  return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);3603}3604 3605namespace {3606 3607// These are structs in the Objective-C meta data and read to produce the3608// comments for disassembly.  While these are part of the ABI they are no3609// public defintions.  So the are here not in include/llvm/BinaryFormat/MachO.h3610// .3611 3612// The cfstring object in a 64-bit Mach-O file.3613struct cfstring64_t {3614  uint64_t isa;        // class64_t * (64-bit pointer)3615  uint64_t flags;      // flag bits3616  uint64_t characters; // char * (64-bit pointer)3617  uint64_t length;     // number of non-NULL characters in above3618};3619 3620// The class object in a 64-bit Mach-O file.3621struct class64_t {3622  uint64_t isa;        // class64_t * (64-bit pointer)3623  uint64_t superclass; // class64_t * (64-bit pointer)3624  uint64_t cache;      // Cache (64-bit pointer)3625  uint64_t vtable;     // IMP * (64-bit pointer)3626  uint64_t data;       // class_ro64_t * (64-bit pointer)3627};3628 3629struct class32_t {3630  uint32_t isa;        /* class32_t * (32-bit pointer) */3631  uint32_t superclass; /* class32_t * (32-bit pointer) */3632  uint32_t cache;      /* Cache (32-bit pointer) */3633  uint32_t vtable;     /* IMP * (32-bit pointer) */3634  uint32_t data;       /* class_ro32_t * (32-bit pointer) */3635};3636 3637struct class_ro64_t {3638  uint32_t flags;3639  uint32_t instanceStart;3640  uint32_t instanceSize;3641  uint32_t reserved;3642  uint64_t ivarLayout;     // const uint8_t * (64-bit pointer)3643  uint64_t name;           // const char * (64-bit pointer)3644  uint64_t baseMethods;    // const method_list_t * (64-bit pointer)3645  uint64_t baseProtocols;  // const protocol_list_t * (64-bit pointer)3646  uint64_t ivars;          // const ivar_list_t * (64-bit pointer)3647  uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)3648  uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)3649};3650 3651struct class_ro32_t {3652  uint32_t flags;3653  uint32_t instanceStart;3654  uint32_t instanceSize;3655  uint32_t ivarLayout;     /* const uint8_t * (32-bit pointer) */3656  uint32_t name;           /* const char * (32-bit pointer) */3657  uint32_t baseMethods;    /* const method_list_t * (32-bit pointer) */3658  uint32_t baseProtocols;  /* const protocol_list_t * (32-bit pointer) */3659  uint32_t ivars;          /* const ivar_list_t * (32-bit pointer) */3660  uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */3661  uint32_t baseProperties; /* const struct objc_property_list *3662                                                   (32-bit pointer) */3663};3664 3665/* Values for class_ro{64,32}_t->flags */3666#define RO_META (1 << 0)3667#define RO_ROOT (1 << 1)3668#define RO_HAS_CXX_STRUCTORS (1 << 2)3669 3670/* Values for method_list{64,32}_t->entsize */3671#define ML_HAS_RELATIVE_PTRS (1 << 31)3672#define ML_ENTSIZE_MASK 0xFFFF3673 3674struct method_list64_t {3675  uint32_t entsize;3676  uint32_t count;3677  /* struct method64_t first;  These structures follow inline */3678};3679 3680struct method_list32_t {3681  uint32_t entsize;3682  uint32_t count;3683  /* struct method32_t first;  These structures follow inline */3684};3685 3686struct method64_t {3687  uint64_t name;  /* SEL (64-bit pointer) */3688  uint64_t types; /* const char * (64-bit pointer) */3689  uint64_t imp;   /* IMP (64-bit pointer) */3690};3691 3692struct method32_t {3693  uint32_t name;  /* SEL (32-bit pointer) */3694  uint32_t types; /* const char * (32-bit pointer) */3695  uint32_t imp;   /* IMP (32-bit pointer) */3696};3697 3698struct method_relative_t {3699  int32_t name;  /* SEL (32-bit relative) */3700  int32_t types; /* const char * (32-bit relative) */3701  int32_t imp;   /* IMP (32-bit relative) */3702};3703 3704struct protocol_list64_t {3705  uint64_t count; /* uintptr_t (a 64-bit value) */3706  /* struct protocol64_t * list[0];  These pointers follow inline */3707};3708 3709struct protocol_list32_t {3710  uint32_t count; /* uintptr_t (a 32-bit value) */3711  /* struct protocol32_t * list[0];  These pointers follow inline */3712};3713 3714struct protocol64_t {3715  uint64_t isa;                     /* id * (64-bit pointer) */3716  uint64_t name;                    /* const char * (64-bit pointer) */3717  uint64_t protocols;               /* struct protocol_list64_t *3718                                                    (64-bit pointer) */3719  uint64_t instanceMethods;         /* method_list_t * (64-bit pointer) */3720  uint64_t classMethods;            /* method_list_t * (64-bit pointer) */3721  uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */3722  uint64_t optionalClassMethods;    /* method_list_t * (64-bit pointer) */3723  uint64_t instanceProperties;      /* struct objc_property_list *3724                                                       (64-bit pointer) */3725};3726 3727struct protocol32_t {3728  uint32_t isa;                     /* id * (32-bit pointer) */3729  uint32_t name;                    /* const char * (32-bit pointer) */3730  uint32_t protocols;               /* struct protocol_list_t *3731                                                    (32-bit pointer) */3732  uint32_t instanceMethods;         /* method_list_t * (32-bit pointer) */3733  uint32_t classMethods;            /* method_list_t * (32-bit pointer) */3734  uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */3735  uint32_t optionalClassMethods;    /* method_list_t * (32-bit pointer) */3736  uint32_t instanceProperties;      /* struct objc_property_list *3737                                                       (32-bit pointer) */3738};3739 3740struct ivar_list64_t {3741  uint32_t entsize;3742  uint32_t count;3743  /* struct ivar64_t first;  These structures follow inline */3744};3745 3746struct ivar_list32_t {3747  uint32_t entsize;3748  uint32_t count;3749  /* struct ivar32_t first;  These structures follow inline */3750};3751 3752struct ivar64_t {3753  uint64_t offset; /* uintptr_t * (64-bit pointer) */3754  uint64_t name;   /* const char * (64-bit pointer) */3755  uint64_t type;   /* const char * (64-bit pointer) */3756  uint32_t alignment;3757  uint32_t size;3758};3759 3760struct ivar32_t {3761  uint32_t offset; /* uintptr_t * (32-bit pointer) */3762  uint32_t name;   /* const char * (32-bit pointer) */3763  uint32_t type;   /* const char * (32-bit pointer) */3764  uint32_t alignment;3765  uint32_t size;3766};3767 3768struct objc_property_list64 {3769  uint32_t entsize;3770  uint32_t count;3771  /* struct objc_property64 first;  These structures follow inline */3772};3773 3774struct objc_property_list32 {3775  uint32_t entsize;3776  uint32_t count;3777  /* struct objc_property32 first;  These structures follow inline */3778};3779 3780struct objc_property64 {3781  uint64_t name;       /* const char * (64-bit pointer) */3782  uint64_t attributes; /* const char * (64-bit pointer) */3783};3784 3785struct objc_property32 {3786  uint32_t name;       /* const char * (32-bit pointer) */3787  uint32_t attributes; /* const char * (32-bit pointer) */3788};3789 3790struct category64_t {3791  uint64_t name;               /* const char * (64-bit pointer) */3792  uint64_t cls;                /* struct class_t * (64-bit pointer) */3793  uint64_t instanceMethods;    /* struct method_list_t * (64-bit pointer) */3794  uint64_t classMethods;       /* struct method_list_t * (64-bit pointer) */3795  uint64_t protocols;          /* struct protocol_list_t * (64-bit pointer) */3796  uint64_t instanceProperties; /* struct objc_property_list *3797                                  (64-bit pointer) */3798};3799 3800struct category32_t {3801  uint32_t name;               /* const char * (32-bit pointer) */3802  uint32_t cls;                /* struct class_t * (32-bit pointer) */3803  uint32_t instanceMethods;    /* struct method_list_t * (32-bit pointer) */3804  uint32_t classMethods;       /* struct method_list_t * (32-bit pointer) */3805  uint32_t protocols;          /* struct protocol_list_t * (32-bit pointer) */3806  uint32_t instanceProperties; /* struct objc_property_list *3807                                  (32-bit pointer) */3808};3809 3810struct objc_image_info64 {3811  uint32_t version;3812  uint32_t flags;3813};3814struct objc_image_info32 {3815  uint32_t version;3816  uint32_t flags;3817};3818struct imageInfo_t {3819  uint32_t version;3820  uint32_t flags;3821};3822/* masks for objc_image_info.flags */3823#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)3824#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)3825#define OBJC_IMAGE_IS_SIMULATED (1 << 5)3826#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)3827 3828struct message_ref64 {3829  uint64_t imp; /* IMP (64-bit pointer) */3830  uint64_t sel; /* SEL (64-bit pointer) */3831};3832 3833struct message_ref32 {3834  uint32_t imp; /* IMP (32-bit pointer) */3835  uint32_t sel; /* SEL (32-bit pointer) */3836};3837 3838// Objective-C 1 (32-bit only) meta data structs.3839 3840struct objc_module_t {3841  uint32_t version;3842  uint32_t size;3843  uint32_t name;   /* char * (32-bit pointer) */3844  uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */3845};3846 3847struct objc_symtab_t {3848  uint32_t sel_ref_cnt;3849  uint32_t refs; /* SEL * (32-bit pointer) */3850  uint16_t cls_def_cnt;3851  uint16_t cat_def_cnt;3852  // uint32_t defs[1];        /* void * (32-bit pointer) variable size */3853};3854 3855struct objc_class_t {3856  uint32_t isa;         /* struct objc_class * (32-bit pointer) */3857  uint32_t super_class; /* struct objc_class * (32-bit pointer) */3858  uint32_t name;        /* const char * (32-bit pointer) */3859  int32_t version;3860  int32_t info;3861  int32_t instance_size;3862  uint32_t ivars;       /* struct objc_ivar_list * (32-bit pointer) */3863  uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */3864  uint32_t cache;       /* struct objc_cache * (32-bit pointer) */3865  uint32_t protocols;   /* struct objc_protocol_list * (32-bit pointer) */3866};3867 3868#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))3869// class is not a metaclass3870#define CLS_CLASS 0x13871// class is a metaclass3872#define CLS_META 0x23873 3874struct objc_category_t {3875  uint32_t category_name;    /* char * (32-bit pointer) */3876  uint32_t class_name;       /* char * (32-bit pointer) */3877  uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */3878  uint32_t class_methods;    /* struct objc_method_list * (32-bit pointer) */3879  uint32_t protocols;        /* struct objc_protocol_list * (32-bit ptr) */3880};3881 3882struct objc_ivar_t {3883  uint32_t ivar_name; /* char * (32-bit pointer) */3884  uint32_t ivar_type; /* char * (32-bit pointer) */3885  int32_t ivar_offset;3886};3887 3888struct objc_ivar_list_t {3889  int32_t ivar_count;3890  // struct objc_ivar_t ivar_list[1];          /* variable length structure */3891};3892 3893struct objc_method_list_t {3894  uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */3895  int32_t method_count;3896  // struct objc_method_t method_list[1];      /* variable length structure */3897};3898 3899struct objc_method_t {3900  uint32_t method_name;  /* SEL, aka struct objc_selector * (32-bit pointer) */3901  uint32_t method_types; /* char * (32-bit pointer) */3902  uint32_t method_imp;   /* IMP, aka function pointer, (*IMP)(id, SEL, ...)3903                            (32-bit pointer) */3904};3905 3906struct objc_protocol_list_t {3907  uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */3908  int32_t count;3909  // uint32_t list[1];   /* Protocol *, aka struct objc_protocol_t *3910  //                        (32-bit pointer) */3911};3912 3913struct objc_protocol_t {3914  uint32_t isa;              /* struct objc_class * (32-bit pointer) */3915  uint32_t protocol_name;    /* char * (32-bit pointer) */3916  uint32_t protocol_list;    /* struct objc_protocol_list * (32-bit pointer) */3917  uint32_t instance_methods; /* struct objc_method_description_list *3918                                (32-bit pointer) */3919  uint32_t class_methods;    /* struct objc_method_description_list *3920                                (32-bit pointer) */3921};3922 3923struct objc_method_description_list_t {3924  int32_t count;3925  // struct objc_method_description_t list[1];3926};3927 3928struct objc_method_description_t {3929  uint32_t name;  /* SEL, aka struct objc_selector * (32-bit pointer) */3930  uint32_t types; /* char * (32-bit pointer) */3931};3932 3933inline void swapStruct(struct cfstring64_t &cfs) {3934  sys::swapByteOrder(cfs.isa);3935  sys::swapByteOrder(cfs.flags);3936  sys::swapByteOrder(cfs.characters);3937  sys::swapByteOrder(cfs.length);3938}3939 3940inline void swapStruct(struct class64_t &c) {3941  sys::swapByteOrder(c.isa);3942  sys::swapByteOrder(c.superclass);3943  sys::swapByteOrder(c.cache);3944  sys::swapByteOrder(c.vtable);3945  sys::swapByteOrder(c.data);3946}3947 3948inline void swapStruct(struct class32_t &c) {3949  sys::swapByteOrder(c.isa);3950  sys::swapByteOrder(c.superclass);3951  sys::swapByteOrder(c.cache);3952  sys::swapByteOrder(c.vtable);3953  sys::swapByteOrder(c.data);3954}3955 3956inline void swapStruct(struct class_ro64_t &cro) {3957  sys::swapByteOrder(cro.flags);3958  sys::swapByteOrder(cro.instanceStart);3959  sys::swapByteOrder(cro.instanceSize);3960  sys::swapByteOrder(cro.reserved);3961  sys::swapByteOrder(cro.ivarLayout);3962  sys::swapByteOrder(cro.name);3963  sys::swapByteOrder(cro.baseMethods);3964  sys::swapByteOrder(cro.baseProtocols);3965  sys::swapByteOrder(cro.ivars);3966  sys::swapByteOrder(cro.weakIvarLayout);3967  sys::swapByteOrder(cro.baseProperties);3968}3969 3970inline void swapStruct(struct class_ro32_t &cro) {3971  sys::swapByteOrder(cro.flags);3972  sys::swapByteOrder(cro.instanceStart);3973  sys::swapByteOrder(cro.instanceSize);3974  sys::swapByteOrder(cro.ivarLayout);3975  sys::swapByteOrder(cro.name);3976  sys::swapByteOrder(cro.baseMethods);3977  sys::swapByteOrder(cro.baseProtocols);3978  sys::swapByteOrder(cro.ivars);3979  sys::swapByteOrder(cro.weakIvarLayout);3980  sys::swapByteOrder(cro.baseProperties);3981}3982 3983inline void swapStruct(struct method_list64_t &ml) {3984  sys::swapByteOrder(ml.entsize);3985  sys::swapByteOrder(ml.count);3986}3987 3988inline void swapStruct(struct method_list32_t &ml) {3989  sys::swapByteOrder(ml.entsize);3990  sys::swapByteOrder(ml.count);3991}3992 3993inline void swapStruct(struct method64_t &m) {3994  sys::swapByteOrder(m.name);3995  sys::swapByteOrder(m.types);3996  sys::swapByteOrder(m.imp);3997}3998 3999inline void swapStruct(struct method32_t &m) {4000  sys::swapByteOrder(m.name);4001  sys::swapByteOrder(m.types);4002  sys::swapByteOrder(m.imp);4003}4004 4005inline void swapStruct(struct method_relative_t &m) {4006  sys::swapByteOrder(m.name);4007  sys::swapByteOrder(m.types);4008  sys::swapByteOrder(m.imp);4009}4010 4011inline void swapStruct(struct protocol_list64_t &pl) {4012  sys::swapByteOrder(pl.count);4013}4014 4015inline void swapStruct(struct protocol_list32_t &pl) {4016  sys::swapByteOrder(pl.count);4017}4018 4019inline void swapStruct(struct protocol64_t &p) {4020  sys::swapByteOrder(p.isa);4021  sys::swapByteOrder(p.name);4022  sys::swapByteOrder(p.protocols);4023  sys::swapByteOrder(p.instanceMethods);4024  sys::swapByteOrder(p.classMethods);4025  sys::swapByteOrder(p.optionalInstanceMethods);4026  sys::swapByteOrder(p.optionalClassMethods);4027  sys::swapByteOrder(p.instanceProperties);4028}4029 4030inline void swapStruct(struct protocol32_t &p) {4031  sys::swapByteOrder(p.isa);4032  sys::swapByteOrder(p.name);4033  sys::swapByteOrder(p.protocols);4034  sys::swapByteOrder(p.instanceMethods);4035  sys::swapByteOrder(p.classMethods);4036  sys::swapByteOrder(p.optionalInstanceMethods);4037  sys::swapByteOrder(p.optionalClassMethods);4038  sys::swapByteOrder(p.instanceProperties);4039}4040 4041inline void swapStruct(struct ivar_list64_t &il) {4042  sys::swapByteOrder(il.entsize);4043  sys::swapByteOrder(il.count);4044}4045 4046inline void swapStruct(struct ivar_list32_t &il) {4047  sys::swapByteOrder(il.entsize);4048  sys::swapByteOrder(il.count);4049}4050 4051inline void swapStruct(struct ivar64_t &i) {4052  sys::swapByteOrder(i.offset);4053  sys::swapByteOrder(i.name);4054  sys::swapByteOrder(i.type);4055  sys::swapByteOrder(i.alignment);4056  sys::swapByteOrder(i.size);4057}4058 4059inline void swapStruct(struct ivar32_t &i) {4060  sys::swapByteOrder(i.offset);4061  sys::swapByteOrder(i.name);4062  sys::swapByteOrder(i.type);4063  sys::swapByteOrder(i.alignment);4064  sys::swapByteOrder(i.size);4065}4066 4067inline void swapStruct(struct objc_property_list64 &pl) {4068  sys::swapByteOrder(pl.entsize);4069  sys::swapByteOrder(pl.count);4070}4071 4072inline void swapStruct(struct objc_property_list32 &pl) {4073  sys::swapByteOrder(pl.entsize);4074  sys::swapByteOrder(pl.count);4075}4076 4077inline void swapStruct(struct objc_property64 &op) {4078  sys::swapByteOrder(op.name);4079  sys::swapByteOrder(op.attributes);4080}4081 4082inline void swapStruct(struct objc_property32 &op) {4083  sys::swapByteOrder(op.name);4084  sys::swapByteOrder(op.attributes);4085}4086 4087inline void swapStruct(struct category64_t &c) {4088  sys::swapByteOrder(c.name);4089  sys::swapByteOrder(c.cls);4090  sys::swapByteOrder(c.instanceMethods);4091  sys::swapByteOrder(c.classMethods);4092  sys::swapByteOrder(c.protocols);4093  sys::swapByteOrder(c.instanceProperties);4094}4095 4096inline void swapStruct(struct category32_t &c) {4097  sys::swapByteOrder(c.name);4098  sys::swapByteOrder(c.cls);4099  sys::swapByteOrder(c.instanceMethods);4100  sys::swapByteOrder(c.classMethods);4101  sys::swapByteOrder(c.protocols);4102  sys::swapByteOrder(c.instanceProperties);4103}4104 4105inline void swapStruct(struct objc_image_info64 &o) {4106  sys::swapByteOrder(o.version);4107  sys::swapByteOrder(o.flags);4108}4109 4110inline void swapStruct(struct objc_image_info32 &o) {4111  sys::swapByteOrder(o.version);4112  sys::swapByteOrder(o.flags);4113}4114 4115inline void swapStruct(struct imageInfo_t &o) {4116  sys::swapByteOrder(o.version);4117  sys::swapByteOrder(o.flags);4118}4119 4120inline void swapStruct(struct message_ref64 &mr) {4121  sys::swapByteOrder(mr.imp);4122  sys::swapByteOrder(mr.sel);4123}4124 4125inline void swapStruct(struct message_ref32 &mr) {4126  sys::swapByteOrder(mr.imp);4127  sys::swapByteOrder(mr.sel);4128}4129 4130inline void swapStruct(struct objc_module_t &module) {4131  sys::swapByteOrder(module.version);4132  sys::swapByteOrder(module.size);4133  sys::swapByteOrder(module.name);4134  sys::swapByteOrder(module.symtab);4135}4136 4137inline void swapStruct(struct objc_symtab_t &symtab) {4138  sys::swapByteOrder(symtab.sel_ref_cnt);4139  sys::swapByteOrder(symtab.refs);4140  sys::swapByteOrder(symtab.cls_def_cnt);4141  sys::swapByteOrder(symtab.cat_def_cnt);4142}4143 4144inline void swapStruct(struct objc_class_t &objc_class) {4145  sys::swapByteOrder(objc_class.isa);4146  sys::swapByteOrder(objc_class.super_class);4147  sys::swapByteOrder(objc_class.name);4148  sys::swapByteOrder(objc_class.version);4149  sys::swapByteOrder(objc_class.info);4150  sys::swapByteOrder(objc_class.instance_size);4151  sys::swapByteOrder(objc_class.ivars);4152  sys::swapByteOrder(objc_class.methodLists);4153  sys::swapByteOrder(objc_class.cache);4154  sys::swapByteOrder(objc_class.protocols);4155}4156 4157inline void swapStruct(struct objc_category_t &objc_category) {4158  sys::swapByteOrder(objc_category.category_name);4159  sys::swapByteOrder(objc_category.class_name);4160  sys::swapByteOrder(objc_category.instance_methods);4161  sys::swapByteOrder(objc_category.class_methods);4162  sys::swapByteOrder(objc_category.protocols);4163}4164 4165inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {4166  sys::swapByteOrder(objc_ivar_list.ivar_count);4167}4168 4169inline void swapStruct(struct objc_ivar_t &objc_ivar) {4170  sys::swapByteOrder(objc_ivar.ivar_name);4171  sys::swapByteOrder(objc_ivar.ivar_type);4172  sys::swapByteOrder(objc_ivar.ivar_offset);4173}4174 4175inline void swapStruct(struct objc_method_list_t &method_list) {4176  sys::swapByteOrder(method_list.obsolete);4177  sys::swapByteOrder(method_list.method_count);4178}4179 4180inline void swapStruct(struct objc_method_t &method) {4181  sys::swapByteOrder(method.method_name);4182  sys::swapByteOrder(method.method_types);4183  sys::swapByteOrder(method.method_imp);4184}4185 4186inline void swapStruct(struct objc_protocol_list_t &protocol_list) {4187  sys::swapByteOrder(protocol_list.next);4188  sys::swapByteOrder(protocol_list.count);4189}4190 4191inline void swapStruct(struct objc_protocol_t &protocol) {4192  sys::swapByteOrder(protocol.isa);4193  sys::swapByteOrder(protocol.protocol_name);4194  sys::swapByteOrder(protocol.protocol_list);4195  sys::swapByteOrder(protocol.instance_methods);4196  sys::swapByteOrder(protocol.class_methods);4197}4198 4199inline void swapStruct(struct objc_method_description_list_t &mdl) {4200  sys::swapByteOrder(mdl.count);4201}4202 4203inline void swapStruct(struct objc_method_description_t &md) {4204  sys::swapByteOrder(md.name);4205  sys::swapByteOrder(md.types);4206}4207 4208} // namespace4209 4210static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,4211                                                 struct DisassembleInfo *info);4212 4213// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer4214// to an Objective-C class and returns the class name.  It is also passed the4215// address of the pointer, so when the pointer is zero as it can be in an .o4216// file, that is used to look for an external relocation entry with a symbol4217// name.4218static const char *get_objc2_64bit_class_name(uint64_t pointer_value,4219                                              uint64_t ReferenceValue,4220                                              struct DisassembleInfo *info) {4221  const char *r;4222  uint32_t offset, left;4223  SectionRef S;4224 4225  // The pointer_value can be 0 in an object file and have a relocation4226  // entry for the class symbol at the ReferenceValue (the address of the4227  // pointer).4228  if (pointer_value == 0) {4229    r = get_pointer_64(ReferenceValue, offset, left, S, info);4230    if (r == nullptr || left < sizeof(uint64_t))4231      return nullptr;4232    uint64_t n_value;4233    const char *symbol_name = get_symbol_64(offset, S, info, n_value);4234    if (symbol_name == nullptr)4235      return nullptr;4236    const char *class_name = strrchr(symbol_name, '$');4237    if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')4238      return class_name + 2;4239    else4240      return nullptr;4241  }4242 4243  // The case were the pointer_value is non-zero and points to a class defined4244  // in this Mach-O file.4245  r = get_pointer_64(pointer_value, offset, left, S, info);4246  if (r == nullptr || left < sizeof(struct class64_t))4247    return nullptr;4248  struct class64_t c;4249  memcpy(&c, r, sizeof(struct class64_t));4250  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4251    swapStruct(c);4252  if (c.data == 0)4253    return nullptr;4254  r = get_pointer_64(c.data, offset, left, S, info);4255  if (r == nullptr || left < sizeof(struct class_ro64_t))4256    return nullptr;4257  struct class_ro64_t cro;4258  memcpy(&cro, r, sizeof(struct class_ro64_t));4259  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4260    swapStruct(cro);4261  if (cro.name == 0)4262    return nullptr;4263  const char *name = get_pointer_64(cro.name, offset, left, S, info);4264  return name;4265}4266 4267// get_objc2_64bit_cfstring_name is used for disassembly and is passed a4268// pointer to a cfstring and returns its name or nullptr.4269static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,4270                                                 struct DisassembleInfo *info) {4271  const char *r, *name;4272  uint32_t offset, left;4273  SectionRef S;4274  struct cfstring64_t cfs;4275  uint64_t cfs_characters;4276 4277  r = get_pointer_64(ReferenceValue, offset, left, S, info);4278  if (r == nullptr || left < sizeof(struct cfstring64_t))4279    return nullptr;4280  memcpy(&cfs, r, sizeof(struct cfstring64_t));4281  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4282    swapStruct(cfs);4283  if (cfs.characters == 0) {4284    uint64_t n_value;4285    const char *symbol_name = get_symbol_64(4286        offset + offsetof(struct cfstring64_t, characters), S, info, n_value);4287    if (symbol_name == nullptr)4288      return nullptr;4289    cfs_characters = n_value;4290  } else4291    cfs_characters = cfs.characters;4292  name = get_pointer_64(cfs_characters, offset, left, S, info);4293 4294  return name;4295}4296 4297// get_objc2_64bit_selref() is used for disassembly and is passed a the address4298// of a pointer to an Objective-C selector reference when the pointer value is4299// zero as in a .o file and is likely to have a external relocation entry with4300// who's symbol's n_value is the real pointer to the selector name.  If that is4301// the case the real pointer to the selector name is returned else 0 is4302// returned4303static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,4304                                       struct DisassembleInfo *info) {4305  uint32_t offset, left;4306  SectionRef S;4307 4308  const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);4309  if (r == nullptr || left < sizeof(uint64_t))4310    return 0;4311  uint64_t n_value;4312  const char *symbol_name = get_symbol_64(offset, S, info, n_value);4313  if (symbol_name == nullptr)4314    return 0;4315  return n_value;4316}4317 4318static const SectionRef get_section(MachOObjectFile *O, const char *segname,4319                                    const char *sectname) {4320  for (const SectionRef &Section : O->sections()) {4321    StringRef SectName;4322    Expected<StringRef> SecNameOrErr = Section.getName();4323    if (SecNameOrErr)4324      SectName = *SecNameOrErr;4325    else4326      consumeError(SecNameOrErr.takeError());4327 4328    DataRefImpl Ref = Section.getRawDataRefImpl();4329    StringRef SegName = O->getSectionFinalSegmentName(Ref);4330    if (SegName == segname && SectName == sectname)4331      return Section;4332  }4333  return SectionRef();4334}4335 4336static void4337walk_pointer_list_64(const char *listname, const SectionRef S,4338                     MachOObjectFile *O, struct DisassembleInfo *info,4339                     void (*func)(uint64_t, struct DisassembleInfo *info)) {4340  if (S == SectionRef())4341    return;4342 4343  StringRef SectName;4344  Expected<StringRef> SecNameOrErr = S.getName();4345  if (SecNameOrErr)4346    SectName = *SecNameOrErr;4347  else4348    consumeError(SecNameOrErr.takeError());4349 4350  DataRefImpl Ref = S.getRawDataRefImpl();4351  StringRef SegName = O->getSectionFinalSegmentName(Ref);4352  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";4353 4354  StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4355  const char *Contents = BytesStr.data();4356 4357  for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {4358    uint32_t left = S.getSize() - i;4359    uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);4360    uint64_t p = 0;4361    memcpy(&p, Contents + i, size);4362    if (i + sizeof(uint64_t) > S.getSize())4363      outs() << listname << " list pointer extends past end of (" << SegName4364             << "," << SectName << ") section\n";4365    outs() << format("%016" PRIx64, S.getAddress() + i) << " ";4366 4367    if (O->isLittleEndian() != sys::IsLittleEndianHost)4368      sys::swapByteOrder(p);4369 4370    uint64_t n_value = 0;4371    const char *name = get_symbol_64(i, S, info, n_value, p);4372    if (name == nullptr)4373      name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);4374 4375    if (n_value != 0) {4376      outs() << format("0x%" PRIx64, n_value);4377      if (p != 0)4378        outs() << " + " << format("0x%" PRIx64, p);4379    } else4380      outs() << format("0x%" PRIx64, p);4381    if (name != nullptr)4382      outs() << " " << name;4383    outs() << "\n";4384 4385    p += n_value;4386    if (func)4387      func(p, info);4388  }4389}4390 4391static void4392walk_pointer_list_32(const char *listname, const SectionRef S,4393                     MachOObjectFile *O, struct DisassembleInfo *info,4394                     void (*func)(uint32_t, struct DisassembleInfo *info)) {4395  if (S == SectionRef())4396    return;4397 4398  StringRef SectName = unwrapOrError(S.getName(), O->getFileName());4399  DataRefImpl Ref = S.getRawDataRefImpl();4400  StringRef SegName = O->getSectionFinalSegmentName(Ref);4401  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";4402 4403  StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4404  const char *Contents = BytesStr.data();4405 4406  for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {4407    uint32_t left = S.getSize() - i;4408    uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);4409    uint32_t p = 0;4410    memcpy(&p, Contents + i, size);4411    if (i + sizeof(uint32_t) > S.getSize())4412      outs() << listname << " list pointer extends past end of (" << SegName4413             << "," << SectName << ") section\n";4414    uint32_t Address = S.getAddress() + i;4415    outs() << format("%08" PRIx32, Address) << " ";4416 4417    if (O->isLittleEndian() != sys::IsLittleEndianHost)4418      sys::swapByteOrder(p);4419    outs() << format("0x%" PRIx32, p);4420 4421    const char *name = get_symbol_32(i, S, info, p);4422    if (name != nullptr)4423      outs() << " " << name;4424    outs() << "\n";4425 4426    if (func)4427      func(p, info);4428  }4429}4430 4431static void print_layout_map(const char *layout_map, uint32_t left) {4432  if (layout_map == nullptr)4433    return;4434  outs() << "                layout map: ";4435  do {4436    outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";4437    left--;4438    layout_map++;4439  } while (*layout_map != '\0' && left != 0);4440  outs() << "\n";4441}4442 4443static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {4444  uint32_t offset, left;4445  SectionRef S;4446  const char *layout_map;4447 4448  if (p == 0)4449    return;4450  layout_map = get_pointer_64(p, offset, left, S, info);4451  print_layout_map(layout_map, left);4452}4453 4454static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {4455  uint32_t offset, left;4456  SectionRef S;4457  const char *layout_map;4458 4459  if (p == 0)4460    return;4461  layout_map = get_pointer_32(p, offset, left, S, info);4462  print_layout_map(layout_map, left);4463}4464 4465static void print_relative_method_list(uint32_t structSizeAndFlags,4466                                       uint32_t structCount, uint64_t p,4467                                       struct DisassembleInfo *info,4468                                       const char *indent,4469                                       uint32_t pointerBits) {4470  struct method_relative_t m;4471  const char *r, *name;4472  uint32_t offset, xoffset, left, i;4473  SectionRef S, xS;4474 4475  assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&4476         "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");4477 4478  outs() << indent << "\t\t   entsize "4479         << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";4480  outs() << indent << "\t\t     count " << structCount << "\n";4481 4482  for (i = 0; i < structCount; i++) {4483    r = get_pointer_64(p, offset, left, S, info);4484    memset(&m, '\0', sizeof(struct method_relative_t));4485    if (left < sizeof(struct method_relative_t)) {4486      memcpy(&m, r, left);4487      outs() << indent << "   (method_t extends past the end of the section)\n";4488    } else4489      memcpy(&m, r, sizeof(struct method_relative_t));4490    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4491      swapStruct(m);4492 4493    outs() << indent << "\t\t      name " << format("0x%" PRIx32, m.name);4494    uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);4495    uint64_t absNameRefVA = relNameRefVA + m.name;4496    outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";4497 4498    // since this is a relative list, absNameRefVA is the address of the4499    // __objc_selrefs entry, so a pointer, not the actual name4500    const char *nameRefPtr =4501        get_pointer_64(absNameRefVA, xoffset, left, xS, info);4502    if (nameRefPtr) {4503      uint32_t pointerSize = pointerBits / CHAR_BIT;4504      if (left < pointerSize)4505        outs() << indent << " (nameRefPtr extends past the end of the section)";4506      else {4507        if (pointerSize == 64) {4508          uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);4509          if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4510            sys::swapByteOrder(nameOff_64);4511          name = get_pointer_64(nameOff_64, xoffset, left, xS, info);4512        } else {4513          uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);4514          if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4515            sys::swapByteOrder(nameOff_32);4516          name = get_pointer_32(nameOff_32, xoffset, left, xS, info);4517        }4518        if (name != nullptr)4519          outs() << format(" %.*s", left, name);4520      }4521    }4522    outs() << "\n";4523 4524    outs() << indent << "\t\t     types " << format("0x%" PRIx32, m.types);4525    uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);4526    uint64_t absTypesVA = relTypesVA + m.types;4527    outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";4528    name = get_pointer_32(absTypesVA, xoffset, left, xS, info);4529    if (name != nullptr)4530      outs() << format(" %.*s", left, name);4531    outs() << "\n";4532 4533    outs() << indent << "\t\t       imp " << format("0x%" PRIx32, m.imp);4534    uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);4535    uint64_t absImpVA = relImpVA + m.imp;4536    outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";4537    name = GuessSymbolName(absImpVA, info->AddrMap);4538    if (name != nullptr)4539      outs() << " " << name;4540    outs() << "\n";4541 4542    p += sizeof(struct method_relative_t);4543    offset += sizeof(struct method_relative_t);4544  }4545}4546 4547static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,4548                                  const char *indent) {4549  struct method_list64_t ml;4550  struct method64_t m;4551  const char *r;4552  uint32_t offset, xoffset, left, i;4553  SectionRef S, xS;4554  const char *name, *sym_name;4555  uint64_t n_value;4556 4557  r = get_pointer_64(p, offset, left, S, info);4558  if (r == nullptr)4559    return;4560  memset(&ml, '\0', sizeof(struct method_list64_t));4561  if (left < sizeof(struct method_list64_t)) {4562    memcpy(&ml, r, left);4563    outs() << "   (method_list_t entends past the end of the section)\n";4564  } else4565    memcpy(&ml, r, sizeof(struct method_list64_t));4566  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4567    swapStruct(ml);4568  p += sizeof(struct method_list64_t);4569 4570  if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4571    print_relative_method_list(ml.entsize, ml.count, p, info, indent,4572                               /*pointerBits=*/64);4573    return;4574  }4575 4576  outs() << indent << "\t\t   entsize " << ml.entsize << "\n";4577  outs() << indent << "\t\t     count " << ml.count << "\n";4578 4579  offset += sizeof(struct method_list64_t);4580  for (i = 0; i < ml.count; i++) {4581    r = get_pointer_64(p, offset, left, S, info);4582    if (r == nullptr)4583      return;4584    memset(&m, '\0', sizeof(struct method64_t));4585    if (left < sizeof(struct method64_t)) {4586      memcpy(&m, r, left);4587      outs() << indent << "   (method_t extends past the end of the section)\n";4588    } else4589      memcpy(&m, r, sizeof(struct method64_t));4590    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4591      swapStruct(m);4592 4593    outs() << indent << "\t\t      name ";4594    sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,4595                             info, n_value, m.name);4596    if (n_value != 0) {4597      if (info->verbose && sym_name != nullptr)4598        outs() << sym_name;4599      else4600        outs() << format("0x%" PRIx64, n_value);4601      if (m.name != 0)4602        outs() << " + " << format("0x%" PRIx64, m.name);4603    } else4604      outs() << format("0x%" PRIx64, m.name);4605    name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);4606    if (name != nullptr)4607      outs() << format(" %.*s", left, name);4608    outs() << "\n";4609 4610    outs() << indent << "\t\t     types ";4611    sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,4612                             info, n_value, m.types);4613    if (n_value != 0) {4614      if (info->verbose && sym_name != nullptr)4615        outs() << sym_name;4616      else4617        outs() << format("0x%" PRIx64, n_value);4618      if (m.types != 0)4619        outs() << " + " << format("0x%" PRIx64, m.types);4620    } else4621      outs() << format("0x%" PRIx64, m.types);4622    name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);4623    if (name != nullptr)4624      outs() << format(" %.*s", left, name);4625    outs() << "\n";4626 4627    outs() << indent << "\t\t       imp ";4628    name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,4629                         n_value, m.imp);4630    if (info->verbose && name == nullptr) {4631      if (n_value != 0) {4632        outs() << format("0x%" PRIx64, n_value) << " ";4633        if (m.imp != 0)4634          outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";4635      } else4636        outs() << format("0x%" PRIx64, m.imp) << " ";4637    }4638    if (name != nullptr)4639      outs() << name;4640    outs() << "\n";4641 4642    p += sizeof(struct method64_t);4643    offset += sizeof(struct method64_t);4644  }4645}4646 4647static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,4648                                  const char *indent) {4649  struct method_list32_t ml;4650  struct method32_t m;4651  const char *r, *name;4652  uint32_t offset, xoffset, left, i;4653  SectionRef S, xS;4654 4655  r = get_pointer_32(p, offset, left, S, info);4656  if (r == nullptr)4657    return;4658  memset(&ml, '\0', sizeof(struct method_list32_t));4659  if (left < sizeof(struct method_list32_t)) {4660    memcpy(&ml, r, left);4661    outs() << "   (method_list_t entends past the end of the section)\n";4662  } else4663    memcpy(&ml, r, sizeof(struct method_list32_t));4664  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4665    swapStruct(ml);4666  p += sizeof(struct method_list32_t);4667 4668  if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4669    print_relative_method_list(ml.entsize, ml.count, p, info, indent,4670                               /*pointerBits=*/32);4671    return;4672  }4673 4674  outs() << indent << "\t\t   entsize " << ml.entsize << "\n";4675  outs() << indent << "\t\t     count " << ml.count << "\n";4676 4677  offset += sizeof(struct method_list32_t);4678  for (i = 0; i < ml.count; i++) {4679    r = get_pointer_32(p, offset, left, S, info);4680    if (r == nullptr)4681      return;4682    memset(&m, '\0', sizeof(struct method32_t));4683    if (left < sizeof(struct method32_t)) {4684      memcpy(&ml, r, left);4685      outs() << indent << "   (method_t entends past the end of the section)\n";4686    } else4687      memcpy(&m, r, sizeof(struct method32_t));4688    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4689      swapStruct(m);4690 4691    outs() << indent << "\t\t      name " << format("0x%" PRIx32, m.name);4692    name = get_pointer_32(m.name, xoffset, left, xS, info);4693    if (name != nullptr)4694      outs() << format(" %.*s", left, name);4695    outs() << "\n";4696 4697    outs() << indent << "\t\t     types " << format("0x%" PRIx32, m.types);4698    name = get_pointer_32(m.types, xoffset, left, xS, info);4699    if (name != nullptr)4700      outs() << format(" %.*s", left, name);4701    outs() << "\n";4702 4703    outs() << indent << "\t\t       imp " << format("0x%" PRIx32, m.imp);4704    name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,4705                         m.imp);4706    if (name != nullptr)4707      outs() << " " << name;4708    outs() << "\n";4709 4710    p += sizeof(struct method32_t);4711    offset += sizeof(struct method32_t);4712  }4713}4714 4715static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {4716  uint32_t offset, left, xleft;4717  SectionRef S;4718  struct objc_method_list_t method_list;4719  struct objc_method_t method;4720  const char *r, *methods, *name, *SymbolName;4721  int32_t i;4722 4723  r = get_pointer_32(p, offset, left, S, info, true);4724  if (r == nullptr)4725    return true;4726 4727  outs() << "\n";4728  if (left > sizeof(struct objc_method_list_t)) {4729    memcpy(&method_list, r, sizeof(struct objc_method_list_t));4730  } else {4731    outs() << "\t\t objc_method_list extends past end of the section\n";4732    memset(&method_list, '\0', sizeof(struct objc_method_list_t));4733    memcpy(&method_list, r, left);4734  }4735  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4736    swapStruct(method_list);4737 4738  outs() << "\t\t         obsolete "4739         << format("0x%08" PRIx32, method_list.obsolete) << "\n";4740  outs() << "\t\t     method_count " << method_list.method_count << "\n";4741 4742  methods = r + sizeof(struct objc_method_list_t);4743  for (i = 0; i < method_list.method_count; i++) {4744    if ((i + 1) * sizeof(struct objc_method_t) > left) {4745      outs() << "\t\t remaining method's extend past the of the section\n";4746      break;4747    }4748    memcpy(&method, methods + i * sizeof(struct objc_method_t),4749           sizeof(struct objc_method_t));4750    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4751      swapStruct(method);4752 4753    outs() << "\t\t      method_name "4754           << format("0x%08" PRIx32, method.method_name);4755    if (info->verbose) {4756      name = get_pointer_32(method.method_name, offset, xleft, S, info, true);4757      if (name != nullptr)4758        outs() << format(" %.*s", xleft, name);4759      else4760        outs() << " (not in an __OBJC section)";4761    }4762    outs() << "\n";4763 4764    outs() << "\t\t     method_types "4765           << format("0x%08" PRIx32, method.method_types);4766    if (info->verbose) {4767      name = get_pointer_32(method.method_types, offset, xleft, S, info, true);4768      if (name != nullptr)4769        outs() << format(" %.*s", xleft, name);4770      else4771        outs() << " (not in an __OBJC section)";4772    }4773    outs() << "\n";4774 4775    outs() << "\t\t       method_imp "4776           << format("0x%08" PRIx32, method.method_imp) << " ";4777    if (info->verbose) {4778      SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);4779      if (SymbolName != nullptr)4780        outs() << SymbolName;4781    }4782    outs() << "\n";4783  }4784  return false;4785}4786 4787static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {4788  struct protocol_list64_t pl;4789  uint64_t q, n_value;4790  struct protocol64_t pc;4791  const char *r;4792  uint32_t offset, xoffset, left, i;4793  SectionRef S, xS;4794  const char *name, *sym_name;4795 4796  r = get_pointer_64(p, offset, left, S, info);4797  if (r == nullptr)4798    return;4799  memset(&pl, '\0', sizeof(struct protocol_list64_t));4800  if (left < sizeof(struct protocol_list64_t)) {4801    memcpy(&pl, r, left);4802    outs() << "   (protocol_list_t entends past the end of the section)\n";4803  } else4804    memcpy(&pl, r, sizeof(struct protocol_list64_t));4805  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4806    swapStruct(pl);4807  outs() << "                      count " << pl.count << "\n";4808 4809  p += sizeof(struct protocol_list64_t);4810  offset += sizeof(struct protocol_list64_t);4811  for (i = 0; i < pl.count; i++) {4812    r = get_pointer_64(p, offset, left, S, info);4813    if (r == nullptr)4814      return;4815    q = 0;4816    if (left < sizeof(uint64_t)) {4817      memcpy(&q, r, left);4818      outs() << "   (protocol_t * entends past the end of the section)\n";4819    } else4820      memcpy(&q, r, sizeof(uint64_t));4821    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4822      sys::swapByteOrder(q);4823 4824    outs() << "\t\t      list[" << i << "] ";4825    sym_name = get_symbol_64(offset, S, info, n_value, q);4826    if (n_value != 0) {4827      if (info->verbose && sym_name != nullptr)4828        outs() << sym_name;4829      else4830        outs() << format("0x%" PRIx64, n_value);4831      if (q != 0)4832        outs() << " + " << format("0x%" PRIx64, q);4833    } else4834      outs() << format("0x%" PRIx64, q);4835    outs() << " (struct protocol_t *)\n";4836 4837    r = get_pointer_64(q + n_value, offset, left, S, info);4838    if (r == nullptr)4839      return;4840    memset(&pc, '\0', sizeof(struct protocol64_t));4841    if (left < sizeof(struct protocol64_t)) {4842      memcpy(&pc, r, left);4843      outs() << "   (protocol_t entends past the end of the section)\n";4844    } else4845      memcpy(&pc, r, sizeof(struct protocol64_t));4846    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4847      swapStruct(pc);4848 4849    outs() << "\t\t\t      isa " << format("0x%" PRIx64, pc.isa) << "\n";4850 4851    outs() << "\t\t\t     name ";4852    sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,4853                             info, n_value, pc.name);4854    if (n_value != 0) {4855      if (info->verbose && sym_name != nullptr)4856        outs() << sym_name;4857      else4858        outs() << format("0x%" PRIx64, n_value);4859      if (pc.name != 0)4860        outs() << " + " << format("0x%" PRIx64, pc.name);4861    } else4862      outs() << format("0x%" PRIx64, pc.name);4863    name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);4864    if (name != nullptr)4865      outs() << format(" %.*s", left, name);4866    outs() << "\n";4867 4868    outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";4869 4870    outs() << "\t\t  instanceMethods ";4871    sym_name =4872        get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),4873                      S, info, n_value, pc.instanceMethods);4874    if (n_value != 0) {4875      if (info->verbose && sym_name != nullptr)4876        outs() << sym_name;4877      else4878        outs() << format("0x%" PRIx64, n_value);4879      if (pc.instanceMethods != 0)4880        outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);4881    } else4882      outs() << format("0x%" PRIx64, pc.instanceMethods);4883    outs() << " (struct method_list_t *)\n";4884    if (pc.instanceMethods + n_value != 0)4885      print_method_list64_t(pc.instanceMethods + n_value, info, "\t");4886 4887    outs() << "\t\t     classMethods ";4888    sym_name =4889        get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,4890                      info, n_value, pc.classMethods);4891    if (n_value != 0) {4892      if (info->verbose && sym_name != nullptr)4893        outs() << sym_name;4894      else4895        outs() << format("0x%" PRIx64, n_value);4896      if (pc.classMethods != 0)4897        outs() << " + " << format("0x%" PRIx64, pc.classMethods);4898    } else4899      outs() << format("0x%" PRIx64, pc.classMethods);4900    outs() << " (struct method_list_t *)\n";4901    if (pc.classMethods + n_value != 0)4902      print_method_list64_t(pc.classMethods + n_value, info, "\t");4903 4904    outs() << "\t  optionalInstanceMethods "4905           << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";4906    outs() << "\t     optionalClassMethods "4907           << format("0x%" PRIx64, pc.optionalClassMethods) << "\n";4908    outs() << "\t       instanceProperties "4909           << format("0x%" PRIx64, pc.instanceProperties) << "\n";4910 4911    p += sizeof(uint64_t);4912    offset += sizeof(uint64_t);4913  }4914}4915 4916static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {4917  struct protocol_list32_t pl;4918  uint32_t q;4919  struct protocol32_t pc;4920  const char *r;4921  uint32_t offset, xoffset, left, i;4922  SectionRef S, xS;4923  const char *name;4924 4925  r = get_pointer_32(p, offset, left, S, info);4926  if (r == nullptr)4927    return;4928  memset(&pl, '\0', sizeof(struct protocol_list32_t));4929  if (left < sizeof(struct protocol_list32_t)) {4930    memcpy(&pl, r, left);4931    outs() << "   (protocol_list_t entends past the end of the section)\n";4932  } else4933    memcpy(&pl, r, sizeof(struct protocol_list32_t));4934  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4935    swapStruct(pl);4936  outs() << "                      count " << pl.count << "\n";4937 4938  p += sizeof(struct protocol_list32_t);4939  offset += sizeof(struct protocol_list32_t);4940  for (i = 0; i < pl.count; i++) {4941    r = get_pointer_32(p, offset, left, S, info);4942    if (r == nullptr)4943      return;4944    q = 0;4945    if (left < sizeof(uint32_t)) {4946      memcpy(&q, r, left);4947      outs() << "   (protocol_t * entends past the end of the section)\n";4948    } else4949      memcpy(&q, r, sizeof(uint32_t));4950    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4951      sys::swapByteOrder(q);4952    outs() << "\t\t      list[" << i << "] " << format("0x%" PRIx32, q)4953           << " (struct protocol_t *)\n";4954    r = get_pointer_32(q, offset, left, S, info);4955    if (r == nullptr)4956      return;4957    memset(&pc, '\0', sizeof(struct protocol32_t));4958    if (left < sizeof(struct protocol32_t)) {4959      memcpy(&pc, r, left);4960      outs() << "   (protocol_t entends past the end of the section)\n";4961    } else4962      memcpy(&pc, r, sizeof(struct protocol32_t));4963    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4964      swapStruct(pc);4965    outs() << "\t\t\t      isa " << format("0x%" PRIx32, pc.isa) << "\n";4966    outs() << "\t\t\t     name " << format("0x%" PRIx32, pc.name);4967    name = get_pointer_32(pc.name, xoffset, left, xS, info);4968    if (name != nullptr)4969      outs() << format(" %.*s", left, name);4970    outs() << "\n";4971    outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";4972    outs() << "\t\t  instanceMethods "4973           << format("0x%" PRIx32, pc.instanceMethods)4974           << " (struct method_list_t *)\n";4975    if (pc.instanceMethods != 0)4976      print_method_list32_t(pc.instanceMethods, info, "\t");4977    outs() << "\t\t     classMethods " << format("0x%" PRIx32, pc.classMethods)4978           << " (struct method_list_t *)\n";4979    if (pc.classMethods != 0)4980      print_method_list32_t(pc.classMethods, info, "\t");4981    outs() << "\t  optionalInstanceMethods "4982           << format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";4983    outs() << "\t     optionalClassMethods "4984           << format("0x%" PRIx32, pc.optionalClassMethods) << "\n";4985    outs() << "\t       instanceProperties "4986           << format("0x%" PRIx32, pc.instanceProperties) << "\n";4987    p += sizeof(uint32_t);4988    offset += sizeof(uint32_t);4989  }4990}4991 4992static void print_indent(uint32_t indent) {4993  for (uint32_t i = 0; i < indent;) {4994    if (indent - i >= 8) {4995      outs() << "\t";4996      i += 8;4997    } else {4998      for (uint32_t j = i; j < indent; j++)4999        outs() << " ";5000      return;5001    }5002  }5003}5004 5005static bool print_method_description_list(uint32_t p, uint32_t indent,5006                                          struct DisassembleInfo *info) {5007  uint32_t offset, left, xleft;5008  SectionRef S;5009  struct objc_method_description_list_t mdl;5010  struct objc_method_description_t md;5011  const char *r, *list, *name;5012  int32_t i;5013 5014  r = get_pointer_32(p, offset, left, S, info, true);5015  if (r == nullptr)5016    return true;5017 5018  outs() << "\n";5019  if (left > sizeof(struct objc_method_description_list_t)) {5020    memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));5021  } else {5022    print_indent(indent);5023    outs() << " objc_method_description_list extends past end of the section\n";5024    memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));5025    memcpy(&mdl, r, left);5026  }5027  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5028    swapStruct(mdl);5029 5030  print_indent(indent);5031  outs() << "        count " << mdl.count << "\n";5032 5033  list = r + sizeof(struct objc_method_description_list_t);5034  for (i = 0; i < mdl.count; i++) {5035    if ((i + 1) * sizeof(struct objc_method_description_t) > left) {5036      print_indent(indent);5037      outs() << " remaining list entries extend past the of the section\n";5038      break;5039    }5040    print_indent(indent);5041    outs() << "        list[" << i << "]\n";5042    memcpy(&md, list + i * sizeof(struct objc_method_description_t),5043           sizeof(struct objc_method_description_t));5044    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5045      swapStruct(md);5046 5047    print_indent(indent);5048    outs() << "             name " << format("0x%08" PRIx32, md.name);5049    if (info->verbose) {5050      name = get_pointer_32(md.name, offset, xleft, S, info, true);5051      if (name != nullptr)5052        outs() << format(" %.*s", xleft, name);5053      else5054        outs() << " (not in an __OBJC section)";5055    }5056    outs() << "\n";5057 5058    print_indent(indent);5059    outs() << "            types " << format("0x%08" PRIx32, md.types);5060    if (info->verbose) {5061      name = get_pointer_32(md.types, offset, xleft, S, info, true);5062      if (name != nullptr)5063        outs() << format(" %.*s", xleft, name);5064      else5065        outs() << " (not in an __OBJC section)";5066    }5067    outs() << "\n";5068  }5069  return false;5070}5071 5072static bool print_protocol_list(uint32_t p, uint32_t indent,5073                                struct DisassembleInfo *info);5074 5075static bool print_protocol(uint32_t p, uint32_t indent,5076                           struct DisassembleInfo *info) {5077  uint32_t offset, left;5078  SectionRef S;5079  struct objc_protocol_t protocol;5080  const char *r, *name;5081 5082  r = get_pointer_32(p, offset, left, S, info, true);5083  if (r == nullptr)5084    return true;5085 5086  outs() << "\n";5087  if (left >= sizeof(struct objc_protocol_t)) {5088    memcpy(&protocol, r, sizeof(struct objc_protocol_t));5089  } else {5090    print_indent(indent);5091    outs() << "            Protocol extends past end of the section\n";5092    memset(&protocol, '\0', sizeof(struct objc_protocol_t));5093    memcpy(&protocol, r, left);5094  }5095  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5096    swapStruct(protocol);5097 5098  print_indent(indent);5099  outs() << "              isa " << format("0x%08" PRIx32, protocol.isa)5100         << "\n";5101 5102  print_indent(indent);5103  outs() << "    protocol_name "5104         << format("0x%08" PRIx32, protocol.protocol_name);5105  if (info->verbose) {5106    name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);5107    if (name != nullptr)5108      outs() << format(" %.*s", left, name);5109    else5110      outs() << " (not in an __OBJC section)";5111  }5112  outs() << "\n";5113 5114  print_indent(indent);5115  outs() << "    protocol_list "5116         << format("0x%08" PRIx32, protocol.protocol_list);5117  if (print_protocol_list(protocol.protocol_list, indent + 4, info))5118    outs() << " (not in an __OBJC section)\n";5119 5120  print_indent(indent);5121  outs() << " instance_methods "5122         << format("0x%08" PRIx32, protocol.instance_methods);5123  if (print_method_description_list(protocol.instance_methods, indent, info))5124    outs() << " (not in an __OBJC section)\n";5125 5126  print_indent(indent);5127  outs() << "    class_methods "5128         << format("0x%08" PRIx32, protocol.class_methods);5129  if (print_method_description_list(protocol.class_methods, indent, info))5130    outs() << " (not in an __OBJC section)\n";5131 5132  return false;5133}5134 5135static bool print_protocol_list(uint32_t p, uint32_t indent,5136                                struct DisassembleInfo *info) {5137  uint32_t offset, left, l;5138  SectionRef S;5139  struct objc_protocol_list_t protocol_list;5140  const char *r, *list;5141  int32_t i;5142 5143  r = get_pointer_32(p, offset, left, S, info, true);5144  if (r == nullptr)5145    return true;5146 5147  outs() << "\n";5148  if (left > sizeof(struct objc_protocol_list_t)) {5149    memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));5150  } else {5151    outs() << "\t\t objc_protocol_list_t extends past end of the section\n";5152    memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));5153    memcpy(&protocol_list, r, left);5154  }5155  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5156    swapStruct(protocol_list);5157 5158  print_indent(indent);5159  outs() << "         next " << format("0x%08" PRIx32, protocol_list.next)5160         << "\n";5161  print_indent(indent);5162  outs() << "        count " << protocol_list.count << "\n";5163 5164  list = r + sizeof(struct objc_protocol_list_t);5165  for (i = 0; i < protocol_list.count; i++) {5166    if ((i + 1) * sizeof(uint32_t) > left) {5167      outs() << "\t\t remaining list entries extend past the of the section\n";5168      break;5169    }5170    memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));5171    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5172      sys::swapByteOrder(l);5173 5174    print_indent(indent);5175    outs() << "      list[" << i << "] " << format("0x%08" PRIx32, l);5176    if (print_protocol(l, indent, info))5177      outs() << "(not in an __OBJC section)\n";5178  }5179  return false;5180}5181 5182static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {5183  struct ivar_list64_t il;5184  struct ivar64_t i;5185  const char *r;5186  uint32_t offset, xoffset, left, j;5187  SectionRef S, xS;5188  const char *name, *sym_name, *ivar_offset_p;5189  uint64_t ivar_offset, n_value;5190 5191  r = get_pointer_64(p, offset, left, S, info);5192  if (r == nullptr)5193    return;5194  memset(&il, '\0', sizeof(struct ivar_list64_t));5195  if (left < sizeof(struct ivar_list64_t)) {5196    memcpy(&il, r, left);5197    outs() << "   (ivar_list_t entends past the end of the section)\n";5198  } else5199    memcpy(&il, r, sizeof(struct ivar_list64_t));5200  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5201    swapStruct(il);5202  outs() << "                    entsize " << il.entsize << "\n";5203  outs() << "                      count " << il.count << "\n";5204 5205  p += sizeof(struct ivar_list64_t);5206  offset += sizeof(struct ivar_list64_t);5207  for (j = 0; j < il.count; j++) {5208    r = get_pointer_64(p, offset, left, S, info);5209    if (r == nullptr)5210      return;5211    memset(&i, '\0', sizeof(struct ivar64_t));5212    if (left < sizeof(struct ivar64_t)) {5213      memcpy(&i, r, left);5214      outs() << "   (ivar_t entends past the end of the section)\n";5215    } else5216      memcpy(&i, r, sizeof(struct ivar64_t));5217    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5218      swapStruct(i);5219 5220    outs() << "\t\t\t   offset ";5221    sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,5222                             info, n_value, i.offset);5223    if (n_value != 0) {5224      if (info->verbose && sym_name != nullptr)5225        outs() << sym_name;5226      else5227        outs() << format("0x%" PRIx64, n_value);5228      if (i.offset != 0)5229        outs() << " + " << format("0x%" PRIx64, i.offset);5230    } else5231      outs() << format("0x%" PRIx64, i.offset);5232    ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);5233    if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5234      memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5235      if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5236        sys::swapByteOrder(ivar_offset);5237      outs() << " " << ivar_offset << "\n";5238    } else5239      outs() << "\n";5240 5241    outs() << "\t\t\t     name ";5242    sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,5243                             n_value, i.name);5244    if (n_value != 0) {5245      if (info->verbose && sym_name != nullptr)5246        outs() << sym_name;5247      else5248        outs() << format("0x%" PRIx64, n_value);5249      if (i.name != 0)5250        outs() << " + " << format("0x%" PRIx64, i.name);5251    } else5252      outs() << format("0x%" PRIx64, i.name);5253    name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);5254    if (name != nullptr)5255      outs() << format(" %.*s", left, name);5256    outs() << "\n";5257 5258    outs() << "\t\t\t     type ";5259    sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,5260                             n_value, i.name);5261    name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);5262    if (n_value != 0) {5263      if (info->verbose && sym_name != nullptr)5264        outs() << sym_name;5265      else5266        outs() << format("0x%" PRIx64, n_value);5267      if (i.type != 0)5268        outs() << " + " << format("0x%" PRIx64, i.type);5269    } else5270      outs() << format("0x%" PRIx64, i.type);5271    if (name != nullptr)5272      outs() << format(" %.*s", left, name);5273    outs() << "\n";5274 5275    outs() << "\t\t\talignment " << i.alignment << "\n";5276    outs() << "\t\t\t     size " << i.size << "\n";5277 5278    p += sizeof(struct ivar64_t);5279    offset += sizeof(struct ivar64_t);5280  }5281}5282 5283static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {5284  struct ivar_list32_t il;5285  struct ivar32_t i;5286  const char *r;5287  uint32_t offset, xoffset, left, j;5288  SectionRef S, xS;5289  const char *name, *ivar_offset_p;5290  uint32_t ivar_offset;5291 5292  r = get_pointer_32(p, offset, left, S, info);5293  if (r == nullptr)5294    return;5295  memset(&il, '\0', sizeof(struct ivar_list32_t));5296  if (left < sizeof(struct ivar_list32_t)) {5297    memcpy(&il, r, left);5298    outs() << "   (ivar_list_t entends past the end of the section)\n";5299  } else5300    memcpy(&il, r, sizeof(struct ivar_list32_t));5301  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5302    swapStruct(il);5303  outs() << "                    entsize " << il.entsize << "\n";5304  outs() << "                      count " << il.count << "\n";5305 5306  p += sizeof(struct ivar_list32_t);5307  offset += sizeof(struct ivar_list32_t);5308  for (j = 0; j < il.count; j++) {5309    r = get_pointer_32(p, offset, left, S, info);5310    if (r == nullptr)5311      return;5312    memset(&i, '\0', sizeof(struct ivar32_t));5313    if (left < sizeof(struct ivar32_t)) {5314      memcpy(&i, r, left);5315      outs() << "   (ivar_t entends past the end of the section)\n";5316    } else5317      memcpy(&i, r, sizeof(struct ivar32_t));5318    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5319      swapStruct(i);5320 5321    outs() << "\t\t\t   offset " << format("0x%" PRIx32, i.offset);5322    ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);5323    if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5324      memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5325      if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5326        sys::swapByteOrder(ivar_offset);5327      outs() << " " << ivar_offset << "\n";5328    } else5329      outs() << "\n";5330 5331    outs() << "\t\t\t     name " << format("0x%" PRIx32, i.name);5332    name = get_pointer_32(i.name, xoffset, left, xS, info);5333    if (name != nullptr)5334      outs() << format(" %.*s", left, name);5335    outs() << "\n";5336 5337    outs() << "\t\t\t     type " << format("0x%" PRIx32, i.type);5338    name = get_pointer_32(i.type, xoffset, left, xS, info);5339    if (name != nullptr)5340      outs() << format(" %.*s", left, name);5341    outs() << "\n";5342 5343    outs() << "\t\t\talignment " << i.alignment << "\n";5344    outs() << "\t\t\t     size " << i.size << "\n";5345 5346    p += sizeof(struct ivar32_t);5347    offset += sizeof(struct ivar32_t);5348  }5349}5350 5351static void print_objc_property_list64(uint64_t p,5352                                       struct DisassembleInfo *info) {5353  struct objc_property_list64 opl;5354  struct objc_property64 op;5355  const char *r;5356  uint32_t offset, xoffset, left, j;5357  SectionRef S, xS;5358  const char *name, *sym_name;5359  uint64_t n_value;5360 5361  r = get_pointer_64(p, offset, left, S, info);5362  if (r == nullptr)5363    return;5364  memset(&opl, '\0', sizeof(struct objc_property_list64));5365  if (left < sizeof(struct objc_property_list64)) {5366    memcpy(&opl, r, left);5367    outs() << "   (objc_property_list entends past the end of the section)\n";5368  } else5369    memcpy(&opl, r, sizeof(struct objc_property_list64));5370  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5371    swapStruct(opl);5372  outs() << "                    entsize " << opl.entsize << "\n";5373  outs() << "                      count " << opl.count << "\n";5374 5375  p += sizeof(struct objc_property_list64);5376  offset += sizeof(struct objc_property_list64);5377  for (j = 0; j < opl.count; j++) {5378    r = get_pointer_64(p, offset, left, S, info);5379    if (r == nullptr)5380      return;5381    memset(&op, '\0', sizeof(struct objc_property64));5382    if (left < sizeof(struct objc_property64)) {5383      memcpy(&op, r, left);5384      outs() << "   (objc_property entends past the end of the section)\n";5385    } else5386      memcpy(&op, r, sizeof(struct objc_property64));5387    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5388      swapStruct(op);5389 5390    outs() << "\t\t\t     name ";5391    sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,5392                             info, n_value, op.name);5393    if (n_value != 0) {5394      if (info->verbose && sym_name != nullptr)5395        outs() << sym_name;5396      else5397        outs() << format("0x%" PRIx64, n_value);5398      if (op.name != 0)5399        outs() << " + " << format("0x%" PRIx64, op.name);5400    } else5401      outs() << format("0x%" PRIx64, op.name);5402    name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);5403    if (name != nullptr)5404      outs() << format(" %.*s", left, name);5405    outs() << "\n";5406 5407    outs() << "\t\t\tattributes ";5408    sym_name =5409        get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,5410                      info, n_value, op.attributes);5411    if (n_value != 0) {5412      if (info->verbose && sym_name != nullptr)5413        outs() << sym_name;5414      else5415        outs() << format("0x%" PRIx64, n_value);5416      if (op.attributes != 0)5417        outs() << " + " << format("0x%" PRIx64, op.attributes);5418    } else5419      outs() << format("0x%" PRIx64, op.attributes);5420    name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);5421    if (name != nullptr)5422      outs() << format(" %.*s", left, name);5423    outs() << "\n";5424 5425    p += sizeof(struct objc_property64);5426    offset += sizeof(struct objc_property64);5427  }5428}5429 5430static void print_objc_property_list32(uint32_t p,5431                                       struct DisassembleInfo *info) {5432  struct objc_property_list32 opl;5433  struct objc_property32 op;5434  const char *r;5435  uint32_t offset, xoffset, left, j;5436  SectionRef S, xS;5437  const char *name;5438 5439  r = get_pointer_32(p, offset, left, S, info);5440  if (r == nullptr)5441    return;5442  memset(&opl, '\0', sizeof(struct objc_property_list32));5443  if (left < sizeof(struct objc_property_list32)) {5444    memcpy(&opl, r, left);5445    outs() << "   (objc_property_list entends past the end of the section)\n";5446  } else5447    memcpy(&opl, r, sizeof(struct objc_property_list32));5448  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5449    swapStruct(opl);5450  outs() << "                    entsize " << opl.entsize << "\n";5451  outs() << "                      count " << opl.count << "\n";5452 5453  p += sizeof(struct objc_property_list32);5454  offset += sizeof(struct objc_property_list32);5455  for (j = 0; j < opl.count; j++) {5456    r = get_pointer_32(p, offset, left, S, info);5457    if (r == nullptr)5458      return;5459    memset(&op, '\0', sizeof(struct objc_property32));5460    if (left < sizeof(struct objc_property32)) {5461      memcpy(&op, r, left);5462      outs() << "   (objc_property entends past the end of the section)\n";5463    } else5464      memcpy(&op, r, sizeof(struct objc_property32));5465    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5466      swapStruct(op);5467 5468    outs() << "\t\t\t     name " << format("0x%" PRIx32, op.name);5469    name = get_pointer_32(op.name, xoffset, left, xS, info);5470    if (name != nullptr)5471      outs() << format(" %.*s", left, name);5472    outs() << "\n";5473 5474    outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);5475    name = get_pointer_32(op.attributes, xoffset, left, xS, info);5476    if (name != nullptr)5477      outs() << format(" %.*s", left, name);5478    outs() << "\n";5479 5480    p += sizeof(struct objc_property32);5481    offset += sizeof(struct objc_property32);5482  }5483}5484 5485static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,5486                               bool &is_meta_class) {5487  struct class_ro64_t cro;5488  const char *r;5489  uint32_t offset, xoffset, left;5490  SectionRef S, xS;5491  const char *name, *sym_name;5492  uint64_t n_value;5493 5494  r = get_pointer_64(p, offset, left, S, info);5495  if (r == nullptr || left < sizeof(struct class_ro64_t))5496    return false;5497  memcpy(&cro, r, sizeof(struct class_ro64_t));5498  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5499    swapStruct(cro);5500  outs() << "                    flags " << format("0x%" PRIx32, cro.flags);5501  if (cro.flags & RO_META)5502    outs() << " RO_META";5503  if (cro.flags & RO_ROOT)5504    outs() << " RO_ROOT";5505  if (cro.flags & RO_HAS_CXX_STRUCTORS)5506    outs() << " RO_HAS_CXX_STRUCTORS";5507  outs() << "\n";5508  outs() << "            instanceStart " << cro.instanceStart << "\n";5509  outs() << "             instanceSize " << cro.instanceSize << "\n";5510  outs() << "                 reserved " << format("0x%" PRIx32, cro.reserved)5511         << "\n";5512  outs() << "               ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)5513         << "\n";5514  print_layout_map64(cro.ivarLayout, info);5515 5516  outs() << "                     name ";5517  sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,5518                           info, n_value, cro.name);5519  if (n_value != 0) {5520    if (info->verbose && sym_name != nullptr)5521      outs() << sym_name;5522    else5523      outs() << format("0x%" PRIx64, n_value);5524    if (cro.name != 0)5525      outs() << " + " << format("0x%" PRIx64, cro.name);5526  } else5527    outs() << format("0x%" PRIx64, cro.name);5528  name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);5529  if (name != nullptr)5530    outs() << format(" %.*s", left, name);5531  outs() << "\n";5532 5533  outs() << "              baseMethods ";5534  sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),5535                           S, info, n_value, cro.baseMethods);5536  if (n_value != 0) {5537    if (info->verbose && sym_name != nullptr)5538      outs() << sym_name;5539    else5540      outs() << format("0x%" PRIx64, n_value);5541    if (cro.baseMethods != 0)5542      outs() << " + " << format("0x%" PRIx64, cro.baseMethods);5543  } else5544    outs() << format("0x%" PRIx64, cro.baseMethods);5545  outs() << " (struct method_list_t *)\n";5546  if (cro.baseMethods + n_value != 0)5547    print_method_list64_t(cro.baseMethods + n_value, info, "");5548 5549  outs() << "            baseProtocols ";5550  sym_name =5551      get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,5552                    info, n_value, cro.baseProtocols);5553  if (n_value != 0) {5554    if (info->verbose && sym_name != nullptr)5555      outs() << sym_name;5556    else5557      outs() << format("0x%" PRIx64, n_value);5558    if (cro.baseProtocols != 0)5559      outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);5560  } else5561    outs() << format("0x%" PRIx64, cro.baseProtocols);5562  outs() << "\n";5563  if (cro.baseProtocols + n_value != 0)5564    print_protocol_list64_t(cro.baseProtocols + n_value, info);5565 5566  outs() << "                    ivars ";5567  sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,5568                           info, n_value, cro.ivars);5569  if (n_value != 0) {5570    if (info->verbose && sym_name != nullptr)5571      outs() << sym_name;5572    else5573      outs() << format("0x%" PRIx64, n_value);5574    if (cro.ivars != 0)5575      outs() << " + " << format("0x%" PRIx64, cro.ivars);5576  } else5577    outs() << format("0x%" PRIx64, cro.ivars);5578  outs() << "\n";5579  if (cro.ivars + n_value != 0)5580    print_ivar_list64_t(cro.ivars + n_value, info);5581 5582  outs() << "           weakIvarLayout ";5583  sym_name =5584      get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,5585                    info, n_value, cro.weakIvarLayout);5586  if (n_value != 0) {5587    if (info->verbose && sym_name != nullptr)5588      outs() << sym_name;5589    else5590      outs() << format("0x%" PRIx64, n_value);5591    if (cro.weakIvarLayout != 0)5592      outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);5593  } else5594    outs() << format("0x%" PRIx64, cro.weakIvarLayout);5595  outs() << "\n";5596  print_layout_map64(cro.weakIvarLayout + n_value, info);5597 5598  outs() << "           baseProperties ";5599  sym_name =5600      get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,5601                    info, n_value, cro.baseProperties);5602  if (n_value != 0) {5603    if (info->verbose && sym_name != nullptr)5604      outs() << sym_name;5605    else5606      outs() << format("0x%" PRIx64, n_value);5607    if (cro.baseProperties != 0)5608      outs() << " + " << format("0x%" PRIx64, cro.baseProperties);5609  } else5610    outs() << format("0x%" PRIx64, cro.baseProperties);5611  outs() << "\n";5612  if (cro.baseProperties + n_value != 0)5613    print_objc_property_list64(cro.baseProperties + n_value, info);5614 5615  is_meta_class = (cro.flags & RO_META) != 0;5616  return true;5617}5618 5619static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,5620                               bool &is_meta_class) {5621  struct class_ro32_t cro;5622  const char *r;5623  uint32_t offset, xoffset, left;5624  SectionRef S, xS;5625  const char *name;5626 5627  r = get_pointer_32(p, offset, left, S, info);5628  if (r == nullptr)5629    return false;5630  memset(&cro, '\0', sizeof(struct class_ro32_t));5631  if (left < sizeof(struct class_ro32_t)) {5632    memcpy(&cro, r, left);5633    outs() << "   (class_ro_t entends past the end of the section)\n";5634  } else5635    memcpy(&cro, r, sizeof(struct class_ro32_t));5636  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5637    swapStruct(cro);5638  outs() << "                    flags " << format("0x%" PRIx32, cro.flags);5639  if (cro.flags & RO_META)5640    outs() << " RO_META";5641  if (cro.flags & RO_ROOT)5642    outs() << " RO_ROOT";5643  if (cro.flags & RO_HAS_CXX_STRUCTORS)5644    outs() << " RO_HAS_CXX_STRUCTORS";5645  outs() << "\n";5646  outs() << "            instanceStart " << cro.instanceStart << "\n";5647  outs() << "             instanceSize " << cro.instanceSize << "\n";5648  outs() << "               ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)5649         << "\n";5650  print_layout_map32(cro.ivarLayout, info);5651 5652  outs() << "                     name " << format("0x%" PRIx32, cro.name);5653  name = get_pointer_32(cro.name, xoffset, left, xS, info);5654  if (name != nullptr)5655    outs() << format(" %.*s", left, name);5656  outs() << "\n";5657 5658  outs() << "              baseMethods "5659         << format("0x%" PRIx32, cro.baseMethods)5660         << " (struct method_list_t *)\n";5661  if (cro.baseMethods != 0)5662    print_method_list32_t(cro.baseMethods, info, "");5663 5664  outs() << "            baseProtocols "5665         << format("0x%" PRIx32, cro.baseProtocols) << "\n";5666  if (cro.baseProtocols != 0)5667    print_protocol_list32_t(cro.baseProtocols, info);5668  outs() << "                    ivars " << format("0x%" PRIx32, cro.ivars)5669         << "\n";5670  if (cro.ivars != 0)5671    print_ivar_list32_t(cro.ivars, info);5672  outs() << "           weakIvarLayout "5673         << format("0x%" PRIx32, cro.weakIvarLayout) << "\n";5674  print_layout_map32(cro.weakIvarLayout, info);5675  outs() << "           baseProperties "5676         << format("0x%" PRIx32, cro.baseProperties) << "\n";5677  if (cro.baseProperties != 0)5678    print_objc_property_list32(cro.baseProperties, info);5679  is_meta_class = (cro.flags & RO_META) != 0;5680  return true;5681}5682 5683static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {5684  struct class64_t c;5685  const char *r;5686  uint32_t offset, left;5687  SectionRef S;5688  const char *name;5689  uint64_t isa_n_value, n_value;5690 5691  r = get_pointer_64(p, offset, left, S, info);5692  if (r == nullptr || left < sizeof(struct class64_t))5693    return;5694  memcpy(&c, r, sizeof(struct class64_t));5695  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5696    swapStruct(c);5697 5698  outs() << "           isa " << format("0x%" PRIx64, c.isa);5699  name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,5700                       isa_n_value, c.isa);5701  if (name != nullptr)5702    outs() << " " << name;5703  outs() << "\n";5704 5705  outs() << "    superclass " << format("0x%" PRIx64, c.superclass);5706  name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,5707                       n_value, c.superclass);5708  if (name != nullptr)5709    outs() << " " << name;5710  else {5711    name = get_dyld_bind_info_symbolname(S.getAddress() +5712             offset + offsetof(struct class64_t, superclass), info);5713    if (name != nullptr)5714      outs() << " " << name;5715  }5716  outs() << "\n";5717 5718  outs() << "         cache " << format("0x%" PRIx64, c.cache);5719  name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,5720                       n_value, c.cache);5721  if (name != nullptr)5722    outs() << " " << name;5723  outs() << "\n";5724 5725  outs() << "        vtable " << format("0x%" PRIx64, c.vtable);5726  name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,5727                       n_value, c.vtable);5728  if (name != nullptr)5729    outs() << " " << name;5730  outs() << "\n";5731 5732  name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,5733                       n_value, c.data);5734  outs() << "          data ";5735  if (n_value != 0) {5736    if (info->verbose && name != nullptr)5737      outs() << name;5738    else5739      outs() << format("0x%" PRIx64, n_value);5740    if (c.data != 0)5741      outs() << " + " << format("0x%" PRIx64, c.data);5742  } else5743    outs() << format("0x%" PRIx64, c.data);5744  outs() << " (struct class_ro_t *)";5745 5746  // This is a Swift class if some of the low bits of the pointer are set.5747  if ((c.data + n_value) & 0x7)5748    outs() << " Swift class";5749  outs() << "\n";5750  bool is_meta_class;5751  if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))5752    return;5753 5754  if (!is_meta_class &&5755      c.isa + isa_n_value != p &&5756      c.isa + isa_n_value != 0 &&5757      info->depth < 100) {5758      info->depth++;5759      outs() << "Meta Class\n";5760      print_class64_t(c.isa + isa_n_value, info);5761  }5762}5763 5764static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {5765  struct class32_t c;5766  const char *r;5767  uint32_t offset, left;5768  SectionRef S;5769  const char *name;5770 5771  r = get_pointer_32(p, offset, left, S, info);5772  if (r == nullptr)5773    return;5774  memset(&c, '\0', sizeof(struct class32_t));5775  if (left < sizeof(struct class32_t)) {5776    memcpy(&c, r, left);5777    outs() << "   (class_t entends past the end of the section)\n";5778  } else5779    memcpy(&c, r, sizeof(struct class32_t));5780  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5781    swapStruct(c);5782 5783  outs() << "           isa " << format("0x%" PRIx32, c.isa);5784  name =5785      get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);5786  if (name != nullptr)5787    outs() << " " << name;5788  outs() << "\n";5789 5790  outs() << "    superclass " << format("0x%" PRIx32, c.superclass);5791  name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,5792                       c.superclass);5793  if (name != nullptr)5794    outs() << " " << name;5795  outs() << "\n";5796 5797  outs() << "         cache " << format("0x%" PRIx32, c.cache);5798  name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,5799                       c.cache);5800  if (name != nullptr)5801    outs() << " " << name;5802  outs() << "\n";5803 5804  outs() << "        vtable " << format("0x%" PRIx32, c.vtable);5805  name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,5806                       c.vtable);5807  if (name != nullptr)5808    outs() << " " << name;5809  outs() << "\n";5810 5811  name =5812      get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);5813  outs() << "          data " << format("0x%" PRIx32, c.data)5814         << " (struct class_ro_t *)";5815 5816  // This is a Swift class if some of the low bits of the pointer are set.5817  if (c.data & 0x3)5818    outs() << " Swift class";5819  outs() << "\n";5820  bool is_meta_class;5821  if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))5822    return;5823 5824  if (!is_meta_class) {5825    outs() << "Meta Class\n";5826    print_class32_t(c.isa, info);5827  }5828}5829 5830static void print_objc_class_t(struct objc_class_t *objc_class,5831                               struct DisassembleInfo *info) {5832  uint32_t offset, left, xleft;5833  const char *name, *p, *ivar_list;5834  SectionRef S;5835  int32_t i;5836  struct objc_ivar_list_t objc_ivar_list;5837  struct objc_ivar_t ivar;5838 5839  outs() << "\t\t      isa " << format("0x%08" PRIx32, objc_class->isa);5840  if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {5841    name = get_pointer_32(objc_class->isa, offset, left, S, info, true);5842    if (name != nullptr)5843      outs() << format(" %.*s", left, name);5844    else5845      outs() << " (not in an __OBJC section)";5846  }5847  outs() << "\n";5848 5849  outs() << "\t      super_class "5850         << format("0x%08" PRIx32, objc_class->super_class);5851  if (info->verbose) {5852    name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);5853    if (name != nullptr)5854      outs() << format(" %.*s", left, name);5855    else5856      outs() << " (not in an __OBJC section)";5857  }5858  outs() << "\n";5859 5860  outs() << "\t\t     name " << format("0x%08" PRIx32, objc_class->name);5861  if (info->verbose) {5862    name = get_pointer_32(objc_class->name, offset, left, S, info, true);5863    if (name != nullptr)5864      outs() << format(" %.*s", left, name);5865    else5866      outs() << " (not in an __OBJC section)";5867  }5868  outs() << "\n";5869 5870  outs() << "\t\t  version " << format("0x%08" PRIx32, objc_class->version)5871         << "\n";5872 5873  outs() << "\t\t     info " << format("0x%08" PRIx32, objc_class->info);5874  if (info->verbose) {5875    if (CLS_GETINFO(objc_class, CLS_CLASS))5876      outs() << " CLS_CLASS";5877    else if (CLS_GETINFO(objc_class, CLS_META))5878      outs() << " CLS_META";5879  }5880  outs() << "\n";5881 5882  outs() << "\t    instance_size "5883         << format("0x%08" PRIx32, objc_class->instance_size) << "\n";5884 5885  p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);5886  outs() << "\t\t    ivars " << format("0x%08" PRIx32, objc_class->ivars);5887  if (p != nullptr) {5888    if (left > sizeof(struct objc_ivar_list_t)) {5889      outs() << "\n";5890      memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));5891    } else {5892      outs() << " (entends past the end of the section)\n";5893      memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));5894      memcpy(&objc_ivar_list, p, left);5895    }5896    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5897      swapStruct(objc_ivar_list);5898    outs() << "\t\t       ivar_count " << objc_ivar_list.ivar_count << "\n";5899    ivar_list = p + sizeof(struct objc_ivar_list_t);5900    for (i = 0; i < objc_ivar_list.ivar_count; i++) {5901      if ((i + 1) * sizeof(struct objc_ivar_t) > left) {5902        outs() << "\t\t remaining ivar's extend past the of the section\n";5903        break;5904      }5905      memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),5906             sizeof(struct objc_ivar_t));5907      if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5908        swapStruct(ivar);5909 5910      outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);5911      if (info->verbose) {5912        name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);5913        if (name != nullptr)5914          outs() << format(" %.*s", xleft, name);5915        else5916          outs() << " (not in an __OBJC section)";5917      }5918      outs() << "\n";5919 5920      outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);5921      if (info->verbose) {5922        name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);5923        if (name != nullptr)5924          outs() << format(" %.*s", xleft, name);5925        else5926          outs() << " (not in an __OBJC section)";5927      }5928      outs() << "\n";5929 5930      outs() << "\t\t      ivar_offset "5931             << format("0x%08" PRIx32, ivar.ivar_offset) << "\n";5932    }5933  } else {5934    outs() << " (not in an __OBJC section)\n";5935  }5936 5937  outs() << "\t\t  methods " << format("0x%08" PRIx32, objc_class->methodLists);5938  if (print_method_list(objc_class->methodLists, info))5939    outs() << " (not in an __OBJC section)\n";5940 5941  outs() << "\t\t    cache " << format("0x%08" PRIx32, objc_class->cache)5942         << "\n";5943 5944  outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);5945  if (print_protocol_list(objc_class->protocols, 16, info))5946    outs() << " (not in an __OBJC section)\n";5947}5948 5949static void print_objc_objc_category_t(struct objc_category_t *objc_category,5950                                       struct DisassembleInfo *info) {5951  uint32_t offset, left;5952  const char *name;5953  SectionRef S;5954 5955  outs() << "\t       category name "5956         << format("0x%08" PRIx32, objc_category->category_name);5957  if (info->verbose) {5958    name = get_pointer_32(objc_category->category_name, offset, left, S, info,5959                          true);5960    if (name != nullptr)5961      outs() << format(" %.*s", left, name);5962    else5963      outs() << " (not in an __OBJC section)";5964  }5965  outs() << "\n";5966 5967  outs() << "\t\t  class name "5968         << format("0x%08" PRIx32, objc_category->class_name);5969  if (info->verbose) {5970    name =5971        get_pointer_32(objc_category->class_name, offset, left, S, info, true);5972    if (name != nullptr)5973      outs() << format(" %.*s", left, name);5974    else5975      outs() << " (not in an __OBJC section)";5976  }5977  outs() << "\n";5978 5979  outs() << "\t    instance methods "5980         << format("0x%08" PRIx32, objc_category->instance_methods);5981  if (print_method_list(objc_category->instance_methods, info))5982    outs() << " (not in an __OBJC section)\n";5983 5984  outs() << "\t       class methods "5985         << format("0x%08" PRIx32, objc_category->class_methods);5986  if (print_method_list(objc_category->class_methods, info))5987    outs() << " (not in an __OBJC section)\n";5988}5989 5990static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {5991  struct category64_t c;5992  const char *r;5993  uint32_t offset, xoffset, left;5994  SectionRef S, xS;5995  const char *name, *sym_name;5996  uint64_t n_value;5997 5998  r = get_pointer_64(p, offset, left, S, info);5999  if (r == nullptr)6000    return;6001  memset(&c, '\0', sizeof(struct category64_t));6002  if (left < sizeof(struct category64_t)) {6003    memcpy(&c, r, left);6004    outs() << "   (category_t entends past the end of the section)\n";6005  } else6006    memcpy(&c, r, sizeof(struct category64_t));6007  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6008    swapStruct(c);6009 6010  outs() << "              name ";6011  sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,6012                           info, n_value, c.name);6013  if (n_value != 0) {6014    if (info->verbose && sym_name != nullptr)6015      outs() << sym_name;6016    else6017      outs() << format("0x%" PRIx64, n_value);6018    if (c.name != 0)6019      outs() << " + " << format("0x%" PRIx64, c.name);6020  } else6021    outs() << format("0x%" PRIx64, c.name);6022  name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);6023  if (name != nullptr)6024    outs() << format(" %.*s", left, name);6025  outs() << "\n";6026 6027  outs() << "               cls ";6028  sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,6029                           n_value, c.cls);6030  if (n_value != 0) {6031    if (info->verbose && sym_name != nullptr)6032      outs() << sym_name;6033    else6034      outs() << format("0x%" PRIx64, n_value);6035    if (c.cls != 0)6036      outs() << " + " << format("0x%" PRIx64, c.cls);6037  } else6038    outs() << format("0x%" PRIx64, c.cls);6039  outs() << "\n";6040  if (c.cls + n_value != 0)6041    print_class64_t(c.cls + n_value, info);6042 6043  outs() << "   instanceMethods ";6044  sym_name =6045      get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,6046                    info, n_value, c.instanceMethods);6047  if (n_value != 0) {6048    if (info->verbose && sym_name != nullptr)6049      outs() << sym_name;6050    else6051      outs() << format("0x%" PRIx64, n_value);6052    if (c.instanceMethods != 0)6053      outs() << " + " << format("0x%" PRIx64, c.instanceMethods);6054  } else6055    outs() << format("0x%" PRIx64, c.instanceMethods);6056  outs() << "\n";6057  if (c.instanceMethods + n_value != 0)6058    print_method_list64_t(c.instanceMethods + n_value, info, "");6059 6060  outs() << "      classMethods ";6061  sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),6062                           S, info, n_value, c.classMethods);6063  if (n_value != 0) {6064    if (info->verbose && sym_name != nullptr)6065      outs() << sym_name;6066    else6067      outs() << format("0x%" PRIx64, n_value);6068    if (c.classMethods != 0)6069      outs() << " + " << format("0x%" PRIx64, c.classMethods);6070  } else6071    outs() << format("0x%" PRIx64, c.classMethods);6072  outs() << "\n";6073  if (c.classMethods + n_value != 0)6074    print_method_list64_t(c.classMethods + n_value, info, "");6075 6076  outs() << "         protocols ";6077  sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,6078                           info, n_value, c.protocols);6079  if (n_value != 0) {6080    if (info->verbose && sym_name != nullptr)6081      outs() << sym_name;6082    else6083      outs() << format("0x%" PRIx64, n_value);6084    if (c.protocols != 0)6085      outs() << " + " << format("0x%" PRIx64, c.protocols);6086  } else6087    outs() << format("0x%" PRIx64, c.protocols);6088  outs() << "\n";6089  if (c.protocols + n_value != 0)6090    print_protocol_list64_t(c.protocols + n_value, info);6091 6092  outs() << "instanceProperties ";6093  sym_name =6094      get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),6095                    S, info, n_value, c.instanceProperties);6096  if (n_value != 0) {6097    if (info->verbose && sym_name != nullptr)6098      outs() << sym_name;6099    else6100      outs() << format("0x%" PRIx64, n_value);6101    if (c.instanceProperties != 0)6102      outs() << " + " << format("0x%" PRIx64, c.instanceProperties);6103  } else6104    outs() << format("0x%" PRIx64, c.instanceProperties);6105  outs() << "\n";6106  if (c.instanceProperties + n_value != 0)6107    print_objc_property_list64(c.instanceProperties + n_value, info);6108}6109 6110static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {6111  struct category32_t c;6112  const char *r;6113  uint32_t offset, left;6114  SectionRef S, xS;6115  const char *name;6116 6117  r = get_pointer_32(p, offset, left, S, info);6118  if (r == nullptr)6119    return;6120  memset(&c, '\0', sizeof(struct category32_t));6121  if (left < sizeof(struct category32_t)) {6122    memcpy(&c, r, left);6123    outs() << "   (category_t entends past the end of the section)\n";6124  } else6125    memcpy(&c, r, sizeof(struct category32_t));6126  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6127    swapStruct(c);6128 6129  outs() << "              name " << format("0x%" PRIx32, c.name);6130  name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,6131                       c.name);6132  if (name)6133    outs() << " " << name;6134  outs() << "\n";6135 6136  outs() << "               cls " << format("0x%" PRIx32, c.cls) << "\n";6137  if (c.cls != 0)6138    print_class32_t(c.cls, info);6139  outs() << "   instanceMethods " << format("0x%" PRIx32, c.instanceMethods)6140         << "\n";6141  if (c.instanceMethods != 0)6142    print_method_list32_t(c.instanceMethods, info, "");6143  outs() << "      classMethods " << format("0x%" PRIx32, c.classMethods)6144         << "\n";6145  if (c.classMethods != 0)6146    print_method_list32_t(c.classMethods, info, "");6147  outs() << "         protocols " << format("0x%" PRIx32, c.protocols) << "\n";6148  if (c.protocols != 0)6149    print_protocol_list32_t(c.protocols, info);6150  outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)6151         << "\n";6152  if (c.instanceProperties != 0)6153    print_objc_property_list32(c.instanceProperties, info);6154}6155 6156static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {6157  uint32_t i, left, offset, xoffset;6158  uint64_t p, n_value;6159  struct message_ref64 mr;6160  const char *name, *sym_name;6161  const char *r;6162  SectionRef xS;6163 6164  if (S == SectionRef())6165    return;6166 6167  StringRef SectName;6168  Expected<StringRef> SecNameOrErr = S.getName();6169  if (SecNameOrErr)6170    SectName = *SecNameOrErr;6171  else6172    consumeError(SecNameOrErr.takeError());6173 6174  DataRefImpl Ref = S.getRawDataRefImpl();6175  StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6176  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6177  offset = 0;6178  for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6179    p = S.getAddress() + i;6180    r = get_pointer_64(p, offset, left, S, info);6181    if (r == nullptr)6182      return;6183    memset(&mr, '\0', sizeof(struct message_ref64));6184    if (left < sizeof(struct message_ref64)) {6185      memcpy(&mr, r, left);6186      outs() << "   (message_ref entends past the end of the section)\n";6187    } else6188      memcpy(&mr, r, sizeof(struct message_ref64));6189    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6190      swapStruct(mr);6191 6192    outs() << "  imp ";6193    name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,6194                         n_value, mr.imp);6195    if (n_value != 0) {6196      outs() << format("0x%" PRIx64, n_value) << " ";6197      if (mr.imp != 0)6198        outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";6199    } else6200      outs() << format("0x%" PRIx64, mr.imp) << " ";6201    if (name != nullptr)6202      outs() << " " << name;6203    outs() << "\n";6204 6205    outs() << "  sel ";6206    sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,6207                             info, n_value, mr.sel);6208    if (n_value != 0) {6209      if (info->verbose && sym_name != nullptr)6210        outs() << sym_name;6211      else6212        outs() << format("0x%" PRIx64, n_value);6213      if (mr.sel != 0)6214        outs() << " + " << format("0x%" PRIx64, mr.sel);6215    } else6216      outs() << format("0x%" PRIx64, mr.sel);6217    name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);6218    if (name != nullptr)6219      outs() << format(" %.*s", left, name);6220    outs() << "\n";6221 6222    offset += sizeof(struct message_ref64);6223  }6224}6225 6226static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {6227  uint32_t i, left, offset, xoffset, p;6228  struct message_ref32 mr;6229  const char *name, *r;6230  SectionRef xS;6231 6232  if (S == SectionRef())6233    return;6234 6235  StringRef SectName;6236  Expected<StringRef> SecNameOrErr = S.getName();6237  if (SecNameOrErr)6238    SectName = *SecNameOrErr;6239  else6240    consumeError(SecNameOrErr.takeError());6241 6242  DataRefImpl Ref = S.getRawDataRefImpl();6243  StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6244  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6245  offset = 0;6246  for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6247    p = S.getAddress() + i;6248    r = get_pointer_32(p, offset, left, S, info);6249    if (r == nullptr)6250      return;6251    memset(&mr, '\0', sizeof(struct message_ref32));6252    if (left < sizeof(struct message_ref32)) {6253      memcpy(&mr, r, left);6254      outs() << "   (message_ref entends past the end of the section)\n";6255    } else6256      memcpy(&mr, r, sizeof(struct message_ref32));6257    if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6258      swapStruct(mr);6259 6260    outs() << "  imp " << format("0x%" PRIx32, mr.imp);6261    name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,6262                         mr.imp);6263    if (name != nullptr)6264      outs() << " " << name;6265    outs() << "\n";6266 6267    outs() << "  sel " << format("0x%" PRIx32, mr.sel);6268    name = get_pointer_32(mr.sel, xoffset, left, xS, info);6269    if (name != nullptr)6270      outs() << " " << name;6271    outs() << "\n";6272 6273    offset += sizeof(struct message_ref32);6274  }6275}6276 6277static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {6278  uint32_t left, offset, swift_version;6279  uint64_t p;6280  struct objc_image_info64 o;6281  const char *r;6282 6283  if (S == SectionRef())6284    return;6285 6286  StringRef SectName;6287  Expected<StringRef> SecNameOrErr = S.getName();6288  if (SecNameOrErr)6289    SectName = *SecNameOrErr;6290  else6291    consumeError(SecNameOrErr.takeError());6292 6293  DataRefImpl Ref = S.getRawDataRefImpl();6294  StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6295  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6296  p = S.getAddress();6297  r = get_pointer_64(p, offset, left, S, info);6298  if (r == nullptr)6299    return;6300  memset(&o, '\0', sizeof(struct objc_image_info64));6301  if (left < sizeof(struct objc_image_info64)) {6302    memcpy(&o, r, left);6303    outs() << "   (objc_image_info entends past the end of the section)\n";6304  } else6305    memcpy(&o, r, sizeof(struct objc_image_info64));6306  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6307    swapStruct(o);6308  outs() << "  version " << o.version << "\n";6309  outs() << "    flags " << format("0x%" PRIx32, o.flags);6310  if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6311    outs() << " OBJC_IMAGE_IS_REPLACEMENT";6312  if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6313    outs() << " OBJC_IMAGE_SUPPORTS_GC";6314  if (o.flags & OBJC_IMAGE_IS_SIMULATED)6315    outs() << " OBJC_IMAGE_IS_SIMULATED";6316  if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)6317    outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";6318  swift_version = (o.flags >> 8) & 0xff;6319  if (swift_version != 0) {6320    if (swift_version == 1)6321      outs() << " Swift 1.0";6322    else if (swift_version == 2)6323      outs() << " Swift 1.1";6324    else if(swift_version == 3)6325      outs() << " Swift 2.0";6326    else if(swift_version == 4)6327      outs() << " Swift 3.0";6328    else if(swift_version == 5)6329      outs() << " Swift 4.0";6330    else if(swift_version == 6)6331      outs() << " Swift 4.1/Swift 4.2";6332    else if(swift_version == 7)6333      outs() << " Swift 5 or later";6334    else6335      outs() << " unknown future Swift version (" << swift_version << ")";6336  }6337  outs() << "\n";6338}6339 6340static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {6341  uint32_t left, offset, swift_version, p;6342  struct objc_image_info32 o;6343  const char *r;6344 6345  if (S == SectionRef())6346    return;6347 6348  StringRef SectName;6349  Expected<StringRef> SecNameOrErr = S.getName();6350  if (SecNameOrErr)6351    SectName = *SecNameOrErr;6352  else6353    consumeError(SecNameOrErr.takeError());6354 6355  DataRefImpl Ref = S.getRawDataRefImpl();6356  StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6357  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6358  p = S.getAddress();6359  r = get_pointer_32(p, offset, left, S, info);6360  if (r == nullptr)6361    return;6362  memset(&o, '\0', sizeof(struct objc_image_info32));6363  if (left < sizeof(struct objc_image_info32)) {6364    memcpy(&o, r, left);6365    outs() << "   (objc_image_info entends past the end of the section)\n";6366  } else6367    memcpy(&o, r, sizeof(struct objc_image_info32));6368  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6369    swapStruct(o);6370  outs() << "  version " << o.version << "\n";6371  outs() << "    flags " << format("0x%" PRIx32, o.flags);6372  if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6373    outs() << " OBJC_IMAGE_IS_REPLACEMENT";6374  if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6375    outs() << " OBJC_IMAGE_SUPPORTS_GC";6376  swift_version = (o.flags >> 8) & 0xff;6377  if (swift_version != 0) {6378    if (swift_version == 1)6379      outs() << " Swift 1.0";6380    else if (swift_version == 2)6381      outs() << " Swift 1.1";6382    else if(swift_version == 3)6383      outs() << " Swift 2.0";6384    else if(swift_version == 4)6385      outs() << " Swift 3.0";6386    else if(swift_version == 5)6387      outs() << " Swift 4.0";6388    else if(swift_version == 6)6389      outs() << " Swift 4.1/Swift 4.2";6390    else if(swift_version == 7)6391      outs() << " Swift 5 or later";6392    else6393      outs() << " unknown future Swift version (" << swift_version << ")";6394  }6395  outs() << "\n";6396}6397 6398static void print_image_info(SectionRef S, struct DisassembleInfo *info) {6399  uint32_t left, offset, p;6400  struct imageInfo_t o;6401  const char *r;6402 6403  StringRef SectName;6404  Expected<StringRef> SecNameOrErr = S.getName();6405  if (SecNameOrErr)6406    SectName = *SecNameOrErr;6407  else6408    consumeError(SecNameOrErr.takeError());6409 6410  DataRefImpl Ref = S.getRawDataRefImpl();6411  StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6412  outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6413  p = S.getAddress();6414  r = get_pointer_32(p, offset, left, S, info);6415  if (r == nullptr)6416    return;6417  memset(&o, '\0', sizeof(struct imageInfo_t));6418  if (left < sizeof(struct imageInfo_t)) {6419    memcpy(&o, r, left);6420    outs() << " (imageInfo entends past the end of the section)\n";6421  } else6422    memcpy(&o, r, sizeof(struct imageInfo_t));6423  if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6424    swapStruct(o);6425  outs() << "  version " << o.version << "\n";6426  outs() << "    flags " << format("0x%" PRIx32, o.flags);6427  if (o.flags & 0x1)6428    outs() << "  F&C";6429  if (o.flags & 0x2)6430    outs() << " GC";6431  if (o.flags & 0x4)6432    outs() << " GC-only";6433  else6434    outs() << " RR";6435  outs() << "\n";6436}6437 6438static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {6439  SymbolAddressMap AddrMap;6440  if (verbose)6441    CreateSymbolAddressMap(O, &AddrMap);6442 6443  std::vector<SectionRef> Sections;6444  append_range(Sections, O->sections());6445 6446  struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6447 6448  SectionRef CL = get_section(O, "__OBJC2", "__class_list");6449  if (CL == SectionRef())6450    CL = get_section(O, "__DATA", "__objc_classlist");6451  if (CL == SectionRef())6452    CL = get_section(O, "__DATA_CONST", "__objc_classlist");6453  if (CL == SectionRef())6454    CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6455  info.S = CL;6456  walk_pointer_list_64("class", CL, O, &info, print_class64_t);6457 6458  SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6459  if (CR == SectionRef())6460    CR = get_section(O, "__DATA", "__objc_classrefs");6461  if (CR == SectionRef())6462    CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6463  if (CR == SectionRef())6464    CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6465  info.S = CR;6466  walk_pointer_list_64("class refs", CR, O, &info, nullptr);6467 6468  SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6469  if (SR == SectionRef())6470    SR = get_section(O, "__DATA", "__objc_superrefs");6471  if (SR == SectionRef())6472    SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6473  if (SR == SectionRef())6474    SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6475  info.S = SR;6476  walk_pointer_list_64("super refs", SR, O, &info, nullptr);6477 6478  SectionRef CA = get_section(O, "__OBJC2", "__category_list");6479  if (CA == SectionRef())6480    CA = get_section(O, "__DATA", "__objc_catlist");6481  if (CA == SectionRef())6482    CA = get_section(O, "__DATA_CONST", "__objc_catlist");6483  if (CA == SectionRef())6484    CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6485  info.S = CA;6486  walk_pointer_list_64("category", CA, O, &info, print_category64_t);6487 6488  SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6489  if (PL == SectionRef())6490    PL = get_section(O, "__DATA", "__objc_protolist");6491  if (PL == SectionRef())6492    PL = get_section(O, "__DATA_CONST", "__objc_protolist");6493  if (PL == SectionRef())6494    PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6495  info.S = PL;6496  walk_pointer_list_64("protocol", PL, O, &info, nullptr);6497 6498  SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6499  if (MR == SectionRef())6500    MR = get_section(O, "__DATA", "__objc_msgrefs");6501  if (MR == SectionRef())6502    MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6503  if (MR == SectionRef())6504    MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6505  info.S = MR;6506  print_message_refs64(MR, &info);6507 6508  SectionRef II = get_section(O, "__OBJC2", "__image_info");6509  if (II == SectionRef())6510    II = get_section(O, "__DATA", "__objc_imageinfo");6511  if (II == SectionRef())6512    II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6513  if (II == SectionRef())6514    II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6515  info.S = II;6516  print_image_info64(II, &info);6517}6518 6519static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {6520  SymbolAddressMap AddrMap;6521  if (verbose)6522    CreateSymbolAddressMap(O, &AddrMap);6523 6524  std::vector<SectionRef> Sections;6525  append_range(Sections, O->sections());6526 6527  struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6528 6529  SectionRef CL = get_section(O, "__OBJC2", "__class_list");6530  if (CL == SectionRef())6531    CL = get_section(O, "__DATA", "__objc_classlist");6532  if (CL == SectionRef())6533    CL = get_section(O, "__DATA_CONST", "__objc_classlist");6534  if (CL == SectionRef())6535    CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6536  info.S = CL;6537  walk_pointer_list_32("class", CL, O, &info, print_class32_t);6538 6539  SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6540  if (CR == SectionRef())6541    CR = get_section(O, "__DATA", "__objc_classrefs");6542  if (CR == SectionRef())6543    CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6544  if (CR == SectionRef())6545    CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6546  info.S = CR;6547  walk_pointer_list_32("class refs", CR, O, &info, nullptr);6548 6549  SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6550  if (SR == SectionRef())6551    SR = get_section(O, "__DATA", "__objc_superrefs");6552  if (SR == SectionRef())6553    SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6554  if (SR == SectionRef())6555    SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6556  info.S = SR;6557  walk_pointer_list_32("super refs", SR, O, &info, nullptr);6558 6559  SectionRef CA = get_section(O, "__OBJC2", "__category_list");6560  if (CA == SectionRef())6561    CA = get_section(O, "__DATA", "__objc_catlist");6562  if (CA == SectionRef())6563    CA = get_section(O, "__DATA_CONST", "__objc_catlist");6564  if (CA == SectionRef())6565    CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6566  info.S = CA;6567  walk_pointer_list_32("category", CA, O, &info, print_category32_t);6568 6569  SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6570  if (PL == SectionRef())6571    PL = get_section(O, "__DATA", "__objc_protolist");6572  if (PL == SectionRef())6573    PL = get_section(O, "__DATA_CONST", "__objc_protolist");6574  if (PL == SectionRef())6575    PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6576  info.S = PL;6577  walk_pointer_list_32("protocol", PL, O, &info, nullptr);6578 6579  SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6580  if (MR == SectionRef())6581    MR = get_section(O, "__DATA", "__objc_msgrefs");6582  if (MR == SectionRef())6583    MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6584  if (MR == SectionRef())6585    MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6586  info.S = MR;6587  print_message_refs32(MR, &info);6588 6589  SectionRef II = get_section(O, "__OBJC2", "__image_info");6590  if (II == SectionRef())6591    II = get_section(O, "__DATA", "__objc_imageinfo");6592  if (II == SectionRef())6593    II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6594  if (II == SectionRef())6595    II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6596  info.S = II;6597  print_image_info32(II, &info);6598}6599 6600static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {6601  uint32_t i, j, p, offset, xoffset, left, defs_left, def;6602  const char *r, *name, *defs;6603  struct objc_module_t module;6604  SectionRef S, xS;6605  struct objc_symtab_t symtab;6606  struct objc_class_t objc_class;6607  struct objc_category_t objc_category;6608 6609  outs() << "Objective-C segment\n";6610  S = get_section(O, "__OBJC", "__module_info");6611  if (S == SectionRef())6612    return false;6613 6614  SymbolAddressMap AddrMap;6615  if (verbose)6616    CreateSymbolAddressMap(O, &AddrMap);6617 6618  std::vector<SectionRef> Sections;6619  append_range(Sections, O->sections());6620 6621  struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6622 6623  for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {6624    p = S.getAddress() + i;6625    r = get_pointer_32(p, offset, left, S, &info, true);6626    if (r == nullptr)6627      return true;6628    memset(&module, '\0', sizeof(struct objc_module_t));6629    if (left < sizeof(struct objc_module_t)) {6630      memcpy(&module, r, left);6631      outs() << "   (module extends past end of __module_info section)\n";6632    } else6633      memcpy(&module, r, sizeof(struct objc_module_t));6634    if (O->isLittleEndian() != sys::IsLittleEndianHost)6635      swapStruct(module);6636 6637    outs() << "Module " << format("0x%" PRIx32, p) << "\n";6638    outs() << "    version " << module.version << "\n";6639    outs() << "       size " << module.size << "\n";6640    outs() << "       name ";6641    name = get_pointer_32(module.name, xoffset, left, xS, &info, true);6642    if (name != nullptr)6643      outs() << format("%.*s", left, name);6644    else6645      outs() << format("0x%08" PRIx32, module.name)6646             << "(not in an __OBJC section)";6647    outs() << "\n";6648 6649    r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);6650    if (module.symtab == 0 || r == nullptr) {6651      outs() << "     symtab " << format("0x%08" PRIx32, module.symtab)6652             << " (not in an __OBJC section)\n";6653      continue;6654    }6655    outs() << "     symtab " << format("0x%08" PRIx32, module.symtab) << "\n";6656    memset(&symtab, '\0', sizeof(struct objc_symtab_t));6657    defs_left = 0;6658    defs = nullptr;6659    if (left < sizeof(struct objc_symtab_t)) {6660      memcpy(&symtab, r, left);6661      outs() << "\tsymtab extends past end of an __OBJC section)\n";6662    } else {6663      memcpy(&symtab, r, sizeof(struct objc_symtab_t));6664      if (left > sizeof(struct objc_symtab_t)) {6665        defs_left = left - sizeof(struct objc_symtab_t);6666        defs = r + sizeof(struct objc_symtab_t);6667      }6668    }6669    if (O->isLittleEndian() != sys::IsLittleEndianHost)6670      swapStruct(symtab);6671 6672    outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";6673    r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);6674    outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);6675    if (r == nullptr)6676      outs() << " (not in an __OBJC section)";6677    outs() << "\n";6678    outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";6679    outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";6680    if (symtab.cls_def_cnt > 0)6681      outs() << "\tClass Definitions\n";6682    for (j = 0; j < symtab.cls_def_cnt; j++) {6683      if ((j + 1) * sizeof(uint32_t) > defs_left) {6684        outs() << "\t(remaining class defs entries entends past the end of the "6685               << "section)\n";6686        break;6687      }6688      memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));6689      if (O->isLittleEndian() != sys::IsLittleEndianHost)6690        sys::swapByteOrder(def);6691 6692      r = get_pointer_32(def, xoffset, left, xS, &info, true);6693      outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);6694      if (r != nullptr) {6695        if (left > sizeof(struct objc_class_t)) {6696          outs() << "\n";6697          memcpy(&objc_class, r, sizeof(struct objc_class_t));6698        } else {6699          outs() << " (entends past the end of the section)\n";6700          memset(&objc_class, '\0', sizeof(struct objc_class_t));6701          memcpy(&objc_class, r, left);6702        }6703        if (O->isLittleEndian() != sys::IsLittleEndianHost)6704          swapStruct(objc_class);6705        print_objc_class_t(&objc_class, &info);6706      } else {6707        outs() << "(not in an __OBJC section)\n";6708      }6709 6710      if (CLS_GETINFO(&objc_class, CLS_CLASS)) {6711        outs() << "\tMeta Class";6712        r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);6713        if (r != nullptr) {6714          if (left > sizeof(struct objc_class_t)) {6715            outs() << "\n";6716            memcpy(&objc_class, r, sizeof(struct objc_class_t));6717          } else {6718            outs() << " (entends past the end of the section)\n";6719            memset(&objc_class, '\0', sizeof(struct objc_class_t));6720            memcpy(&objc_class, r, left);6721          }6722          if (O->isLittleEndian() != sys::IsLittleEndianHost)6723            swapStruct(objc_class);6724          print_objc_class_t(&objc_class, &info);6725        } else {6726          outs() << "(not in an __OBJC section)\n";6727        }6728      }6729    }6730    if (symtab.cat_def_cnt > 0)6731      outs() << "\tCategory Definitions\n";6732    for (j = 0; j < symtab.cat_def_cnt; j++) {6733      if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {6734        outs() << "\t(remaining category defs entries entends past the end of "6735               << "the section)\n";6736        break;6737      }6738      memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),6739             sizeof(uint32_t));6740      if (O->isLittleEndian() != sys::IsLittleEndianHost)6741        sys::swapByteOrder(def);6742 6743      r = get_pointer_32(def, xoffset, left, xS, &info, true);6744      outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "6745             << format("0x%08" PRIx32, def);6746      if (r != nullptr) {6747        if (left > sizeof(struct objc_category_t)) {6748          outs() << "\n";6749          memcpy(&objc_category, r, sizeof(struct objc_category_t));6750        } else {6751          outs() << " (entends past the end of the section)\n";6752          memset(&objc_category, '\0', sizeof(struct objc_category_t));6753          memcpy(&objc_category, r, left);6754        }6755        if (O->isLittleEndian() != sys::IsLittleEndianHost)6756          swapStruct(objc_category);6757        print_objc_objc_category_t(&objc_category, &info);6758      } else {6759        outs() << "(not in an __OBJC section)\n";6760      }6761    }6762  }6763  const SectionRef II = get_section(O, "__OBJC", "__image_info");6764  if (II != SectionRef())6765    print_image_info(II, &info);6766 6767  return true;6768}6769 6770static void DumpProtocolSection(MachOObjectFile *O, const char *sect,6771                                uint32_t size, uint32_t addr) {6772  SymbolAddressMap AddrMap;6773  CreateSymbolAddressMap(O, &AddrMap);6774 6775  std::vector<SectionRef> Sections;6776  append_range(Sections, O->sections());6777 6778  struct DisassembleInfo info(O, &AddrMap, &Sections, true);6779 6780  const char *p;6781  struct objc_protocol_t protocol;6782  uint32_t left, paddr;6783  for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {6784    memset(&protocol, '\0', sizeof(struct objc_protocol_t));6785    left = size - (p - sect);6786    if (left < sizeof(struct objc_protocol_t)) {6787      outs() << "Protocol extends past end of __protocol section\n";6788      memcpy(&protocol, p, left);6789    } else6790      memcpy(&protocol, p, sizeof(struct objc_protocol_t));6791    if (O->isLittleEndian() != sys::IsLittleEndianHost)6792      swapStruct(protocol);6793    paddr = addr + (p - sect);6794    outs() << "Protocol " << format("0x%" PRIx32, paddr);6795    if (print_protocol(paddr, 0, &info))6796      outs() << "(not in an __OBJC section)\n";6797  }6798}6799 6800static void printObjcMetaData(MachOObjectFile *O, bool verbose) {6801  if (O->is64Bit())6802    printObjc2_64bit_MetaData(O, verbose);6803  else {6804    MachO::mach_header H;6805    H = O->getHeader();6806    if (H.cputype == MachO::CPU_TYPE_ARM)6807      printObjc2_32bit_MetaData(O, verbose);6808    else {6809      // This is the 32-bit non-arm cputype case.  Which is normally6810      // the first Objective-C ABI.  But it may be the case of a6811      // binary for the iOS simulator which is the second Objective-C6812      // ABI.  In that case printObjc1_32bit_MetaData() will determine that6813      // and return false.6814      if (!printObjc1_32bit_MetaData(O, verbose))6815        printObjc2_32bit_MetaData(O, verbose);6816    }6817  }6818}6819 6820// GuessLiteralPointer returns a string which for the item in the Mach-O file6821// for the address passed in as ReferenceValue for printing as a comment with6822// the instruction and also returns the corresponding type of that item6823// indirectly through ReferenceType.6824//6825// If ReferenceValue is an address of literal cstring then a pointer to the6826// cstring is returned and ReferenceType is set to6827// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .6828//6829// If ReferenceValue is an address of an Objective-C CFString, Selector ref or6830// Class ref that name is returned and the ReferenceType is set accordingly.6831//6832// Lastly, literals which are Symbol address in a literal pool are looked for6833// and if found the symbol name is returned and ReferenceType is set to6834// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .6835//6836// If there is no item in the Mach-O file for the address passed in as6837// ReferenceValue nullptr is returned and ReferenceType is unchanged.6838static const char *GuessLiteralPointer(uint64_t ReferenceValue,6839                                       uint64_t ReferencePC,6840                                       uint64_t *ReferenceType,6841                                       struct DisassembleInfo *info) {6842  // First see if there is an external relocation entry at the ReferencePC.6843  if (info->O->getHeader().filetype == MachO::MH_OBJECT) {6844    uint64_t sect_addr = info->S.getAddress();6845    uint64_t sect_offset = ReferencePC - sect_addr;6846    bool reloc_found = false;6847    DataRefImpl Rel;6848    MachO::any_relocation_info RE;6849    bool isExtern = false;6850    SymbolRef Symbol;6851    for (const RelocationRef &Reloc : info->S.relocations()) {6852      uint64_t RelocOffset = Reloc.getOffset();6853      if (RelocOffset == sect_offset) {6854        Rel = Reloc.getRawDataRefImpl();6855        RE = info->O->getRelocation(Rel);6856        if (info->O->isRelocationScattered(RE))6857          continue;6858        isExtern = info->O->getPlainRelocationExternal(RE);6859        if (isExtern) {6860          symbol_iterator RelocSym = Reloc.getSymbol();6861          Symbol = *RelocSym;6862        }6863        reloc_found = true;6864        break;6865      }6866    }6867    // If there is an external relocation entry for a symbol in a section6868    // then used that symbol's value for the value of the reference.6869    if (reloc_found && isExtern) {6870      if (info->O->getAnyRelocationPCRel(RE)) {6871        unsigned Type = info->O->getAnyRelocationType(RE);6872        if (Type == MachO::X86_64_RELOC_SIGNED) {6873          ReferenceValue = cantFail(Symbol.getValue());6874        }6875      }6876    }6877  }6878 6879  // Look for literals such as Objective-C CFStrings refs, Selector refs,6880  // Message refs and Class refs.6881  bool classref, selref, msgref, cfstring;6882  uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,6883                                               selref, msgref, cfstring);6884  if (classref && pointer_value == 0) {6885    // Note the ReferenceValue is a pointer into the __objc_classrefs section.6886    // And the pointer_value in that section is typically zero as it will be6887    // set by dyld as part of the "bind information".6888    const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);6889    if (name != nullptr) {6890      *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6891      const char *class_name = strrchr(name, '$');6892      if (class_name != nullptr && class_name[1] == '_' &&6893          class_name[2] != '\0') {6894        info->class_name = class_name + 2;6895        return name;6896      }6897    }6898  }6899 6900  if (classref) {6901    *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6902    const char *name =6903        get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);6904    if (name != nullptr)6905      info->class_name = name;6906    else6907      name = "bad class ref";6908    return name;6909  }6910 6911  if (cfstring) {6912    *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;6913    const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);6914    return name;6915  }6916 6917  if (selref && pointer_value == 0)6918    pointer_value = get_objc2_64bit_selref(ReferenceValue, info);6919 6920  if (pointer_value != 0)6921    ReferenceValue = pointer_value;6922 6923  const char *name = GuessCstringPointer(ReferenceValue, info);6924  if (name) {6925    if (pointer_value != 0 && selref) {6926      *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;6927      info->selector_name = name;6928    } else if (pointer_value != 0 && msgref) {6929      info->class_name = nullptr;6930      *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;6931      info->selector_name = name;6932    } else6933      *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;6934    return name;6935  }6936 6937  // Lastly look for an indirect symbol with this ReferenceValue which is in6938  // a literal pool.  If found return that symbol name.6939  name = GuessIndirectSymbol(ReferenceValue, info);6940  if (name) {6941    *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;6942    return name;6943  }6944 6945  return nullptr;6946}6947 6948// SymbolizerSymbolLookUp is the symbol lookup function passed when creating6949// the Symbolizer.  It looks up the ReferenceValue using the info passed via the6950// pointer to the struct DisassembleInfo that was passed when MCSymbolizer6951// is created and returns the symbol name that matches the ReferenceValue or6952// nullptr if none.  The ReferenceType is passed in for the IN type of6953// reference the instruction is making from the values in defined in the header6954// "llvm-c/Disassembler.h".  On return the ReferenceType can set to a specific6955// Out type and the ReferenceName will also be set which is added as a comment6956// to the disassembled instruction.6957//6958// If the symbol name is a C++ mangled name then the demangled name is6959// returned through ReferenceName and ReferenceType is set to6960// LLVMDisassembler_ReferenceType_DeMangled_Name .6961//6962// When this is called to get a symbol name for a branch target then the6963// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then6964// SymbolValue will be looked for in the indirect symbol table to determine if6965// it is an address for a symbol stub.  If so then the symbol name for that6966// stub is returned indirectly through ReferenceName and then ReferenceType is6967// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.6968//6969// When this is called with an value loaded via a PC relative load then6970// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the6971// SymbolValue is checked to be an address of literal pointer, symbol pointer,6972// or an Objective-C meta data reference.  If so the output ReferenceType is6973// set to correspond to that as well as setting the ReferenceName.6974static const char *SymbolizerSymbolLookUp(void *DisInfo,6975                                          uint64_t ReferenceValue,6976                                          uint64_t *ReferenceType,6977                                          uint64_t ReferencePC,6978                                          const char **ReferenceName) {6979  struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;6980  // If no verbose symbolic information is wanted then just return nullptr.6981  if (!info->verbose) {6982    *ReferenceName = nullptr;6983    *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;6984    return nullptr;6985  }6986 6987  const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);6988 6989  if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {6990    *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);6991    if (*ReferenceName != nullptr) {6992      method_reference(info, ReferenceType, ReferenceName);6993      if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)6994        *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;6995    } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {6996      if (info->demangled_name != nullptr)6997        free(info->demangled_name);6998      info->demangled_name = itaniumDemangle(SymbolName + 1);6999      if (info->demangled_name != nullptr) {7000        *ReferenceName = info->demangled_name;7001        *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;7002      } else7003        *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7004    } else7005      *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7006  } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {7007    *ReferenceName =7008        GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7009    if (*ReferenceName)7010      method_reference(info, ReferenceType, ReferenceName);7011    else7012      *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7013    // If this is arm64 and the reference is an adrp instruction save the7014    // instruction, passed in ReferenceValue and the address of the instruction7015    // for use later if we see and add immediate instruction.7016  } else if (info->O->getArch() == Triple::aarch64 &&7017             *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {7018    info->adrp_inst = ReferenceValue;7019    info->adrp_addr = ReferencePC;7020    SymbolName = nullptr;7021    *ReferenceName = nullptr;7022    *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7023    // If this is arm64 and reference is an add immediate instruction and we7024    // have7025    // seen an adrp instruction just before it and the adrp's Xd register7026    // matches7027    // this add's Xn register reconstruct the value being referenced and look to7028    // see if it is a literal pointer.  Note the add immediate instruction is7029    // passed in ReferenceValue.7030  } else if (info->O->getArch() == Triple::aarch64 &&7031             *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&7032             ReferencePC - 4 == info->adrp_addr &&7033             (info->adrp_inst & 0x9f000000) == 0x90000000 &&7034             (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7035    uint32_t addxri_inst;7036    uint64_t adrp_imm, addxri_imm;7037 7038    adrp_imm =7039        ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7040    if (info->adrp_inst & 0x0200000)7041      adrp_imm |= 0xfffffffffc000000LL;7042 7043    addxri_inst = ReferenceValue;7044    addxri_imm = (addxri_inst >> 10) & 0xfff;7045    if (((addxri_inst >> 22) & 0x3) == 1)7046      addxri_imm <<= 12;7047 7048    ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7049                     (adrp_imm << 12) + addxri_imm;7050 7051    *ReferenceName =7052        GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7053    if (*ReferenceName == nullptr)7054      *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7055    // If this is arm64 and the reference is a load register instruction and we7056    // have seen an adrp instruction just before it and the adrp's Xd register7057    // matches this add's Xn register reconstruct the value being referenced and7058    // look to see if it is a literal pointer.  Note the load register7059    // instruction is passed in ReferenceValue.7060  } else if (info->O->getArch() == Triple::aarch64 &&7061             *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&7062             ReferencePC - 4 == info->adrp_addr &&7063             (info->adrp_inst & 0x9f000000) == 0x90000000 &&7064             (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7065    uint32_t ldrxui_inst;7066    uint64_t adrp_imm, ldrxui_imm;7067 7068    adrp_imm =7069        ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7070    if (info->adrp_inst & 0x0200000)7071      adrp_imm |= 0xfffffffffc000000LL;7072 7073    ldrxui_inst = ReferenceValue;7074    ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;7075 7076    ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7077                     (adrp_imm << 12) + (ldrxui_imm << 3);7078 7079    *ReferenceName =7080        GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7081    if (*ReferenceName == nullptr)7082      *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7083  }7084  // If this arm64 and is an load register (PC-relative) instruction the7085  // ReferenceValue is the PC plus the immediate value.7086  else if (info->O->getArch() == Triple::aarch64 &&7087           (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||7088            *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {7089    *ReferenceName =7090        GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7091    if (*ReferenceName == nullptr)7092      *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7093  } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {7094    if (info->demangled_name != nullptr)7095      free(info->demangled_name);7096    info->demangled_name = itaniumDemangle(SymbolName + 1);7097    if (info->demangled_name != nullptr) {7098      *ReferenceName = info->demangled_name;7099      *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;7100    }7101  }7102  else {7103    *ReferenceName = nullptr;7104    *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7105  }7106 7107  return SymbolName;7108}7109 7110/// Emits the comments that are stored in the CommentStream.7111/// Each comment in the CommentStream must end with a newline.7112static void emitComments(raw_svector_ostream &CommentStream,7113                         SmallString<128> &CommentsToEmit,7114                         formatted_raw_ostream &FormattedOS,7115                         const MCAsmInfo &MAI) {7116  // Flush the stream before taking its content.7117  StringRef Comments = CommentsToEmit.str();7118  // Get the default information for printing a comment.7119  StringRef CommentBegin = MAI.getCommentString();7120  unsigned CommentColumn = MAI.getCommentColumn();7121  ListSeparator LS("\n");7122  while (!Comments.empty()) {7123    FormattedOS << LS;7124    // Emit a line of comments.7125    FormattedOS.PadToColumn(CommentColumn);7126    size_t Position = Comments.find('\n');7127    FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);7128    // Move after the newline character.7129    Comments = Comments.substr(Position + 1);7130  }7131  FormattedOS.flush();7132 7133  // Tell the comment stream that the vector changed underneath it.7134  CommentsToEmit.clear();7135}7136 7137const MachOObjectFile *7138objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,7139                            std::unique_ptr<Binary> &DSYMBinary,7140                            std::unique_ptr<MemoryBuffer> &DSYMBuf) {7141  const MachOObjectFile *DbgObj = MachOOF;7142  std::string DSYMPath;7143 7144  // Auto-detect w/o --dsym.7145  if (DSYMFile.empty()) {7146    sys::fs::file_status DSYMStatus;7147    Twine FilenameDSYM = Filename + ".dSYM";7148    if (!status(FilenameDSYM, DSYMStatus)) {7149      if (sys::fs::is_directory(DSYMStatus)) {7150        SmallString<1024> Path;7151        FilenameDSYM.toVector(Path);7152        sys::path::append(Path, "Contents", "Resources", "DWARF",7153                          sys::path::filename(Filename));7154        DSYMPath = std::string(Path);7155      } else if (sys::fs::is_regular_file(DSYMStatus)) {7156        DSYMPath = FilenameDSYM.str();7157      }7158    }7159  }7160 7161  if (DSYMPath.empty() && !DSYMFile.empty()) {7162    // If DSYMPath is a .dSYM directory, append the Mach-O file.7163    if (sys::fs::is_directory(DSYMFile) &&7164        sys::path::extension(DSYMFile) == ".dSYM") {7165      SmallString<128> ShortName(sys::path::filename(DSYMFile));7166      sys::path::replace_extension(ShortName, "");7167      SmallString<1024> FullPath(DSYMFile);7168      sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);7169      DSYMPath = FullPath.str();7170    } else {7171      DSYMPath = DSYMFile;7172    }7173  }7174 7175  if (!DSYMPath.empty()) {7176    // Load the file.7177    ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =7178        MemoryBuffer::getFileOrSTDIN(DSYMPath);7179    if (std::error_code EC = BufOrErr.getError()) {7180      reportError(errorCodeToError(EC), DSYMPath);7181      return nullptr;7182    }7183 7184    // We need to keep the file alive, because we're replacing DbgObj with it.7185    DSYMBuf = std::move(BufOrErr.get());7186 7187    Expected<std::unique_ptr<Binary>> BinaryOrErr =7188        createBinary(DSYMBuf->getMemBufferRef());7189    if (!BinaryOrErr) {7190      reportError(BinaryOrErr.takeError(), DSYMPath);7191      return nullptr;7192    }7193 7194    // We need to keep the Binary alive with the buffer7195    DSYMBinary = std::move(BinaryOrErr.get());7196    if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {7197      // this is a Mach-O object file, use it7198      if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {7199        DbgObj = MachDSYM;7200      } else {7201        WithColor::error(errs(), "llvm-objdump")7202            << DSYMPath << " is not a Mach-O file type.\n";7203        return nullptr;7204      }7205    } else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {7206      // this is a Universal Binary, find a Mach-O for this architecture7207      uint32_t CPUType, CPUSubType;7208      const char *ArchFlag;7209      if (MachOOF->is64Bit()) {7210        const MachO::mach_header_64 H_64 = MachOOF->getHeader64();7211        CPUType = H_64.cputype;7212        CPUSubType = H_64.cpusubtype;7213      } else {7214        const MachO::mach_header H = MachOOF->getHeader();7215        CPUType = H.cputype;7216        CPUSubType = H.cpusubtype;7217      }7218      Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,7219                                                &ArchFlag);7220      Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =7221          UB->getMachOObjectForArch(ArchFlag);7222      if (!MachDSYM) {7223        reportError(MachDSYM.takeError(), DSYMPath);7224        return nullptr;7225      }7226 7227      // We need to keep the Binary alive with the buffer7228      DbgObj = &*MachDSYM.get();7229      DSYMBinary = std::move(*MachDSYM);7230    } else {7231      WithColor::error(errs(), "llvm-objdump")7232          << DSYMPath << " is not a Mach-O or Universal file type.\n";7233      return nullptr;7234    }7235  }7236  return DbgObj;7237}7238 7239static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,7240                             StringRef DisSegName, StringRef DisSectName) {7241  const char *McpuDefault = nullptr;7242  const Target *ThumbTarget = nullptr;7243  Triple ThumbTriple;7244  const Target *TheTarget =7245      GetTarget(MachOOF, &McpuDefault, &ThumbTarget, ThumbTriple);7246  if (!TheTarget) {7247    // GetTarget prints out stuff.7248    return;7249  }7250  std::string MachOMCPU;7251  if (MCPU.empty() && McpuDefault)7252    MachOMCPU = McpuDefault;7253  else7254    MachOMCPU = MCPU;7255 7256#define CHECK_TARGET_INFO_CREATION(NAME)                                       \7257  do {                                                                         \7258    if (!NAME) {                                                               \7259      WithColor::error(errs(), "llvm-objdump")                                 \7260          << "couldn't initialize disassembler for target " << TripleName      \7261          << '\n';                                                             \7262      return;                                                                  \7263    }                                                                          \7264  } while (false)7265#define CHECK_THUMB_TARGET_INFO_CREATION(NAME)                                 \7266  do {                                                                         \7267    if (!NAME) {                                                               \7268      WithColor::error(errs(), "llvm-objdump")                                 \7269          << "couldn't initialize disassembler for target " << ThumbTripleName \7270          << '\n';                                                             \7271      return;                                                                  \7272    }                                                                          \7273  } while (false)7274 7275  std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());7276  CHECK_TARGET_INFO_CREATION(InstrInfo);7277  std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;7278  if (ThumbTarget) {7279    ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());7280    CHECK_THUMB_TARGET_INFO_CREATION(ThumbInstrInfo);7281  }7282 7283  // Package up features to be passed to target/subtarget7284  std::string FeaturesStr;7285  if (!MAttrs.empty()) {7286    SubtargetFeatures Features;7287    for (unsigned i = 0; i != MAttrs.size(); ++i)7288      Features.AddFeature(MAttrs[i]);7289    FeaturesStr = Features.getString();7290  }7291 7292  Triple TheTriple(TripleName);7293 7294  MCTargetOptions MCOptions;7295  // Set up disassembler.7296  std::unique_ptr<const MCRegisterInfo> MRI(7297      TheTarget->createMCRegInfo(TheTriple));7298  CHECK_TARGET_INFO_CREATION(MRI);7299  std::unique_ptr<const MCAsmInfo> AsmInfo(7300      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));7301  CHECK_TARGET_INFO_CREATION(AsmInfo);7302  std::unique_ptr<const MCSubtargetInfo> STI(7303      TheTarget->createMCSubtargetInfo(TheTriple, MachOMCPU, FeaturesStr));7304  CHECK_TARGET_INFO_CREATION(STI);7305  MCContext Ctx(TheTriple, AsmInfo.get(), MRI.get(), STI.get());7306  std::unique_ptr<MCDisassembler> DisAsm(7307      TheTarget->createMCDisassembler(*STI, Ctx));7308  CHECK_TARGET_INFO_CREATION(DisAsm);7309  std::unique_ptr<MCSymbolizer> Symbolizer;7310  struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);7311  std::unique_ptr<MCRelocationInfo> RelInfo(7312      TheTarget->createMCRelocationInfo(TheTriple, Ctx));7313  if (RelInfo) {7314    Symbolizer.reset(TheTarget->createMCSymbolizer(7315        TheTriple, SymbolizerGetOpInfo, SymbolizerSymbolLookUp, &SymbolizerInfo,7316        &Ctx, std::move(RelInfo)));7317    DisAsm->setSymbolizer(std::move(Symbolizer));7318  }7319  int AsmPrinterVariant = AsmInfo->getAssemblerDialect();7320  std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(7321      TheTriple, AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));7322  CHECK_TARGET_INFO_CREATION(IP);7323  // Set the display preference for hex vs. decimal immediates.7324  IP->setPrintImmHex(PrintImmHex);7325  // Comment stream and backing vector.7326  SmallString<128> CommentsToEmit;7327  raw_svector_ostream CommentStream(CommentsToEmit);7328  // FIXME: Setting the CommentStream in the InstPrinter is problematic in that7329  // if it is done then arm64 comments for string literals don't get printed7330  // and some constant get printed instead and not setting it causes intel7331  // (32-bit and 64-bit) comments printed with different spacing before the7332  // comment causing different diffs with the 'C' disassembler library API.7333  // IP->setCommentStream(CommentStream);7334 7335  for (StringRef Opt : DisassemblerOptions)7336    if (!IP->applyTargetSpecificCLOption(Opt))7337      reportError(Filename, "unrecognized disassembler option: " + Opt);7338 7339  // Set up separate thumb disassembler if needed.7340  std::unique_ptr<const MCRegisterInfo> ThumbMRI;7341  std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;7342  std::unique_ptr<const MCSubtargetInfo> ThumbSTI;7343  std::unique_ptr<MCDisassembler> ThumbDisAsm;7344  std::unique_ptr<MCInstPrinter> ThumbIP;7345  std::unique_ptr<MCContext> ThumbCtx;7346  std::unique_ptr<MCSymbolizer> ThumbSymbolizer;7347  struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);7348  std::unique_ptr<MCRelocationInfo> ThumbRelInfo;7349  if (ThumbTarget) {7350    ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTriple));7351    CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);7352    ThumbAsmInfo.reset(7353        ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTriple, MCOptions));7354    CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);7355    ThumbSTI.reset(ThumbTarget->createMCSubtargetInfo(ThumbTriple, MachOMCPU,7356                                                      FeaturesStr));7357    CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);7358    ThumbCtx.reset(new MCContext(ThumbTriple, ThumbAsmInfo.get(),7359                                 ThumbMRI.get(), ThumbSTI.get()));7360    ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));7361    CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);7362    MCContext *PtrThumbCtx = ThumbCtx.get();7363    ThumbRelInfo.reset(7364        ThumbTarget->createMCRelocationInfo(ThumbTriple, *PtrThumbCtx));7365    if (ThumbRelInfo) {7366      ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(7367          ThumbTriple, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,7368          &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));7369      ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));7370    }7371    int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();7372    ThumbIP.reset(ThumbTarget->createMCInstPrinter(7373        ThumbTriple, ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo,7374        *ThumbMRI));7375    CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);7376    // Set the display preference for hex vs. decimal immediates.7377    ThumbIP->setPrintImmHex(PrintImmHex);7378  }7379 7380#undef CHECK_TARGET_INFO_CREATION7381#undef CHECK_THUMB_TARGET_INFO_CREATION7382 7383  MachO::mach_header Header = MachOOF->getHeader();7384 7385  // FIXME: Using the -cfg command line option, this code used to be able to7386  // annotate relocations with the referenced symbol's name, and if this was7387  // inside a __[cf]string section, the data it points to. This is now replaced7388  // by the upcoming MCSymbolizer, which needs the appropriate setup done above.7389  std::vector<SectionRef> Sections;7390  std::vector<SymbolRef> Symbols;7391  SmallVector<uint64_t, 8> FoundFns;7392  uint64_t BaseSegmentAddress = 0;7393 7394  getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,7395                        BaseSegmentAddress);7396 7397  // Sort the symbols by address, just in case they didn't come in that way.7398  llvm::stable_sort(Symbols, SymbolSorter());7399 7400  // Build a data in code table that is sorted on by the address of each entry.7401  uint64_t BaseAddress = 0;7402  if (Header.filetype == MachO::MH_OBJECT)7403    BaseAddress = Sections[0].getAddress();7404  else7405    BaseAddress = BaseSegmentAddress;7406  DiceTable Dices;7407  for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();7408       DI != DE; ++DI) {7409    uint32_t Offset;7410    DI->getOffset(Offset);7411    Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));7412  }7413  array_pod_sort(Dices.begin(), Dices.end());7414 7415  // Try to find debug info and set up the DIContext for it.7416  std::unique_ptr<DIContext> diContext;7417  std::unique_ptr<Binary> DSYMBinary;7418  std::unique_ptr<MemoryBuffer> DSYMBuf;7419  const ObjectFile *DbgObj = MachOOF;7420  if (UseDbg || PrintSource || PrintLines) {7421    // Look for debug info in external dSYM file or embedded in the object.7422    // getMachODSymObject returns MachOOF by default if no external dSYM found.7423    const ObjectFile *DSym =7424        getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf);7425    if (!DSym)7426      return;7427    DbgObj = DSym;7428    if (UseDbg || PrintLines) {7429      // Setup the DIContext7430      diContext = DWARFContext::create(*DbgObj);7431    }7432  }7433 7434  std::optional<SourcePrinter> SP;7435  std::optional<LiveElementPrinter> LEP;7436  if (PrintSource || PrintLines) {7437    SP.emplace(DbgObj, TheTarget->getName());7438    LEP.emplace(*MRI, *STI);7439  }7440 7441  if (FilterSections.empty())7442    outs() << "(" << DisSegName << "," << DisSectName << ") section\n";7443 7444  for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {7445    Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();7446    if (!SecNameOrErr) {7447      consumeError(SecNameOrErr.takeError());7448      continue;7449    }7450    if (*SecNameOrErr != DisSectName)7451      continue;7452 7453    DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();7454 7455    StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);7456    if (SegmentName != DisSegName)7457      continue;7458 7459    StringRef BytesStr =7460        unwrapOrError(Sections[SectIdx].getContents(), Filename);7461    ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);7462    uint64_t SectAddress = Sections[SectIdx].getAddress();7463 7464    bool symbolTableWorked = false;7465 7466    // Create a map of symbol addresses to symbol names for use by7467    // the SymbolizerSymbolLookUp() routine.7468    SymbolAddressMap AddrMap;7469    bool DisSymNameFound = false;7470    for (const SymbolRef &Symbol : MachOOF->symbols()) {7471      SymbolRef::Type ST =7472          unwrapOrError(Symbol.getType(), MachOOF->getFileName());7473      if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||7474          ST == SymbolRef::ST_Other) {7475        uint64_t Address = cantFail(Symbol.getValue());7476        StringRef SymName =7477            unwrapOrError(Symbol.getName(), MachOOF->getFileName());7478        AddrMap[Address] = SymName;7479        if (!DisSymName.empty() && DisSymName == SymName)7480          DisSymNameFound = true;7481      }7482    }7483    if (!DisSymName.empty() && !DisSymNameFound) {7484      outs() << "Can't find -dis-symname: " << DisSymName << "\n";7485      return;7486    }7487    // Set up the block of info used by the Symbolizer call backs.7488    SymbolizerInfo.verbose = SymbolicOperands;7489    SymbolizerInfo.O = MachOOF;7490    SymbolizerInfo.S = Sections[SectIdx];7491    SymbolizerInfo.AddrMap = &AddrMap;7492    SymbolizerInfo.Sections = &Sections;7493    // Same for the ThumbSymbolizer7494    ThumbSymbolizerInfo.verbose = SymbolicOperands;7495    ThumbSymbolizerInfo.O = MachOOF;7496    ThumbSymbolizerInfo.S = Sections[SectIdx];7497    ThumbSymbolizerInfo.AddrMap = &AddrMap;7498    ThumbSymbolizerInfo.Sections = &Sections;7499 7500    unsigned int Arch = MachOOF->getArch();7501 7502    // Skip all symbols if this is a stubs file.7503    if (Bytes.empty())7504      return;7505 7506    // If the section has symbols but no symbol at the start of the section7507    // these are used to make sure the bytes before the first symbol are7508    // disassembled.7509    bool FirstSymbol = true;7510    bool FirstSymbolAtSectionStart = true;7511 7512    // Disassemble symbol by symbol.7513    for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {7514      StringRef SymName =7515          unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());7516      SymbolRef::Type ST =7517          unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());7518      if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)7519        continue;7520 7521      // Make sure the symbol is defined in this section.7522      bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);7523      if (!containsSym) {7524        if (!DisSymName.empty() && DisSymName == SymName) {7525          outs() << "-dis-symname: " << DisSymName << " not in the section\n";7526          return;7527        }7528        continue;7529      }7530      // The __mh_execute_header is special and we need to deal with that fact7531      // this symbol is before the start of the (__TEXT,__text) section and at the7532      // address of the start of the __TEXT segment.  This is because this symbol7533      // is an N_SECT symbol in the (__TEXT,__text) but its address is before the7534      // start of the section in a standard MH_EXECUTE filetype.7535      if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {7536        outs() << "-dis-symname: __mh_execute_header not in any section\n";7537        return;7538      }7539      // When this code is trying to disassemble a symbol at a time and in the7540      // case there is only the __mh_execute_header symbol left as in a stripped7541      // executable, we need to deal with this by ignoring this symbol so the7542      // whole section is disassembled and this symbol is then not displayed.7543      if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||7544          SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||7545          SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")7546        continue;7547 7548      // If we are only disassembling one symbol see if this is that symbol.7549      if (!DisSymName.empty() && DisSymName != SymName)7550        continue;7551 7552      // Start at the address of the symbol relative to the section's address.7553      uint64_t SectSize = Sections[SectIdx].getSize();7554      uint64_t Start = cantFail(Symbols[SymIdx].getValue());7555      uint64_t SectionAddress = Sections[SectIdx].getAddress();7556      Start -= SectionAddress;7557 7558      if (Start > SectSize) {7559        outs() << "section data ends, " << SymName7560               << " lies outside valid range\n";7561        return;7562      }7563 7564      // Stop disassembling either at the beginning of the next symbol or at7565      // the end of the section.7566      bool containsNextSym = false;7567      uint64_t NextSym = 0;7568      uint64_t NextSymIdx = SymIdx + 1;7569      while (Symbols.size() > NextSymIdx) {7570        SymbolRef::Type NextSymType = unwrapOrError(7571            Symbols[NextSymIdx].getType(), MachOOF->getFileName());7572        if (NextSymType == SymbolRef::ST_Function) {7573          containsNextSym =7574              Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);7575          NextSym = cantFail(Symbols[NextSymIdx].getValue());7576          NextSym -= SectionAddress;7577          break;7578        }7579        ++NextSymIdx;7580      }7581 7582      uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;7583      uint64_t Size;7584 7585      symbolTableWorked = true;7586 7587      DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();7588      uint32_t SymbolFlags = cantFail(MachOOF->getSymbolFlags(Symb));7589      bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;7590 7591      // We only need the dedicated Thumb target if there's a real choice7592      // (i.e. we're not targeting M-class) and the function is Thumb.7593      bool UseThumbTarget = IsThumb && ThumbTarget;7594 7595      // If we are not specifying a symbol to start disassembly with and this7596      // is the first symbol in the section but not at the start of the section7597      // then move the disassembly index to the start of the section and7598      // don't print the symbol name just yet.  This is so the bytes before the7599      // first symbol are disassembled.7600      uint64_t SymbolStart = Start;7601      if (DisSymName.empty() && FirstSymbol && Start != 0) {7602        FirstSymbolAtSectionStart = false;7603        Start = 0;7604      }7605      else7606        outs() << SymName << ":\n";7607 7608      DILineInfo lastLine;7609      for (uint64_t Index = Start; Index < End; Index += Size) {7610        MCInst Inst;7611 7612        // If this is the first symbol in the section and it was not at the7613        // start of the section, see if we are at its Index now and if so print7614        // the symbol name.7615        if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)7616          outs() << SymName << ":\n";7617 7618        uint64_t PC = SectAddress + Index;7619 7620        if (PrintSource || PrintLines) {7621          formatted_raw_ostream FOS(outs());7622          SP->printSourceLine(FOS, {PC, SectIdx}, Filename, *LEP);7623        }7624 7625        if (LeadingAddr) {7626          if (FullLeadingAddr) {7627            if (MachOOF->is64Bit())7628              outs() << format("%016" PRIx64, PC);7629            else7630              outs() << format("%08" PRIx64, PC);7631          } else {7632            outs() << format("%8" PRIx64 ":", PC);7633          }7634        }7635        if (ShowRawInsn || Arch == Triple::arm)7636          outs() << "\t";7637 7638        if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))7639          continue;7640 7641        SmallVector<char, 64> AnnotationsBytes;7642        raw_svector_ostream Annotations(AnnotationsBytes);7643 7644        bool gotInst;7645        if (UseThumbTarget)7646          gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),7647                                                PC, Annotations);7648        else7649          gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,7650                                           Annotations);7651        if (gotInst) {7652          if (ShowRawInsn || Arch == Triple::arm) {7653            dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());7654          }7655          formatted_raw_ostream FormattedOS(outs());7656          StringRef AnnotationsStr = Annotations.str();7657          if (UseThumbTarget)7658            ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI,7659                               FormattedOS);7660          else7661            IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);7662          emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);7663 7664          // Print debug info.7665          if (diContext) {7666            DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx})7667                                 .value_or(DILineInfo());7668            // Print valid line info if it changed.7669            if (dli != lastLine && dli.Line != 0)7670              outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'7671                     << dli.Column;7672            lastLine = dli;7673          }7674          outs() << "\n";7675        } else {7676          if (MachOOF->getArchTriple().isX86()) {7677            outs() << format("\t.byte 0x%02x #bad opcode\n",7678                             *(Bytes.data() + Index) & 0xff);7679            Size = 1; // skip exactly one illegible byte and move on.7680          } else if (Arch == Triple::aarch64 ||7681                     (Arch == Triple::arm && !IsThumb)) {7682            uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7683                              (*(Bytes.data() + Index + 1) & 0xff) << 8 |7684                              (*(Bytes.data() + Index + 2) & 0xff) << 16 |7685                              (*(Bytes.data() + Index + 3) & 0xff) << 24;7686            outs() << format("\t.long\t0x%08x\n", opcode);7687            Size = 4;7688          } else if (Arch == Triple::arm) {7689            assert(IsThumb && "ARM mode should have been dealt with above");7690            uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7691                              (*(Bytes.data() + Index + 1) & 0xff) << 8;7692            outs() << format("\t.short\t0x%04x\n", opcode);7693            Size = 2;7694          } else{7695            WithColor::warning(errs(), "llvm-objdump")7696                << "invalid instruction encoding\n";7697            if (Size == 0)7698              Size = 1; // skip illegible bytes7699          }7700        }7701      }7702      // Now that we are done disassembled the first symbol set the bool that7703      // were doing this to false.7704      FirstSymbol = false;7705    }7706    if (!symbolTableWorked) {7707      // Reading the symbol table didn't work, disassemble the whole section.7708      uint64_t SectAddress = Sections[SectIdx].getAddress();7709      uint64_t SectSize = Sections[SectIdx].getSize();7710      uint64_t InstSize;7711      for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {7712        MCInst Inst;7713 7714        uint64_t PC = SectAddress + Index;7715 7716        if (PrintSource || PrintLines) {7717          formatted_raw_ostream FOS(outs());7718          SP->printSourceLine(FOS, {PC, SectIdx}, Filename, *LEP);7719        }7720 7721        if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize))7722          continue;7723 7724        SmallVector<char, 64> AnnotationsBytes;7725        raw_svector_ostream Annotations(AnnotationsBytes);7726        if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,7727                                   Annotations)) {7728          if (LeadingAddr) {7729            if (FullLeadingAddr) {7730              if (MachOOF->is64Bit())7731                outs() << format("%016" PRIx64, PC);7732              else7733                outs() << format("%08" PRIx64, PC);7734            } else {7735              outs() << format("%8" PRIx64 ":", PC);7736            }7737          }7738          if (ShowRawInsn || Arch == Triple::arm) {7739            outs() << "\t";7740            dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());7741          }7742          StringRef AnnotationsStr = Annotations.str();7743          IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());7744          outs() << "\n";7745        } else {7746          if (MachOOF->getArchTriple().isX86()) {7747            outs() << format("\t.byte 0x%02x #bad opcode\n",7748                             *(Bytes.data() + Index) & 0xff);7749            InstSize = 1; // skip exactly one illegible byte and move on.7750          } else {7751            WithColor::warning(errs(), "llvm-objdump")7752                << "invalid instruction encoding\n";7753            if (InstSize == 0)7754              InstSize = 1; // skip illegible bytes7755          }7756        }7757      }7758    }7759    // The TripleName's need to be reset if we are called again for a different7760    // architecture.7761    TripleName = "";7762    ThumbTripleName = "";7763 7764    if (SymbolizerInfo.demangled_name != nullptr)7765      free(SymbolizerInfo.demangled_name);7766    if (ThumbSymbolizerInfo.demangled_name != nullptr)7767      free(ThumbSymbolizerInfo.demangled_name);7768  }7769}7770 7771//===----------------------------------------------------------------------===//7772// __compact_unwind section dumping7773//===----------------------------------------------------------------------===//7774 7775namespace {7776 7777template <typename T>7778static uint64_t read(StringRef Contents, ptrdiff_t Offset) {7779  if (Offset + sizeof(T) > Contents.size()) {7780    outs() << "warning: attempt to read past end of buffer\n";7781    return T();7782  }7783 7784  uint64_t Val = support::endian::read<T, llvm::endianness::little>(7785      Contents.data() + Offset);7786  return Val;7787}7788 7789template <typename T>7790static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {7791  T Val = read<T>(Contents, Offset);7792  Offset += sizeof(T);7793  return Val;7794}7795 7796struct CompactUnwindEntry {7797  uint32_t OffsetInSection;7798 7799  uint64_t FunctionAddr;7800  uint32_t Length;7801  uint32_t CompactEncoding;7802  uint64_t PersonalityAddr;7803  uint64_t LSDAAddr;7804 7805  RelocationRef FunctionReloc;7806  RelocationRef PersonalityReloc;7807  RelocationRef LSDAReloc;7808 7809  CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)7810      : OffsetInSection(Offset) {7811    if (Is64)7812      read<uint64_t>(Contents, Offset);7813    else7814      read<uint32_t>(Contents, Offset);7815  }7816 7817private:7818  template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {7819    FunctionAddr = readNext<UIntPtr>(Contents, Offset);7820    Length = readNext<uint32_t>(Contents, Offset);7821    CompactEncoding = readNext<uint32_t>(Contents, Offset);7822    PersonalityAddr = readNext<UIntPtr>(Contents, Offset);7823    LSDAAddr = readNext<UIntPtr>(Contents, Offset);7824  }7825};7826}7827 7828/// Given a relocation from __compact_unwind, consisting of the RelocationRef7829/// and data being relocated, determine the best base Name and Addend to use for7830/// display purposes.7831///7832/// 1. An Extern relocation will directly reference a symbol (and the data is7833///    then already an addend), so use that.7834/// 2. Otherwise the data is an offset in the object file's layout; try to find7835//     a symbol before it in the same section, and use the offset from there.7836/// 3. Finally, if all that fails, fall back to an offset from the start of the7837///    referenced section.7838static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,7839                                      std::map<uint64_t, SymbolRef> &Symbols,7840                                      const RelocationRef &Reloc, uint64_t Addr,7841                                      StringRef &Name, uint64_t &Addend) {7842  if (Reloc.getSymbol() != Obj->symbol_end()) {7843    Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());7844    Addend = Addr;7845    return;7846  }7847 7848  auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());7849  SectionRef RelocSection = Obj->getAnyRelocationSection(RE);7850 7851  uint64_t SectionAddr = RelocSection.getAddress();7852 7853  auto Sym = Symbols.upper_bound(Addr);7854  if (Sym == Symbols.begin()) {7855    // The first symbol in the object is after this reference, the best we can7856    // do is section-relative notation.7857    if (Expected<StringRef> NameOrErr = RelocSection.getName())7858      Name = *NameOrErr;7859    else7860      consumeError(NameOrErr.takeError());7861 7862    Addend = Addr - SectionAddr;7863    return;7864  }7865 7866  // Go back one so that SymbolAddress <= Addr.7867  --Sym;7868 7869  section_iterator SymSection =7870      unwrapOrError(Sym->second.getSection(), Obj->getFileName());7871  if (RelocSection == *SymSection) {7872    // There's a valid symbol in the same section before this reference.7873    Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());7874    Addend = Addr - Sym->first;7875    return;7876  }7877 7878  // There is a symbol before this reference, but it's in a different7879  // section. Probably not helpful to mention it, so use the section name.7880  if (Expected<StringRef> NameOrErr = RelocSection.getName())7881    Name = *NameOrErr;7882  else7883    consumeError(NameOrErr.takeError());7884 7885  Addend = Addr - SectionAddr;7886}7887 7888static void printUnwindRelocDest(const MachOObjectFile *Obj,7889                                 std::map<uint64_t, SymbolRef> &Symbols,7890                                 const RelocationRef &Reloc, uint64_t Addr) {7891  StringRef Name;7892  uint64_t Addend;7893 7894  if (!Reloc.getObject())7895    return;7896 7897  findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);7898 7899  outs() << Name;7900  if (Addend)7901    outs() << " + " << format("0x%" PRIx64, Addend);7902}7903 7904static void7905printMachOCompactUnwindSection(const MachOObjectFile *Obj,7906                               std::map<uint64_t, SymbolRef> &Symbols,7907                               const SectionRef &CompactUnwind) {7908 7909  if (!Obj->isLittleEndian()) {7910    outs() << "Skipping big-endian __compact_unwind section\n";7911    return;7912  }7913 7914  bool Is64 = Obj->is64Bit();7915  uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);7916  uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);7917 7918  StringRef Contents =7919      unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());7920  SmallVector<CompactUnwindEntry, 4> CompactUnwinds;7921 7922  // First populate the initial raw offsets, encodings and so on from the entry.7923  for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {7924    CompactUnwindEntry Entry(Contents, Offset, Is64);7925    CompactUnwinds.push_back(Entry);7926  }7927 7928  // Next we need to look at the relocations to find out what objects are7929  // actually being referred to.7930  for (const RelocationRef &Reloc : CompactUnwind.relocations()) {7931    uint64_t RelocAddress = Reloc.getOffset();7932 7933    uint32_t EntryIdx = RelocAddress / EntrySize;7934    uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;7935    CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];7936 7937    if (OffsetInEntry == 0)7938      Entry.FunctionReloc = Reloc;7939    else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))7940      Entry.PersonalityReloc = Reloc;7941    else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))7942      Entry.LSDAReloc = Reloc;7943    else {7944      outs() << "Invalid relocation in __compact_unwind section\n";7945      return;7946    }7947  }7948 7949  // Finally, we're ready to print the data we've gathered.7950  outs() << "Contents of __compact_unwind section:\n";7951  for (auto &Entry : CompactUnwinds) {7952    outs() << "  Entry at offset "7953           << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";7954 7955    // 1. Start of the region this entry applies to.7956    outs() << "    start:                " << format("0x%" PRIx64,7957                                                     Entry.FunctionAddr) << ' ';7958    printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);7959    outs() << '\n';7960 7961    // 2. Length of the region this entry applies to.7962    outs() << "    length:               " << format("0x%" PRIx32, Entry.Length)7963           << '\n';7964    // 3. The 32-bit compact encoding.7965    outs() << "    compact encoding:     "7966           << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';7967 7968    // 4. The personality function, if present.7969    if (Entry.PersonalityReloc.getObject()) {7970      outs() << "    personality function: "7971             << format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';7972      printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,7973                           Entry.PersonalityAddr);7974      outs() << '\n';7975    }7976 7977    // 5. This entry's language-specific data area.7978    if (Entry.LSDAReloc.getObject()) {7979      outs() << "    LSDA:                 " << format("0x%" PRIx64,7980                                                       Entry.LSDAAddr) << ' ';7981      printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);7982      outs() << '\n';7983    }7984  }7985}7986 7987//===----------------------------------------------------------------------===//7988// __unwind_info section dumping7989//===----------------------------------------------------------------------===//7990 7991static void printRegularSecondLevelUnwindPage(StringRef PageData) {7992  ptrdiff_t Pos = 0;7993  uint32_t Kind = readNext<uint32_t>(PageData, Pos);7994  (void)Kind;7995  assert(Kind == 2 && "kind for a regular 2nd level index should be 2");7996 7997  uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);7998  uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);7999 8000  Pos = EntriesStart;8001  for (unsigned i = 0; i < NumEntries; ++i) {8002    uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);8003    uint32_t Encoding = readNext<uint32_t>(PageData, Pos);8004 8005    outs() << "      [" << i << "]: "8006           << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8007           << ", "8008           << "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';8009  }8010}8011 8012static void printCompressedSecondLevelUnwindPage(8013    StringRef PageData, uint32_t FunctionBase,8014    const SmallVectorImpl<uint32_t> &CommonEncodings) {8015  ptrdiff_t Pos = 0;8016  uint32_t Kind = readNext<uint32_t>(PageData, Pos);8017  (void)Kind;8018  assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");8019 8020  uint32_t NumCommonEncodings = CommonEncodings.size();8021  uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);8022  uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);8023 8024  uint16_t PageEncodingsStart = readNext<uint16_t>(PageData, Pos);8025  uint16_t NumPageEncodings = readNext<uint16_t>(PageData, Pos);8026  SmallVector<uint32_t, 64> PageEncodings;8027  if (NumPageEncodings) {8028    outs() << "      Page encodings: (count = " << NumPageEncodings << ")\n";8029    Pos = PageEncodingsStart;8030    for (unsigned i = 0; i < NumPageEncodings; ++i) {8031      uint32_t Encoding = readNext<uint32_t>(PageData, Pos);8032      PageEncodings.push_back(Encoding);8033      outs() << "        encoding[" << (i + NumCommonEncodings)8034             << "]: " << format("0x%08" PRIx32, Encoding) << '\n';8035    }8036  }8037 8038  Pos = EntriesStart;8039  for (unsigned i = 0; i < NumEntries; ++i) {8040    uint32_t Entry = readNext<uint32_t>(PageData, Pos);8041    uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);8042    uint32_t EncodingIdx = Entry >> 24;8043 8044    uint32_t Encoding;8045    if (EncodingIdx < NumCommonEncodings)8046      Encoding = CommonEncodings[EncodingIdx];8047    else8048      Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];8049 8050    outs() << "      [" << i << "]: "8051           << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8052           << ", "8053           << "encoding[" << EncodingIdx8054           << "]=" << format("0x%08" PRIx32, Encoding) << '\n';8055  }8056}8057 8058static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,8059                                        std::map<uint64_t, SymbolRef> &Symbols,8060                                        const SectionRef &UnwindInfo) {8061 8062  if (!Obj->isLittleEndian()) {8063    outs() << "Skipping big-endian __unwind_info section\n";8064    return;8065  }8066 8067  outs() << "Contents of __unwind_info section:\n";8068 8069  StringRef Contents =8070      unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());8071  ptrdiff_t Pos = 0;8072 8073  //===----------------------------------8074  // Section header8075  //===----------------------------------8076 8077  uint32_t Version = readNext<uint32_t>(Contents, Pos);8078  outs() << "  Version:                                   "8079         << format("0x%" PRIx32, Version) << '\n';8080  if (Version != 1) {8081    outs() << "    Skipping section with unknown version\n";8082    return;8083  }8084 8085  uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);8086  outs() << "  Common encodings array section offset:     "8087         << format("0x%" PRIx32, CommonEncodingsStart) << '\n';8088  uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);8089  outs() << "  Number of common encodings in array:       "8090         << format("0x%" PRIx32, NumCommonEncodings) << '\n';8091 8092  uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);8093  outs() << "  Personality function array section offset: "8094         << format("0x%" PRIx32, PersonalitiesStart) << '\n';8095  uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);8096  outs() << "  Number of personality functions in array:  "8097         << format("0x%" PRIx32, NumPersonalities) << '\n';8098 8099  uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);8100  outs() << "  Index array section offset:                "8101         << format("0x%" PRIx32, IndicesStart) << '\n';8102  uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);8103  outs() << "  Number of indices in array:                "8104         << format("0x%" PRIx32, NumIndices) << '\n';8105 8106  //===----------------------------------8107  // A shared list of common encodings8108  //===----------------------------------8109 8110  // These occupy indices in the range [0, N] whenever an encoding is referenced8111  // from a compressed 2nd level index table. In practice the linker only8112  // creates ~128 of these, so that indices are available to embed encodings in8113  // the 2nd level index.8114 8115  SmallVector<uint32_t, 64> CommonEncodings;8116  outs() << "  Common encodings: (count = " << NumCommonEncodings << ")\n";8117  Pos = CommonEncodingsStart;8118  for (unsigned i = 0; i < NumCommonEncodings; ++i) {8119    uint32_t Encoding = readNext<uint32_t>(Contents, Pos);8120    CommonEncodings.push_back(Encoding);8121 8122    outs() << "    encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)8123           << '\n';8124  }8125 8126  //===----------------------------------8127  // Personality functions used in this executable8128  //===----------------------------------8129 8130  // There should be only a handful of these (one per source language,8131  // roughly). Particularly since they only get 2 bits in the compact encoding.8132 8133  outs() << "  Personality functions: (count = " << NumPersonalities << ")\n";8134  Pos = PersonalitiesStart;8135  for (unsigned i = 0; i < NumPersonalities; ++i) {8136    uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);8137    outs() << "    personality[" << i + 18138           << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';8139  }8140 8141  //===----------------------------------8142  // The level 1 index entries8143  //===----------------------------------8144 8145  // These specify an approximate place to start searching for the more detailed8146  // information, sorted by PC.8147 8148  struct IndexEntry {8149    uint32_t FunctionOffset;8150    uint32_t SecondLevelPageStart;8151    uint32_t LSDAStart;8152  };8153 8154  SmallVector<IndexEntry, 4> IndexEntries;8155 8156  outs() << "  Top level indices: (count = " << NumIndices << ")\n";8157  Pos = IndicesStart;8158  for (unsigned i = 0; i < NumIndices; ++i) {8159    IndexEntry Entry;8160 8161    Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);8162    Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);8163    Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);8164    IndexEntries.push_back(Entry);8165 8166    outs() << "    [" << i << "]: "8167           << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)8168           << ", "8169           << "2nd level page offset="8170           << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "8171           << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';8172  }8173 8174  //===----------------------------------8175  // Next come the LSDA tables8176  //===----------------------------------8177 8178  // The LSDA layout is rather implicit: it's a contiguous array of entries from8179  // the first top-level index's LSDAOffset to the last (sentinel).8180 8181  outs() << "  LSDA descriptors:\n";8182  Pos = IndexEntries[0].LSDAStart;8183  const uint32_t LSDASize = 2 * sizeof(uint32_t);8184  int NumLSDAs =8185      (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;8186 8187  for (int i = 0; i < NumLSDAs; ++i) {8188    uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);8189    uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);8190    outs() << "    [" << i << "]: "8191           << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8192           << ", "8193           << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';8194  }8195 8196  //===----------------------------------8197  // Finally, the 2nd level indices8198  //===----------------------------------8199 8200  // Generally these are 4K in size, and have 2 possible forms:8201  //   + Regular stores up to 511 entries with disparate encodings8202  //   + Compressed stores up to 1021 entries if few enough compact encoding8203  //     values are used.8204  outs() << "  Second level indices:\n";8205  for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {8206    // The final sentinel top-level index has no associated 2nd level page8207    if (IndexEntries[i].SecondLevelPageStart == 0)8208      break;8209 8210    outs() << "    Second level index[" << i << "]: "8211           << "offset in section="8212           << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)8213           << ", "8214           << "base function offset="8215           << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';8216 8217    Pos = IndexEntries[i].SecondLevelPageStart;8218    if (Pos + sizeof(uint32_t) > Contents.size()) {8219      outs() << "warning: invalid offset for second level page: " << Pos << '\n';8220      continue;8221    }8222 8223    uint32_t Kind =8224        *reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);8225    if (Kind == 2)8226      printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));8227    else if (Kind == 3)8228      printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),8229                                           IndexEntries[i].FunctionOffset,8230                                           CommonEncodings);8231    else8232      outs() << "    Skipping 2nd level page with unknown kind " << Kind8233             << '\n';8234  }8235}8236 8237void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {8238  std::map<uint64_t, SymbolRef> Symbols;8239  for (const SymbolRef &SymRef : Obj->symbols()) {8240    // Discard any undefined or absolute symbols. They're not going to take part8241    // in the convenience lookup for unwind info and just take up resources.8242    auto SectOrErr = SymRef.getSection();8243    if (!SectOrErr) {8244      // TODO: Actually report errors helpfully.8245      consumeError(SectOrErr.takeError());8246      continue;8247    }8248    section_iterator Section = *SectOrErr;8249    if (Section == Obj->section_end())8250      continue;8251 8252    uint64_t Addr = cantFail(SymRef.getValue());8253    Symbols.insert(std::make_pair(Addr, SymRef));8254  }8255 8256  for (const SectionRef &Section : Obj->sections()) {8257    StringRef SectName;8258    if (Expected<StringRef> NameOrErr = Section.getName())8259      SectName = *NameOrErr;8260    else8261      consumeError(NameOrErr.takeError());8262 8263    if (SectName == "__compact_unwind")8264      printMachOCompactUnwindSection(Obj, Symbols, Section);8265    else if (SectName == "__unwind_info")8266      printMachOUnwindInfoSection(Obj, Symbols, Section);8267  }8268}8269 8270static void PrintMachHeader(uint32_t magic, uint32_t cputype,8271                            uint32_t cpusubtype, uint32_t filetype,8272                            uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,8273                            bool verbose) {8274  outs() << "Mach header\n";8275  outs() << "      magic cputype cpusubtype  caps    filetype ncmds "8276            "sizeofcmds      flags\n";8277  if (verbose) {8278    if (magic == MachO::MH_MAGIC)8279      outs() << "   MH_MAGIC";8280    else if (magic == MachO::MH_MAGIC_64)8281      outs() << "MH_MAGIC_64";8282    else8283      outs() << format(" 0x%08" PRIx32, magic);8284    switch (cputype) {8285    case MachO::CPU_TYPE_I386:8286      outs() << "    I386";8287      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8288      case MachO::CPU_SUBTYPE_I386_ALL:8289        outs() << "        ALL";8290        break;8291      default:8292        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8293        break;8294      }8295      break;8296    case MachO::CPU_TYPE_X86_64:8297      outs() << "  X86_64";8298      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8299      case MachO::CPU_SUBTYPE_X86_64_ALL:8300        outs() << "        ALL";8301        break;8302      case MachO::CPU_SUBTYPE_X86_64_H:8303        outs() << "    Haswell";8304        break;8305      default:8306        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8307        break;8308      }8309      break;8310    case MachO::CPU_TYPE_ARM:8311      outs() << "     ARM";8312      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8313      case MachO::CPU_SUBTYPE_ARM_ALL:8314        outs() << "        ALL";8315        break;8316      case MachO::CPU_SUBTYPE_ARM_V4T:8317        outs() << "        V4T";8318        break;8319      case MachO::CPU_SUBTYPE_ARM_V5TEJ:8320        outs() << "      V5TEJ";8321        break;8322      case MachO::CPU_SUBTYPE_ARM_XSCALE:8323        outs() << "     XSCALE";8324        break;8325      case MachO::CPU_SUBTYPE_ARM_V6:8326        outs() << "         V6";8327        break;8328      case MachO::CPU_SUBTYPE_ARM_V6M:8329        outs() << "        V6M";8330        break;8331      case MachO::CPU_SUBTYPE_ARM_V7:8332        outs() << "         V7";8333        break;8334      case MachO::CPU_SUBTYPE_ARM_V7EM:8335        outs() << "       V7EM";8336        break;8337      case MachO::CPU_SUBTYPE_ARM_V7K:8338        outs() << "        V7K";8339        break;8340      case MachO::CPU_SUBTYPE_ARM_V7M:8341        outs() << "        V7M";8342        break;8343      case MachO::CPU_SUBTYPE_ARM_V7S:8344        outs() << "        V7S";8345        break;8346      default:8347        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8348        break;8349      }8350      break;8351    case MachO::CPU_TYPE_ARM64:8352      outs() << "   ARM64";8353      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8354      case MachO::CPU_SUBTYPE_ARM64_ALL:8355        outs() << "        ALL";8356        break;8357      case MachO::CPU_SUBTYPE_ARM64_V8:8358        outs() << "         V8";8359        break;8360      case MachO::CPU_SUBTYPE_ARM64E:8361        outs() << "          E";8362        break;8363      default:8364        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8365        break;8366      }8367      break;8368    case MachO::CPU_TYPE_ARM64_32:8369      outs() << " ARM64_32";8370      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8371      case MachO::CPU_SUBTYPE_ARM64_32_V8:8372        outs() << "        V8";8373        break;8374      default:8375        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8376        break;8377      }8378      break;8379    case MachO::CPU_TYPE_POWERPC:8380      outs() << "     PPC";8381      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8382      case MachO::CPU_SUBTYPE_POWERPC_ALL:8383        outs() << "        ALL";8384        break;8385      default:8386        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8387        break;8388      }8389      break;8390    case MachO::CPU_TYPE_POWERPC64:8391      outs() << "   PPC64";8392      switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8393      case MachO::CPU_SUBTYPE_POWERPC_ALL:8394        outs() << "        ALL";8395        break;8396      default:8397        outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8398        break;8399      }8400      break;8401    default:8402      outs() << format(" %7d", cputype);8403      outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8404      break;8405    }8406 8407    if (cputype == MachO::CPU_TYPE_ARM64 &&8408        MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {8409      const char *Format =8410          MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype)8411              ? " PAK%02d"8412              : " PAC%02d";8413      outs() << format(Format,8414                       MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype));8415    } else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) ==8416               MachO::CPU_SUBTYPE_LIB64) {8417      outs() << " LIB64";8418    } else {8419      outs() << format("  0x%02" PRIx32,8420                       (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8421    }8422    switch (filetype) {8423    case MachO::MH_OBJECT:8424      outs() << "      OBJECT";8425      break;8426    case MachO::MH_EXECUTE:8427      outs() << "     EXECUTE";8428      break;8429    case MachO::MH_FVMLIB:8430      outs() << "      FVMLIB";8431      break;8432    case MachO::MH_CORE:8433      outs() << "        CORE";8434      break;8435    case MachO::MH_PRELOAD:8436      outs() << "     PRELOAD";8437      break;8438    case MachO::MH_DYLIB:8439      outs() << "       DYLIB";8440      break;8441    case MachO::MH_DYLIB_STUB:8442      outs() << "  DYLIB_STUB";8443      break;8444    case MachO::MH_DYLINKER:8445      outs() << "    DYLINKER";8446      break;8447    case MachO::MH_BUNDLE:8448      outs() << "      BUNDLE";8449      break;8450    case MachO::MH_DSYM:8451      outs() << "        DSYM";8452      break;8453    case MachO::MH_KEXT_BUNDLE:8454      outs() << "  KEXTBUNDLE";8455      break;8456    case MachO::MH_FILESET:8457      outs() << "     FILESET";8458      break;8459    default:8460      outs() << format("  %10u", filetype);8461      break;8462    }8463    outs() << format(" %5u", ncmds);8464    outs() << format(" %10u", sizeofcmds);8465    uint32_t f = flags;8466    if (f & MachO::MH_NOUNDEFS) {8467      outs() << "   NOUNDEFS";8468      f &= ~MachO::MH_NOUNDEFS;8469    }8470    if (f & MachO::MH_INCRLINK) {8471      outs() << " INCRLINK";8472      f &= ~MachO::MH_INCRLINK;8473    }8474    if (f & MachO::MH_DYLDLINK) {8475      outs() << " DYLDLINK";8476      f &= ~MachO::MH_DYLDLINK;8477    }8478    if (f & MachO::MH_BINDATLOAD) {8479      outs() << " BINDATLOAD";8480      f &= ~MachO::MH_BINDATLOAD;8481    }8482    if (f & MachO::MH_PREBOUND) {8483      outs() << " PREBOUND";8484      f &= ~MachO::MH_PREBOUND;8485    }8486    if (f & MachO::MH_SPLIT_SEGS) {8487      outs() << " SPLIT_SEGS";8488      f &= ~MachO::MH_SPLIT_SEGS;8489    }8490    if (f & MachO::MH_LAZY_INIT) {8491      outs() << " LAZY_INIT";8492      f &= ~MachO::MH_LAZY_INIT;8493    }8494    if (f & MachO::MH_TWOLEVEL) {8495      outs() << " TWOLEVEL";8496      f &= ~MachO::MH_TWOLEVEL;8497    }8498    if (f & MachO::MH_FORCE_FLAT) {8499      outs() << " FORCE_FLAT";8500      f &= ~MachO::MH_FORCE_FLAT;8501    }8502    if (f & MachO::MH_NOMULTIDEFS) {8503      outs() << " NOMULTIDEFS";8504      f &= ~MachO::MH_NOMULTIDEFS;8505    }8506    if (f & MachO::MH_NOFIXPREBINDING) {8507      outs() << " NOFIXPREBINDING";8508      f &= ~MachO::MH_NOFIXPREBINDING;8509    }8510    if (f & MachO::MH_PREBINDABLE) {8511      outs() << " PREBINDABLE";8512      f &= ~MachO::MH_PREBINDABLE;8513    }8514    if (f & MachO::MH_ALLMODSBOUND) {8515      outs() << " ALLMODSBOUND";8516      f &= ~MachO::MH_ALLMODSBOUND;8517    }8518    if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {8519      outs() << " SUBSECTIONS_VIA_SYMBOLS";8520      f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;8521    }8522    if (f & MachO::MH_CANONICAL) {8523      outs() << " CANONICAL";8524      f &= ~MachO::MH_CANONICAL;8525    }8526    if (f & MachO::MH_WEAK_DEFINES) {8527      outs() << " WEAK_DEFINES";8528      f &= ~MachO::MH_WEAK_DEFINES;8529    }8530    if (f & MachO::MH_BINDS_TO_WEAK) {8531      outs() << " BINDS_TO_WEAK";8532      f &= ~MachO::MH_BINDS_TO_WEAK;8533    }8534    if (f & MachO::MH_ALLOW_STACK_EXECUTION) {8535      outs() << " ALLOW_STACK_EXECUTION";8536      f &= ~MachO::MH_ALLOW_STACK_EXECUTION;8537    }8538    if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {8539      outs() << " DEAD_STRIPPABLE_DYLIB";8540      f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;8541    }8542    if (f & MachO::MH_PIE) {8543      outs() << " PIE";8544      f &= ~MachO::MH_PIE;8545    }8546    if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {8547      outs() << " NO_REEXPORTED_DYLIBS";8548      f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;8549    }8550    if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {8551      outs() << " MH_HAS_TLV_DESCRIPTORS";8552      f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;8553    }8554    if (f & MachO::MH_NO_HEAP_EXECUTION) {8555      outs() << " MH_NO_HEAP_EXECUTION";8556      f &= ~MachO::MH_NO_HEAP_EXECUTION;8557    }8558    if (f & MachO::MH_APP_EXTENSION_SAFE) {8559      outs() << " APP_EXTENSION_SAFE";8560      f &= ~MachO::MH_APP_EXTENSION_SAFE;8561    }8562    if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {8563      outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";8564      f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;8565    }8566    if (f != 0 || flags == 0)8567      outs() << format(" 0x%08" PRIx32, f);8568  } else {8569    outs() << format(" 0x%08" PRIx32, magic);8570    outs() << format(" %7d", cputype);8571    outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8572    outs() << format("  0x%02" PRIx32,8573                     (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8574    outs() << format("  %10u", filetype);8575    outs() << format(" %5u", ncmds);8576    outs() << format(" %10u", sizeofcmds);8577    outs() << format(" 0x%08" PRIx32, flags);8578  }8579  outs() << "\n";8580}8581 8582static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,8583                                StringRef SegName, uint64_t vmaddr,8584                                uint64_t vmsize, uint64_t fileoff,8585                                uint64_t filesize, uint32_t maxprot,8586                                uint32_t initprot, uint32_t nsects,8587                                uint32_t flags, uint32_t object_size,8588                                bool verbose) {8589  uint64_t expected_cmdsize;8590  if (cmd == MachO::LC_SEGMENT) {8591    outs() << "      cmd LC_SEGMENT\n";8592    expected_cmdsize = nsects;8593    expected_cmdsize *= sizeof(struct MachO::section);8594    expected_cmdsize += sizeof(struct MachO::segment_command);8595  } else {8596    outs() << "      cmd LC_SEGMENT_64\n";8597    expected_cmdsize = nsects;8598    expected_cmdsize *= sizeof(struct MachO::section_64);8599    expected_cmdsize += sizeof(struct MachO::segment_command_64);8600  }8601  outs() << "  cmdsize " << cmdsize;8602  if (cmdsize != expected_cmdsize)8603    outs() << " Inconsistent size\n";8604  else8605    outs() << "\n";8606  outs() << "  segname " << SegName << "\n";8607  if (cmd == MachO::LC_SEGMENT_64) {8608    outs() << "   vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";8609    outs() << "   vmsize " << format("0x%016" PRIx64, vmsize) << "\n";8610  } else {8611    outs() << "   vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";8612    outs() << "   vmsize " << format("0x%08" PRIx64, vmsize) << "\n";8613  }8614  outs() << "  fileoff " << fileoff;8615  if (fileoff > object_size)8616    outs() << " (past end of file)\n";8617  else8618    outs() << "\n";8619  outs() << " filesize " << filesize;8620  if (fileoff + filesize > object_size)8621    outs() << " (past end of file)\n";8622  else8623    outs() << "\n";8624  if (verbose) {8625    if ((maxprot &8626         ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8627           MachO::VM_PROT_EXECUTE)) != 0)8628      outs() << "  maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";8629    else {8630      outs() << "  maxprot ";8631      outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");8632      outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");8633      outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8634    }8635    if ((initprot &8636         ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8637           MachO::VM_PROT_EXECUTE)) != 0)8638      outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";8639    else {8640      outs() << " initprot ";8641      outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");8642      outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");8643      outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8644    }8645  } else {8646    outs() << "  maxprot " << format("0x%08" PRIx32, maxprot) << "\n";8647    outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";8648  }8649  outs() << "   nsects " << nsects << "\n";8650  if (verbose) {8651    outs() << "    flags";8652    if (flags == 0)8653      outs() << " (none)\n";8654    else {8655      if (flags & MachO::SG_HIGHVM) {8656        outs() << " HIGHVM";8657        flags &= ~MachO::SG_HIGHVM;8658      }8659      if (flags & MachO::SG_FVMLIB) {8660        outs() << " FVMLIB";8661        flags &= ~MachO::SG_FVMLIB;8662      }8663      if (flags & MachO::SG_NORELOC) {8664        outs() << " NORELOC";8665        flags &= ~MachO::SG_NORELOC;8666      }8667      if (flags & MachO::SG_PROTECTED_VERSION_1) {8668        outs() << " PROTECTED_VERSION_1";8669        flags &= ~MachO::SG_PROTECTED_VERSION_1;8670      }8671      if (flags & MachO::SG_READ_ONLY) {8672        // Apple's otool prints the SG_ prefix for this flag, but not for the8673        // others.8674        outs() << " SG_READ_ONLY";8675        flags &= ~MachO::SG_READ_ONLY;8676      }8677      if (flags)8678        outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";8679      else8680        outs() << "\n";8681    }8682  } else {8683    outs() << "    flags " << format("0x%" PRIx32, flags) << "\n";8684  }8685}8686 8687static void PrintSection(const char *sectname, const char *segname,8688                         uint64_t addr, uint64_t size, uint32_t offset,8689                         uint32_t align, uint32_t reloff, uint32_t nreloc,8690                         uint32_t flags, uint32_t reserved1, uint32_t reserved2,8691                         uint32_t cmd, const char *sg_segname,8692                         uint32_t filetype, uint32_t object_size,8693                         bool verbose) {8694  outs() << "Section\n";8695  outs() << "  sectname " << format("%.16s\n", sectname);8696  outs() << "   segname " << format("%.16s", segname);8697  if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)8698    outs() << " (does not match segment)\n";8699  else8700    outs() << "\n";8701  if (cmd == MachO::LC_SEGMENT_64) {8702    outs() << "      addr " << format("0x%016" PRIx64, addr) << "\n";8703    outs() << "      size " << format("0x%016" PRIx64, size);8704  } else {8705    outs() << "      addr " << format("0x%08" PRIx64, addr) << "\n";8706    outs() << "      size " << format("0x%08" PRIx64, size);8707  }8708  if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)8709    outs() << " (past end of file)\n";8710  else8711    outs() << "\n";8712  outs() << "    offset " << offset;8713  if (offset > object_size)8714    outs() << " (past end of file)\n";8715  else8716    outs() << "\n";8717  uint32_t align_shifted = 1 << align;8718  outs() << "     align 2^" << align << " (" << align_shifted << ")\n";8719  outs() << "    reloff " << reloff;8720  if (reloff > object_size)8721    outs() << " (past end of file)\n";8722  else8723    outs() << "\n";8724  outs() << "    nreloc " << nreloc;8725  if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)8726    outs() << " (past end of file)\n";8727  else8728    outs() << "\n";8729  uint32_t section_type = flags & MachO::SECTION_TYPE;8730  if (verbose) {8731    outs() << "      type";8732    if (section_type == MachO::S_REGULAR)8733      outs() << " S_REGULAR\n";8734    else if (section_type == MachO::S_ZEROFILL)8735      outs() << " S_ZEROFILL\n";8736    else if (section_type == MachO::S_CSTRING_LITERALS)8737      outs() << " S_CSTRING_LITERALS\n";8738    else if (section_type == MachO::S_4BYTE_LITERALS)8739      outs() << " S_4BYTE_LITERALS\n";8740    else if (section_type == MachO::S_8BYTE_LITERALS)8741      outs() << " S_8BYTE_LITERALS\n";8742    else if (section_type == MachO::S_16BYTE_LITERALS)8743      outs() << " S_16BYTE_LITERALS\n";8744    else if (section_type == MachO::S_LITERAL_POINTERS)8745      outs() << " S_LITERAL_POINTERS\n";8746    else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)8747      outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";8748    else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)8749      outs() << " S_LAZY_SYMBOL_POINTERS\n";8750    else if (section_type == MachO::S_SYMBOL_STUBS)8751      outs() << " S_SYMBOL_STUBS\n";8752    else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)8753      outs() << " S_MOD_INIT_FUNC_POINTERS\n";8754    else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)8755      outs() << " S_MOD_TERM_FUNC_POINTERS\n";8756    else if (section_type == MachO::S_COALESCED)8757      outs() << " S_COALESCED\n";8758    else if (section_type == MachO::S_INTERPOSING)8759      outs() << " S_INTERPOSING\n";8760    else if (section_type == MachO::S_DTRACE_DOF)8761      outs() << " S_DTRACE_DOF\n";8762    else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)8763      outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";8764    else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)8765      outs() << " S_THREAD_LOCAL_REGULAR\n";8766    else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)8767      outs() << " S_THREAD_LOCAL_ZEROFILL\n";8768    else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)8769      outs() << " S_THREAD_LOCAL_VARIABLES\n";8770    else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8771      outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";8772    else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)8773      outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";8774    else if (section_type == MachO::S_INIT_FUNC_OFFSETS)8775      outs() << " S_INIT_FUNC_OFFSETS\n";8776    else8777      outs() << format("0x%08" PRIx32, section_type) << "\n";8778    outs() << "attributes";8779    uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;8780    if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)8781      outs() << " PURE_INSTRUCTIONS";8782    if (section_attributes & MachO::S_ATTR_NO_TOC)8783      outs() << " NO_TOC";8784    if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)8785      outs() << " STRIP_STATIC_SYMS";8786    if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)8787      outs() << " NO_DEAD_STRIP";8788    if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)8789      outs() << " LIVE_SUPPORT";8790    if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)8791      outs() << " SELF_MODIFYING_CODE";8792    if (section_attributes & MachO::S_ATTR_DEBUG)8793      outs() << " DEBUG";8794    if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)8795      outs() << " SOME_INSTRUCTIONS";8796    if (section_attributes & MachO::S_ATTR_EXT_RELOC)8797      outs() << " EXT_RELOC";8798    if (section_attributes & MachO::S_ATTR_LOC_RELOC)8799      outs() << " LOC_RELOC";8800    if (section_attributes == 0)8801      outs() << " (none)";8802    outs() << "\n";8803  } else8804    outs() << "     flags " << format("0x%08" PRIx32, flags) << "\n";8805  outs() << " reserved1 " << reserved1;8806  if (section_type == MachO::S_SYMBOL_STUBS ||8807      section_type == MachO::S_LAZY_SYMBOL_POINTERS ||8808      section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||8809      section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||8810      section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8811    outs() << " (index into indirect symbol table)\n";8812  else8813    outs() << "\n";8814  outs() << " reserved2 " << reserved2;8815  if (section_type == MachO::S_SYMBOL_STUBS)8816    outs() << " (size of stubs)\n";8817  else8818    outs() << "\n";8819}8820 8821static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,8822                                   uint32_t object_size) {8823  outs() << "     cmd LC_SYMTAB\n";8824  outs() << " cmdsize " << st.cmdsize;8825  if (st.cmdsize != sizeof(struct MachO::symtab_command))8826    outs() << " Incorrect size\n";8827  else8828    outs() << "\n";8829  outs() << "  symoff " << st.symoff;8830  if (st.symoff > object_size)8831    outs() << " (past end of file)\n";8832  else8833    outs() << "\n";8834  outs() << "   nsyms " << st.nsyms;8835  uint64_t big_size;8836  if (Is64Bit) {8837    big_size = st.nsyms;8838    big_size *= sizeof(struct MachO::nlist_64);8839    big_size += st.symoff;8840    if (big_size > object_size)8841      outs() << " (past end of file)\n";8842    else8843      outs() << "\n";8844  } else {8845    big_size = st.nsyms;8846    big_size *= sizeof(struct MachO::nlist);8847    big_size += st.symoff;8848    if (big_size > object_size)8849      outs() << " (past end of file)\n";8850    else8851      outs() << "\n";8852  }8853  outs() << "  stroff " << st.stroff;8854  if (st.stroff > object_size)8855    outs() << " (past end of file)\n";8856  else8857    outs() << "\n";8858  outs() << " strsize " << st.strsize;8859  big_size = st.stroff;8860  big_size += st.strsize;8861  if (big_size > object_size)8862    outs() << " (past end of file)\n";8863  else8864    outs() << "\n";8865}8866 8867static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,8868                                     uint32_t nsyms, uint32_t object_size,8869                                     bool Is64Bit) {8870  outs() << "            cmd LC_DYSYMTAB\n";8871  outs() << "        cmdsize " << dyst.cmdsize;8872  if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))8873    outs() << " Incorrect size\n";8874  else8875    outs() << "\n";8876  outs() << "      ilocalsym " << dyst.ilocalsym;8877  if (dyst.ilocalsym > nsyms)8878    outs() << " (greater than the number of symbols)\n";8879  else8880    outs() << "\n";8881  outs() << "      nlocalsym " << dyst.nlocalsym;8882  uint64_t big_size;8883  big_size = dyst.ilocalsym;8884  big_size += dyst.nlocalsym;8885  if (big_size > nsyms)8886    outs() << " (past the end of the symbol table)\n";8887  else8888    outs() << "\n";8889  outs() << "     iextdefsym " << dyst.iextdefsym;8890  if (dyst.iextdefsym > nsyms)8891    outs() << " (greater than the number of symbols)\n";8892  else8893    outs() << "\n";8894  outs() << "     nextdefsym " << dyst.nextdefsym;8895  big_size = dyst.iextdefsym;8896  big_size += dyst.nextdefsym;8897  if (big_size > nsyms)8898    outs() << " (past the end of the symbol table)\n";8899  else8900    outs() << "\n";8901  outs() << "      iundefsym " << dyst.iundefsym;8902  if (dyst.iundefsym > nsyms)8903    outs() << " (greater than the number of symbols)\n";8904  else8905    outs() << "\n";8906  outs() << "      nundefsym " << dyst.nundefsym;8907  big_size = dyst.iundefsym;8908  big_size += dyst.nundefsym;8909  if (big_size > nsyms)8910    outs() << " (past the end of the symbol table)\n";8911  else8912    outs() << "\n";8913  outs() << "         tocoff " << dyst.tocoff;8914  if (dyst.tocoff > object_size)8915    outs() << " (past end of file)\n";8916  else8917    outs() << "\n";8918  outs() << "           ntoc " << dyst.ntoc;8919  big_size = dyst.ntoc;8920  big_size *= sizeof(struct MachO::dylib_table_of_contents);8921  big_size += dyst.tocoff;8922  if (big_size > object_size)8923    outs() << " (past end of file)\n";8924  else8925    outs() << "\n";8926  outs() << "      modtaboff " << dyst.modtaboff;8927  if (dyst.modtaboff > object_size)8928    outs() << " (past end of file)\n";8929  else8930    outs() << "\n";8931  outs() << "        nmodtab " << dyst.nmodtab;8932  uint64_t modtabend;8933  if (Is64Bit) {8934    modtabend = dyst.nmodtab;8935    modtabend *= sizeof(struct MachO::dylib_module_64);8936    modtabend += dyst.modtaboff;8937  } else {8938    modtabend = dyst.nmodtab;8939    modtabend *= sizeof(struct MachO::dylib_module);8940    modtabend += dyst.modtaboff;8941  }8942  if (modtabend > object_size)8943    outs() << " (past end of file)\n";8944  else8945    outs() << "\n";8946  outs() << "   extrefsymoff " << dyst.extrefsymoff;8947  if (dyst.extrefsymoff > object_size)8948    outs() << " (past end of file)\n";8949  else8950    outs() << "\n";8951  outs() << "    nextrefsyms " << dyst.nextrefsyms;8952  big_size = dyst.nextrefsyms;8953  big_size *= sizeof(struct MachO::dylib_reference);8954  big_size += dyst.extrefsymoff;8955  if (big_size > object_size)8956    outs() << " (past end of file)\n";8957  else8958    outs() << "\n";8959  outs() << " indirectsymoff " << dyst.indirectsymoff;8960  if (dyst.indirectsymoff > object_size)8961    outs() << " (past end of file)\n";8962  else8963    outs() << "\n";8964  outs() << "  nindirectsyms " << dyst.nindirectsyms;8965  big_size = dyst.nindirectsyms;8966  big_size *= sizeof(uint32_t);8967  big_size += dyst.indirectsymoff;8968  if (big_size > object_size)8969    outs() << " (past end of file)\n";8970  else8971    outs() << "\n";8972  outs() << "      extreloff " << dyst.extreloff;8973  if (dyst.extreloff > object_size)8974    outs() << " (past end of file)\n";8975  else8976    outs() << "\n";8977  outs() << "        nextrel " << dyst.nextrel;8978  big_size = dyst.nextrel;8979  big_size *= sizeof(struct MachO::relocation_info);8980  big_size += dyst.extreloff;8981  if (big_size > object_size)8982    outs() << " (past end of file)\n";8983  else8984    outs() << "\n";8985  outs() << "      locreloff " << dyst.locreloff;8986  if (dyst.locreloff > object_size)8987    outs() << " (past end of file)\n";8988  else8989    outs() << "\n";8990  outs() << "        nlocrel " << dyst.nlocrel;8991  big_size = dyst.nlocrel;8992  big_size *= sizeof(struct MachO::relocation_info);8993  big_size += dyst.locreloff;8994  if (big_size > object_size)8995    outs() << " (past end of file)\n";8996  else8997    outs() << "\n";8998}8999 9000static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,9001                                     uint32_t object_size) {9002  if (dc.cmd == MachO::LC_DYLD_INFO)9003    outs() << "            cmd LC_DYLD_INFO\n";9004  else9005    outs() << "            cmd LC_DYLD_INFO_ONLY\n";9006  outs() << "        cmdsize " << dc.cmdsize;9007  if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))9008    outs() << " Incorrect size\n";9009  else9010    outs() << "\n";9011  outs() << "     rebase_off " << dc.rebase_off;9012  if (dc.rebase_off > object_size)9013    outs() << " (past end of file)\n";9014  else9015    outs() << "\n";9016  outs() << "    rebase_size " << dc.rebase_size;9017  uint64_t big_size;9018  big_size = dc.rebase_off;9019  big_size += dc.rebase_size;9020  if (big_size > object_size)9021    outs() << " (past end of file)\n";9022  else9023    outs() << "\n";9024  outs() << "       bind_off " << dc.bind_off;9025  if (dc.bind_off > object_size)9026    outs() << " (past end of file)\n";9027  else9028    outs() << "\n";9029  outs() << "      bind_size " << dc.bind_size;9030  big_size = dc.bind_off;9031  big_size += dc.bind_size;9032  if (big_size > object_size)9033    outs() << " (past end of file)\n";9034  else9035    outs() << "\n";9036  outs() << "  weak_bind_off " << dc.weak_bind_off;9037  if (dc.weak_bind_off > object_size)9038    outs() << " (past end of file)\n";9039  else9040    outs() << "\n";9041  outs() << " weak_bind_size " << dc.weak_bind_size;9042  big_size = dc.weak_bind_off;9043  big_size += dc.weak_bind_size;9044  if (big_size > object_size)9045    outs() << " (past end of file)\n";9046  else9047    outs() << "\n";9048  outs() << "  lazy_bind_off " << dc.lazy_bind_off;9049  if (dc.lazy_bind_off > object_size)9050    outs() << " (past end of file)\n";9051  else9052    outs() << "\n";9053  outs() << " lazy_bind_size " << dc.lazy_bind_size;9054  big_size = dc.lazy_bind_off;9055  big_size += dc.lazy_bind_size;9056  if (big_size > object_size)9057    outs() << " (past end of file)\n";9058  else9059    outs() << "\n";9060  outs() << "     export_off " << dc.export_off;9061  if (dc.export_off > object_size)9062    outs() << " (past end of file)\n";9063  else9064    outs() << "\n";9065  outs() << "    export_size " << dc.export_size;9066  big_size = dc.export_off;9067  big_size += dc.export_size;9068  if (big_size > object_size)9069    outs() << " (past end of file)\n";9070  else9071    outs() << "\n";9072}9073 9074static void PrintDyldLoadCommand(MachO::dylinker_command dyld,9075                                 const char *Ptr) {9076  if (dyld.cmd == MachO::LC_ID_DYLINKER)9077    outs() << "          cmd LC_ID_DYLINKER\n";9078  else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)9079    outs() << "          cmd LC_LOAD_DYLINKER\n";9080  else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)9081    outs() << "          cmd LC_DYLD_ENVIRONMENT\n";9082  else9083    outs() << "          cmd ?(" << dyld.cmd << ")\n";9084  outs() << "      cmdsize " << dyld.cmdsize;9085  if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))9086    outs() << " Incorrect size\n";9087  else9088    outs() << "\n";9089  if (dyld.name >= dyld.cmdsize)9090    outs() << "         name ?(bad offset " << dyld.name << ")\n";9091  else {9092    const char *P = Ptr + dyld.name;9093    outs() << "         name " << P << " (offset " << dyld.name << ")\n";9094  }9095}9096 9097static void PrintUuidLoadCommand(MachO::uuid_command uuid) {9098  outs() << "     cmd LC_UUID\n";9099  outs() << " cmdsize " << uuid.cmdsize;9100  if (uuid.cmdsize != sizeof(struct MachO::uuid_command))9101    outs() << " Incorrect size\n";9102  else9103    outs() << "\n";9104  outs() << "    uuid ";9105  for (int i = 0; i < 16; ++i) {9106    outs() << format("%02" PRIX32, uuid.uuid[i]);9107    if (i == 3 || i == 5 || i == 7 || i == 9)9108      outs() << "-";9109  }9110  outs() << "\n";9111}9112 9113static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {9114  outs() << "          cmd LC_RPATH\n";9115  outs() << "      cmdsize " << rpath.cmdsize;9116  if (rpath.cmdsize < sizeof(struct MachO::rpath_command))9117    outs() << " Incorrect size\n";9118  else9119    outs() << "\n";9120  if (rpath.path >= rpath.cmdsize)9121    outs() << "         path ?(bad offset " << rpath.path << ")\n";9122  else {9123    const char *P = Ptr + rpath.path;9124    outs() << "         path " << P << " (offset " << rpath.path << ")\n";9125  }9126}9127 9128static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {9129  StringRef LoadCmdName;9130  switch (vd.cmd) {9131  case MachO::LC_VERSION_MIN_MACOSX:9132    LoadCmdName = "LC_VERSION_MIN_MACOSX";9133    break;9134  case MachO::LC_VERSION_MIN_IPHONEOS:9135    LoadCmdName = "LC_VERSION_MIN_IPHONEOS";9136    break;9137  case MachO::LC_VERSION_MIN_TVOS:9138    LoadCmdName = "LC_VERSION_MIN_TVOS";9139    break;9140  case MachO::LC_VERSION_MIN_WATCHOS:9141    LoadCmdName = "LC_VERSION_MIN_WATCHOS";9142    break;9143  default:9144    llvm_unreachable("Unknown version min load command");9145  }9146 9147  outs() << "      cmd " << LoadCmdName << '\n';9148  outs() << "  cmdsize " << vd.cmdsize;9149  if (vd.cmdsize != sizeof(struct MachO::version_min_command))9150    outs() << " Incorrect size\n";9151  else9152    outs() << "\n";9153  outs() << "  version "9154         << MachOObjectFile::getVersionMinMajor(vd, false) << "."9155         << MachOObjectFile::getVersionMinMinor(vd, false);9156  uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);9157  if (Update != 0)9158    outs() << "." << Update;9159  outs() << "\n";9160  if (vd.sdk == 0)9161    outs() << "      sdk n/a";9162  else {9163    outs() << "      sdk "9164           << MachOObjectFile::getVersionMinMajor(vd, true) << "."9165           << MachOObjectFile::getVersionMinMinor(vd, true);9166  }9167  Update = MachOObjectFile::getVersionMinUpdate(vd, true);9168  if (Update != 0)9169    outs() << "." << Update;9170  outs() << "\n";9171}9172 9173static void PrintNoteLoadCommand(MachO::note_command Nt) {9174  outs() << "       cmd LC_NOTE\n";9175  outs() << "   cmdsize " << Nt.cmdsize;9176  if (Nt.cmdsize != sizeof(struct MachO::note_command))9177    outs() << " Incorrect size\n";9178  else9179    outs() << "\n";9180  const char *d = Nt.data_owner;9181  outs() << "data_owner " << format("%.16s\n", d);9182  outs() << "    offset " << Nt.offset << "\n";9183  outs() << "      size " << Nt.size << "\n";9184}9185 9186static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {9187  outs() << "      tool ";9188  if (verbose)9189    outs() << MachOObjectFile::getBuildTool(bv.tool);9190  else9191    outs() << bv.tool;9192  outs() << "\n";9193  outs() << "   version " << MachOObjectFile::getVersionString(bv.version)9194         << "\n";9195}9196 9197static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,9198                                         MachO::build_version_command bd,9199                                         bool verbose) {9200  outs() << "       cmd LC_BUILD_VERSION\n";9201  outs() << "   cmdsize " << bd.cmdsize;9202  if (bd.cmdsize !=9203      sizeof(struct MachO::build_version_command) +9204          bd.ntools * sizeof(struct MachO::build_tool_version))9205    outs() << " Incorrect size\n";9206  else9207    outs() << "\n";9208  outs() << "  platform ";9209  if (verbose)9210    outs() << MachOObjectFile::getBuildPlatform(bd.platform);9211  else9212    outs() << bd.platform;9213  outs() << "\n";9214  if (bd.sdk)9215    outs() << "       sdk " << MachOObjectFile::getVersionString(bd.sdk)9216           << "\n";9217  else9218    outs() << "       sdk n/a\n";9219  outs() << "     minos " << MachOObjectFile::getVersionString(bd.minos)9220         << "\n";9221  outs() << "    ntools " << bd.ntools << "\n";9222  for (unsigned i = 0; i < bd.ntools; ++i) {9223    MachO::build_tool_version bv = obj->getBuildToolVersion(i);9224    PrintBuildToolVersion(bv, verbose);9225  }9226}9227 9228static void PrintSourceVersionCommand(MachO::source_version_command sd) {9229  outs() << "      cmd LC_SOURCE_VERSION\n";9230  outs() << "  cmdsize " << sd.cmdsize;9231  if (sd.cmdsize != sizeof(struct MachO::source_version_command))9232    outs() << " Incorrect size\n";9233  else9234    outs() << "\n";9235  uint64_t a = (sd.version >> 40) & 0xffffff;9236  uint64_t b = (sd.version >> 30) & 0x3ff;9237  uint64_t c = (sd.version >> 20) & 0x3ff;9238  uint64_t d = (sd.version >> 10) & 0x3ff;9239  uint64_t e = sd.version & 0x3ff;9240  outs() << "  version " << a << "." << b;9241  if (e != 0)9242    outs() << "." << c << "." << d << "." << e;9243  else if (d != 0)9244    outs() << "." << c << "." << d;9245  else if (c != 0)9246    outs() << "." << c;9247  outs() << "\n";9248}9249 9250static void PrintEntryPointCommand(MachO::entry_point_command ep) {9251  outs() << "       cmd LC_MAIN\n";9252  outs() << "   cmdsize " << ep.cmdsize;9253  if (ep.cmdsize != sizeof(struct MachO::entry_point_command))9254    outs() << " Incorrect size\n";9255  else9256    outs() << "\n";9257  outs() << "  entryoff " << ep.entryoff << "\n";9258  outs() << " stacksize " << ep.stacksize << "\n";9259}9260 9261static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,9262                                       uint32_t object_size) {9263  outs() << "          cmd LC_ENCRYPTION_INFO\n";9264  outs() << "      cmdsize " << ec.cmdsize;9265  if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))9266    outs() << " Incorrect size\n";9267  else9268    outs() << "\n";9269  outs() << "     cryptoff " << ec.cryptoff;9270  if (ec.cryptoff > object_size)9271    outs() << " (past end of file)\n";9272  else9273    outs() << "\n";9274  outs() << "    cryptsize " << ec.cryptsize;9275  if (ec.cryptsize > object_size)9276    outs() << " (past end of file)\n";9277  else9278    outs() << "\n";9279  outs() << "      cryptid " << ec.cryptid << "\n";9280}9281 9282static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,9283                                         uint32_t object_size) {9284  outs() << "          cmd LC_ENCRYPTION_INFO_64\n";9285  outs() << "      cmdsize " << ec.cmdsize;9286  if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))9287    outs() << " Incorrect size\n";9288  else9289    outs() << "\n";9290  outs() << "     cryptoff " << ec.cryptoff;9291  if (ec.cryptoff > object_size)9292    outs() << " (past end of file)\n";9293  else9294    outs() << "\n";9295  outs() << "    cryptsize " << ec.cryptsize;9296  if (ec.cryptsize > object_size)9297    outs() << " (past end of file)\n";9298  else9299    outs() << "\n";9300  outs() << "      cryptid " << ec.cryptid << "\n";9301  outs() << "          pad " << ec.pad << "\n";9302}9303 9304static void PrintLinkerOptionCommand(MachO::linker_option_command lo,9305                                     const char *Ptr) {9306  outs() << "     cmd LC_LINKER_OPTION\n";9307  outs() << " cmdsize " << lo.cmdsize;9308  if (lo.cmdsize < sizeof(struct MachO::linker_option_command))9309    outs() << " Incorrect size\n";9310  else9311    outs() << "\n";9312  outs() << "   count " << lo.count << "\n";9313  const char *string = Ptr + sizeof(struct MachO::linker_option_command);9314  uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);9315  uint32_t i = 0;9316  while (left > 0) {9317    while (*string == '\0' && left > 0) {9318      string++;9319      left--;9320    }9321    if (left > 0) {9322      i++;9323      outs() << "  string #" << i << " " << format("%.*s\n", left, string);9324      uint32_t NullPos = StringRef(string, left).find('\0');9325      uint32_t len = std::min(NullPos, left) + 1;9326      string += len;9327      left -= len;9328    }9329  }9330  if (lo.count != i)9331    outs() << "   count " << lo.count << " does not match number of strings "9332           << i << "\n";9333}9334 9335static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,9336                                     const char *Ptr) {9337  outs() << "          cmd LC_SUB_FRAMEWORK\n";9338  outs() << "      cmdsize " << sub.cmdsize;9339  if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))9340    outs() << " Incorrect size\n";9341  else9342    outs() << "\n";9343  if (sub.umbrella < sub.cmdsize) {9344    const char *P = Ptr + sub.umbrella;9345    outs() << "     umbrella " << P << " (offset " << sub.umbrella << ")\n";9346  } else {9347    outs() << "     umbrella ?(bad offset " << sub.umbrella << ")\n";9348  }9349}9350 9351static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,9352                                    const char *Ptr) {9353  outs() << "          cmd LC_SUB_UMBRELLA\n";9354  outs() << "      cmdsize " << sub.cmdsize;9355  if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))9356    outs() << " Incorrect size\n";9357  else9358    outs() << "\n";9359  if (sub.sub_umbrella < sub.cmdsize) {9360    const char *P = Ptr + sub.sub_umbrella;9361    outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";9362  } else {9363    outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";9364  }9365}9366 9367static void PrintSubLibraryCommand(MachO::sub_library_command sub,9368                                   const char *Ptr) {9369  outs() << "          cmd LC_SUB_LIBRARY\n";9370  outs() << "      cmdsize " << sub.cmdsize;9371  if (sub.cmdsize < sizeof(struct MachO::sub_library_command))9372    outs() << " Incorrect size\n";9373  else9374    outs() << "\n";9375  if (sub.sub_library < sub.cmdsize) {9376    const char *P = Ptr + sub.sub_library;9377    outs() << "  sub_library " << P << " (offset " << sub.sub_library << ")\n";9378  } else {9379    outs() << "  sub_library ?(bad offset " << sub.sub_library << ")\n";9380  }9381}9382 9383static void PrintSubClientCommand(MachO::sub_client_command sub,9384                                  const char *Ptr) {9385  outs() << "          cmd LC_SUB_CLIENT\n";9386  outs() << "      cmdsize " << sub.cmdsize;9387  if (sub.cmdsize < sizeof(struct MachO::sub_client_command))9388    outs() << " Incorrect size\n";9389  else9390    outs() << "\n";9391  if (sub.client < sub.cmdsize) {9392    const char *P = Ptr + sub.client;9393    outs() << "       client " << P << " (offset " << sub.client << ")\n";9394  } else {9395    outs() << "       client ?(bad offset " << sub.client << ")\n";9396  }9397}9398 9399static void PrintRoutinesCommand(MachO::routines_command r) {9400  outs() << "          cmd LC_ROUTINES\n";9401  outs() << "      cmdsize " << r.cmdsize;9402  if (r.cmdsize != sizeof(struct MachO::routines_command))9403    outs() << " Incorrect size\n";9404  else9405    outs() << "\n";9406  outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";9407  outs() << "  init_module " << r.init_module << "\n";9408  outs() << "    reserved1 " << r.reserved1 << "\n";9409  outs() << "    reserved2 " << r.reserved2 << "\n";9410  outs() << "    reserved3 " << r.reserved3 << "\n";9411  outs() << "    reserved4 " << r.reserved4 << "\n";9412  outs() << "    reserved5 " << r.reserved5 << "\n";9413  outs() << "    reserved6 " << r.reserved6 << "\n";9414}9415 9416static void PrintRoutinesCommand64(MachO::routines_command_64 r) {9417  outs() << "          cmd LC_ROUTINES_64\n";9418  outs() << "      cmdsize " << r.cmdsize;9419  if (r.cmdsize != sizeof(struct MachO::routines_command_64))9420    outs() << " Incorrect size\n";9421  else9422    outs() << "\n";9423  outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";9424  outs() << "  init_module " << r.init_module << "\n";9425  outs() << "    reserved1 " << r.reserved1 << "\n";9426  outs() << "    reserved2 " << r.reserved2 << "\n";9427  outs() << "    reserved3 " << r.reserved3 << "\n";9428  outs() << "    reserved4 " << r.reserved4 << "\n";9429  outs() << "    reserved5 " << r.reserved5 << "\n";9430  outs() << "    reserved6 " << r.reserved6 << "\n";9431}9432 9433static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {9434  outs() << "\t    eax " << format("0x%08" PRIx32, cpu32.eax);9435  outs() << " ebx    " << format("0x%08" PRIx32, cpu32.ebx);9436  outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);9437  outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";9438  outs() << "\t    edi " << format("0x%08" PRIx32, cpu32.edi);9439  outs() << " esi    " << format("0x%08" PRIx32, cpu32.esi);9440  outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);9441  outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";9442  outs() << "\t    ss  " << format("0x%08" PRIx32, cpu32.ss);9443  outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);9444  outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);9445  outs() << " cs  " << format("0x%08" PRIx32, cpu32.cs) << "\n";9446  outs() << "\t    ds  " << format("0x%08" PRIx32, cpu32.ds);9447  outs() << " es     " << format("0x%08" PRIx32, cpu32.es);9448  outs() << " fs  " << format("0x%08" PRIx32, cpu32.fs);9449  outs() << " gs  " << format("0x%08" PRIx32, cpu32.gs) << "\n";9450}9451 9452static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {9453  outs() << "   rax  " << format("0x%016" PRIx64, cpu64.rax);9454  outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);9455  outs() << " rcx  " << format("0x%016" PRIx64, cpu64.rcx) << "\n";9456  outs() << "   rdx  " << format("0x%016" PRIx64, cpu64.rdx);9457  outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);9458  outs() << " rsi  " << format("0x%016" PRIx64, cpu64.rsi) << "\n";9459  outs() << "   rbp  " << format("0x%016" PRIx64, cpu64.rbp);9460  outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);9461  outs() << " r8   " << format("0x%016" PRIx64, cpu64.r8) << "\n";9462  outs() << "    r9  " << format("0x%016" PRIx64, cpu64.r9);9463  outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);9464  outs() << " r11  " << format("0x%016" PRIx64, cpu64.r11) << "\n";9465  outs() << "   r12  " << format("0x%016" PRIx64, cpu64.r12);9466  outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);9467  outs() << " r14  " << format("0x%016" PRIx64, cpu64.r14) << "\n";9468  outs() << "   r15  " << format("0x%016" PRIx64, cpu64.r15);9469  outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";9470  outs() << "rflags  " << format("0x%016" PRIx64, cpu64.rflags);9471  outs() << " cs  " << format("0x%016" PRIx64, cpu64.cs);9472  outs() << " fs   " << format("0x%016" PRIx64, cpu64.fs) << "\n";9473  outs() << "    gs  " << format("0x%016" PRIx64, cpu64.gs) << "\n";9474}9475 9476static void Print_mmst_reg(MachO::mmst_reg_t &r) {9477  uint32_t f;9478  outs() << "\t      mmst_reg  ";9479  for (f = 0; f < 10; f++)9480    outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";9481  outs() << "\n";9482  outs() << "\t      mmst_rsrv ";9483  for (f = 0; f < 6; f++)9484    outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";9485  outs() << "\n";9486}9487 9488static void Print_xmm_reg(MachO::xmm_reg_t &r) {9489  uint32_t f;9490  outs() << "\t      xmm_reg ";9491  for (f = 0; f < 16; f++)9492    outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";9493  outs() << "\n";9494}9495 9496static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {9497  outs() << "\t    fpu_reserved[0] " << fpu.fpu_reserved[0];9498  outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";9499  outs() << "\t    control: invalid " << fpu.fpu_fcw.invalid;9500  outs() << " denorm " << fpu.fpu_fcw.denorm;9501  outs() << " zdiv " << fpu.fpu_fcw.zdiv;9502  outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;9503  outs() << " undfl " << fpu.fpu_fcw.undfl;9504  outs() << " precis " << fpu.fpu_fcw.precis << "\n";9505  outs() << "\t\t     pc ";9506  if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)9507    outs() << "FP_PREC_24B ";9508  else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)9509    outs() << "FP_PREC_53B ";9510  else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)9511    outs() << "FP_PREC_64B ";9512  else9513    outs() << fpu.fpu_fcw.pc << " ";9514  outs() << "rc ";9515  if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)9516    outs() << "FP_RND_NEAR ";9517  else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)9518    outs() << "FP_RND_DOWN ";9519  else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)9520    outs() << "FP_RND_UP ";9521  else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)9522    outs() << "FP_CHOP ";9523  outs() << "\n";9524  outs() << "\t    status: invalid " << fpu.fpu_fsw.invalid;9525  outs() << " denorm " << fpu.fpu_fsw.denorm;9526  outs() << " zdiv " << fpu.fpu_fsw.zdiv;9527  outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;9528  outs() << " undfl " << fpu.fpu_fsw.undfl;9529  outs() << " precis " << fpu.fpu_fsw.precis;9530  outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";9531  outs() << "\t            errsumm " << fpu.fpu_fsw.errsumm;9532  outs() << " c0 " << fpu.fpu_fsw.c0;9533  outs() << " c1 " << fpu.fpu_fsw.c1;9534  outs() << " c2 " << fpu.fpu_fsw.c2;9535  outs() << " tos " << fpu.fpu_fsw.tos;9536  outs() << " c3 " << fpu.fpu_fsw.c3;9537  outs() << " busy " << fpu.fpu_fsw.busy << "\n";9538  outs() << "\t    fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);9539  outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);9540  outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);9541  outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";9542  outs() << "\t    fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);9543  outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);9544  outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);9545  outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";9546  outs() << "\t    fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);9547  outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);9548  outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);9549  outs() << "\n";9550  outs() << "\t    fpu_stmm0:\n";9551  Print_mmst_reg(fpu.fpu_stmm0);9552  outs() << "\t    fpu_stmm1:\n";9553  Print_mmst_reg(fpu.fpu_stmm1);9554  outs() << "\t    fpu_stmm2:\n";9555  Print_mmst_reg(fpu.fpu_stmm2);9556  outs() << "\t    fpu_stmm3:\n";9557  Print_mmst_reg(fpu.fpu_stmm3);9558  outs() << "\t    fpu_stmm4:\n";9559  Print_mmst_reg(fpu.fpu_stmm4);9560  outs() << "\t    fpu_stmm5:\n";9561  Print_mmst_reg(fpu.fpu_stmm5);9562  outs() << "\t    fpu_stmm6:\n";9563  Print_mmst_reg(fpu.fpu_stmm6);9564  outs() << "\t    fpu_stmm7:\n";9565  Print_mmst_reg(fpu.fpu_stmm7);9566  outs() << "\t    fpu_xmm0:\n";9567  Print_xmm_reg(fpu.fpu_xmm0);9568  outs() << "\t    fpu_xmm1:\n";9569  Print_xmm_reg(fpu.fpu_xmm1);9570  outs() << "\t    fpu_xmm2:\n";9571  Print_xmm_reg(fpu.fpu_xmm2);9572  outs() << "\t    fpu_xmm3:\n";9573  Print_xmm_reg(fpu.fpu_xmm3);9574  outs() << "\t    fpu_xmm4:\n";9575  Print_xmm_reg(fpu.fpu_xmm4);9576  outs() << "\t    fpu_xmm5:\n";9577  Print_xmm_reg(fpu.fpu_xmm5);9578  outs() << "\t    fpu_xmm6:\n";9579  Print_xmm_reg(fpu.fpu_xmm6);9580  outs() << "\t    fpu_xmm7:\n";9581  Print_xmm_reg(fpu.fpu_xmm7);9582  outs() << "\t    fpu_xmm8:\n";9583  Print_xmm_reg(fpu.fpu_xmm8);9584  outs() << "\t    fpu_xmm9:\n";9585  Print_xmm_reg(fpu.fpu_xmm9);9586  outs() << "\t    fpu_xmm10:\n";9587  Print_xmm_reg(fpu.fpu_xmm10);9588  outs() << "\t    fpu_xmm11:\n";9589  Print_xmm_reg(fpu.fpu_xmm11);9590  outs() << "\t    fpu_xmm12:\n";9591  Print_xmm_reg(fpu.fpu_xmm12);9592  outs() << "\t    fpu_xmm13:\n";9593  Print_xmm_reg(fpu.fpu_xmm13);9594  outs() << "\t    fpu_xmm14:\n";9595  Print_xmm_reg(fpu.fpu_xmm14);9596  outs() << "\t    fpu_xmm15:\n";9597  Print_xmm_reg(fpu.fpu_xmm15);9598  outs() << "\t    fpu_rsrv4:\n";9599  for (uint32_t f = 0; f < 6; f++) {9600    outs() << "\t            ";9601    for (uint32_t g = 0; g < 16; g++)9602      outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";9603    outs() << "\n";9604  }9605  outs() << "\t    fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);9606  outs() << "\n";9607}9608 9609static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {9610  outs() << "\t    trapno " << format("0x%08" PRIx32, exc64.trapno);9611  outs() << " err " << format("0x%08" PRIx32, exc64.err);9612  outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";9613}9614 9615static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {9616  outs() << "\t    r0  " << format("0x%08" PRIx32, cpu32.r[0]);9617  outs() << " r1     "   << format("0x%08" PRIx32, cpu32.r[1]);9618  outs() << " r2  "      << format("0x%08" PRIx32, cpu32.r[2]);9619  outs() << " r3  "      << format("0x%08" PRIx32, cpu32.r[3]) << "\n";9620  outs() << "\t    r4  " << format("0x%08" PRIx32, cpu32.r[4]);9621  outs() << " r5     "   << format("0x%08" PRIx32, cpu32.r[5]);9622  outs() << " r6  "      << format("0x%08" PRIx32, cpu32.r[6]);9623  outs() << " r7  "      << format("0x%08" PRIx32, cpu32.r[7]) << "\n";9624  outs() << "\t    r8  " << format("0x%08" PRIx32, cpu32.r[8]);9625  outs() << " r9     "   << format("0x%08" PRIx32, cpu32.r[9]);9626  outs() << " r10 "      << format("0x%08" PRIx32, cpu32.r[10]);9627  outs() << " r11 "      << format("0x%08" PRIx32, cpu32.r[11]) << "\n";9628  outs() << "\t    r12 " << format("0x%08" PRIx32, cpu32.r[12]);9629  outs() << " sp     "   << format("0x%08" PRIx32, cpu32.sp);9630  outs() << " lr  "      << format("0x%08" PRIx32, cpu32.lr);9631  outs() << " pc  "      << format("0x%08" PRIx32, cpu32.pc) << "\n";9632  outs() << "\t   cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";9633}9634 9635static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {9636  outs() << "\t    x0  " << format("0x%016" PRIx64, cpu64.x[0]);9637  outs() << " x1  "      << format("0x%016" PRIx64, cpu64.x[1]);9638  outs() << " x2  "      << format("0x%016" PRIx64, cpu64.x[2]) << "\n";9639  outs() << "\t    x3  " << format("0x%016" PRIx64, cpu64.x[3]);9640  outs() << " x4  "      << format("0x%016" PRIx64, cpu64.x[4]);9641  outs() << " x5  "      << format("0x%016" PRIx64, cpu64.x[5]) << "\n";9642  outs() << "\t    x6  " << format("0x%016" PRIx64, cpu64.x[6]);9643  outs() << " x7  "      << format("0x%016" PRIx64, cpu64.x[7]);9644  outs() << " x8  "      << format("0x%016" PRIx64, cpu64.x[8]) << "\n";9645  outs() << "\t    x9  " << format("0x%016" PRIx64, cpu64.x[9]);9646  outs() << " x10 "      << format("0x%016" PRIx64, cpu64.x[10]);9647  outs() << " x11 "      << format("0x%016" PRIx64, cpu64.x[11]) << "\n";9648  outs() << "\t    x12 " << format("0x%016" PRIx64, cpu64.x[12]);9649  outs() << " x13 "      << format("0x%016" PRIx64, cpu64.x[13]);9650  outs() << " x14 "      << format("0x%016" PRIx64, cpu64.x[14]) << "\n";9651  outs() << "\t    x15 " << format("0x%016" PRIx64, cpu64.x[15]);9652  outs() << " x16 "      << format("0x%016" PRIx64, cpu64.x[16]);9653  outs() << " x17 "      << format("0x%016" PRIx64, cpu64.x[17]) << "\n";9654  outs() << "\t    x18 " << format("0x%016" PRIx64, cpu64.x[18]);9655  outs() << " x19 "      << format("0x%016" PRIx64, cpu64.x[19]);9656  outs() << " x20 "      << format("0x%016" PRIx64, cpu64.x[20]) << "\n";9657  outs() << "\t    x21 " << format("0x%016" PRIx64, cpu64.x[21]);9658  outs() << " x22 "      << format("0x%016" PRIx64, cpu64.x[22]);9659  outs() << " x23 "      << format("0x%016" PRIx64, cpu64.x[23]) << "\n";9660  outs() << "\t    x24 " << format("0x%016" PRIx64, cpu64.x[24]);9661  outs() << " x25 "      << format("0x%016" PRIx64, cpu64.x[25]);9662  outs() << " x26 "      << format("0x%016" PRIx64, cpu64.x[26]) << "\n";9663  outs() << "\t    x27 " << format("0x%016" PRIx64, cpu64.x[27]);9664  outs() << " x28 "      << format("0x%016" PRIx64, cpu64.x[28]);9665  outs() << "  fp "      << format("0x%016" PRIx64, cpu64.fp) << "\n";9666  outs() << "\t     lr " << format("0x%016" PRIx64, cpu64.lr);9667  outs() << " sp  "      << format("0x%016" PRIx64, cpu64.sp);9668  outs() << "  pc "      << format("0x%016" PRIx64, cpu64.pc) << "\n";9669  outs() << "\t   cpsr " << format("0x%08"  PRIx32, cpu64.cpsr) << "\n";9670}9671 9672static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,9673                               bool isLittleEndian, uint32_t cputype) {9674  if (t.cmd == MachO::LC_THREAD)9675    outs() << "        cmd LC_THREAD\n";9676  else if (t.cmd == MachO::LC_UNIXTHREAD)9677    outs() << "        cmd LC_UNIXTHREAD\n";9678  else9679    outs() << "        cmd " << t.cmd << " (unknown)\n";9680  outs() << "    cmdsize " << t.cmdsize;9681  if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))9682    outs() << " Incorrect size\n";9683  else9684    outs() << "\n";9685 9686  const char *begin = Ptr + sizeof(struct MachO::thread_command);9687  const char *end = Ptr + t.cmdsize;9688  uint32_t flavor, count, left;9689  if (cputype == MachO::CPU_TYPE_I386) {9690    while (begin < end) {9691      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9692        memcpy((char *)&flavor, begin, sizeof(uint32_t));9693        begin += sizeof(uint32_t);9694      } else {9695        flavor = 0;9696        begin = end;9697      }9698      if (isLittleEndian != sys::IsLittleEndianHost)9699        sys::swapByteOrder(flavor);9700      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9701        memcpy((char *)&count, begin, sizeof(uint32_t));9702        begin += sizeof(uint32_t);9703      } else {9704        count = 0;9705        begin = end;9706      }9707      if (isLittleEndian != sys::IsLittleEndianHost)9708        sys::swapByteOrder(count);9709      if (flavor == MachO::x86_THREAD_STATE32) {9710        outs() << "     flavor i386_THREAD_STATE\n";9711        if (count == MachO::x86_THREAD_STATE32_COUNT)9712          outs() << "      count i386_THREAD_STATE_COUNT\n";9713        else9714          outs() << "      count " << count9715                 << " (not x86_THREAD_STATE32_COUNT)\n";9716        MachO::x86_thread_state32_t cpu32;9717        left = end - begin;9718        if (left >= sizeof(MachO::x86_thread_state32_t)) {9719          memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));9720          begin += sizeof(MachO::x86_thread_state32_t);9721        } else {9722          memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));9723          memcpy(&cpu32, begin, left);9724          begin += left;9725        }9726        if (isLittleEndian != sys::IsLittleEndianHost)9727          swapStruct(cpu32);9728        Print_x86_thread_state32_t(cpu32);9729      } else if (flavor == MachO::x86_THREAD_STATE) {9730        outs() << "     flavor x86_THREAD_STATE\n";9731        if (count == MachO::x86_THREAD_STATE_COUNT)9732          outs() << "      count x86_THREAD_STATE_COUNT\n";9733        else9734          outs() << "      count " << count9735                 << " (not x86_THREAD_STATE_COUNT)\n";9736        struct MachO::x86_thread_state_t ts;9737        left = end - begin;9738        if (left >= sizeof(MachO::x86_thread_state_t)) {9739          memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9740          begin += sizeof(MachO::x86_thread_state_t);9741        } else {9742          memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9743          memcpy(&ts, begin, left);9744          begin += left;9745        }9746        if (isLittleEndian != sys::IsLittleEndianHost)9747          swapStruct(ts);9748        if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {9749          outs() << "\t    tsh.flavor x86_THREAD_STATE32 ";9750          if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)9751            outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";9752          else9753            outs() << "tsh.count " << ts.tsh.count9754                   << " (not x86_THREAD_STATE32_COUNT\n";9755          Print_x86_thread_state32_t(ts.uts.ts32);9756        } else {9757          outs() << "\t    tsh.flavor " << ts.tsh.flavor << "  tsh.count "9758                 << ts.tsh.count << "\n";9759        }9760      } else {9761        outs() << "     flavor " << flavor << " (unknown)\n";9762        outs() << "      count " << count << "\n";9763        outs() << "      state (unknown)\n";9764        begin += count * sizeof(uint32_t);9765      }9766    }9767  } else if (cputype == MachO::CPU_TYPE_X86_64) {9768    while (begin < end) {9769      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9770        memcpy((char *)&flavor, begin, sizeof(uint32_t));9771        begin += sizeof(uint32_t);9772      } else {9773        flavor = 0;9774        begin = end;9775      }9776      if (isLittleEndian != sys::IsLittleEndianHost)9777        sys::swapByteOrder(flavor);9778      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9779        memcpy((char *)&count, begin, sizeof(uint32_t));9780        begin += sizeof(uint32_t);9781      } else {9782        count = 0;9783        begin = end;9784      }9785      if (isLittleEndian != sys::IsLittleEndianHost)9786        sys::swapByteOrder(count);9787      if (flavor == MachO::x86_THREAD_STATE64) {9788        outs() << "     flavor x86_THREAD_STATE64\n";9789        if (count == MachO::x86_THREAD_STATE64_COUNT)9790          outs() << "      count x86_THREAD_STATE64_COUNT\n";9791        else9792          outs() << "      count " << count9793                 << " (not x86_THREAD_STATE64_COUNT)\n";9794        MachO::x86_thread_state64_t cpu64;9795        left = end - begin;9796        if (left >= sizeof(MachO::x86_thread_state64_t)) {9797          memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));9798          begin += sizeof(MachO::x86_thread_state64_t);9799        } else {9800          memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));9801          memcpy(&cpu64, begin, left);9802          begin += left;9803        }9804        if (isLittleEndian != sys::IsLittleEndianHost)9805          swapStruct(cpu64);9806        Print_x86_thread_state64_t(cpu64);9807      } else if (flavor == MachO::x86_THREAD_STATE) {9808        outs() << "     flavor x86_THREAD_STATE\n";9809        if (count == MachO::x86_THREAD_STATE_COUNT)9810          outs() << "      count x86_THREAD_STATE_COUNT\n";9811        else9812          outs() << "      count " << count9813                 << " (not x86_THREAD_STATE_COUNT)\n";9814        struct MachO::x86_thread_state_t ts;9815        left = end - begin;9816        if (left >= sizeof(MachO::x86_thread_state_t)) {9817          memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9818          begin += sizeof(MachO::x86_thread_state_t);9819        } else {9820          memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9821          memcpy(&ts, begin, left);9822          begin += left;9823        }9824        if (isLittleEndian != sys::IsLittleEndianHost)9825          swapStruct(ts);9826        if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {9827          outs() << "\t    tsh.flavor x86_THREAD_STATE64 ";9828          if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)9829            outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";9830          else9831            outs() << "tsh.count " << ts.tsh.count9832                   << " (not x86_THREAD_STATE64_COUNT\n";9833          Print_x86_thread_state64_t(ts.uts.ts64);9834        } else {9835          outs() << "\t    tsh.flavor " << ts.tsh.flavor << "  tsh.count "9836                 << ts.tsh.count << "\n";9837        }9838      } else if (flavor == MachO::x86_FLOAT_STATE) {9839        outs() << "     flavor x86_FLOAT_STATE\n";9840        if (count == MachO::x86_FLOAT_STATE_COUNT)9841          outs() << "      count x86_FLOAT_STATE_COUNT\n";9842        else9843          outs() << "      count " << count << " (not x86_FLOAT_STATE_COUNT)\n";9844        struct MachO::x86_float_state_t fs;9845        left = end - begin;9846        if (left >= sizeof(MachO::x86_float_state_t)) {9847          memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));9848          begin += sizeof(MachO::x86_float_state_t);9849        } else {9850          memset(&fs, '\0', sizeof(MachO::x86_float_state_t));9851          memcpy(&fs, begin, left);9852          begin += left;9853        }9854        if (isLittleEndian != sys::IsLittleEndianHost)9855          swapStruct(fs);9856        if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {9857          outs() << "\t    fsh.flavor x86_FLOAT_STATE64 ";9858          if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)9859            outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";9860          else9861            outs() << "fsh.count " << fs.fsh.count9862                   << " (not x86_FLOAT_STATE64_COUNT\n";9863          Print_x86_float_state_t(fs.ufs.fs64);9864        } else {9865          outs() << "\t    fsh.flavor " << fs.fsh.flavor << "  fsh.count "9866                 << fs.fsh.count << "\n";9867        }9868      } else if (flavor == MachO::x86_EXCEPTION_STATE) {9869        outs() << "     flavor x86_EXCEPTION_STATE\n";9870        if (count == MachO::x86_EXCEPTION_STATE_COUNT)9871          outs() << "      count x86_EXCEPTION_STATE_COUNT\n";9872        else9873          outs() << "      count " << count9874                 << " (not x86_EXCEPTION_STATE_COUNT)\n";9875        struct MachO::x86_exception_state_t es;9876        left = end - begin;9877        if (left >= sizeof(MachO::x86_exception_state_t)) {9878          memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));9879          begin += sizeof(MachO::x86_exception_state_t);9880        } else {9881          memset(&es, '\0', sizeof(MachO::x86_exception_state_t));9882          memcpy(&es, begin, left);9883          begin += left;9884        }9885        if (isLittleEndian != sys::IsLittleEndianHost)9886          swapStruct(es);9887        if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {9888          outs() << "\t    esh.flavor x86_EXCEPTION_STATE64\n";9889          if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)9890            outs() << "\t    esh.count x86_EXCEPTION_STATE64_COUNT\n";9891          else9892            outs() << "\t    esh.count " << es.esh.count9893                   << " (not x86_EXCEPTION_STATE64_COUNT\n";9894          Print_x86_exception_state_t(es.ues.es64);9895        } else {9896          outs() << "\t    esh.flavor " << es.esh.flavor << "  esh.count "9897                 << es.esh.count << "\n";9898        }9899      } else if (flavor == MachO::x86_EXCEPTION_STATE64) {9900        outs() << "     flavor x86_EXCEPTION_STATE64\n";9901        if (count == MachO::x86_EXCEPTION_STATE64_COUNT)9902          outs() << "      count x86_EXCEPTION_STATE64_COUNT\n";9903        else9904          outs() << "      count " << count9905                 << " (not x86_EXCEPTION_STATE64_COUNT)\n";9906        struct MachO::x86_exception_state64_t es64;9907        left = end - begin;9908        if (left >= sizeof(MachO::x86_exception_state64_t)) {9909          memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));9910          begin += sizeof(MachO::x86_exception_state64_t);9911        } else {9912          memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));9913          memcpy(&es64, begin, left);9914          begin += left;9915        }9916        if (isLittleEndian != sys::IsLittleEndianHost)9917          swapStruct(es64);9918        Print_x86_exception_state_t(es64);9919      } else {9920        outs() << "     flavor " << flavor << " (unknown)\n";9921        outs() << "      count " << count << "\n";9922        outs() << "      state (unknown)\n";9923        begin += count * sizeof(uint32_t);9924      }9925    }9926  } else if (cputype == MachO::CPU_TYPE_ARM) {9927    while (begin < end) {9928      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9929        memcpy((char *)&flavor, begin, sizeof(uint32_t));9930        begin += sizeof(uint32_t);9931      } else {9932        flavor = 0;9933        begin = end;9934      }9935      if (isLittleEndian != sys::IsLittleEndianHost)9936        sys::swapByteOrder(flavor);9937      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9938        memcpy((char *)&count, begin, sizeof(uint32_t));9939        begin += sizeof(uint32_t);9940      } else {9941        count = 0;9942        begin = end;9943      }9944      if (isLittleEndian != sys::IsLittleEndianHost)9945        sys::swapByteOrder(count);9946      if (flavor == MachO::ARM_THREAD_STATE) {9947        outs() << "     flavor ARM_THREAD_STATE\n";9948        if (count == MachO::ARM_THREAD_STATE_COUNT)9949          outs() << "      count ARM_THREAD_STATE_COUNT\n";9950        else9951          outs() << "      count " << count9952                 << " (not ARM_THREAD_STATE_COUNT)\n";9953        MachO::arm_thread_state32_t cpu32;9954        left = end - begin;9955        if (left >= sizeof(MachO::arm_thread_state32_t)) {9956          memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));9957          begin += sizeof(MachO::arm_thread_state32_t);9958        } else {9959          memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));9960          memcpy(&cpu32, begin, left);9961          begin += left;9962        }9963        if (isLittleEndian != sys::IsLittleEndianHost)9964          swapStruct(cpu32);9965        Print_arm_thread_state32_t(cpu32);9966      } else {9967        outs() << "     flavor " << flavor << " (unknown)\n";9968        outs() << "      count " << count << "\n";9969        outs() << "      state (unknown)\n";9970        begin += count * sizeof(uint32_t);9971      }9972    }9973  } else if (cputype == MachO::CPU_TYPE_ARM64 ||9974             cputype == MachO::CPU_TYPE_ARM64_32) {9975    while (begin < end) {9976      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9977        memcpy((char *)&flavor, begin, sizeof(uint32_t));9978        begin += sizeof(uint32_t);9979      } else {9980        flavor = 0;9981        begin = end;9982      }9983      if (isLittleEndian != sys::IsLittleEndianHost)9984        sys::swapByteOrder(flavor);9985      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9986        memcpy((char *)&count, begin, sizeof(uint32_t));9987        begin += sizeof(uint32_t);9988      } else {9989        count = 0;9990        begin = end;9991      }9992      if (isLittleEndian != sys::IsLittleEndianHost)9993        sys::swapByteOrder(count);9994      if (flavor == MachO::ARM_THREAD_STATE64) {9995        outs() << "     flavor ARM_THREAD_STATE64\n";9996        if (count == MachO::ARM_THREAD_STATE64_COUNT)9997          outs() << "      count ARM_THREAD_STATE64_COUNT\n";9998        else9999          outs() << "      count " << count10000                 << " (not ARM_THREAD_STATE64_COUNT)\n";10001        MachO::arm_thread_state64_t cpu64;10002        left = end - begin;10003        if (left >= sizeof(MachO::arm_thread_state64_t)) {10004          memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));10005          begin += sizeof(MachO::arm_thread_state64_t);10006        } else {10007          memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));10008          memcpy(&cpu64, begin, left);10009          begin += left;10010        }10011        if (isLittleEndian != sys::IsLittleEndianHost)10012          swapStruct(cpu64);10013        Print_arm_thread_state64_t(cpu64);10014      } else {10015        outs() << "     flavor " << flavor << " (unknown)\n";10016        outs() << "      count " << count << "\n";10017        outs() << "      state (unknown)\n";10018        begin += count * sizeof(uint32_t);10019      }10020    }10021  } else {10022    while (begin < end) {10023      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {10024        memcpy((char *)&flavor, begin, sizeof(uint32_t));10025        begin += sizeof(uint32_t);10026      } else {10027        flavor = 0;10028        begin = end;10029      }10030      if (isLittleEndian != sys::IsLittleEndianHost)10031        sys::swapByteOrder(flavor);10032      if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {10033        memcpy((char *)&count, begin, sizeof(uint32_t));10034        begin += sizeof(uint32_t);10035      } else {10036        count = 0;10037        begin = end;10038      }10039      if (isLittleEndian != sys::IsLittleEndianHost)10040        sys::swapByteOrder(count);10041      outs() << "     flavor " << flavor << "\n";10042      outs() << "      count " << count << "\n";10043      outs() << "      state (Unknown cputype/cpusubtype)\n";10044      begin += count * sizeof(uint32_t);10045    }10046  }10047}10048 10049static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {10050  if (dl.cmd == MachO::LC_ID_DYLIB)10051    outs() << "          cmd LC_ID_DYLIB\n";10052  else if (dl.cmd == MachO::LC_LOAD_DYLIB)10053    outs() << "          cmd LC_LOAD_DYLIB\n";10054  else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)10055    outs() << "          cmd LC_LOAD_WEAK_DYLIB\n";10056  else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)10057    outs() << "          cmd LC_REEXPORT_DYLIB\n";10058  else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)10059    outs() << "          cmd LC_LAZY_LOAD_DYLIB\n";10060  else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)10061    outs() << "          cmd LC_LOAD_UPWARD_DYLIB\n";10062  else10063    outs() << "          cmd " << dl.cmd << " (unknown)\n";10064  outs() << "      cmdsize " << dl.cmdsize;10065  if (dl.cmdsize < sizeof(struct MachO::dylib_command))10066    outs() << " Incorrect size\n";10067  else10068    outs() << "\n";10069  if (dl.dylib.name < dl.cmdsize) {10070    const char *P = Ptr + dl.dylib.name;10071    outs() << "         name " << P << " (offset " << dl.dylib.name << ")\n";10072  } else {10073    outs() << "         name ?(bad offset " << dl.dylib.name << ")\n";10074  }10075  outs() << "   time stamp " << dl.dylib.timestamp << " ";10076  time_t t = dl.dylib.timestamp;10077  outs() << ctime(&t);10078  outs() << "      current version ";10079  if (dl.dylib.current_version == 0xffffffff)10080    outs() << "n/a\n";10081  else10082    outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."10083           << ((dl.dylib.current_version >> 8) & 0xff) << "."10084           << (dl.dylib.current_version & 0xff) << "\n";10085  outs() << "compatibility version ";10086  if (dl.dylib.compatibility_version == 0xffffffff)10087    outs() << "n/a\n";10088  else10089    outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."10090           << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."10091           << (dl.dylib.compatibility_version & 0xff) << "\n";10092}10093 10094static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,10095                                     uint32_t object_size) {10096  if (ld.cmd == MachO::LC_CODE_SIGNATURE)10097    outs() << "      cmd LC_CODE_SIGNATURE\n";10098  else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)10099    outs() << "      cmd LC_SEGMENT_SPLIT_INFO\n";10100  else if (ld.cmd == MachO::LC_FUNCTION_STARTS)10101    outs() << "      cmd LC_FUNCTION_STARTS\n";10102  else if (ld.cmd == MachO::LC_DATA_IN_CODE)10103    outs() << "      cmd LC_DATA_IN_CODE\n";10104  else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)10105    outs() << "      cmd LC_DYLIB_CODE_SIGN_DRS\n";10106  else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)10107    outs() << "      cmd LC_LINKER_OPTIMIZATION_HINT\n";10108  else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)10109    outs() << "      cmd LC_DYLD_EXPORTS_TRIE\n";10110  else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)10111    outs() << "      cmd LC_DYLD_CHAINED_FIXUPS\n";10112  else if (ld.cmd == MachO::LC_ATOM_INFO)10113    outs() << "      cmd LC_ATOM_INFO\n";10114  else10115    outs() << "      cmd " << ld.cmd << " (?)\n";10116  outs() << "  cmdsize " << ld.cmdsize;10117  if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))10118    outs() << " Incorrect size\n";10119  else10120    outs() << "\n";10121  outs() << "  dataoff " << ld.dataoff;10122  if (ld.dataoff > object_size)10123    outs() << " (past end of file)\n";10124  else10125    outs() << "\n";10126  outs() << " datasize " << ld.datasize;10127  uint64_t big_size = ld.dataoff;10128  big_size += ld.datasize;10129  if (big_size > object_size)10130    outs() << " (past end of file)\n";10131  else10132    outs() << "\n";10133}10134 10135static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,10136                              uint32_t cputype, bool verbose) {10137  StringRef Buf = Obj->getData();10138  unsigned Index = 0;10139  for (const auto &Command : Obj->load_commands()) {10140    outs() << "Load command " << Index++ << "\n";10141    if (Command.C.cmd == MachO::LC_SEGMENT) {10142      MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);10143      const char *sg_segname = SLC.segname;10144      PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,10145                          SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,10146                          SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),10147                          verbose);10148      for (unsigned j = 0; j < SLC.nsects; j++) {10149        MachO::section S = Obj->getSection(Command, j);10150        PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,10151                     S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,10152                     SLC.cmd, sg_segname, filetype, Buf.size(), verbose);10153      }10154    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10155      MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);10156      const char *sg_segname = SLC_64.segname;10157      PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,10158                          SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,10159                          SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,10160                          SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);10161      for (unsigned j = 0; j < SLC_64.nsects; j++) {10162        MachO::section_64 S_64 = Obj->getSection64(Command, j);10163        PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,10164                     S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,10165                     S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,10166                     sg_segname, filetype, Buf.size(), verbose);10167      }10168    } else if (Command.C.cmd == MachO::LC_SYMTAB) {10169      MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10170      PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());10171    } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {10172      MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();10173      MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10174      PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),10175                               Obj->is64Bit());10176    } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||10177               Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {10178      MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);10179      PrintDyldInfoLoadCommand(DyldInfo, Buf.size());10180    } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||10181               Command.C.cmd == MachO::LC_ID_DYLINKER ||10182               Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {10183      MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);10184      PrintDyldLoadCommand(Dyld, Command.Ptr);10185    } else if (Command.C.cmd == MachO::LC_UUID) {10186      MachO::uuid_command Uuid = Obj->getUuidCommand(Command);10187      PrintUuidLoadCommand(Uuid);10188    } else if (Command.C.cmd == MachO::LC_RPATH) {10189      MachO::rpath_command Rpath = Obj->getRpathCommand(Command);10190      PrintRpathLoadCommand(Rpath, Command.Ptr);10191    } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||10192               Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||10193               Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||10194               Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {10195      MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);10196      PrintVersionMinLoadCommand(Vd);10197    } else if (Command.C.cmd == MachO::LC_NOTE) {10198      MachO::note_command Nt = Obj->getNoteLoadCommand(Command);10199      PrintNoteLoadCommand(Nt);10200    } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {10201      MachO::build_version_command Bv =10202          Obj->getBuildVersionLoadCommand(Command);10203      PrintBuildVersionLoadCommand(Obj, Bv, verbose);10204    } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {10205      MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);10206      PrintSourceVersionCommand(Sd);10207    } else if (Command.C.cmd == MachO::LC_MAIN) {10208      MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);10209      PrintEntryPointCommand(Ep);10210    } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {10211      MachO::encryption_info_command Ei =10212          Obj->getEncryptionInfoCommand(Command);10213      PrintEncryptionInfoCommand(Ei, Buf.size());10214    } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {10215      MachO::encryption_info_command_64 Ei =10216          Obj->getEncryptionInfoCommand64(Command);10217      PrintEncryptionInfoCommand64(Ei, Buf.size());10218    } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {10219      MachO::linker_option_command Lo =10220          Obj->getLinkerOptionLoadCommand(Command);10221      PrintLinkerOptionCommand(Lo, Command.Ptr);10222    } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {10223      MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);10224      PrintSubFrameworkCommand(Sf, Command.Ptr);10225    } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {10226      MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);10227      PrintSubUmbrellaCommand(Sf, Command.Ptr);10228    } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {10229      MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);10230      PrintSubLibraryCommand(Sl, Command.Ptr);10231    } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {10232      MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);10233      PrintSubClientCommand(Sc, Command.Ptr);10234    } else if (Command.C.cmd == MachO::LC_ROUTINES) {10235      MachO::routines_command Rc = Obj->getRoutinesCommand(Command);10236      PrintRoutinesCommand(Rc);10237    } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {10238      MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);10239      PrintRoutinesCommand64(Rc);10240    } else if (Command.C.cmd == MachO::LC_THREAD ||10241               Command.C.cmd == MachO::LC_UNIXTHREAD) {10242      MachO::thread_command Tc = Obj->getThreadCommand(Command);10243      PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);10244    } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||10245               Command.C.cmd == MachO::LC_ID_DYLIB ||10246               Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||10247               Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||10248               Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||10249               Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {10250      MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);10251      PrintDylibCommand(Dl, Command.Ptr);10252    } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||10253               Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||10254               Command.C.cmd == MachO::LC_FUNCTION_STARTS ||10255               Command.C.cmd == MachO::LC_DATA_IN_CODE ||10256               Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||10257               Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||10258               Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||10259               Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||10260               Command.C.cmd == MachO::LC_ATOM_INFO) {10261      MachO::linkedit_data_command Ld =10262          Obj->getLinkeditDataLoadCommand(Command);10263      PrintLinkEditDataCommand(Ld, Buf.size());10264    } else {10265      outs() << "      cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)10266             << ")\n";10267      outs() << "  cmdsize " << Command.C.cmdsize << "\n";10268      // TODO: get and print the raw bytes of the load command.10269    }10270    // TODO: print all the other kinds of load commands.10271  }10272}10273 10274static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {10275  if (Obj->is64Bit()) {10276    MachO::mach_header_64 H_64;10277    H_64 = Obj->getHeader64();10278    PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,10279                    H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);10280  } else {10281    MachO::mach_header H;10282    H = Obj->getHeader();10283    PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,10284                    H.sizeofcmds, H.flags, verbose);10285  }10286}10287 10288void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {10289  const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10290  PrintMachHeader(file, Verbose);10291}10292 10293void MachODumper::printPrivateHeaders() {10294  printMachOFileHeader(&Obj);10295  if (!FirstPrivateHeader)10296    printMachOLoadCommands(&Obj);10297}10298 10299void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {10300  const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10301  uint32_t filetype = 0;10302  uint32_t cputype = 0;10303  if (file->is64Bit()) {10304    MachO::mach_header_64 H_64;10305    H_64 = file->getHeader64();10306    filetype = H_64.filetype;10307    cputype = H_64.cputype;10308  } else {10309    MachO::mach_header H;10310    H = file->getHeader();10311    filetype = H.filetype;10312    cputype = H.cputype;10313  }10314  PrintLoadCommands(file, filetype, cputype, Verbose);10315}10316 10317//===----------------------------------------------------------------------===//10318// export trie dumping10319//===----------------------------------------------------------------------===//10320 10321static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {10322  uint64_t BaseSegmentAddress = 0;10323  for (const auto &Command : Obj->load_commands()) {10324    if (Command.C.cmd == MachO::LC_SEGMENT) {10325      MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);10326      if (Seg.fileoff == 0 && Seg.filesize != 0) {10327        BaseSegmentAddress = Seg.vmaddr;10328        break;10329      }10330    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10331      MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);10332      if (Seg.fileoff == 0 && Seg.filesize != 0) {10333        BaseSegmentAddress = Seg.vmaddr;10334        break;10335      }10336    }10337  }10338  Error Err = Error::success();10339  for (const object::ExportEntry &Entry : Obj->exports(Err)) {10340    uint64_t Flags = Entry.flags();10341    bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);10342    bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);10343    bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10344                        MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);10345    bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10346                MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);10347    bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);10348    if (ReExport)10349      outs() << "[re-export] ";10350    else10351      outs() << format("0x%08llX  ",10352                       Entry.address() + BaseSegmentAddress);10353    outs() << Entry.name();10354    if (WeakDef || ThreadLocal || Resolver || Abs) {10355      ListSeparator LS;10356      outs() << " [";10357      if (WeakDef)10358        outs() << LS << "weak_def";10359      if (ThreadLocal)10360        outs() << LS << "per-thread";10361      if (Abs)10362        outs() << LS << "absolute";10363      if (Resolver)10364        outs() << LS << format("resolver=0x%08llX", Entry.other());10365      outs() << "]";10366    }10367    if (ReExport) {10368      StringRef DylibName = "unknown";10369      int Ordinal = Entry.other() - 1;10370      Obj->getLibraryShortNameByIndex(Ordinal, DylibName);10371      if (Entry.otherName().empty())10372        outs() << " (from " << DylibName << ")";10373      else10374        outs() << " (" << Entry.otherName() << " from " << DylibName << ")";10375    }10376    outs() << "\n";10377  }10378  if (Err)10379    reportError(std::move(Err), Obj->getFileName());10380}10381 10382//===----------------------------------------------------------------------===//10383// rebase table dumping10384//===----------------------------------------------------------------------===//10385 10386static void printMachORebaseTable(object::MachOObjectFile *Obj) {10387  outs() << "segment  section            address     type\n";10388  Error Err = Error::success();10389  for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {10390    StringRef SegmentName = Entry.segmentName();10391    StringRef SectionName = Entry.sectionName();10392    uint64_t Address = Entry.address();10393 10394    // Table lines look like: __DATA  __nl_symbol_ptr  0x0000F00C  pointer10395    outs() << format("%-8s %-18s 0x%08" PRIX64 "  %s\n",10396                     SegmentName.str().c_str(), SectionName.str().c_str(),10397                     Address, Entry.typeName().str().c_str());10398  }10399  if (Err)10400    reportError(std::move(Err), Obj->getFileName());10401}10402 10403static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {10404  StringRef DylibName;10405  switch (Ordinal) {10406  case MachO::BIND_SPECIAL_DYLIB_SELF:10407    return "this-image";10408  case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:10409    return "main-executable";10410  case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:10411    return "flat-namespace";10412  case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:10413    return "weak";10414  default:10415    if (Ordinal > 0) {10416      std::error_code EC =10417          Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);10418      if (EC)10419        return "<<bad library ordinal>>";10420      return DylibName;10421    }10422  }10423  return "<<unknown special ordinal>>";10424}10425 10426//===----------------------------------------------------------------------===//10427// bind table dumping10428//===----------------------------------------------------------------------===//10429 10430static void printMachOBindTable(object::MachOObjectFile *Obj) {10431  // Build table of sections so names can used in final output.10432  outs() << "segment  section            address    type       "10433            "addend dylib            symbol\n";10434  Error Err = Error::success();10435  for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {10436    StringRef SegmentName = Entry.segmentName();10437    StringRef SectionName = Entry.sectionName();10438    uint64_t Address = Entry.address();10439 10440    // Table lines look like:10441    //  __DATA  __got  0x00012010    pointer   0 libSystem ___stack_chk_guard10442    StringRef Attr;10443    if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)10444      Attr = " (weak_import)";10445    outs() << left_justify(SegmentName, 8) << " "10446           << left_justify(SectionName, 18) << " "10447           << format_hex(Address, 10, true) << " "10448           << left_justify(Entry.typeName(), 8) << " "10449           << format_decimal(Entry.addend(), 8) << " "10450           << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10451           << Entry.symbolName() << Attr << "\n";10452  }10453  if (Err)10454    reportError(std::move(Err), Obj->getFileName());10455}10456 10457//===----------------------------------------------------------------------===//10458// lazy bind table dumping10459//===----------------------------------------------------------------------===//10460 10461static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {10462  outs() << "segment  section            address     "10463            "dylib            symbol\n";10464  Error Err = Error::success();10465  for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {10466    StringRef SegmentName = Entry.segmentName();10467    StringRef SectionName = Entry.sectionName();10468    uint64_t Address = Entry.address();10469 10470    // Table lines look like:10471    //  __DATA  __got  0x00012010 libSystem ___stack_chk_guard10472    outs() << left_justify(SegmentName, 8) << " "10473           << left_justify(SectionName, 18) << " "10474           << format_hex(Address, 10, true) << " "10475           << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10476           << Entry.symbolName() << "\n";10477  }10478  if (Err)10479    reportError(std::move(Err), Obj->getFileName());10480}10481 10482//===----------------------------------------------------------------------===//10483// weak bind table dumping10484//===----------------------------------------------------------------------===//10485 10486static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {10487  outs() << "segment  section            address     "10488            "type       addend   symbol\n";10489  Error Err = Error::success();10490  for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {10491    // Strong symbols don't have a location to update.10492    if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {10493      outs() << "                                        strong              "10494             << Entry.symbolName() << "\n";10495      continue;10496    }10497    StringRef SegmentName = Entry.segmentName();10498    StringRef SectionName = Entry.sectionName();10499    uint64_t Address = Entry.address();10500 10501    // Table lines look like:10502    // __DATA  __data  0x00001000  pointer    0   _foo10503    outs() << left_justify(SegmentName, 8) << " "10504           << left_justify(SectionName, 18) << " "10505           << format_hex(Address, 10, true) << " "10506           << left_justify(Entry.typeName(), 8) << " "10507           << format_decimal(Entry.addend(), 8) << "   " << Entry.symbolName()10508           << "\n";10509  }10510  if (Err)10511    reportError(std::move(Err), Obj->getFileName());10512}10513 10514// get_dyld_bind_info_symbolname() is used for disassembly and passed an10515// address, ReferenceValue, in the Mach-O file and looks in the dyld bind10516// information for that address. If the address is found its binding symbol10517// name is returned.  If not nullptr is returned.10518static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,10519                                                 struct DisassembleInfo *info) {10520  if (info->bindtable == nullptr) {10521    info->bindtable = std::make_unique<SymbolAddressMap>();10522    Error Err = Error::success();10523    for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {10524      uint64_t Address = Entry.address();10525      StringRef name = Entry.symbolName();10526      if (!name.empty())10527        (*info->bindtable)[Address] = name;10528    }10529    if (Err)10530      reportError(std::move(Err), info->O->getFileName());10531  }10532  auto name = info->bindtable->lookup(ReferenceValue);10533  return !name.empty() ? name.data() : nullptr;10534}10535 10536void objdump::printLazyBindTable(ObjectFile *o) {10537  outs() << "\nLazy bind table:\n";10538  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10539    printMachOLazyBindTable(MachO);10540  else10541    WithColor::error()10542        << "This operation is only currently supported "10543           "for Mach-O executable files.\n";10544}10545 10546void objdump::printWeakBindTable(ObjectFile *o) {10547  outs() << "\nWeak bind table:\n";10548  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10549    printMachOWeakBindTable(MachO);10550  else10551    WithColor::error()10552        << "This operation is only currently supported "10553           "for Mach-O executable files.\n";10554}10555 10556void objdump::printExportsTrie(const ObjectFile *o) {10557  outs() << "\nExports trie:\n";10558  if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10559    printMachOExportsTrie(MachO);10560  else10561    WithColor::error()10562        << "This operation is only currently supported "10563           "for Mach-O executable files.\n";10564}10565 10566void objdump::printRebaseTable(ObjectFile *o) {10567  outs() << "\nRebase table:\n";10568  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10569    printMachORebaseTable(MachO);10570  else10571    WithColor::error()10572        << "This operation is only currently supported "10573           "for Mach-O executable files.\n";10574}10575 10576void objdump::printBindTable(ObjectFile *o) {10577  outs() << "\nBind table:\n";10578  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10579    printMachOBindTable(MachO);10580  else10581    WithColor::error()10582        << "This operation is only currently supported "10583           "for Mach-O executable files.\n";10584}10585