Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
35231 views
//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the MachO-specific dumper for llvm-objdump.9//10//===----------------------------------------------------------------------===//1112#include "MachODump.h"1314#include "ObjdumpOptID.h"15#include "llvm-objdump.h"16#include "llvm-c/Disassembler.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/BinaryFormat/MachO.h"20#include "llvm/Config/config.h"21#include "llvm/DebugInfo/DIContext.h"22#include "llvm/DebugInfo/DWARF/DWARFContext.h"23#include "llvm/Demangle/Demangle.h"24#include "llvm/MC/MCAsmInfo.h"25#include "llvm/MC/MCContext.h"26#include "llvm/MC/MCDisassembler/MCDisassembler.h"27#include "llvm/MC/MCInst.h"28#include "llvm/MC/MCInstPrinter.h"29#include "llvm/MC/MCInstrDesc.h"30#include "llvm/MC/MCInstrInfo.h"31#include "llvm/MC/MCRegisterInfo.h"32#include "llvm/MC/MCSubtargetInfo.h"33#include "llvm/MC/MCTargetOptions.h"34#include "llvm/MC/TargetRegistry.h"35#include "llvm/Object/MachO.h"36#include "llvm/Object/MachOUniversal.h"37#include "llvm/Option/ArgList.h"38#include "llvm/Support/Casting.h"39#include "llvm/Support/Debug.h"40#include "llvm/Support/Endian.h"41#include "llvm/Support/Format.h"42#include "llvm/Support/FormattedStream.h"43#include "llvm/Support/GraphWriter.h"44#include "llvm/Support/LEB128.h"45#include "llvm/Support/MemoryBuffer.h"46#include "llvm/Support/TargetSelect.h"47#include "llvm/Support/ToolOutputFile.h"48#include "llvm/Support/WithColor.h"49#include "llvm/Support/raw_ostream.h"50#include "llvm/TargetParser/Triple.h"51#include <algorithm>52#include <cstring>53#include <system_error>5455using namespace llvm;56using namespace llvm::object;57using namespace llvm::objdump;5859bool objdump::FirstPrivateHeader;60bool objdump::ExportsTrie;61bool objdump::Rebase;62bool objdump::Rpaths;63bool objdump::Bind;64bool objdump::LazyBind;65bool objdump::WeakBind;66static bool UseDbg;67static std::string DSYMFile;68bool objdump::FullLeadingAddr;69bool objdump::LeadingHeaders;70bool objdump::UniversalHeaders;71static bool ArchiveMemberOffsets;72bool objdump::IndirectSymbols;73bool objdump::DataInCode;74FunctionStartsMode objdump::FunctionStartsType =75objdump::FunctionStartsMode::None;76bool objdump::LinkOptHints;77bool objdump::InfoPlist;78bool objdump::ChainedFixups;79bool objdump::DyldInfo;80bool objdump::DylibsUsed;81bool objdump::DylibId;82bool objdump::Verbose;83bool objdump::ObjcMetaData;84std::string objdump::DisSymName;85bool objdump::SymbolicOperands;86static std::vector<std::string> ArchFlags;8788static bool ArchAll = false;89static std::string ThumbTripleName;9091static StringRef ordinalName(const object::MachOObjectFile *, int);9293void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {94FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);95ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);96Rebase = InputArgs.hasArg(OBJDUMP_rebase);97Rpaths = InputArgs.hasArg(OBJDUMP_rpaths);98Bind = InputArgs.hasArg(OBJDUMP_bind);99LazyBind = InputArgs.hasArg(OBJDUMP_lazy_bind);100WeakBind = InputArgs.hasArg(OBJDUMP_weak_bind);101UseDbg = InputArgs.hasArg(OBJDUMP_g);102DSYMFile = InputArgs.getLastArgValue(OBJDUMP_dsym_EQ).str();103FullLeadingAddr = InputArgs.hasArg(OBJDUMP_full_leading_addr);104LeadingHeaders = !InputArgs.hasArg(OBJDUMP_no_leading_headers);105UniversalHeaders = InputArgs.hasArg(OBJDUMP_universal_headers);106ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);107IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);108DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);109if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {110FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())111.Case("addrs", FunctionStartsMode::Addrs)112.Case("names", FunctionStartsMode::Names)113.Case("both", FunctionStartsMode::Both)114.Default(FunctionStartsMode::None);115if (FunctionStartsType == FunctionStartsMode::None)116invalidArgValue(A);117}118LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);119InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);120ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);121DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);122DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);123DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);124Verbose = !InputArgs.hasArg(OBJDUMP_non_verbose);125ObjcMetaData = InputArgs.hasArg(OBJDUMP_objc_meta_data);126DisSymName = InputArgs.getLastArgValue(OBJDUMP_dis_symname).str();127SymbolicOperands = !InputArgs.hasArg(OBJDUMP_no_symbolic_operands);128ArchFlags = InputArgs.getAllArgValues(OBJDUMP_arch_EQ);129}130131static const Target *GetTarget(const MachOObjectFile *MachOObj,132const char **McpuDefault,133const Target **ThumbTarget) {134// Figure out the target triple.135Triple TT(TripleName);136if (TripleName.empty()) {137TT = MachOObj->getArchTriple(McpuDefault);138TripleName = TT.str();139}140141if (TT.getArch() == Triple::arm) {142// We've inferred a 32-bit ARM target from the object file. All MachO CPUs143// that support ARM are also capable of Thumb mode.144Triple ThumbTriple = TT;145std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();146ThumbTriple.setArchName(ThumbName);147ThumbTripleName = ThumbTriple.str();148}149150// Get the target specific parser.151std::string Error;152const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);153if (TheTarget && ThumbTripleName.empty())154return TheTarget;155156*ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);157if (*ThumbTarget)158return TheTarget;159160WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";161if (!TheTarget)162errs() << TripleName;163else164errs() << ThumbTripleName;165errs() << "', see --version and --triple.\n";166return nullptr;167}168169namespace {170struct SymbolSorter {171bool operator()(const SymbolRef &A, const SymbolRef &B) {172Expected<SymbolRef::Type> ATypeOrErr = A.getType();173if (!ATypeOrErr)174reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());175SymbolRef::Type AType = *ATypeOrErr;176Expected<SymbolRef::Type> BTypeOrErr = B.getType();177if (!BTypeOrErr)178reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());179SymbolRef::Type BType = *BTypeOrErr;180uint64_t AAddr =181(AType != SymbolRef::ST_Function) ? 0 : cantFail(A.getValue());182uint64_t BAddr =183(BType != SymbolRef::ST_Function) ? 0 : cantFail(B.getValue());184return AAddr < BAddr;185}186};187188class MachODumper : public Dumper {189const object::MachOObjectFile &Obj;190191public:192MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}193void printPrivateHeaders() override;194};195} // namespace196197std::unique_ptr<Dumper>198objdump::createMachODumper(const object::MachOObjectFile &Obj) {199return std::make_unique<MachODumper>(Obj);200}201202// Types for the storted data in code table that is built before disassembly203// and the predicate function to sort them.204typedef std::pair<uint64_t, DiceRef> DiceTableEntry;205typedef std::vector<DiceTableEntry> DiceTable;206typedef DiceTable::iterator dice_table_iterator;207208// This is used to search for a data in code table entry for the PC being209// disassembled. The j parameter has the PC in j.first. A single data in code210// table entry can cover many bytes for each of its Kind's. So if the offset,211// aka the i.first value, of the data in code table entry plus its Length212// covers the PC being searched for this will return true. If not it will213// return false.214static bool compareDiceTableEntries(const DiceTableEntry &i,215const DiceTableEntry &j) {216uint16_t Length;217i.second.getLength(Length);218219return j.first >= i.first && j.first < i.first + Length;220}221222static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,223unsigned short Kind) {224uint32_t Value, Size = 1;225226switch (Kind) {227default:228case MachO::DICE_KIND_DATA:229if (Length >= 4) {230if (ShowRawInsn)231dumpBytes(ArrayRef(bytes, 4), outs());232Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];233outs() << "\t.long " << Value;234Size = 4;235} else if (Length >= 2) {236if (ShowRawInsn)237dumpBytes(ArrayRef(bytes, 2), outs());238Value = bytes[1] << 8 | bytes[0];239outs() << "\t.short " << Value;240Size = 2;241} else {242if (ShowRawInsn)243dumpBytes(ArrayRef(bytes, 2), outs());244Value = bytes[0];245outs() << "\t.byte " << Value;246Size = 1;247}248if (Kind == MachO::DICE_KIND_DATA)249outs() << "\t@ KIND_DATA\n";250else251outs() << "\t@ data in code kind = " << Kind << "\n";252break;253case MachO::DICE_KIND_JUMP_TABLE8:254if (ShowRawInsn)255dumpBytes(ArrayRef(bytes, 1), outs());256Value = bytes[0];257outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";258Size = 1;259break;260case MachO::DICE_KIND_JUMP_TABLE16:261if (ShowRawInsn)262dumpBytes(ArrayRef(bytes, 2), outs());263Value = bytes[1] << 8 | bytes[0];264outs() << "\t.short " << format("%5u", Value & 0xffff)265<< "\t@ KIND_JUMP_TABLE16\n";266Size = 2;267break;268case MachO::DICE_KIND_JUMP_TABLE32:269case MachO::DICE_KIND_ABS_JUMP_TABLE32:270if (ShowRawInsn)271dumpBytes(ArrayRef(bytes, 4), outs());272Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];273outs() << "\t.long " << Value;274if (Kind == MachO::DICE_KIND_JUMP_TABLE32)275outs() << "\t@ KIND_JUMP_TABLE32\n";276else277outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";278Size = 4;279break;280}281return Size;282}283284static void getSectionsAndSymbols(MachOObjectFile *MachOObj,285std::vector<SectionRef> &Sections,286std::vector<SymbolRef> &Symbols,287SmallVectorImpl<uint64_t> &FoundFns,288uint64_t &BaseSegmentAddress) {289const StringRef FileName = MachOObj->getFileName();290for (const SymbolRef &Symbol : MachOObj->symbols()) {291StringRef SymName = unwrapOrError(Symbol.getName(), FileName);292if (!SymName.starts_with("ltmp"))293Symbols.push_back(Symbol);294}295296append_range(Sections, MachOObj->sections());297298bool BaseSegmentAddressSet = false;299for (const auto &Command : MachOObj->load_commands()) {300if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {301// We found a function starts segment, parse the addresses for later302// consumption.303MachO::linkedit_data_command LLC =304MachOObj->getLinkeditDataLoadCommand(Command);305306MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);307} else if (Command.C.cmd == MachO::LC_SEGMENT) {308MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);309StringRef SegName = SLC.segname;310if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {311BaseSegmentAddressSet = true;312BaseSegmentAddress = SLC.vmaddr;313}314} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {315MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command);316StringRef SegName = SLC.segname;317if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {318BaseSegmentAddressSet = true;319BaseSegmentAddress = SLC.vmaddr;320}321}322}323}324325static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,326DiceTable &Dices, uint64_t &InstSize) {327// Check the data in code table here to see if this is data not an328// instruction to be disassembled.329DiceTable Dice;330Dice.push_back(std::make_pair(PC, DiceRef()));331dice_table_iterator DTI =332std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),333compareDiceTableEntries);334if (DTI != Dices.end()) {335uint16_t Length;336DTI->second.getLength(Length);337uint16_t Kind;338DTI->second.getKind(Kind);339InstSize = DumpDataInCode(bytes, Length, Kind);340if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&341(PC == (DTI->first + Length - 1)) && (Length & 1))342InstSize++;343return true;344}345return false;346}347348static void printRelocationTargetName(const MachOObjectFile *O,349const MachO::any_relocation_info &RE,350raw_string_ostream &Fmt) {351// Target of a scattered relocation is an address. In the interest of352// generating pretty output, scan through the symbol table looking for a353// symbol that aligns with that address. If we find one, print it.354// Otherwise, we just print the hex address of the target.355const StringRef FileName = O->getFileName();356if (O->isRelocationScattered(RE)) {357uint32_t Val = O->getPlainRelocationSymbolNum(RE);358359for (const SymbolRef &Symbol : O->symbols()) {360uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);361if (Addr != Val)362continue;363Fmt << unwrapOrError(Symbol.getName(), FileName);364return;365}366367// If we couldn't find a symbol that this relocation refers to, try368// to find a section beginning instead.369for (const SectionRef &Section : ToolSectionFilter(*O)) {370uint64_t Addr = Section.getAddress();371if (Addr != Val)372continue;373StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName());374Fmt << NameOrErr;375return;376}377378Fmt << format("0x%x", Val);379return;380}381382StringRef S;383bool isExtern = O->getPlainRelocationExternal(RE);384uint64_t Val = O->getPlainRelocationSymbolNum(RE);385386if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&387(O->getArch() == Triple::aarch64 || O->getArch() == Triple::aarch64_be)) {388Fmt << format("0x%0" PRIx64, Val);389return;390}391392if (isExtern) {393symbol_iterator SI = O->symbol_begin();394std::advance(SI, Val);395S = unwrapOrError(SI->getName(), FileName);396} else {397section_iterator SI = O->section_begin();398// Adjust for the fact that sections are 1-indexed.399if (Val == 0) {400Fmt << "0 (?,?)";401return;402}403uint32_t I = Val - 1;404while (I != 0 && SI != O->section_end()) {405--I;406std::advance(SI, 1);407}408if (SI == O->section_end()) {409Fmt << Val << " (?,?)";410} else {411if (Expected<StringRef> NameOrErr = SI->getName())412S = *NameOrErr;413else414consumeError(NameOrErr.takeError());415}416}417418Fmt << S;419}420421Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,422const RelocationRef &RelRef,423SmallVectorImpl<char> &Result) {424DataRefImpl Rel = RelRef.getRawDataRefImpl();425MachO::any_relocation_info RE = Obj->getRelocation(Rel);426427unsigned Arch = Obj->getArch();428429std::string FmtBuf;430raw_string_ostream Fmt(FmtBuf);431unsigned Type = Obj->getAnyRelocationType(RE);432bool IsPCRel = Obj->getAnyRelocationPCRel(RE);433434// Determine any addends that should be displayed with the relocation.435// These require decoding the relocation type, which is triple-specific.436437// X86_64 has entirely custom relocation types.438if (Arch == Triple::x86_64) {439switch (Type) {440case MachO::X86_64_RELOC_GOT_LOAD:441case MachO::X86_64_RELOC_GOT: {442printRelocationTargetName(Obj, RE, Fmt);443Fmt << "@GOT";444if (IsPCRel)445Fmt << "PCREL";446break;447}448case MachO::X86_64_RELOC_SUBTRACTOR: {449DataRefImpl RelNext = Rel;450Obj->moveRelocationNext(RelNext);451MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);452453// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type454// X86_64_RELOC_UNSIGNED.455// NOTE: Scattered relocations don't exist on x86_64.456unsigned RType = Obj->getAnyRelocationType(RENext);457if (RType != MachO::X86_64_RELOC_UNSIGNED)458reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "459"X86_64_RELOC_SUBTRACTOR.");460461// The X86_64_RELOC_UNSIGNED contains the minuend symbol;462// X86_64_RELOC_SUBTRACTOR contains the subtrahend.463printRelocationTargetName(Obj, RENext, Fmt);464Fmt << "-";465printRelocationTargetName(Obj, RE, Fmt);466break;467}468case MachO::X86_64_RELOC_TLV:469printRelocationTargetName(Obj, RE, Fmt);470Fmt << "@TLV";471if (IsPCRel)472Fmt << "P";473break;474case MachO::X86_64_RELOC_SIGNED_1:475printRelocationTargetName(Obj, RE, Fmt);476Fmt << "-1";477break;478case MachO::X86_64_RELOC_SIGNED_2:479printRelocationTargetName(Obj, RE, Fmt);480Fmt << "-2";481break;482case MachO::X86_64_RELOC_SIGNED_4:483printRelocationTargetName(Obj, RE, Fmt);484Fmt << "-4";485break;486default:487printRelocationTargetName(Obj, RE, Fmt);488break;489}490// X86 and ARM share some relocation types in common.491} else if (Arch == Triple::x86 || Arch == Triple::arm ||492Arch == Triple::ppc) {493// Generic relocation types...494switch (Type) {495case MachO::GENERIC_RELOC_PAIR: // prints no info496return Error::success();497case MachO::GENERIC_RELOC_SECTDIFF: {498DataRefImpl RelNext = Rel;499Obj->moveRelocationNext(RelNext);500MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);501502// X86 sect diff's must be followed by a relocation of type503// GENERIC_RELOC_PAIR.504unsigned RType = Obj->getAnyRelocationType(RENext);505506if (RType != MachO::GENERIC_RELOC_PAIR)507reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "508"GENERIC_RELOC_SECTDIFF.");509510printRelocationTargetName(Obj, RE, Fmt);511Fmt << "-";512printRelocationTargetName(Obj, RENext, Fmt);513break;514}515}516517if (Arch == Triple::x86 || Arch == Triple::ppc) {518switch (Type) {519case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {520DataRefImpl RelNext = Rel;521Obj->moveRelocationNext(RelNext);522MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);523524// X86 sect diff's must be followed by a relocation of type525// GENERIC_RELOC_PAIR.526unsigned RType = Obj->getAnyRelocationType(RENext);527if (RType != MachO::GENERIC_RELOC_PAIR)528reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "529"GENERIC_RELOC_LOCAL_SECTDIFF.");530531printRelocationTargetName(Obj, RE, Fmt);532Fmt << "-";533printRelocationTargetName(Obj, RENext, Fmt);534break;535}536case MachO::GENERIC_RELOC_TLV: {537printRelocationTargetName(Obj, RE, Fmt);538Fmt << "@TLV";539if (IsPCRel)540Fmt << "P";541break;542}543default:544printRelocationTargetName(Obj, RE, Fmt);545}546} else { // ARM-specific relocations547switch (Type) {548case MachO::ARM_RELOC_HALF:549case MachO::ARM_RELOC_HALF_SECTDIFF: {550// Half relocations steal a bit from the length field to encode551// whether this is an upper16 or a lower16 relocation.552bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;553554if (isUpper)555Fmt << ":upper16:(";556else557Fmt << ":lower16:(";558printRelocationTargetName(Obj, RE, Fmt);559560DataRefImpl RelNext = Rel;561Obj->moveRelocationNext(RelNext);562MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);563564// ARM half relocs must be followed by a relocation of type565// ARM_RELOC_PAIR.566unsigned RType = Obj->getAnyRelocationType(RENext);567if (RType != MachO::ARM_RELOC_PAIR)568reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "569"ARM_RELOC_HALF");570571// NOTE: The half of the target virtual address is stashed in the572// address field of the secondary relocation, but we can't reverse573// engineer the constant offset from it without decoding the movw/movt574// instruction to find the other half in its immediate field.575576// ARM_RELOC_HALF_SECTDIFF encodes the second section in the577// symbol/section pointer of the follow-on relocation.578if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {579Fmt << "-";580printRelocationTargetName(Obj, RENext, Fmt);581}582583Fmt << ")";584break;585}586default: {587printRelocationTargetName(Obj, RE, Fmt);588}589}590}591} else592printRelocationTargetName(Obj, RE, Fmt);593594Fmt.flush();595Result.append(FmtBuf.begin(), FmtBuf.end());596return Error::success();597}598599static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,600uint32_t n, uint32_t count,601uint32_t stride, uint64_t addr) {602MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();603uint32_t nindirectsyms = Dysymtab.nindirectsyms;604if (n > nindirectsyms)605outs() << " (entries start past the end of the indirect symbol "606"table) (reserved1 field greater than the table size)";607else if (n + count > nindirectsyms)608outs() << " (entries extends past the end of the indirect symbol "609"table)";610outs() << "\n";611uint32_t cputype = O->getHeader().cputype;612if (cputype & MachO::CPU_ARCH_ABI64)613outs() << "address index";614else615outs() << "address index";616if (verbose)617outs() << " name\n";618else619outs() << "\n";620for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {621if (cputype & MachO::CPU_ARCH_ABI64)622outs() << format("0x%016" PRIx64, addr + j * stride) << " ";623else624outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";625MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();626uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);627if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {628outs() << "LOCAL\n";629continue;630}631if (indirect_symbol ==632(MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {633outs() << "LOCAL ABSOLUTE\n";634continue;635}636if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {637outs() << "ABSOLUTE\n";638continue;639}640outs() << format("%5u ", indirect_symbol);641if (verbose) {642MachO::symtab_command Symtab = O->getSymtabLoadCommand();643if (indirect_symbol < Symtab.nsyms) {644symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);645SymbolRef Symbol = *Sym;646outs() << unwrapOrError(Symbol.getName(), O->getFileName());647} else {648outs() << "?";649}650}651outs() << "\n";652}653}654655static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {656for (const auto &Load : O->load_commands()) {657if (Load.C.cmd == MachO::LC_SEGMENT_64) {658MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);659for (unsigned J = 0; J < Seg.nsects; ++J) {660MachO::section_64 Sec = O->getSection64(Load, J);661uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;662if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||663section_type == MachO::S_LAZY_SYMBOL_POINTERS ||664section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||665section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||666section_type == MachO::S_SYMBOL_STUBS) {667uint32_t stride;668if (section_type == MachO::S_SYMBOL_STUBS)669stride = Sec.reserved2;670else671stride = 8;672if (stride == 0) {673outs() << "Can't print indirect symbols for (" << Sec.segname << ","674<< Sec.sectname << ") "675<< "(size of stubs in reserved2 field is zero)\n";676continue;677}678uint32_t count = Sec.size / stride;679outs() << "Indirect symbols for (" << Sec.segname << ","680<< Sec.sectname << ") " << count << " entries";681uint32_t n = Sec.reserved1;682PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);683}684}685} else if (Load.C.cmd == MachO::LC_SEGMENT) {686MachO::segment_command Seg = O->getSegmentLoadCommand(Load);687for (unsigned J = 0; J < Seg.nsects; ++J) {688MachO::section Sec = O->getSection(Load, J);689uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;690if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||691section_type == MachO::S_LAZY_SYMBOL_POINTERS ||692section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||693section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||694section_type == MachO::S_SYMBOL_STUBS) {695uint32_t stride;696if (section_type == MachO::S_SYMBOL_STUBS)697stride = Sec.reserved2;698else699stride = 4;700if (stride == 0) {701outs() << "Can't print indirect symbols for (" << Sec.segname << ","702<< Sec.sectname << ") "703<< "(size of stubs in reserved2 field is zero)\n";704continue;705}706uint32_t count = Sec.size / stride;707outs() << "Indirect symbols for (" << Sec.segname << ","708<< Sec.sectname << ") " << count << " entries";709uint32_t n = Sec.reserved1;710PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);711}712}713}714}715}716717static void PrintRType(const uint64_t cputype, const unsigned r_type) {718static char const *generic_r_types[] = {719"VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",720" 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",721" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "722};723static char const *x86_64_r_types[] = {724"UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",725"SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",726" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "727};728static char const *arm_r_types[] = {729"VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",730"BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",731" 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "732};733static char const *arm64_r_types[] = {734"UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",735"GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",736"ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "737};738739if (r_type > 0xf){740outs() << format("%-7u", r_type) << " ";741return;742}743switch (cputype) {744case MachO::CPU_TYPE_I386:745outs() << generic_r_types[r_type];746break;747case MachO::CPU_TYPE_X86_64:748outs() << x86_64_r_types[r_type];749break;750case MachO::CPU_TYPE_ARM:751outs() << arm_r_types[r_type];752break;753case MachO::CPU_TYPE_ARM64:754case MachO::CPU_TYPE_ARM64_32:755outs() << arm64_r_types[r_type];756break;757default:758outs() << format("%-7u ", r_type);759}760}761762static void PrintRLength(const uint64_t cputype, const unsigned r_type,763const unsigned r_length, const bool previous_arm_half){764if (cputype == MachO::CPU_TYPE_ARM &&765(r_type == MachO::ARM_RELOC_HALF ||766r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {767if ((r_length & 0x1) == 0)768outs() << "lo/";769else770outs() << "hi/";771if ((r_length & 0x1) == 0)772outs() << "arm ";773else774outs() << "thm ";775} else {776switch (r_length) {777case 0:778outs() << "byte ";779break;780case 1:781outs() << "word ";782break;783case 2:784outs() << "long ";785break;786case 3:787if (cputype == MachO::CPU_TYPE_X86_64)788outs() << "quad ";789else790outs() << format("?(%2d) ", r_length);791break;792default:793outs() << format("?(%2d) ", r_length);794}795}796}797798static void PrintRelocationEntries(const MachOObjectFile *O,799const relocation_iterator Begin,800const relocation_iterator End,801const uint64_t cputype,802const bool verbose) {803const MachO::symtab_command Symtab = O->getSymtabLoadCommand();804bool previous_arm_half = false;805bool previous_sectdiff = false;806uint32_t sectdiff_r_type = 0;807808for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {809const DataRefImpl Rel = Reloc->getRawDataRefImpl();810const MachO::any_relocation_info RE = O->getRelocation(Rel);811const unsigned r_type = O->getAnyRelocationType(RE);812const bool r_scattered = O->isRelocationScattered(RE);813const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);814const unsigned r_length = O->getAnyRelocationLength(RE);815const unsigned r_address = O->getAnyRelocationAddress(RE);816const bool r_extern = (r_scattered ? false :817O->getPlainRelocationExternal(RE));818const uint32_t r_value = (r_scattered ?819O->getScatteredRelocationValue(RE) : 0);820const unsigned r_symbolnum = (r_scattered ? 0 :821O->getPlainRelocationSymbolNum(RE));822823if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {824if (verbose) {825// scattered: address826if ((cputype == MachO::CPU_TYPE_I386 &&827r_type == MachO::GENERIC_RELOC_PAIR) ||828(cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))829outs() << " ";830else831outs() << format("%08x ", (unsigned int)r_address);832833// scattered: pcrel834if (r_pcrel)835outs() << "True ";836else837outs() << "False ";838839// scattered: length840PrintRLength(cputype, r_type, r_length, previous_arm_half);841842// scattered: extern & type843outs() << "n/a ";844PrintRType(cputype, r_type);845846// scattered: scattered & value847outs() << format("True 0x%08x", (unsigned int)r_value);848if (previous_sectdiff == false) {849if ((cputype == MachO::CPU_TYPE_ARM &&850r_type == MachO::ARM_RELOC_PAIR))851outs() << format(" half = 0x%04x ", (unsigned int)r_address);852} else if (cputype == MachO::CPU_TYPE_ARM &&853sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)854outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);855if ((cputype == MachO::CPU_TYPE_I386 &&856(r_type == MachO::GENERIC_RELOC_SECTDIFF ||857r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||858(cputype == MachO::CPU_TYPE_ARM &&859(sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||860sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||861sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {862previous_sectdiff = true;863sectdiff_r_type = r_type;864} else {865previous_sectdiff = false;866sectdiff_r_type = 0;867}868if (cputype == MachO::CPU_TYPE_ARM &&869(r_type == MachO::ARM_RELOC_HALF ||870r_type == MachO::ARM_RELOC_HALF_SECTDIFF))871previous_arm_half = true;872else873previous_arm_half = false;874outs() << "\n";875}876else {877// scattered: address pcrel length extern type scattered value878outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",879(unsigned int)r_address, r_pcrel, r_length, r_type,880(unsigned int)r_value);881}882}883else {884if (verbose) {885// plain: address886if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)887outs() << " ";888else889outs() << format("%08x ", (unsigned int)r_address);890891// plain: pcrel892if (r_pcrel)893outs() << "True ";894else895outs() << "False ";896897// plain: length898PrintRLength(cputype, r_type, r_length, previous_arm_half);899900if (r_extern) {901// plain: extern & type & scattered902outs() << "True ";903PrintRType(cputype, r_type);904outs() << "False ";905906// plain: symbolnum/value907if (r_symbolnum > Symtab.nsyms)908outs() << format("?(%d)\n", r_symbolnum);909else {910SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);911Expected<StringRef> SymNameNext = Symbol.getName();912const char *name = nullptr;913if (SymNameNext)914name = SymNameNext->data();915if (name == nullptr)916outs() << format("?(%d)\n", r_symbolnum);917else918outs() << name << "\n";919}920}921else {922// plain: extern & type & scattered923outs() << "False ";924PrintRType(cputype, r_type);925outs() << "False ";926927// plain: symbolnum/value928if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)929outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);930else if ((cputype == MachO::CPU_TYPE_ARM64 ||931cputype == MachO::CPU_TYPE_ARM64_32) &&932r_type == MachO::ARM64_RELOC_ADDEND)933outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);934else {935outs() << format("%d ", r_symbolnum);936if (r_symbolnum == MachO::R_ABS)937outs() << "R_ABS\n";938else {939// in this case, r_symbolnum is actually a 1-based section number940uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;941if (r_symbolnum > 0 && r_symbolnum <= nsects) {942object::DataRefImpl DRI;943DRI.d.a = r_symbolnum-1;944StringRef SegName = O->getSectionFinalSegmentName(DRI);945if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))946outs() << "(" << SegName << "," << *NameOrErr << ")\n";947else948outs() << "(?,?)\n";949}950else {951outs() << "(?,?)\n";952}953}954}955}956if (cputype == MachO::CPU_TYPE_ARM &&957(r_type == MachO::ARM_RELOC_HALF ||958r_type == MachO::ARM_RELOC_HALF_SECTDIFF))959previous_arm_half = true;960else961previous_arm_half = false;962}963else {964// plain: address pcrel length extern type scattered symbolnum/section965outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",966(unsigned int)r_address, r_pcrel, r_length, r_extern,967r_type, r_symbolnum);968}969}970}971}972973static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {974const uint64_t cputype = O->getHeader().cputype;975const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();976if (Dysymtab.nextrel != 0) {977outs() << "External relocation information " << Dysymtab.nextrel978<< " entries";979outs() << "\naddress pcrel length extern type scattered "980"symbolnum/value\n";981PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,982verbose);983}984if (Dysymtab.nlocrel != 0) {985outs() << format("Local relocation information %u entries",986Dysymtab.nlocrel);987outs() << "\naddress pcrel length extern type scattered "988"symbolnum/value\n";989PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,990verbose);991}992for (const auto &Load : O->load_commands()) {993if (Load.C.cmd == MachO::LC_SEGMENT_64) {994const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);995for (unsigned J = 0; J < Seg.nsects; ++J) {996const MachO::section_64 Sec = O->getSection64(Load, J);997if (Sec.nreloc != 0) {998DataRefImpl DRI;999DRI.d.a = J;1000const StringRef SegName = O->getSectionFinalSegmentName(DRI);1001if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1002outs() << "Relocation information (" << SegName << "," << *NameOrErr1003<< format(") %u entries", Sec.nreloc);1004else1005outs() << "Relocation information (" << SegName << ",?) "1006<< format("%u entries", Sec.nreloc);1007outs() << "\naddress pcrel length extern type scattered "1008"symbolnum/value\n";1009PrintRelocationEntries(O, O->section_rel_begin(DRI),1010O->section_rel_end(DRI), cputype, verbose);1011}1012}1013} else if (Load.C.cmd == MachO::LC_SEGMENT) {1014const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);1015for (unsigned J = 0; J < Seg.nsects; ++J) {1016const MachO::section Sec = O->getSection(Load, J);1017if (Sec.nreloc != 0) {1018DataRefImpl DRI;1019DRI.d.a = J;1020const StringRef SegName = O->getSectionFinalSegmentName(DRI);1021if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1022outs() << "Relocation information (" << SegName << "," << *NameOrErr1023<< format(") %u entries", Sec.nreloc);1024else1025outs() << "Relocation information (" << SegName << ",?) "1026<< format("%u entries", Sec.nreloc);1027outs() << "\naddress pcrel length extern type scattered "1028"symbolnum/value\n";1029PrintRelocationEntries(O, O->section_rel_begin(DRI),1030O->section_rel_end(DRI), cputype, verbose);1031}1032}1033}1034}1035}10361037static void PrintFunctionStarts(MachOObjectFile *O) {1038uint64_t BaseSegmentAddress = 0;1039for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1040if (Command.C.cmd == MachO::LC_SEGMENT) {1041MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1042if (StringRef(SLC.segname) == "__TEXT") {1043BaseSegmentAddress = SLC.vmaddr;1044break;1045}1046} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1047MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1048if (StringRef(SLC.segname) == "__TEXT") {1049BaseSegmentAddress = SLC.vmaddr;1050break;1051}1052}1053}10541055SmallVector<uint64_t, 8> FunctionStarts;1056for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {1057if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {1058MachO::linkedit_data_command FunctionStartsLC =1059O->getLinkeditDataLoadCommand(LC);1060O->ReadULEB128s(FunctionStartsLC.dataoff, FunctionStarts);1061break;1062}1063}10641065DenseMap<uint64_t, StringRef> SymbolNames;1066if (FunctionStartsType == FunctionStartsMode::Names ||1067FunctionStartsType == FunctionStartsMode::Both) {1068for (SymbolRef Sym : O->symbols()) {1069if (Expected<uint64_t> Addr = Sym.getAddress()) {1070if (Expected<StringRef> Name = Sym.getName()) {1071SymbolNames[*Addr] = *Name;1072}1073}1074}1075}10761077for (uint64_t S : FunctionStarts) {1078uint64_t Addr = BaseSegmentAddress + S;1079if (FunctionStartsType == FunctionStartsMode::Names) {1080auto It = SymbolNames.find(Addr);1081if (It != SymbolNames.end())1082outs() << It->second << "\n";1083} else {1084if (O->is64Bit())1085outs() << format("%016" PRIx64, Addr);1086else1087outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));10881089if (FunctionStartsType == FunctionStartsMode::Both) {1090auto It = SymbolNames.find(Addr);1091if (It != SymbolNames.end())1092outs() << " " << It->second;1093else1094outs() << " ?";1095}1096outs() << "\n";1097}1098}1099}11001101static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {1102MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();1103uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);1104outs() << "Data in code table (" << nentries << " entries)\n";1105outs() << "offset length kind\n";1106for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;1107++DI) {1108uint32_t Offset;1109DI->getOffset(Offset);1110outs() << format("0x%08" PRIx32, Offset) << " ";1111uint16_t Length;1112DI->getLength(Length);1113outs() << format("%6u", Length) << " ";1114uint16_t Kind;1115DI->getKind(Kind);1116if (verbose) {1117switch (Kind) {1118case MachO::DICE_KIND_DATA:1119outs() << "DATA";1120break;1121case MachO::DICE_KIND_JUMP_TABLE8:1122outs() << "JUMP_TABLE8";1123break;1124case MachO::DICE_KIND_JUMP_TABLE16:1125outs() << "JUMP_TABLE16";1126break;1127case MachO::DICE_KIND_JUMP_TABLE32:1128outs() << "JUMP_TABLE32";1129break;1130case MachO::DICE_KIND_ABS_JUMP_TABLE32:1131outs() << "ABS_JUMP_TABLE32";1132break;1133default:1134outs() << format("0x%04" PRIx32, Kind);1135break;1136}1137} else1138outs() << format("0x%04" PRIx32, Kind);1139outs() << "\n";1140}1141}11421143static void PrintLinkOptHints(MachOObjectFile *O) {1144MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();1145const char *loh = O->getData().substr(LohLC.dataoff, 1).data();1146uint32_t nloh = LohLC.datasize;1147outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";1148for (uint32_t i = 0; i < nloh;) {1149unsigned n;1150uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);1151i += n;1152outs() << " identifier " << identifier << " ";1153if (i >= nloh)1154return;1155switch (identifier) {1156case 1:1157outs() << "AdrpAdrp\n";1158break;1159case 2:1160outs() << "AdrpLdr\n";1161break;1162case 3:1163outs() << "AdrpAddLdr\n";1164break;1165case 4:1166outs() << "AdrpLdrGotLdr\n";1167break;1168case 5:1169outs() << "AdrpAddStr\n";1170break;1171case 6:1172outs() << "AdrpLdrGotStr\n";1173break;1174case 7:1175outs() << "AdrpAdd\n";1176break;1177case 8:1178outs() << "AdrpLdrGot\n";1179break;1180default:1181outs() << "Unknown identifier value\n";1182break;1183}1184uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);1185i += n;1186outs() << " narguments " << narguments << "\n";1187if (i >= nloh)1188return;11891190for (uint32_t j = 0; j < narguments; j++) {1191uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);1192i += n;1193outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";1194if (i >= nloh)1195return;1196}1197}1198}11991200static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {1201SmallVector<std::string> Ret;1202for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1203if (Command.C.cmd == MachO::LC_SEGMENT) {1204MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1205Ret.push_back(SLC.segname);1206} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1207MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1208Ret.push_back(SLC.segname);1209}1210}1211return Ret;1212}12131214static void1215PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {1216outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";1217outs() << " fixups_version = " << H.fixups_version << '\n';1218outs() << " starts_offset = " << H.starts_offset << '\n';1219outs() << " imports_offset = " << H.imports_offset << '\n';1220outs() << " symbols_offset = " << H.symbols_offset << '\n';1221outs() << " imports_count = " << H.imports_count << '\n';12221223outs() << " imports_format = " << H.imports_format;1224switch (H.imports_format) {1225case llvm::MachO::DYLD_CHAINED_IMPORT:1226outs() << " (DYLD_CHAINED_IMPORT)";1227break;1228case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:1229outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";1230break;1231case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:1232outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";1233break;1234}1235outs() << '\n';12361237outs() << " symbols_format = " << H.symbols_format;1238if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)1239outs() << " (zlib compressed)";1240outs() << '\n';1241}12421243static constexpr std::array<StringRef, 13> PointerFormats{1244"DYLD_CHAINED_PTR_ARM64E",1245"DYLD_CHAINED_PTR_64",1246"DYLD_CHAINED_PTR_32",1247"DYLD_CHAINED_PTR_32_CACHE",1248"DYLD_CHAINED_PTR_32_FIRMWARE",1249"DYLD_CHAINED_PTR_64_OFFSET",1250"DYLD_CHAINED_PTR_ARM64E_KERNEL",1251"DYLD_CHAINED_PTR_64_KERNEL_CACHE",1252"DYLD_CHAINED_PTR_ARM64E_USERLAND",1253"DYLD_CHAINED_PTR_ARM64E_FIRMWARE",1254"DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",1255"DYLD_CHAINED_PTR_ARM64E_USERLAND24",1256};12571258static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,1259StringRef SegName) {1260outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName1261<< ")\n";1262outs() << " size = " << Segment.Header.size << '\n';1263outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)1264<< '\n';12651266outs() << " pointer_format = " << Segment.Header.pointer_format;1267if ((Segment.Header.pointer_format - 1) <1268MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)1269outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";1270outs() << '\n';12711272outs() << " segment_offset = "1273<< format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';1274outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer1275<< '\n';1276outs() << " page_count = " << Segment.Header.page_count << '\n';1277for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {1278outs() << " page_start[" << Index << "] = " << PageStart;1279// FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)1280if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)1281outs() << " (DYLD_CHAINED_PTR_START_NONE)";1282outs() << '\n';1283}1284}12851286static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,1287int Format, MachOObjectFile *O) {1288if (Format == MachO::DYLD_CHAINED_IMPORT)1289outs() << "dyld chained import";1290else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)1291outs() << "dyld chained import addend";1292else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)1293outs() << "dyld chained import addend64";1294// FIXME: otool prints the encoded value as well.1295outs() << '[' << Idx << "]\n";12961297outs() << " lib_ordinal = " << Target.libOrdinal() << " ("1298<< ordinalName(O, Target.libOrdinal()) << ")\n";1299outs() << " weak_import = " << Target.weakImport() << '\n';1300outs() << " name_offset = " << Target.nameOffset() << " ("1301<< Target.symbolName() << ")\n";1302if (Format != MachO::DYLD_CHAINED_IMPORT)1303outs() << " addend = " << (int64_t)Target.addend() << '\n';1304}13051306static void PrintChainedFixups(MachOObjectFile *O) {1307// MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.1308// FIXME: Support chained fixups in __TEXT,__chain_starts section too.1309auto ChainedFixupHeader =1310unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());1311if (!ChainedFixupHeader)1312return;13131314PrintChainedFixupsHeader(*ChainedFixupHeader);13151316auto [SegCount, Segments] =1317unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());13181319auto SegNames = GetSegmentNames(O);13201321size_t StartsIdx = 0;1322outs() << "chained starts in image\n";1323outs() << " seg_count = " << SegCount << '\n';1324for (size_t I = 0; I < SegCount; ++I) {1325uint64_t SegOffset = 0;1326if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {1327SegOffset = Segments[StartsIdx].Offset;1328++StartsIdx;1329}13301331outs() << " seg_offset[" << I << "] = " << SegOffset << " ("1332<< SegNames[I] << ")\n";1333}13341335for (const ChainedFixupsSegment &S : Segments)1336PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);13371338auto FixupTargets =1339unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());13401341uint32_t ImportsFormat = ChainedFixupHeader->imports_format;1342for (auto [Idx, Target] : enumerate(FixupTargets))1343PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);1344}13451346static void PrintDyldInfo(MachOObjectFile *O) {1347Error Err = Error::success();13481349size_t SegmentWidth = strlen("segment");1350size_t SectionWidth = strlen("section");1351size_t AddressWidth = strlen("address");1352size_t AddendWidth = strlen("addend");1353size_t DylibWidth = strlen("dylib");1354const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;13551356auto HexLength = [](uint64_t Num) {1357return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;1358};1359for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1360SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());1361SectionWidth = std::max(SectionWidth, Entry.sectionName().size());1362AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);1363if (Entry.isBind()) {1364AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);1365DylibWidth = std::max(DylibWidth, Entry.symbolName().size());1366}1367}1368// Errors will be handled when printing the table.1369if (Err)1370consumeError(std::move(Err));13711372outs() << "dyld information:\n";1373outs() << left_justify("segment", SegmentWidth) << ' '1374<< left_justify("section", SectionWidth) << ' '1375<< left_justify("address", AddressWidth) << ' '1376<< left_justify("pointer", PointerWidth) << " type "1377<< left_justify("addend", AddendWidth) << ' '1378<< left_justify("dylib", DylibWidth) << " symbol/vm address\n";1379for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1380outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '1381<< left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"1382<< left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '1383<< format_hex(Entry.rawValue(), PointerWidth, true) << ' ';1384if (Entry.isBind()) {1385outs() << "bind "1386<< "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)1387<< ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)1388<< ' ' << Entry.symbolName();1389if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)1390outs() << " (weak import)";1391outs() << '\n';1392} else {1393assert(Entry.isRebase());1394outs() << "rebase";1395outs().indent(AddendWidth + DylibWidth + 2);1396outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';1397}1398}1399if (Err)1400reportError(std::move(Err), O->getFileName());14011402// TODO: Print opcode-based fixups if the object uses those.1403}14041405static void PrintDylibs(MachOObjectFile *O, bool JustId) {1406unsigned Index = 0;1407for (const auto &Load : O->load_commands()) {1408if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||1409(!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||1410Load.C.cmd == MachO::LC_LOAD_DYLIB ||1411Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||1412Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||1413Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||1414Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {1415MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);1416if (dl.dylib.name < dl.cmdsize) {1417const char *p = (const char *)(Load.Ptr) + dl.dylib.name;1418if (JustId)1419outs() << p << "\n";1420else {1421outs() << "\t" << p;1422outs() << " (compatibility version "1423<< ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."1424<< ((dl.dylib.compatibility_version >> 8) & 0xff) << "."1425<< (dl.dylib.compatibility_version & 0xff) << ",";1426outs() << " current version "1427<< ((dl.dylib.current_version >> 16) & 0xffff) << "."1428<< ((dl.dylib.current_version >> 8) & 0xff) << "."1429<< (dl.dylib.current_version & 0xff);1430if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1431outs() << ", weak";1432if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1433outs() << ", reexport";1434if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1435outs() << ", upward";1436if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1437outs() << ", lazy";1438outs() << ")\n";1439}1440} else {1441outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";1442if (Load.C.cmd == MachO::LC_ID_DYLIB)1443outs() << "LC_ID_DYLIB ";1444else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)1445outs() << "LC_LOAD_DYLIB ";1446else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1447outs() << "LC_LOAD_WEAK_DYLIB ";1448else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1449outs() << "LC_LAZY_LOAD_DYLIB ";1450else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1451outs() << "LC_REEXPORT_DYLIB ";1452else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1453outs() << "LC_LOAD_UPWARD_DYLIB ";1454else1455outs() << "LC_??? ";1456outs() << "command " << Index++ << "\n";1457}1458}1459}1460}14611462static void printRpaths(MachOObjectFile *O) {1463for (const auto &Command : O->load_commands()) {1464if (Command.C.cmd == MachO::LC_RPATH) {1465auto Rpath = O->getRpathCommand(Command);1466const char *P = (const char *)(Command.Ptr) + Rpath.path;1467outs() << P << "\n";1468}1469}1470}14711472typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;14731474static void CreateSymbolAddressMap(MachOObjectFile *O,1475SymbolAddressMap *AddrMap) {1476// Create a map of symbol addresses to symbol names.1477const StringRef FileName = O->getFileName();1478for (const SymbolRef &Symbol : O->symbols()) {1479SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);1480if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||1481ST == SymbolRef::ST_Other) {1482uint64_t Address = cantFail(Symbol.getValue());1483StringRef SymName = unwrapOrError(Symbol.getName(), FileName);1484if (!SymName.starts_with(".objc"))1485(*AddrMap)[Address] = SymName;1486}1487}1488}14891490// GuessSymbolName is passed the address of what might be a symbol and a1491// pointer to the SymbolAddressMap. It returns the name of a symbol1492// with that address or nullptr if no symbol is found with that address.1493static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {1494const char *SymbolName = nullptr;1495// A DenseMap can't lookup up some values.1496if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {1497StringRef name = AddrMap->lookup(value);1498if (!name.empty())1499SymbolName = name.data();1500}1501return SymbolName;1502}15031504static void DumpCstringChar(const char c) {1505char p[2];1506p[0] = c;1507p[1] = '\0';1508outs().write_escaped(p);1509}15101511static void DumpCstringSection(MachOObjectFile *O, const char *sect,1512uint32_t sect_size, uint64_t sect_addr,1513bool print_addresses) {1514for (uint32_t i = 0; i < sect_size; i++) {1515if (print_addresses) {1516if (O->is64Bit())1517outs() << format("%016" PRIx64, sect_addr + i) << " ";1518else1519outs() << format("%08" PRIx64, sect_addr + i) << " ";1520}1521for (; i < sect_size && sect[i] != '\0'; i++)1522DumpCstringChar(sect[i]);1523if (i < sect_size && sect[i] == '\0')1524outs() << "\n";1525}1526}15271528static void DumpLiteral4(uint32_t l, float f) {1529outs() << format("0x%08" PRIx32, l);1530if ((l & 0x7f800000) != 0x7f800000)1531outs() << format(" (%.16e)\n", f);1532else {1533if (l == 0x7f800000)1534outs() << " (+Infinity)\n";1535else if (l == 0xff800000)1536outs() << " (-Infinity)\n";1537else if ((l & 0x00400000) == 0x00400000)1538outs() << " (non-signaling Not-a-Number)\n";1539else1540outs() << " (signaling Not-a-Number)\n";1541}1542}15431544static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,1545uint32_t sect_size, uint64_t sect_addr,1546bool print_addresses) {1547for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {1548if (print_addresses) {1549if (O->is64Bit())1550outs() << format("%016" PRIx64, sect_addr + i) << " ";1551else1552outs() << format("%08" PRIx64, sect_addr + i) << " ";1553}1554float f;1555memcpy(&f, sect + i, sizeof(float));1556if (O->isLittleEndian() != sys::IsLittleEndianHost)1557sys::swapByteOrder(f);1558uint32_t l;1559memcpy(&l, sect + i, sizeof(uint32_t));1560if (O->isLittleEndian() != sys::IsLittleEndianHost)1561sys::swapByteOrder(l);1562DumpLiteral4(l, f);1563}1564}15651566static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,1567double d) {1568outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);1569uint32_t Hi, Lo;1570Hi = (O->isLittleEndian()) ? l1 : l0;1571Lo = (O->isLittleEndian()) ? l0 : l1;15721573// Hi is the high word, so this is equivalent to if(isfinite(d))1574if ((Hi & 0x7ff00000) != 0x7ff00000)1575outs() << format(" (%.16e)\n", d);1576else {1577if (Hi == 0x7ff00000 && Lo == 0)1578outs() << " (+Infinity)\n";1579else if (Hi == 0xfff00000 && Lo == 0)1580outs() << " (-Infinity)\n";1581else if ((Hi & 0x00080000) == 0x00080000)1582outs() << " (non-signaling Not-a-Number)\n";1583else1584outs() << " (signaling Not-a-Number)\n";1585}1586}15871588static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,1589uint32_t sect_size, uint64_t sect_addr,1590bool print_addresses) {1591for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {1592if (print_addresses) {1593if (O->is64Bit())1594outs() << format("%016" PRIx64, sect_addr + i) << " ";1595else1596outs() << format("%08" PRIx64, sect_addr + i) << " ";1597}1598double d;1599memcpy(&d, sect + i, sizeof(double));1600if (O->isLittleEndian() != sys::IsLittleEndianHost)1601sys::swapByteOrder(d);1602uint32_t l0, l1;1603memcpy(&l0, sect + i, sizeof(uint32_t));1604memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1605if (O->isLittleEndian() != sys::IsLittleEndianHost) {1606sys::swapByteOrder(l0);1607sys::swapByteOrder(l1);1608}1609DumpLiteral8(O, l0, l1, d);1610}1611}16121613static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {1614outs() << format("0x%08" PRIx32, l0) << " ";1615outs() << format("0x%08" PRIx32, l1) << " ";1616outs() << format("0x%08" PRIx32, l2) << " ";1617outs() << format("0x%08" PRIx32, l3) << "\n";1618}16191620static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,1621uint32_t sect_size, uint64_t sect_addr,1622bool print_addresses) {1623for (uint32_t i = 0; i < sect_size; i += 16) {1624if (print_addresses) {1625if (O->is64Bit())1626outs() << format("%016" PRIx64, sect_addr + i) << " ";1627else1628outs() << format("%08" PRIx64, sect_addr + i) << " ";1629}1630uint32_t l0, l1, l2, l3;1631memcpy(&l0, sect + i, sizeof(uint32_t));1632memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1633memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));1634memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));1635if (O->isLittleEndian() != sys::IsLittleEndianHost) {1636sys::swapByteOrder(l0);1637sys::swapByteOrder(l1);1638sys::swapByteOrder(l2);1639sys::swapByteOrder(l3);1640}1641DumpLiteral16(l0, l1, l2, l3);1642}1643}16441645static void DumpLiteralPointerSection(MachOObjectFile *O,1646const SectionRef &Section,1647const char *sect, uint32_t sect_size,1648uint64_t sect_addr,1649bool print_addresses) {1650// Collect the literal sections in this Mach-O file.1651std::vector<SectionRef> LiteralSections;1652for (const SectionRef &Section : O->sections()) {1653DataRefImpl Ref = Section.getRawDataRefImpl();1654uint32_t section_type;1655if (O->is64Bit()) {1656const MachO::section_64 Sec = O->getSection64(Ref);1657section_type = Sec.flags & MachO::SECTION_TYPE;1658} else {1659const MachO::section Sec = O->getSection(Ref);1660section_type = Sec.flags & MachO::SECTION_TYPE;1661}1662if (section_type == MachO::S_CSTRING_LITERALS ||1663section_type == MachO::S_4BYTE_LITERALS ||1664section_type == MachO::S_8BYTE_LITERALS ||1665section_type == MachO::S_16BYTE_LITERALS)1666LiteralSections.push_back(Section);1667}16681669// Set the size of the literal pointer.1670uint32_t lp_size = O->is64Bit() ? 8 : 4;16711672// Collect the external relocation symbols for the literal pointers.1673std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1674for (const RelocationRef &Reloc : Section.relocations()) {1675DataRefImpl Rel;1676MachO::any_relocation_info RE;1677bool isExtern = false;1678Rel = Reloc.getRawDataRefImpl();1679RE = O->getRelocation(Rel);1680isExtern = O->getPlainRelocationExternal(RE);1681if (isExtern) {1682uint64_t RelocOffset = Reloc.getOffset();1683symbol_iterator RelocSym = Reloc.getSymbol();1684Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1685}1686}1687array_pod_sort(Relocs.begin(), Relocs.end());16881689// Dump each literal pointer.1690for (uint32_t i = 0; i < sect_size; i += lp_size) {1691if (print_addresses) {1692if (O->is64Bit())1693outs() << format("%016" PRIx64, sect_addr + i) << " ";1694else1695outs() << format("%08" PRIx64, sect_addr + i) << " ";1696}1697uint64_t lp;1698if (O->is64Bit()) {1699memcpy(&lp, sect + i, sizeof(uint64_t));1700if (O->isLittleEndian() != sys::IsLittleEndianHost)1701sys::swapByteOrder(lp);1702} else {1703uint32_t li;1704memcpy(&li, sect + i, sizeof(uint32_t));1705if (O->isLittleEndian() != sys::IsLittleEndianHost)1706sys::swapByteOrder(li);1707lp = li;1708}17091710// First look for an external relocation entry for this literal pointer.1711auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1712return P.first == i;1713});1714if (Reloc != Relocs.end()) {1715symbol_iterator RelocSym = Reloc->second;1716StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());1717outs() << "external relocation entry for symbol:" << SymName << "\n";1718continue;1719}17201721// For local references see what the section the literal pointer points to.1722auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {1723return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();1724});1725if (Sect == LiteralSections.end()) {1726outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";1727continue;1728}17291730uint64_t SectAddress = Sect->getAddress();1731uint64_t SectSize = Sect->getSize();17321733StringRef SectName;1734Expected<StringRef> SectNameOrErr = Sect->getName();1735if (SectNameOrErr)1736SectName = *SectNameOrErr;1737else1738consumeError(SectNameOrErr.takeError());17391740DataRefImpl Ref = Sect->getRawDataRefImpl();1741StringRef SegmentName = O->getSectionFinalSegmentName(Ref);1742outs() << SegmentName << ":" << SectName << ":";17431744uint32_t section_type;1745if (O->is64Bit()) {1746const MachO::section_64 Sec = O->getSection64(Ref);1747section_type = Sec.flags & MachO::SECTION_TYPE;1748} else {1749const MachO::section Sec = O->getSection(Ref);1750section_type = Sec.flags & MachO::SECTION_TYPE;1751}17521753StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());17541755const char *Contents = reinterpret_cast<const char *>(BytesStr.data());17561757switch (section_type) {1758case MachO::S_CSTRING_LITERALS:1759for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';1760i++) {1761DumpCstringChar(Contents[i]);1762}1763outs() << "\n";1764break;1765case MachO::S_4BYTE_LITERALS:1766float f;1767memcpy(&f, Contents + (lp - SectAddress), sizeof(float));1768uint32_t l;1769memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));1770if (O->isLittleEndian() != sys::IsLittleEndianHost) {1771sys::swapByteOrder(f);1772sys::swapByteOrder(l);1773}1774DumpLiteral4(l, f);1775break;1776case MachO::S_8BYTE_LITERALS: {1777double d;1778memcpy(&d, Contents + (lp - SectAddress), sizeof(double));1779uint32_t l0, l1;1780memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1781memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1782sizeof(uint32_t));1783if (O->isLittleEndian() != sys::IsLittleEndianHost) {1784sys::swapByteOrder(f);1785sys::swapByteOrder(l0);1786sys::swapByteOrder(l1);1787}1788DumpLiteral8(O, l0, l1, d);1789break;1790}1791case MachO::S_16BYTE_LITERALS: {1792uint32_t l0, l1, l2, l3;1793memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1794memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1795sizeof(uint32_t));1796memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),1797sizeof(uint32_t));1798memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),1799sizeof(uint32_t));1800if (O->isLittleEndian() != sys::IsLittleEndianHost) {1801sys::swapByteOrder(l0);1802sys::swapByteOrder(l1);1803sys::swapByteOrder(l2);1804sys::swapByteOrder(l3);1805}1806DumpLiteral16(l0, l1, l2, l3);1807break;1808}1809}1810}1811}18121813static void DumpInitTermPointerSection(MachOObjectFile *O,1814const SectionRef &Section,1815const char *sect,1816uint32_t sect_size, uint64_t sect_addr,1817SymbolAddressMap *AddrMap,1818bool verbose) {1819uint32_t stride;1820stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);18211822// Collect the external relocation symbols for the pointers.1823std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1824for (const RelocationRef &Reloc : Section.relocations()) {1825DataRefImpl Rel;1826MachO::any_relocation_info RE;1827bool isExtern = false;1828Rel = Reloc.getRawDataRefImpl();1829RE = O->getRelocation(Rel);1830isExtern = O->getPlainRelocationExternal(RE);1831if (isExtern) {1832uint64_t RelocOffset = Reloc.getOffset();1833symbol_iterator RelocSym = Reloc.getSymbol();1834Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1835}1836}1837array_pod_sort(Relocs.begin(), Relocs.end());18381839for (uint32_t i = 0; i < sect_size; i += stride) {1840const char *SymbolName = nullptr;1841uint64_t p;1842if (O->is64Bit()) {1843outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";1844uint64_t pointer_value;1845memcpy(&pointer_value, sect + i, stride);1846if (O->isLittleEndian() != sys::IsLittleEndianHost)1847sys::swapByteOrder(pointer_value);1848outs() << format("0x%016" PRIx64, pointer_value);1849p = pointer_value;1850} else {1851outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";1852uint32_t pointer_value;1853memcpy(&pointer_value, sect + i, stride);1854if (O->isLittleEndian() != sys::IsLittleEndianHost)1855sys::swapByteOrder(pointer_value);1856outs() << format("0x%08" PRIx32, pointer_value);1857p = pointer_value;1858}1859if (verbose) {1860// First look for an external relocation entry for this pointer.1861auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1862return P.first == i;1863});1864if (Reloc != Relocs.end()) {1865symbol_iterator RelocSym = Reloc->second;1866outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());1867} else {1868SymbolName = GuessSymbolName(p, AddrMap);1869if (SymbolName)1870outs() << " " << SymbolName;1871}1872}1873outs() << "\n";1874}1875}18761877static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,1878uint32_t size, uint64_t addr) {1879uint32_t cputype = O->getHeader().cputype;1880if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {1881uint32_t j;1882for (uint32_t i = 0; i < size; i += j, addr += j) {1883if (O->is64Bit())1884outs() << format("%016" PRIx64, addr) << "\t";1885else1886outs() << format("%08" PRIx64, addr) << "\t";1887for (j = 0; j < 16 && i + j < size; j++) {1888uint8_t byte_word = *(sect + i + j);1889outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1890}1891outs() << "\n";1892}1893} else {1894uint32_t j;1895for (uint32_t i = 0; i < size; i += j, addr += j) {1896if (O->is64Bit())1897outs() << format("%016" PRIx64, addr) << "\t";1898else1899outs() << format("%08" PRIx64, addr) << "\t";1900for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;1901j += sizeof(int32_t)) {1902if (i + j + sizeof(int32_t) <= size) {1903uint32_t long_word;1904memcpy(&long_word, sect + i + j, sizeof(int32_t));1905if (O->isLittleEndian() != sys::IsLittleEndianHost)1906sys::swapByteOrder(long_word);1907outs() << format("%08" PRIx32, long_word) << " ";1908} else {1909for (uint32_t k = 0; i + j + k < size; k++) {1910uint8_t byte_word = *(sect + i + j + k);1911outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1912}1913}1914}1915outs() << "\n";1916}1917}1918}19191920static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,1921StringRef DisSegName, StringRef DisSectName);1922static void DumpProtocolSection(MachOObjectFile *O, const char *sect,1923uint32_t size, uint32_t addr);1924static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,1925bool verbose) {1926SymbolAddressMap AddrMap;1927if (verbose)1928CreateSymbolAddressMap(O, &AddrMap);19291930for (unsigned i = 0; i < FilterSections.size(); ++i) {1931StringRef DumpSection = FilterSections[i];1932std::pair<StringRef, StringRef> DumpSegSectName;1933DumpSegSectName = DumpSection.split(',');1934StringRef DumpSegName, DumpSectName;1935if (!DumpSegSectName.second.empty()) {1936DumpSegName = DumpSegSectName.first;1937DumpSectName = DumpSegSectName.second;1938} else {1939DumpSegName = "";1940DumpSectName = DumpSegSectName.first;1941}1942for (const SectionRef &Section : O->sections()) {1943StringRef SectName;1944Expected<StringRef> SecNameOrErr = Section.getName();1945if (SecNameOrErr)1946SectName = *SecNameOrErr;1947else1948consumeError(SecNameOrErr.takeError());19491950if (!DumpSection.empty())1951FoundSectionSet.insert(DumpSection);19521953DataRefImpl Ref = Section.getRawDataRefImpl();1954StringRef SegName = O->getSectionFinalSegmentName(Ref);1955if ((DumpSegName.empty() || SegName == DumpSegName) &&1956(SectName == DumpSectName)) {19571958uint32_t section_flags;1959if (O->is64Bit()) {1960const MachO::section_64 Sec = O->getSection64(Ref);1961section_flags = Sec.flags;19621963} else {1964const MachO::section Sec = O->getSection(Ref);1965section_flags = Sec.flags;1966}1967uint32_t section_type = section_flags & MachO::SECTION_TYPE;19681969StringRef BytesStr =1970unwrapOrError(Section.getContents(), O->getFileName());1971const char *sect = reinterpret_cast<const char *>(BytesStr.data());1972uint32_t sect_size = BytesStr.size();1973uint64_t sect_addr = Section.getAddress();19741975if (LeadingHeaders)1976outs() << "Contents of (" << SegName << "," << SectName1977<< ") section\n";19781979if (verbose) {1980if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||1981(section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {1982DisassembleMachO(Filename, O, SegName, SectName);1983continue;1984}1985if (SegName == "__TEXT" && SectName == "__info_plist") {1986outs() << sect;1987continue;1988}1989if (SegName == "__OBJC" && SectName == "__protocol") {1990DumpProtocolSection(O, sect, sect_size, sect_addr);1991continue;1992}1993switch (section_type) {1994case MachO::S_REGULAR:1995DumpRawSectionContents(O, sect, sect_size, sect_addr);1996break;1997case MachO::S_ZEROFILL:1998outs() << "zerofill section and has no contents in the file\n";1999break;2000case MachO::S_CSTRING_LITERALS:2001DumpCstringSection(O, sect, sect_size, sect_addr, LeadingAddr);2002break;2003case MachO::S_4BYTE_LITERALS:2004DumpLiteral4Section(O, sect, sect_size, sect_addr, LeadingAddr);2005break;2006case MachO::S_8BYTE_LITERALS:2007DumpLiteral8Section(O, sect, sect_size, sect_addr, LeadingAddr);2008break;2009case MachO::S_16BYTE_LITERALS:2010DumpLiteral16Section(O, sect, sect_size, sect_addr, LeadingAddr);2011break;2012case MachO::S_LITERAL_POINTERS:2013DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,2014LeadingAddr);2015break;2016case MachO::S_MOD_INIT_FUNC_POINTERS:2017case MachO::S_MOD_TERM_FUNC_POINTERS:2018DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,2019&AddrMap, verbose);2020break;2021default:2022outs() << "Unknown section type ("2023<< format("0x%08" PRIx32, section_type) << ")\n";2024DumpRawSectionContents(O, sect, sect_size, sect_addr);2025break;2026}2027} else {2028if (section_type == MachO::S_ZEROFILL)2029outs() << "zerofill section and has no contents in the file\n";2030else2031DumpRawSectionContents(O, sect, sect_size, sect_addr);2032}2033}2034}2035}2036}20372038static void DumpInfoPlistSectionContents(StringRef Filename,2039MachOObjectFile *O) {2040for (const SectionRef &Section : O->sections()) {2041StringRef SectName;2042Expected<StringRef> SecNameOrErr = Section.getName();2043if (SecNameOrErr)2044SectName = *SecNameOrErr;2045else2046consumeError(SecNameOrErr.takeError());20472048DataRefImpl Ref = Section.getRawDataRefImpl();2049StringRef SegName = O->getSectionFinalSegmentName(Ref);2050if (SegName == "__TEXT" && SectName == "__info_plist") {2051if (LeadingHeaders)2052outs() << "Contents of (" << SegName << "," << SectName << ") section\n";2053StringRef BytesStr =2054unwrapOrError(Section.getContents(), O->getFileName());2055const char *sect = reinterpret_cast<const char *>(BytesStr.data());2056outs() << format("%.*s", BytesStr.size(), sect) << "\n";2057return;2058}2059}2060}20612062// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file2063// and if it is and there is a list of architecture flags is specified then2064// check to make sure this Mach-O file is one of those architectures or all2065// architectures were specified. If not then an error is generated and this2066// routine returns false. Else it returns true.2067static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {2068auto *MachO = dyn_cast<MachOObjectFile>(O);20692070if (!MachO || ArchAll || ArchFlags.empty())2071return true;20722073MachO::mach_header H;2074MachO::mach_header_64 H_64;2075Triple T;2076const char *McpuDefault, *ArchFlag;2077if (MachO->is64Bit()) {2078H_64 = MachO->MachOObjectFile::getHeader64();2079T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,2080&McpuDefault, &ArchFlag);2081} else {2082H = MachO->MachOObjectFile::getHeader();2083T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,2084&McpuDefault, &ArchFlag);2085}2086const std::string ArchFlagName(ArchFlag);2087if (!llvm::is_contained(ArchFlags, ArchFlagName)) {2088WithColor::error(errs(), "llvm-objdump")2089<< Filename << ": no architecture specified.\n";2090return false;2091}2092return true;2093}20942095static void printObjcMetaData(MachOObjectFile *O, bool verbose);20962097// ProcessMachO() is passed a single opened Mach-O file, which may be an2098// archive member and or in a slice of a universal file. It prints the2099// the file name and header info and then processes it according to the2100// command line options.2101static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,2102StringRef ArchiveMemberName = StringRef(),2103StringRef ArchitectureName = StringRef()) {2104std::unique_ptr<Dumper> D = createMachODumper(*MachOOF);21052106// If we are doing some processing here on the Mach-O file print the header2107// info. And don't print it otherwise like in the case of printing the2108// UniversalHeaders or ArchiveHeaders.2109if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||2110Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||2111DataInCode || FunctionStartsType != FunctionStartsMode::None ||2112LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||2113Rpaths || ObjcMetaData || (!FilterSections.empty())) {2114if (LeadingHeaders) {2115outs() << Name;2116if (!ArchiveMemberName.empty())2117outs() << '(' << ArchiveMemberName << ')';2118if (!ArchitectureName.empty())2119outs() << " (architecture " << ArchitectureName << ")";2120outs() << ":\n";2121}2122}2123// To use the report_error() form with an ArchiveName and FileName set2124// these up based on what is passed for Name and ArchiveMemberName.2125StringRef ArchiveName;2126StringRef FileName;2127if (!ArchiveMemberName.empty()) {2128ArchiveName = Name;2129FileName = ArchiveMemberName;2130} else {2131ArchiveName = StringRef();2132FileName = Name;2133}21342135// If we need the symbol table to do the operation then check it here to2136// produce a good error message as to where the Mach-O file comes from in2137// the error message.2138if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)2139if (Error Err = MachOOF->checkSymbolTable())2140reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);21412142if (DisassembleAll) {2143for (const SectionRef &Section : MachOOF->sections()) {2144StringRef SectName;2145if (Expected<StringRef> NameOrErr = Section.getName())2146SectName = *NameOrErr;2147else2148consumeError(NameOrErr.takeError());21492150if (SectName == "__text") {2151DataRefImpl Ref = Section.getRawDataRefImpl();2152StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);2153DisassembleMachO(FileName, MachOOF, SegName, SectName);2154}2155}2156}2157else if (Disassemble) {2158if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&2159MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)2160DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");2161else2162DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");2163}2164if (IndirectSymbols)2165PrintIndirectSymbols(MachOOF, Verbose);2166if (DataInCode)2167PrintDataInCodeTable(MachOOF, Verbose);2168if (FunctionStartsType != FunctionStartsMode::None)2169PrintFunctionStarts(MachOOF);2170if (LinkOptHints)2171PrintLinkOptHints(MachOOF);2172if (Relocations)2173PrintRelocations(MachOOF, Verbose);2174if (SectionHeaders)2175printSectionHeaders(*MachOOF);2176if (SectionContents)2177printSectionContents(MachOOF);2178if (!FilterSections.empty())2179DumpSectionContents(FileName, MachOOF, Verbose);2180if (InfoPlist)2181DumpInfoPlistSectionContents(FileName, MachOOF);2182if (DyldInfo)2183PrintDyldInfo(MachOOF);2184if (ChainedFixups)2185PrintChainedFixups(MachOOF);2186if (DylibsUsed)2187PrintDylibs(MachOOF, false);2188if (DylibId)2189PrintDylibs(MachOOF, true);2190if (SymbolTable)2191D->printSymbolTable(ArchiveName, ArchitectureName);2192if (UnwindInfo)2193printMachOUnwindInfo(MachOOF);2194if (PrivateHeaders) {2195printMachOFileHeader(MachOOF);2196printMachOLoadCommands(MachOOF);2197}2198if (FirstPrivateHeader)2199printMachOFileHeader(MachOOF);2200if (ObjcMetaData)2201printObjcMetaData(MachOOF, Verbose);2202if (ExportsTrie)2203printExportsTrie(MachOOF);2204if (Rebase)2205printRebaseTable(MachOOF);2206if (Rpaths)2207printRpaths(MachOOF);2208if (Bind)2209printBindTable(MachOOF);2210if (LazyBind)2211printLazyBindTable(MachOOF);2212if (WeakBind)2213printWeakBindTable(MachOOF);22142215if (DwarfDumpType != DIDT_Null) {2216std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);2217// Dump the complete DWARF structure.2218DIDumpOptions DumpOpts;2219DumpOpts.DumpType = DwarfDumpType;2220DICtx->dump(outs(), DumpOpts);2221}2222}22232224// printUnknownCPUType() helps print_fat_headers for unknown CPU's.2225static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {2226outs() << " cputype (" << cputype << ")\n";2227outs() << " cpusubtype (" << cpusubtype << ")\n";2228}22292230// printCPUType() helps print_fat_headers by printing the cputype and2231// pusubtype (symbolically for the one's it knows about).2232static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {2233switch (cputype) {2234case MachO::CPU_TYPE_I386:2235switch (cpusubtype) {2236case MachO::CPU_SUBTYPE_I386_ALL:2237outs() << " cputype CPU_TYPE_I386\n";2238outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";2239break;2240default:2241printUnknownCPUType(cputype, cpusubtype);2242break;2243}2244break;2245case MachO::CPU_TYPE_X86_64:2246switch (cpusubtype) {2247case MachO::CPU_SUBTYPE_X86_64_ALL:2248outs() << " cputype CPU_TYPE_X86_64\n";2249outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";2250break;2251case MachO::CPU_SUBTYPE_X86_64_H:2252outs() << " cputype CPU_TYPE_X86_64\n";2253outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";2254break;2255default:2256printUnknownCPUType(cputype, cpusubtype);2257break;2258}2259break;2260case MachO::CPU_TYPE_ARM:2261switch (cpusubtype) {2262case MachO::CPU_SUBTYPE_ARM_ALL:2263outs() << " cputype CPU_TYPE_ARM\n";2264outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";2265break;2266case MachO::CPU_SUBTYPE_ARM_V4T:2267outs() << " cputype CPU_TYPE_ARM\n";2268outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";2269break;2270case MachO::CPU_SUBTYPE_ARM_V5TEJ:2271outs() << " cputype CPU_TYPE_ARM\n";2272outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";2273break;2274case MachO::CPU_SUBTYPE_ARM_XSCALE:2275outs() << " cputype CPU_TYPE_ARM\n";2276outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";2277break;2278case MachO::CPU_SUBTYPE_ARM_V6:2279outs() << " cputype CPU_TYPE_ARM\n";2280outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";2281break;2282case MachO::CPU_SUBTYPE_ARM_V6M:2283outs() << " cputype CPU_TYPE_ARM\n";2284outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";2285break;2286case MachO::CPU_SUBTYPE_ARM_V7:2287outs() << " cputype CPU_TYPE_ARM\n";2288outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";2289break;2290case MachO::CPU_SUBTYPE_ARM_V7EM:2291outs() << " cputype CPU_TYPE_ARM\n";2292outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";2293break;2294case MachO::CPU_SUBTYPE_ARM_V7K:2295outs() << " cputype CPU_TYPE_ARM\n";2296outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";2297break;2298case MachO::CPU_SUBTYPE_ARM_V7M:2299outs() << " cputype CPU_TYPE_ARM\n";2300outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";2301break;2302case MachO::CPU_SUBTYPE_ARM_V7S:2303outs() << " cputype CPU_TYPE_ARM\n";2304outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";2305break;2306default:2307printUnknownCPUType(cputype, cpusubtype);2308break;2309}2310break;2311case MachO::CPU_TYPE_ARM64:2312switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2313case MachO::CPU_SUBTYPE_ARM64_ALL:2314outs() << " cputype CPU_TYPE_ARM64\n";2315outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";2316break;2317case MachO::CPU_SUBTYPE_ARM64_V8:2318outs() << " cputype CPU_TYPE_ARM64\n";2319outs() << " cpusubtype CPU_SUBTYPE_ARM64_V8\n";2320break;2321case MachO::CPU_SUBTYPE_ARM64E:2322outs() << " cputype CPU_TYPE_ARM64\n";2323outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";2324break;2325default:2326printUnknownCPUType(cputype, cpusubtype);2327break;2328}2329break;2330case MachO::CPU_TYPE_ARM64_32:2331switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2332case MachO::CPU_SUBTYPE_ARM64_32_V8:2333outs() << " cputype CPU_TYPE_ARM64_32\n";2334outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";2335break;2336default:2337printUnknownCPUType(cputype, cpusubtype);2338break;2339}2340break;2341default:2342printUnknownCPUType(cputype, cpusubtype);2343break;2344}2345}23462347static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,2348bool verbose) {2349outs() << "Fat headers\n";2350if (verbose) {2351if (UB->getMagic() == MachO::FAT_MAGIC)2352outs() << "fat_magic FAT_MAGIC\n";2353else // UB->getMagic() == MachO::FAT_MAGIC_642354outs() << "fat_magic FAT_MAGIC_64\n";2355} else2356outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";23572358uint32_t nfat_arch = UB->getNumberOfObjects();2359StringRef Buf = UB->getData();2360uint64_t size = Buf.size();2361uint64_t big_size = sizeof(struct MachO::fat_header) +2362nfat_arch * sizeof(struct MachO::fat_arch);2363outs() << "nfat_arch " << UB->getNumberOfObjects();2364if (nfat_arch == 0)2365outs() << " (malformed, contains zero architecture types)\n";2366else if (big_size > size)2367outs() << " (malformed, architectures past end of file)\n";2368else2369outs() << "\n";23702371for (uint32_t i = 0; i < nfat_arch; ++i) {2372MachOUniversalBinary::ObjectForArch OFA(UB, i);2373uint32_t cputype = OFA.getCPUType();2374uint32_t cpusubtype = OFA.getCPUSubType();2375outs() << "architecture ";2376for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {2377MachOUniversalBinary::ObjectForArch other_OFA(UB, j);2378uint32_t other_cputype = other_OFA.getCPUType();2379uint32_t other_cpusubtype = other_OFA.getCPUSubType();2380if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&2381(cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==2382(other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {2383outs() << "(illegal duplicate architecture) ";2384break;2385}2386}2387if (verbose) {2388outs() << OFA.getArchFlagName() << "\n";2389printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);2390} else {2391outs() << i << "\n";2392outs() << " cputype " << cputype << "\n";2393outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)2394<< "\n";2395}2396if (verbose &&2397(cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)2398outs() << " capabilities CPU_SUBTYPE_LIB64\n";2399else2400outs() << " capabilities "2401<< format("0x%" PRIx32,2402(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";2403outs() << " offset " << OFA.getOffset();2404if (OFA.getOffset() > size)2405outs() << " (past end of file)";2406if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)2407outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";2408outs() << "\n";2409outs() << " size " << OFA.getSize();2410big_size = OFA.getOffset() + OFA.getSize();2411if (big_size > size)2412outs() << " (past end of file)";2413outs() << "\n";2414outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())2415<< ")\n";2416}2417}24182419static void printArchiveChild(StringRef Filename, const Archive::Child &C,2420size_t ChildIndex, bool verbose,2421bool print_offset,2422StringRef ArchitectureName = StringRef()) {2423if (print_offset)2424outs() << C.getChildOffset() << "\t";2425sys::fs::perms Mode =2426unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex),2427Filename, ArchitectureName);2428if (verbose) {2429// FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.2430// But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.2431outs() << "-";2432outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");2433outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");2434outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");2435outs() << ((Mode & sys::fs::group_read) ? "r" : "-");2436outs() << ((Mode & sys::fs::group_write) ? "w" : "-");2437outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");2438outs() << ((Mode & sys::fs::others_read) ? "r" : "-");2439outs() << ((Mode & sys::fs::others_write) ? "w" : "-");2440outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");2441} else {2442outs() << format("0%o ", Mode);2443}24442445outs() << format("%3d/%-3d %5" PRId64 " ",2446unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex),2447Filename, ArchitectureName),2448unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex),2449Filename, ArchitectureName),2450unwrapOrError(C.getRawSize(),2451getFileNameForError(C, ChildIndex), Filename,2452ArchitectureName));24532454StringRef RawLastModified = C.getRawLastModified();2455if (verbose) {2456unsigned Seconds;2457if (RawLastModified.getAsInteger(10, Seconds))2458outs() << "(date: \"" << RawLastModified2459<< "\" contains non-decimal chars) ";2460else {2461// Since cime(3) returns a 26 character string of the form:2462// "Sun Sep 16 01:03:52 1973\n\0"2463// just print 24 characters.2464time_t t = Seconds;2465outs() << format("%.24s ", ctime(&t));2466}2467} else {2468outs() << RawLastModified << " ";2469}24702471if (verbose) {2472Expected<StringRef> NameOrErr = C.getName();2473if (!NameOrErr) {2474consumeError(NameOrErr.takeError());2475outs() << unwrapOrError(C.getRawName(),2476getFileNameForError(C, ChildIndex), Filename,2477ArchitectureName)2478<< "\n";2479} else {2480StringRef Name = NameOrErr.get();2481outs() << Name << "\n";2482}2483} else {2484outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex),2485Filename, ArchitectureName)2486<< "\n";2487}2488}24892490static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,2491bool print_offset,2492StringRef ArchitectureName = StringRef()) {2493Error Err = Error::success();2494size_t I = 0;2495for (const auto &C : A->children(Err, false))2496printArchiveChild(Filename, C, I++, verbose, print_offset,2497ArchitectureName);24982499if (Err)2500reportError(std::move(Err), Filename, "", ArchitectureName);2501}25022503static bool ValidateArchFlags() {2504// Check for -arch all and verifiy the -arch flags are valid.2505for (unsigned i = 0; i < ArchFlags.size(); ++i) {2506if (ArchFlags[i] == "all") {2507ArchAll = true;2508} else {2509if (!MachOObjectFile::isValidArch(ArchFlags[i])) {2510WithColor::error(errs(), "llvm-objdump")2511<< "unknown architecture named '" + ArchFlags[i] +2512"'for the -arch option\n";2513return false;2514}2515}2516}2517return true;2518}25192520// ParseInputMachO() parses the named Mach-O file in Filename and handles the2521// -arch flags selecting just those slices as specified by them and also parses2522// archive files. Then for each individual Mach-O file ProcessMachO() is2523// called to process the file based on the command line options.2524void objdump::parseInputMachO(StringRef Filename) {2525if (!ValidateArchFlags())2526return;25272528// Attempt to open the binary.2529Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);2530if (!BinaryOrErr) {2531if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))2532reportError(std::move(E), Filename);2533else2534outs() << Filename << ": is not an object file\n";2535return;2536}2537Binary &Bin = *BinaryOrErr.get().getBinary();25382539if (Archive *A = dyn_cast<Archive>(&Bin)) {2540outs() << "Archive : " << Filename << "\n";2541if (ArchiveHeaders)2542printArchiveHeaders(Filename, A, Verbose, ArchiveMemberOffsets);25432544Error Err = Error::success();2545unsigned I = -1;2546for (auto &C : A->children(Err)) {2547++I;2548Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2549if (!ChildOrErr) {2550if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2551reportError(std::move(E), getFileNameForError(C, I), Filename);2552continue;2553}2554if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2555if (!checkMachOAndArchFlags(O, Filename))2556return;2557ProcessMachO(Filename, O, O->getFileName());2558}2559}2560if (Err)2561reportError(std::move(Err), Filename);2562return;2563}2564if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {2565parseInputMachO(UB);2566return;2567}2568if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {2569if (!checkMachOAndArchFlags(O, Filename))2570return;2571if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))2572ProcessMachO(Filename, MachOOF);2573else2574WithColor::error(errs(), "llvm-objdump")2575<< Filename << "': "2576<< "object is not a Mach-O file type.\n";2577return;2578}2579llvm_unreachable("Input object can't be invalid at this point");2580}25812582void objdump::parseInputMachO(MachOUniversalBinary *UB) {2583if (!ValidateArchFlags())2584return;25852586auto Filename = UB->getFileName();25872588if (UniversalHeaders)2589printMachOUniversalHeaders(UB, Verbose);25902591// If we have a list of architecture flags specified dump only those.2592if (!ArchAll && !ArchFlags.empty()) {2593// Look for a slice in the universal binary that matches each ArchFlag.2594bool ArchFound;2595for (unsigned i = 0; i < ArchFlags.size(); ++i) {2596ArchFound = false;2597for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2598E = UB->end_objects();2599I != E; ++I) {2600if (ArchFlags[i] == I->getArchFlagName()) {2601ArchFound = true;2602Expected<std::unique_ptr<ObjectFile>> ObjOrErr =2603I->getAsObjectFile();2604std::string ArchitectureName;2605if (ArchFlags.size() > 1)2606ArchitectureName = I->getArchFlagName();2607if (ObjOrErr) {2608ObjectFile &O = *ObjOrErr.get();2609if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2610ProcessMachO(Filename, MachOOF, "", ArchitectureName);2611} else if (Error E = isNotObjectErrorInvalidFileType(2612ObjOrErr.takeError())) {2613reportError(std::move(E), "", Filename, ArchitectureName);2614continue;2615} else if (Expected<std::unique_ptr<Archive>> AOrErr =2616I->getAsArchive()) {2617std::unique_ptr<Archive> &A = *AOrErr;2618outs() << "Archive : " << Filename;2619if (!ArchitectureName.empty())2620outs() << " (architecture " << ArchitectureName << ")";2621outs() << "\n";2622if (ArchiveHeaders)2623printArchiveHeaders(Filename, A.get(), Verbose,2624ArchiveMemberOffsets, ArchitectureName);2625Error Err = Error::success();2626unsigned I = -1;2627for (auto &C : A->children(Err)) {2628++I;2629Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2630if (!ChildOrErr) {2631if (Error E =2632isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2633reportError(std::move(E), getFileNameForError(C, I), Filename,2634ArchitectureName);2635continue;2636}2637if (MachOObjectFile *O =2638dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2639ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);2640}2641if (Err)2642reportError(std::move(Err), Filename);2643} else {2644consumeError(AOrErr.takeError());2645reportError(Filename,2646"Mach-O universal file for architecture " +2647StringRef(I->getArchFlagName()) +2648" is not a Mach-O file or an archive file");2649}2650}2651}2652if (!ArchFound) {2653WithColor::error(errs(), "llvm-objdump")2654<< "file: " + Filename + " does not contain "2655<< "architecture: " + ArchFlags[i] + "\n";2656return;2657}2658}2659return;2660}2661// No architecture flags were specified so if this contains a slice that2662// matches the host architecture dump only that.2663if (!ArchAll) {2664for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2665E = UB->end_objects();2666I != E; ++I) {2667if (MachOObjectFile::getHostArch().getArchName() ==2668I->getArchFlagName()) {2669Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2670std::string ArchiveName;2671ArchiveName.clear();2672if (ObjOrErr) {2673ObjectFile &O = *ObjOrErr.get();2674if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2675ProcessMachO(Filename, MachOOF);2676} else if (Error E =2677isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2678reportError(std::move(E), Filename);2679} else if (Expected<std::unique_ptr<Archive>> AOrErr =2680I->getAsArchive()) {2681std::unique_ptr<Archive> &A = *AOrErr;2682outs() << "Archive : " << Filename << "\n";2683if (ArchiveHeaders)2684printArchiveHeaders(Filename, A.get(), Verbose,2685ArchiveMemberOffsets);2686Error Err = Error::success();2687unsigned I = -1;2688for (auto &C : A->children(Err)) {2689++I;2690Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2691if (!ChildOrErr) {2692if (Error E =2693isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2694reportError(std::move(E), getFileNameForError(C, I), Filename);2695continue;2696}2697if (MachOObjectFile *O =2698dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2699ProcessMachO(Filename, O, O->getFileName());2700}2701if (Err)2702reportError(std::move(Err), Filename);2703} else {2704consumeError(AOrErr.takeError());2705reportError(Filename, "Mach-O universal file for architecture " +2706StringRef(I->getArchFlagName()) +2707" is not a Mach-O file or an archive file");2708}2709return;2710}2711}2712}2713// Either all architectures have been specified or none have been specified2714// and this does not contain the host architecture so dump all the slices.2715bool moreThanOneArch = UB->getNumberOfObjects() > 1;2716for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2717E = UB->end_objects();2718I != E; ++I) {2719Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2720std::string ArchitectureName;2721if (moreThanOneArch)2722ArchitectureName = I->getArchFlagName();2723if (ObjOrErr) {2724ObjectFile &Obj = *ObjOrErr.get();2725if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))2726ProcessMachO(Filename, MachOOF, "", ArchitectureName);2727} else if (Error E =2728isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2729reportError(std::move(E), Filename, "", ArchitectureName);2730} else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {2731std::unique_ptr<Archive> &A = *AOrErr;2732outs() << "Archive : " << Filename;2733if (!ArchitectureName.empty())2734outs() << " (architecture " << ArchitectureName << ")";2735outs() << "\n";2736if (ArchiveHeaders)2737printArchiveHeaders(Filename, A.get(), Verbose, ArchiveMemberOffsets,2738ArchitectureName);2739Error Err = Error::success();2740unsigned I = -1;2741for (auto &C : A->children(Err)) {2742++I;2743Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2744if (!ChildOrErr) {2745if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2746reportError(std::move(E), getFileNameForError(C, I), Filename,2747ArchitectureName);2748continue;2749}2750if (MachOObjectFile *O =2751dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2752if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))2753ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),2754ArchitectureName);2755}2756}2757if (Err)2758reportError(std::move(Err), Filename);2759} else {2760consumeError(AOrErr.takeError());2761reportError(Filename, "Mach-O universal file for architecture " +2762StringRef(I->getArchFlagName()) +2763" is not a Mach-O file or an archive file");2764}2765}2766}27672768namespace {2769// The block of info used by the Symbolizer call backs.2770struct DisassembleInfo {2771DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,2772std::vector<SectionRef> *Sections, bool verbose)2773: verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}2774bool verbose;2775MachOObjectFile *O;2776SectionRef S;2777SymbolAddressMap *AddrMap;2778std::vector<SectionRef> *Sections;2779const char *class_name = nullptr;2780const char *selector_name = nullptr;2781std::unique_ptr<char[]> method = nullptr;2782char *demangled_name = nullptr;2783uint64_t adrp_addr = 0;2784uint32_t adrp_inst = 0;2785std::unique_ptr<SymbolAddressMap> bindtable;2786uint32_t depth = 0;2787};2788} // namespace27892790// SymbolizerGetOpInfo() is the operand information call back function.2791// This is called to get the symbolic information for operand(s) of an2792// instruction when it is being done. This routine does this from2793// the relocation information, symbol table, etc. That block of information2794// is a pointer to the struct DisassembleInfo that was passed when the2795// disassembler context was created and passed to back to here when2796// called back by the disassembler for instruction operands that could have2797// relocation information. The address of the instruction containing operand is2798// at the Pc parameter. The immediate value the operand has is passed in2799// op_info->Value and is at Offset past the start of the instruction and has a2800// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the2801// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol2802// names and addends of the symbolic expression to add for the operand. The2803// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic2804// information is returned then this function returns 1 else it returns 0.2805static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,2806uint64_t OpSize, uint64_t InstSize, int TagType,2807void *TagBuf) {2808struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;2809struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;2810uint64_t value = op_info->Value;28112812// Make sure all fields returned are zero if we don't set them.2813memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));2814op_info->Value = value;28152816// If the TagType is not the value 1 which it code knows about or if no2817// verbose symbolic information is wanted then just return 0, indicating no2818// information is being returned.2819if (TagType != 1 || !info->verbose)2820return 0;28212822unsigned int Arch = info->O->getArch();2823if (Arch == Triple::x86) {2824if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2825return 0;2826if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2827// TODO:2828// Search the external relocation entries of a fully linked image2829// (if any) for an entry that matches this segment offset.2830// uint32_t seg_offset = (Pc + Offset);2831return 0;2832}2833// In MH_OBJECT filetypes search the section's relocation entries (if any)2834// for an entry for this section offset.2835uint32_t sect_addr = info->S.getAddress();2836uint32_t sect_offset = (Pc + Offset) - sect_addr;2837bool reloc_found = false;2838DataRefImpl Rel;2839MachO::any_relocation_info RE;2840bool isExtern = false;2841SymbolRef Symbol;2842bool r_scattered = false;2843uint32_t r_value, pair_r_value, r_type;2844for (const RelocationRef &Reloc : info->S.relocations()) {2845uint64_t RelocOffset = Reloc.getOffset();2846if (RelocOffset == sect_offset) {2847Rel = Reloc.getRawDataRefImpl();2848RE = info->O->getRelocation(Rel);2849r_type = info->O->getAnyRelocationType(RE);2850r_scattered = info->O->isRelocationScattered(RE);2851if (r_scattered) {2852r_value = info->O->getScatteredRelocationValue(RE);2853if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2854r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {2855DataRefImpl RelNext = Rel;2856info->O->moveRelocationNext(RelNext);2857MachO::any_relocation_info RENext;2858RENext = info->O->getRelocation(RelNext);2859if (info->O->isRelocationScattered(RENext))2860pair_r_value = info->O->getScatteredRelocationValue(RENext);2861else2862return 0;2863}2864} else {2865isExtern = info->O->getPlainRelocationExternal(RE);2866if (isExtern) {2867symbol_iterator RelocSym = Reloc.getSymbol();2868Symbol = *RelocSym;2869}2870}2871reloc_found = true;2872break;2873}2874}2875if (reloc_found && isExtern) {2876op_info->AddSymbol.Present = 1;2877op_info->AddSymbol.Name =2878unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2879// For i386 extern relocation entries the value in the instruction is2880// the offset from the symbol, and value is already set in op_info->Value.2881return 1;2882}2883if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2884r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {2885const char *add = GuessSymbolName(r_value, info->AddrMap);2886const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);2887uint32_t offset = value - (r_value - pair_r_value);2888op_info->AddSymbol.Present = 1;2889if (add != nullptr)2890op_info->AddSymbol.Name = add;2891else2892op_info->AddSymbol.Value = r_value;2893op_info->SubtractSymbol.Present = 1;2894if (sub != nullptr)2895op_info->SubtractSymbol.Name = sub;2896else2897op_info->SubtractSymbol.Value = pair_r_value;2898op_info->Value = offset;2899return 1;2900}2901return 0;2902}2903if (Arch == Triple::x86_64) {2904if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2905return 0;2906// For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external2907// relocation entries of a linked image (if any) for an entry that matches2908// this segment offset.2909if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2910uint64_t seg_offset = Pc + Offset;2911bool reloc_found = false;2912DataRefImpl Rel;2913MachO::any_relocation_info RE;2914bool isExtern = false;2915SymbolRef Symbol;2916for (const RelocationRef &Reloc : info->O->external_relocations()) {2917uint64_t RelocOffset = Reloc.getOffset();2918if (RelocOffset == seg_offset) {2919Rel = Reloc.getRawDataRefImpl();2920RE = info->O->getRelocation(Rel);2921// external relocation entries should always be external.2922isExtern = info->O->getPlainRelocationExternal(RE);2923if (isExtern) {2924symbol_iterator RelocSym = Reloc.getSymbol();2925Symbol = *RelocSym;2926}2927reloc_found = true;2928break;2929}2930}2931if (reloc_found && isExtern) {2932// The Value passed in will be adjusted by the Pc if the instruction2933// adds the Pc. But for x86_64 external relocation entries the Value2934// is the offset from the external symbol.2935if (info->O->getAnyRelocationPCRel(RE))2936op_info->Value -= Pc + InstSize;2937const char *name =2938unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2939op_info->AddSymbol.Present = 1;2940op_info->AddSymbol.Name = name;2941return 1;2942}2943return 0;2944}2945// In MH_OBJECT filetypes search the section's relocation entries (if any)2946// for an entry for this section offset.2947uint64_t sect_addr = info->S.getAddress();2948uint64_t sect_offset = (Pc + Offset) - sect_addr;2949bool reloc_found = false;2950DataRefImpl Rel;2951MachO::any_relocation_info RE;2952bool isExtern = false;2953SymbolRef Symbol;2954for (const RelocationRef &Reloc : info->S.relocations()) {2955uint64_t RelocOffset = Reloc.getOffset();2956if (RelocOffset == sect_offset) {2957Rel = Reloc.getRawDataRefImpl();2958RE = info->O->getRelocation(Rel);2959// NOTE: Scattered relocations don't exist on x86_64.2960isExtern = info->O->getPlainRelocationExternal(RE);2961if (isExtern) {2962symbol_iterator RelocSym = Reloc.getSymbol();2963Symbol = *RelocSym;2964}2965reloc_found = true;2966break;2967}2968}2969if (reloc_found && isExtern) {2970// The Value passed in will be adjusted by the Pc if the instruction2971// adds the Pc. But for x86_64 external relocation entries the Value2972// is the offset from the external symbol.2973if (info->O->getAnyRelocationPCRel(RE))2974op_info->Value -= Pc + InstSize;2975const char *name =2976unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2977unsigned Type = info->O->getAnyRelocationType(RE);2978if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {2979DataRefImpl RelNext = Rel;2980info->O->moveRelocationNext(RelNext);2981MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);2982unsigned TypeNext = info->O->getAnyRelocationType(RENext);2983bool isExternNext = info->O->getPlainRelocationExternal(RENext);2984unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);2985if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {2986op_info->SubtractSymbol.Present = 1;2987op_info->SubtractSymbol.Name = name;2988symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);2989Symbol = *RelocSymNext;2990name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2991}2992}2993// TODO: add the VariantKinds to op_info->VariantKind for relocation types2994// like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.2995op_info->AddSymbol.Present = 1;2996op_info->AddSymbol.Name = name;2997return 1;2998}2999return 0;3000}3001if (Arch == Triple::arm) {3002if (Offset != 0 || (InstSize != 4 && InstSize != 2))3003return 0;3004if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3005// TODO:3006// Search the external relocation entries of a fully linked image3007// (if any) for an entry that matches this segment offset.3008// uint32_t seg_offset = (Pc + Offset);3009return 0;3010}3011// In MH_OBJECT filetypes search the section's relocation entries (if any)3012// for an entry for this section offset.3013uint32_t sect_addr = info->S.getAddress();3014uint32_t sect_offset = (Pc + Offset) - sect_addr;3015DataRefImpl Rel;3016MachO::any_relocation_info RE;3017bool isExtern = false;3018SymbolRef Symbol;3019bool r_scattered = false;3020uint32_t r_value, pair_r_value, r_type, r_length, other_half;3021auto Reloc =3022find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3023uint64_t RelocOffset = Reloc.getOffset();3024return RelocOffset == sect_offset;3025});30263027if (Reloc == info->S.relocations().end())3028return 0;30293030Rel = Reloc->getRawDataRefImpl();3031RE = info->O->getRelocation(Rel);3032r_length = info->O->getAnyRelocationLength(RE);3033r_scattered = info->O->isRelocationScattered(RE);3034if (r_scattered) {3035r_value = info->O->getScatteredRelocationValue(RE);3036r_type = info->O->getScatteredRelocationType(RE);3037} else {3038r_type = info->O->getAnyRelocationType(RE);3039isExtern = info->O->getPlainRelocationExternal(RE);3040if (isExtern) {3041symbol_iterator RelocSym = Reloc->getSymbol();3042Symbol = *RelocSym;3043}3044}3045if (r_type == MachO::ARM_RELOC_HALF ||3046r_type == MachO::ARM_RELOC_SECTDIFF ||3047r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||3048r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3049DataRefImpl RelNext = Rel;3050info->O->moveRelocationNext(RelNext);3051MachO::any_relocation_info RENext;3052RENext = info->O->getRelocation(RelNext);3053other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;3054if (info->O->isRelocationScattered(RENext))3055pair_r_value = info->O->getScatteredRelocationValue(RENext);3056}30573058if (isExtern) {3059const char *name =3060unwrapOrError(Symbol.getName(), info->O->getFileName()).data();3061op_info->AddSymbol.Present = 1;3062op_info->AddSymbol.Name = name;3063switch (r_type) {3064case MachO::ARM_RELOC_HALF:3065if ((r_length & 0x1) == 1) {3066op_info->Value = value << 16 | other_half;3067op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3068} else {3069op_info->Value = other_half << 16 | value;3070op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3071}3072break;3073default:3074break;3075}3076return 1;3077}3078// If we have a branch that is not an external relocation entry then3079// return 0 so the code in tryAddingSymbolicOperand() can use the3080// SymbolLookUp call back with the branch target address to look up the3081// symbol and possibility add an annotation for a symbol stub.3082if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||3083r_type == MachO::ARM_THUMB_RELOC_BR22))3084return 0;30853086uint32_t offset = 0;3087if (r_type == MachO::ARM_RELOC_HALF ||3088r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3089if ((r_length & 0x1) == 1)3090value = value << 16 | other_half;3091else3092value = other_half << 16 | value;3093}3094if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&3095r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {3096offset = value - r_value;3097value = r_value;3098}30993100if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3101if ((r_length & 0x1) == 1)3102op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3103else3104op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3105const char *add = GuessSymbolName(r_value, info->AddrMap);3106const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);3107int32_t offset = value - (r_value - pair_r_value);3108op_info->AddSymbol.Present = 1;3109if (add != nullptr)3110op_info->AddSymbol.Name = add;3111else3112op_info->AddSymbol.Value = r_value;3113op_info->SubtractSymbol.Present = 1;3114if (sub != nullptr)3115op_info->SubtractSymbol.Name = sub;3116else3117op_info->SubtractSymbol.Value = pair_r_value;3118op_info->Value = offset;3119return 1;3120}31213122op_info->AddSymbol.Present = 1;3123op_info->Value = offset;3124if (r_type == MachO::ARM_RELOC_HALF) {3125if ((r_length & 0x1) == 1)3126op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3127else3128op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3129}3130const char *add = GuessSymbolName(value, info->AddrMap);3131if (add != nullptr) {3132op_info->AddSymbol.Name = add;3133return 1;3134}3135op_info->AddSymbol.Value = value;3136return 1;3137}3138if (Arch == Triple::aarch64) {3139if (Offset != 0 || InstSize != 4)3140return 0;3141if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3142// TODO:3143// Search the external relocation entries of a fully linked image3144// (if any) for an entry that matches this segment offset.3145// uint64_t seg_offset = (Pc + Offset);3146return 0;3147}3148// In MH_OBJECT filetypes search the section's relocation entries (if any)3149// for an entry for this section offset.3150uint64_t sect_addr = info->S.getAddress();3151uint64_t sect_offset = (Pc + Offset) - sect_addr;3152auto Reloc =3153find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3154uint64_t RelocOffset = Reloc.getOffset();3155return RelocOffset == sect_offset;3156});31573158if (Reloc == info->S.relocations().end())3159return 0;31603161DataRefImpl Rel = Reloc->getRawDataRefImpl();3162MachO::any_relocation_info RE = info->O->getRelocation(Rel);3163uint32_t r_type = info->O->getAnyRelocationType(RE);3164if (r_type == MachO::ARM64_RELOC_ADDEND) {3165DataRefImpl RelNext = Rel;3166info->O->moveRelocationNext(RelNext);3167MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);3168if (value == 0) {3169value = info->O->getPlainRelocationSymbolNum(RENext);3170op_info->Value = value;3171}3172}3173// NOTE: Scattered relocations don't exist on arm64.3174if (!info->O->getPlainRelocationExternal(RE))3175return 0;3176const char *name =3177unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())3178.data();3179op_info->AddSymbol.Present = 1;3180op_info->AddSymbol.Name = name;31813182switch (r_type) {3183case MachO::ARM64_RELOC_PAGE21:3184/* @page */3185op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;3186break;3187case MachO::ARM64_RELOC_PAGEOFF12:3188/* @pageoff */3189op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;3190break;3191case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:3192/* @gotpage */3193op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;3194break;3195case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:3196/* @gotpageoff */3197op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;3198break;3199case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:3200/* @tvlppage is not implemented in llvm-mc */3201op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;3202break;3203case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:3204/* @tvlppageoff is not implemented in llvm-mc */3205op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;3206break;3207default:3208case MachO::ARM64_RELOC_BRANCH26:3209op_info->VariantKind = LLVMDisassembler_VariantKind_None;3210break;3211}3212return 1;3213}3214return 0;3215}32163217// GuessCstringPointer is passed the address of what might be a pointer to a3218// literal string in a cstring section. If that address is in a cstring section3219// it returns a pointer to that string. Else it returns nullptr.3220static const char *GuessCstringPointer(uint64_t ReferenceValue,3221struct DisassembleInfo *info) {3222for (const auto &Load : info->O->load_commands()) {3223if (Load.C.cmd == MachO::LC_SEGMENT_64) {3224MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3225for (unsigned J = 0; J < Seg.nsects; ++J) {3226MachO::section_64 Sec = info->O->getSection64(Load, J);3227uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3228if (section_type == MachO::S_CSTRING_LITERALS &&3229ReferenceValue >= Sec.addr &&3230ReferenceValue < Sec.addr + Sec.size) {3231uint64_t sect_offset = ReferenceValue - Sec.addr;3232uint64_t object_offset = Sec.offset + sect_offset;3233StringRef MachOContents = info->O->getData();3234uint64_t object_size = MachOContents.size();3235const char *object_addr = (const char *)MachOContents.data();3236if (object_offset < object_size) {3237const char *name = object_addr + object_offset;3238return name;3239} else {3240return nullptr;3241}3242}3243}3244} else if (Load.C.cmd == MachO::LC_SEGMENT) {3245MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3246for (unsigned J = 0; J < Seg.nsects; ++J) {3247MachO::section Sec = info->O->getSection(Load, J);3248uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3249if (section_type == MachO::S_CSTRING_LITERALS &&3250ReferenceValue >= Sec.addr &&3251ReferenceValue < Sec.addr + Sec.size) {3252uint64_t sect_offset = ReferenceValue - Sec.addr;3253uint64_t object_offset = Sec.offset + sect_offset;3254StringRef MachOContents = info->O->getData();3255uint64_t object_size = MachOContents.size();3256const char *object_addr = (const char *)MachOContents.data();3257if (object_offset < object_size) {3258const char *name = object_addr + object_offset;3259return name;3260} else {3261return nullptr;3262}3263}3264}3265}3266}3267return nullptr;3268}32693270// GuessIndirectSymbol returns the name of the indirect symbol for the3271// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe3272// an address of a symbol stub or a lazy or non-lazy pointer to associate the3273// symbol name being referenced by the stub or pointer.3274static const char *GuessIndirectSymbol(uint64_t ReferenceValue,3275struct DisassembleInfo *info) {3276MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();3277MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();3278for (const auto &Load : info->O->load_commands()) {3279if (Load.C.cmd == MachO::LC_SEGMENT_64) {3280MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3281for (unsigned J = 0; J < Seg.nsects; ++J) {3282MachO::section_64 Sec = info->O->getSection64(Load, J);3283uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3284if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3285section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3286section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3287section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3288section_type == MachO::S_SYMBOL_STUBS) &&3289ReferenceValue >= Sec.addr &&3290ReferenceValue < Sec.addr + Sec.size) {3291uint32_t stride;3292if (section_type == MachO::S_SYMBOL_STUBS)3293stride = Sec.reserved2;3294else3295stride = 8;3296if (stride == 0)3297return nullptr;3298uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3299if (index < Dysymtab.nindirectsyms) {3300uint32_t indirect_symbol =3301info->O->getIndirectSymbolTableEntry(Dysymtab, index);3302if (indirect_symbol < Symtab.nsyms) {3303symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3304return unwrapOrError(Sym->getName(), info->O->getFileName())3305.data();3306}3307}3308}3309}3310} else if (Load.C.cmd == MachO::LC_SEGMENT) {3311MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3312for (unsigned J = 0; J < Seg.nsects; ++J) {3313MachO::section Sec = info->O->getSection(Load, J);3314uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3315if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3316section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3317section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3318section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3319section_type == MachO::S_SYMBOL_STUBS) &&3320ReferenceValue >= Sec.addr &&3321ReferenceValue < Sec.addr + Sec.size) {3322uint32_t stride;3323if (section_type == MachO::S_SYMBOL_STUBS)3324stride = Sec.reserved2;3325else3326stride = 4;3327if (stride == 0)3328return nullptr;3329uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3330if (index < Dysymtab.nindirectsyms) {3331uint32_t indirect_symbol =3332info->O->getIndirectSymbolTableEntry(Dysymtab, index);3333if (indirect_symbol < Symtab.nsyms) {3334symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3335return unwrapOrError(Sym->getName(), info->O->getFileName())3336.data();3337}3338}3339}3340}3341}3342}3343return nullptr;3344}33453346// method_reference() is called passing it the ReferenceName that might be3347// a reference it to an Objective-C method call. If so then it allocates and3348// assembles a method call string with the values last seen and saved in3349// the DisassembleInfo's class_name and selector_name fields. This is saved3350// into the method field of the info and any previous string is free'ed.3351// Then the class_name field in the info is set to nullptr. The method call3352// string is set into ReferenceName and ReferenceType is set to3353// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call3354// then both ReferenceType and ReferenceName are left unchanged.3355static void method_reference(struct DisassembleInfo *info,3356uint64_t *ReferenceType,3357const char **ReferenceName) {3358unsigned int Arch = info->O->getArch();3359if (*ReferenceName != nullptr) {3360if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {3361if (info->selector_name != nullptr) {3362if (info->class_name != nullptr) {3363info->method = std::make_unique<char[]>(33645 + strlen(info->class_name) + strlen(info->selector_name));3365char *method = info->method.get();3366if (method != nullptr) {3367strcpy(method, "+[");3368strcat(method, info->class_name);3369strcat(method, " ");3370strcat(method, info->selector_name);3371strcat(method, "]");3372*ReferenceName = method;3373*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3374}3375} else {3376info->method =3377std::make_unique<char[]>(9 + strlen(info->selector_name));3378char *method = info->method.get();3379if (method != nullptr) {3380if (Arch == Triple::x86_64)3381strcpy(method, "-[%rdi ");3382else if (Arch == Triple::aarch64)3383strcpy(method, "-[x0 ");3384else3385strcpy(method, "-[r? ");3386strcat(method, info->selector_name);3387strcat(method, "]");3388*ReferenceName = method;3389*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3390}3391}3392info->class_name = nullptr;3393}3394} else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {3395if (info->selector_name != nullptr) {3396info->method =3397std::make_unique<char[]>(17 + strlen(info->selector_name));3398char *method = info->method.get();3399if (method != nullptr) {3400if (Arch == Triple::x86_64)3401strcpy(method, "-[[%rdi super] ");3402else if (Arch == Triple::aarch64)3403strcpy(method, "-[[x0 super] ");3404else3405strcpy(method, "-[[r? super] ");3406strcat(method, info->selector_name);3407strcat(method, "]");3408*ReferenceName = method;3409*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3410}3411info->class_name = nullptr;3412}3413}3414}3415}34163417// GuessPointerPointer() is passed the address of what might be a pointer to3418// a reference to an Objective-C class, selector, message ref or cfstring.3419// If so the value of the pointer is returned and one of the booleans are set3420// to true. If not zero is returned and all the booleans are set to false.3421static uint64_t GuessPointerPointer(uint64_t ReferenceValue,3422struct DisassembleInfo *info,3423bool &classref, bool &selref, bool &msgref,3424bool &cfstring) {3425classref = false;3426selref = false;3427msgref = false;3428cfstring = false;3429for (const auto &Load : info->O->load_commands()) {3430if (Load.C.cmd == MachO::LC_SEGMENT_64) {3431MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3432for (unsigned J = 0; J < Seg.nsects; ++J) {3433MachO::section_64 Sec = info->O->getSection64(Load, J);3434if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||3435strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3436strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||3437strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||3438strncmp(Sec.sectname, "__cfstring", 16) == 0) &&3439ReferenceValue >= Sec.addr &&3440ReferenceValue < Sec.addr + Sec.size) {3441uint64_t sect_offset = ReferenceValue - Sec.addr;3442uint64_t object_offset = Sec.offset + sect_offset;3443StringRef MachOContents = info->O->getData();3444uint64_t object_size = MachOContents.size();3445const char *object_addr = (const char *)MachOContents.data();3446if (object_offset < object_size) {3447uint64_t pointer_value;3448memcpy(&pointer_value, object_addr + object_offset,3449sizeof(uint64_t));3450if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3451sys::swapByteOrder(pointer_value);3452if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)3453selref = true;3454else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3455strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)3456classref = true;3457else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&3458ReferenceValue + 8 < Sec.addr + Sec.size) {3459msgref = true;3460memcpy(&pointer_value, object_addr + object_offset + 8,3461sizeof(uint64_t));3462if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3463sys::swapByteOrder(pointer_value);3464} else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)3465cfstring = true;3466return pointer_value;3467} else {3468return 0;3469}3470}3471}3472}3473// TODO: Look for LC_SEGMENT for 32-bit Mach-O files.3474}3475return 0;3476}34773478// get_pointer_64 returns a pointer to the bytes in the object file at the3479// Address from a section in the Mach-O file. And indirectly returns the3480// offset into the section, number of bytes left in the section past the offset3481// and which section is was being referenced. If the Address is not in a3482// section nullptr is returned.3483static const char *get_pointer_64(uint64_t Address, uint32_t &offset,3484uint32_t &left, SectionRef &S,3485DisassembleInfo *info,3486bool objc_only = false) {3487offset = 0;3488left = 0;3489S = SectionRef();3490for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {3491uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();3492uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();3493if (SectSize == 0)3494continue;3495if (objc_only) {3496StringRef SectName;3497Expected<StringRef> SecNameOrErr =3498((*(info->Sections))[SectIdx]).getName();3499if (SecNameOrErr)3500SectName = *SecNameOrErr;3501else3502consumeError(SecNameOrErr.takeError());35033504DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();3505StringRef SegName = info->O->getSectionFinalSegmentName(Ref);3506if (SegName != "__OBJC" && SectName != "__cstring")3507continue;3508}3509if (Address >= SectAddress && Address < SectAddress + SectSize) {3510S = (*(info->Sections))[SectIdx];3511offset = Address - SectAddress;3512left = SectSize - offset;3513StringRef SectContents = unwrapOrError(3514((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());3515return SectContents.data() + offset;3516}3517}3518return nullptr;3519}35203521static const char *get_pointer_32(uint32_t Address, uint32_t &offset,3522uint32_t &left, SectionRef &S,3523DisassembleInfo *info,3524bool objc_only = false) {3525return get_pointer_64(Address, offset, left, S, info, objc_only);3526}35273528// get_symbol_64() returns the name of a symbol (or nullptr) and the address of3529// the symbol indirectly through n_value. Based on the relocation information3530// for the specified section offset in the specified section reference.3531// If no relocation information is found and a non-zero ReferenceValue for the3532// symbol is passed, look up that address in the info's AddrMap.3533static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,3534DisassembleInfo *info, uint64_t &n_value,3535uint64_t ReferenceValue = 0) {3536n_value = 0;3537if (!info->verbose)3538return nullptr;35393540// See if there is an external relocation entry at the sect_offset.3541bool reloc_found = false;3542DataRefImpl Rel;3543MachO::any_relocation_info RE;3544bool isExtern = false;3545SymbolRef Symbol;3546for (const RelocationRef &Reloc : S.relocations()) {3547uint64_t RelocOffset = Reloc.getOffset();3548if (RelocOffset == sect_offset) {3549Rel = Reloc.getRawDataRefImpl();3550RE = info->O->getRelocation(Rel);3551if (info->O->isRelocationScattered(RE))3552continue;3553isExtern = info->O->getPlainRelocationExternal(RE);3554if (isExtern) {3555symbol_iterator RelocSym = Reloc.getSymbol();3556Symbol = *RelocSym;3557}3558reloc_found = true;3559break;3560}3561}3562// If there is an external relocation entry for a symbol in this section3563// at this section_offset then use that symbol's value for the n_value3564// and return its name.3565const char *SymbolName = nullptr;3566if (reloc_found && isExtern) {3567n_value = cantFail(Symbol.getValue());3568StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());3569if (!Name.empty()) {3570SymbolName = Name.data();3571return SymbolName;3572}3573}35743575// TODO: For fully linked images, look through the external relocation3576// entries off the dynamic symtab command. For these the r_offset is from the3577// start of the first writeable segment in the Mach-O file. So the offset3578// to this section from that segment is passed to this routine by the caller,3579// as the database_offset. Which is the difference of the section's starting3580// address and the first writable segment.3581//3582// NOTE: need add passing the database_offset to this routine.35833584// We did not find an external relocation entry so look up the ReferenceValue3585// as an address of a symbol and if found return that symbol's name.3586SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);35873588return SymbolName;3589}35903591static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,3592DisassembleInfo *info,3593uint32_t ReferenceValue) {3594uint64_t n_value64;3595return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);3596}35973598namespace {35993600// These are structs in the Objective-C meta data and read to produce the3601// comments for disassembly. While these are part of the ABI they are no3602// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h3603// .36043605// The cfstring object in a 64-bit Mach-O file.3606struct cfstring64_t {3607uint64_t isa; // class64_t * (64-bit pointer)3608uint64_t flags; // flag bits3609uint64_t characters; // char * (64-bit pointer)3610uint64_t length; // number of non-NULL characters in above3611};36123613// The class object in a 64-bit Mach-O file.3614struct class64_t {3615uint64_t isa; // class64_t * (64-bit pointer)3616uint64_t superclass; // class64_t * (64-bit pointer)3617uint64_t cache; // Cache (64-bit pointer)3618uint64_t vtable; // IMP * (64-bit pointer)3619uint64_t data; // class_ro64_t * (64-bit pointer)3620};36213622struct class32_t {3623uint32_t isa; /* class32_t * (32-bit pointer) */3624uint32_t superclass; /* class32_t * (32-bit pointer) */3625uint32_t cache; /* Cache (32-bit pointer) */3626uint32_t vtable; /* IMP * (32-bit pointer) */3627uint32_t data; /* class_ro32_t * (32-bit pointer) */3628};36293630struct class_ro64_t {3631uint32_t flags;3632uint32_t instanceStart;3633uint32_t instanceSize;3634uint32_t reserved;3635uint64_t ivarLayout; // const uint8_t * (64-bit pointer)3636uint64_t name; // const char * (64-bit pointer)3637uint64_t baseMethods; // const method_list_t * (64-bit pointer)3638uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)3639uint64_t ivars; // const ivar_list_t * (64-bit pointer)3640uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)3641uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)3642};36433644struct class_ro32_t {3645uint32_t flags;3646uint32_t instanceStart;3647uint32_t instanceSize;3648uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */3649uint32_t name; /* const char * (32-bit pointer) */3650uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */3651uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */3652uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */3653uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */3654uint32_t baseProperties; /* const struct objc_property_list *3655(32-bit pointer) */3656};36573658/* Values for class_ro{64,32}_t->flags */3659#define RO_META (1 << 0)3660#define RO_ROOT (1 << 1)3661#define RO_HAS_CXX_STRUCTORS (1 << 2)36623663/* Values for method_list{64,32}_t->entsize */3664#define ML_HAS_RELATIVE_PTRS (1 << 31)3665#define ML_ENTSIZE_MASK 0xFFFF36663667struct method_list64_t {3668uint32_t entsize;3669uint32_t count;3670/* struct method64_t first; These structures follow inline */3671};36723673struct method_list32_t {3674uint32_t entsize;3675uint32_t count;3676/* struct method32_t first; These structures follow inline */3677};36783679struct method64_t {3680uint64_t name; /* SEL (64-bit pointer) */3681uint64_t types; /* const char * (64-bit pointer) */3682uint64_t imp; /* IMP (64-bit pointer) */3683};36843685struct method32_t {3686uint32_t name; /* SEL (32-bit pointer) */3687uint32_t types; /* const char * (32-bit pointer) */3688uint32_t imp; /* IMP (32-bit pointer) */3689};36903691struct method_relative_t {3692int32_t name; /* SEL (32-bit relative) */3693int32_t types; /* const char * (32-bit relative) */3694int32_t imp; /* IMP (32-bit relative) */3695};36963697struct protocol_list64_t {3698uint64_t count; /* uintptr_t (a 64-bit value) */3699/* struct protocol64_t * list[0]; These pointers follow inline */3700};37013702struct protocol_list32_t {3703uint32_t count; /* uintptr_t (a 32-bit value) */3704/* struct protocol32_t * list[0]; These pointers follow inline */3705};37063707struct protocol64_t {3708uint64_t isa; /* id * (64-bit pointer) */3709uint64_t name; /* const char * (64-bit pointer) */3710uint64_t protocols; /* struct protocol_list64_t *3711(64-bit pointer) */3712uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */3713uint64_t classMethods; /* method_list_t * (64-bit pointer) */3714uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */3715uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */3716uint64_t instanceProperties; /* struct objc_property_list *3717(64-bit pointer) */3718};37193720struct protocol32_t {3721uint32_t isa; /* id * (32-bit pointer) */3722uint32_t name; /* const char * (32-bit pointer) */3723uint32_t protocols; /* struct protocol_list_t *3724(32-bit pointer) */3725uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */3726uint32_t classMethods; /* method_list_t * (32-bit pointer) */3727uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */3728uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */3729uint32_t instanceProperties; /* struct objc_property_list *3730(32-bit pointer) */3731};37323733struct ivar_list64_t {3734uint32_t entsize;3735uint32_t count;3736/* struct ivar64_t first; These structures follow inline */3737};37383739struct ivar_list32_t {3740uint32_t entsize;3741uint32_t count;3742/* struct ivar32_t first; These structures follow inline */3743};37443745struct ivar64_t {3746uint64_t offset; /* uintptr_t * (64-bit pointer) */3747uint64_t name; /* const char * (64-bit pointer) */3748uint64_t type; /* const char * (64-bit pointer) */3749uint32_t alignment;3750uint32_t size;3751};37523753struct ivar32_t {3754uint32_t offset; /* uintptr_t * (32-bit pointer) */3755uint32_t name; /* const char * (32-bit pointer) */3756uint32_t type; /* const char * (32-bit pointer) */3757uint32_t alignment;3758uint32_t size;3759};37603761struct objc_property_list64 {3762uint32_t entsize;3763uint32_t count;3764/* struct objc_property64 first; These structures follow inline */3765};37663767struct objc_property_list32 {3768uint32_t entsize;3769uint32_t count;3770/* struct objc_property32 first; These structures follow inline */3771};37723773struct objc_property64 {3774uint64_t name; /* const char * (64-bit pointer) */3775uint64_t attributes; /* const char * (64-bit pointer) */3776};37773778struct objc_property32 {3779uint32_t name; /* const char * (32-bit pointer) */3780uint32_t attributes; /* const char * (32-bit pointer) */3781};37823783struct category64_t {3784uint64_t name; /* const char * (64-bit pointer) */3785uint64_t cls; /* struct class_t * (64-bit pointer) */3786uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */3787uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */3788uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */3789uint64_t instanceProperties; /* struct objc_property_list *3790(64-bit pointer) */3791};37923793struct category32_t {3794uint32_t name; /* const char * (32-bit pointer) */3795uint32_t cls; /* struct class_t * (32-bit pointer) */3796uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */3797uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */3798uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */3799uint32_t instanceProperties; /* struct objc_property_list *3800(32-bit pointer) */3801};38023803struct objc_image_info64 {3804uint32_t version;3805uint32_t flags;3806};3807struct objc_image_info32 {3808uint32_t version;3809uint32_t flags;3810};3811struct imageInfo_t {3812uint32_t version;3813uint32_t flags;3814};3815/* masks for objc_image_info.flags */3816#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)3817#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)3818#define OBJC_IMAGE_IS_SIMULATED (1 << 5)3819#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)38203821struct message_ref64 {3822uint64_t imp; /* IMP (64-bit pointer) */3823uint64_t sel; /* SEL (64-bit pointer) */3824};38253826struct message_ref32 {3827uint32_t imp; /* IMP (32-bit pointer) */3828uint32_t sel; /* SEL (32-bit pointer) */3829};38303831// Objective-C 1 (32-bit only) meta data structs.38323833struct objc_module_t {3834uint32_t version;3835uint32_t size;3836uint32_t name; /* char * (32-bit pointer) */3837uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */3838};38393840struct objc_symtab_t {3841uint32_t sel_ref_cnt;3842uint32_t refs; /* SEL * (32-bit pointer) */3843uint16_t cls_def_cnt;3844uint16_t cat_def_cnt;3845// uint32_t defs[1]; /* void * (32-bit pointer) variable size */3846};38473848struct objc_class_t {3849uint32_t isa; /* struct objc_class * (32-bit pointer) */3850uint32_t super_class; /* struct objc_class * (32-bit pointer) */3851uint32_t name; /* const char * (32-bit pointer) */3852int32_t version;3853int32_t info;3854int32_t instance_size;3855uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */3856uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */3857uint32_t cache; /* struct objc_cache * (32-bit pointer) */3858uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */3859};38603861#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))3862// class is not a metaclass3863#define CLS_CLASS 0x13864// class is a metaclass3865#define CLS_META 0x238663867struct objc_category_t {3868uint32_t category_name; /* char * (32-bit pointer) */3869uint32_t class_name; /* char * (32-bit pointer) */3870uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */3871uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */3872uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */3873};38743875struct objc_ivar_t {3876uint32_t ivar_name; /* char * (32-bit pointer) */3877uint32_t ivar_type; /* char * (32-bit pointer) */3878int32_t ivar_offset;3879};38803881struct objc_ivar_list_t {3882int32_t ivar_count;3883// struct objc_ivar_t ivar_list[1]; /* variable length structure */3884};38853886struct objc_method_list_t {3887uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */3888int32_t method_count;3889// struct objc_method_t method_list[1]; /* variable length structure */3890};38913892struct objc_method_t {3893uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */3894uint32_t method_types; /* char * (32-bit pointer) */3895uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)3896(32-bit pointer) */3897};38983899struct objc_protocol_list_t {3900uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */3901int32_t count;3902// uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *3903// (32-bit pointer) */3904};39053906struct objc_protocol_t {3907uint32_t isa; /* struct objc_class * (32-bit pointer) */3908uint32_t protocol_name; /* char * (32-bit pointer) */3909uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */3910uint32_t instance_methods; /* struct objc_method_description_list *3911(32-bit pointer) */3912uint32_t class_methods; /* struct objc_method_description_list *3913(32-bit pointer) */3914};39153916struct objc_method_description_list_t {3917int32_t count;3918// struct objc_method_description_t list[1];3919};39203921struct objc_method_description_t {3922uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */3923uint32_t types; /* char * (32-bit pointer) */3924};39253926inline void swapStruct(struct cfstring64_t &cfs) {3927sys::swapByteOrder(cfs.isa);3928sys::swapByteOrder(cfs.flags);3929sys::swapByteOrder(cfs.characters);3930sys::swapByteOrder(cfs.length);3931}39323933inline void swapStruct(struct class64_t &c) {3934sys::swapByteOrder(c.isa);3935sys::swapByteOrder(c.superclass);3936sys::swapByteOrder(c.cache);3937sys::swapByteOrder(c.vtable);3938sys::swapByteOrder(c.data);3939}39403941inline void swapStruct(struct class32_t &c) {3942sys::swapByteOrder(c.isa);3943sys::swapByteOrder(c.superclass);3944sys::swapByteOrder(c.cache);3945sys::swapByteOrder(c.vtable);3946sys::swapByteOrder(c.data);3947}39483949inline void swapStruct(struct class_ro64_t &cro) {3950sys::swapByteOrder(cro.flags);3951sys::swapByteOrder(cro.instanceStart);3952sys::swapByteOrder(cro.instanceSize);3953sys::swapByteOrder(cro.reserved);3954sys::swapByteOrder(cro.ivarLayout);3955sys::swapByteOrder(cro.name);3956sys::swapByteOrder(cro.baseMethods);3957sys::swapByteOrder(cro.baseProtocols);3958sys::swapByteOrder(cro.ivars);3959sys::swapByteOrder(cro.weakIvarLayout);3960sys::swapByteOrder(cro.baseProperties);3961}39623963inline void swapStruct(struct class_ro32_t &cro) {3964sys::swapByteOrder(cro.flags);3965sys::swapByteOrder(cro.instanceStart);3966sys::swapByteOrder(cro.instanceSize);3967sys::swapByteOrder(cro.ivarLayout);3968sys::swapByteOrder(cro.name);3969sys::swapByteOrder(cro.baseMethods);3970sys::swapByteOrder(cro.baseProtocols);3971sys::swapByteOrder(cro.ivars);3972sys::swapByteOrder(cro.weakIvarLayout);3973sys::swapByteOrder(cro.baseProperties);3974}39753976inline void swapStruct(struct method_list64_t &ml) {3977sys::swapByteOrder(ml.entsize);3978sys::swapByteOrder(ml.count);3979}39803981inline void swapStruct(struct method_list32_t &ml) {3982sys::swapByteOrder(ml.entsize);3983sys::swapByteOrder(ml.count);3984}39853986inline void swapStruct(struct method64_t &m) {3987sys::swapByteOrder(m.name);3988sys::swapByteOrder(m.types);3989sys::swapByteOrder(m.imp);3990}39913992inline void swapStruct(struct method32_t &m) {3993sys::swapByteOrder(m.name);3994sys::swapByteOrder(m.types);3995sys::swapByteOrder(m.imp);3996}39973998inline void swapStruct(struct method_relative_t &m) {3999sys::swapByteOrder(m.name);4000sys::swapByteOrder(m.types);4001sys::swapByteOrder(m.imp);4002}40034004inline void swapStruct(struct protocol_list64_t &pl) {4005sys::swapByteOrder(pl.count);4006}40074008inline void swapStruct(struct protocol_list32_t &pl) {4009sys::swapByteOrder(pl.count);4010}40114012inline void swapStruct(struct protocol64_t &p) {4013sys::swapByteOrder(p.isa);4014sys::swapByteOrder(p.name);4015sys::swapByteOrder(p.protocols);4016sys::swapByteOrder(p.instanceMethods);4017sys::swapByteOrder(p.classMethods);4018sys::swapByteOrder(p.optionalInstanceMethods);4019sys::swapByteOrder(p.optionalClassMethods);4020sys::swapByteOrder(p.instanceProperties);4021}40224023inline void swapStruct(struct protocol32_t &p) {4024sys::swapByteOrder(p.isa);4025sys::swapByteOrder(p.name);4026sys::swapByteOrder(p.protocols);4027sys::swapByteOrder(p.instanceMethods);4028sys::swapByteOrder(p.classMethods);4029sys::swapByteOrder(p.optionalInstanceMethods);4030sys::swapByteOrder(p.optionalClassMethods);4031sys::swapByteOrder(p.instanceProperties);4032}40334034inline void swapStruct(struct ivar_list64_t &il) {4035sys::swapByteOrder(il.entsize);4036sys::swapByteOrder(il.count);4037}40384039inline void swapStruct(struct ivar_list32_t &il) {4040sys::swapByteOrder(il.entsize);4041sys::swapByteOrder(il.count);4042}40434044inline void swapStruct(struct ivar64_t &i) {4045sys::swapByteOrder(i.offset);4046sys::swapByteOrder(i.name);4047sys::swapByteOrder(i.type);4048sys::swapByteOrder(i.alignment);4049sys::swapByteOrder(i.size);4050}40514052inline void swapStruct(struct ivar32_t &i) {4053sys::swapByteOrder(i.offset);4054sys::swapByteOrder(i.name);4055sys::swapByteOrder(i.type);4056sys::swapByteOrder(i.alignment);4057sys::swapByteOrder(i.size);4058}40594060inline void swapStruct(struct objc_property_list64 &pl) {4061sys::swapByteOrder(pl.entsize);4062sys::swapByteOrder(pl.count);4063}40644065inline void swapStruct(struct objc_property_list32 &pl) {4066sys::swapByteOrder(pl.entsize);4067sys::swapByteOrder(pl.count);4068}40694070inline void swapStruct(struct objc_property64 &op) {4071sys::swapByteOrder(op.name);4072sys::swapByteOrder(op.attributes);4073}40744075inline void swapStruct(struct objc_property32 &op) {4076sys::swapByteOrder(op.name);4077sys::swapByteOrder(op.attributes);4078}40794080inline void swapStruct(struct category64_t &c) {4081sys::swapByteOrder(c.name);4082sys::swapByteOrder(c.cls);4083sys::swapByteOrder(c.instanceMethods);4084sys::swapByteOrder(c.classMethods);4085sys::swapByteOrder(c.protocols);4086sys::swapByteOrder(c.instanceProperties);4087}40884089inline void swapStruct(struct category32_t &c) {4090sys::swapByteOrder(c.name);4091sys::swapByteOrder(c.cls);4092sys::swapByteOrder(c.instanceMethods);4093sys::swapByteOrder(c.classMethods);4094sys::swapByteOrder(c.protocols);4095sys::swapByteOrder(c.instanceProperties);4096}40974098inline void swapStruct(struct objc_image_info64 &o) {4099sys::swapByteOrder(o.version);4100sys::swapByteOrder(o.flags);4101}41024103inline void swapStruct(struct objc_image_info32 &o) {4104sys::swapByteOrder(o.version);4105sys::swapByteOrder(o.flags);4106}41074108inline void swapStruct(struct imageInfo_t &o) {4109sys::swapByteOrder(o.version);4110sys::swapByteOrder(o.flags);4111}41124113inline void swapStruct(struct message_ref64 &mr) {4114sys::swapByteOrder(mr.imp);4115sys::swapByteOrder(mr.sel);4116}41174118inline void swapStruct(struct message_ref32 &mr) {4119sys::swapByteOrder(mr.imp);4120sys::swapByteOrder(mr.sel);4121}41224123inline void swapStruct(struct objc_module_t &module) {4124sys::swapByteOrder(module.version);4125sys::swapByteOrder(module.size);4126sys::swapByteOrder(module.name);4127sys::swapByteOrder(module.symtab);4128}41294130inline void swapStruct(struct objc_symtab_t &symtab) {4131sys::swapByteOrder(symtab.sel_ref_cnt);4132sys::swapByteOrder(symtab.refs);4133sys::swapByteOrder(symtab.cls_def_cnt);4134sys::swapByteOrder(symtab.cat_def_cnt);4135}41364137inline void swapStruct(struct objc_class_t &objc_class) {4138sys::swapByteOrder(objc_class.isa);4139sys::swapByteOrder(objc_class.super_class);4140sys::swapByteOrder(objc_class.name);4141sys::swapByteOrder(objc_class.version);4142sys::swapByteOrder(objc_class.info);4143sys::swapByteOrder(objc_class.instance_size);4144sys::swapByteOrder(objc_class.ivars);4145sys::swapByteOrder(objc_class.methodLists);4146sys::swapByteOrder(objc_class.cache);4147sys::swapByteOrder(objc_class.protocols);4148}41494150inline void swapStruct(struct objc_category_t &objc_category) {4151sys::swapByteOrder(objc_category.category_name);4152sys::swapByteOrder(objc_category.class_name);4153sys::swapByteOrder(objc_category.instance_methods);4154sys::swapByteOrder(objc_category.class_methods);4155sys::swapByteOrder(objc_category.protocols);4156}41574158inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {4159sys::swapByteOrder(objc_ivar_list.ivar_count);4160}41614162inline void swapStruct(struct objc_ivar_t &objc_ivar) {4163sys::swapByteOrder(objc_ivar.ivar_name);4164sys::swapByteOrder(objc_ivar.ivar_type);4165sys::swapByteOrder(objc_ivar.ivar_offset);4166}41674168inline void swapStruct(struct objc_method_list_t &method_list) {4169sys::swapByteOrder(method_list.obsolete);4170sys::swapByteOrder(method_list.method_count);4171}41724173inline void swapStruct(struct objc_method_t &method) {4174sys::swapByteOrder(method.method_name);4175sys::swapByteOrder(method.method_types);4176sys::swapByteOrder(method.method_imp);4177}41784179inline void swapStruct(struct objc_protocol_list_t &protocol_list) {4180sys::swapByteOrder(protocol_list.next);4181sys::swapByteOrder(protocol_list.count);4182}41834184inline void swapStruct(struct objc_protocol_t &protocol) {4185sys::swapByteOrder(protocol.isa);4186sys::swapByteOrder(protocol.protocol_name);4187sys::swapByteOrder(protocol.protocol_list);4188sys::swapByteOrder(protocol.instance_methods);4189sys::swapByteOrder(protocol.class_methods);4190}41914192inline void swapStruct(struct objc_method_description_list_t &mdl) {4193sys::swapByteOrder(mdl.count);4194}41954196inline void swapStruct(struct objc_method_description_t &md) {4197sys::swapByteOrder(md.name);4198sys::swapByteOrder(md.types);4199}42004201} // namespace42024203static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,4204struct DisassembleInfo *info);42054206// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer4207// to an Objective-C class and returns the class name. It is also passed the4208// address of the pointer, so when the pointer is zero as it can be in an .o4209// file, that is used to look for an external relocation entry with a symbol4210// name.4211static const char *get_objc2_64bit_class_name(uint64_t pointer_value,4212uint64_t ReferenceValue,4213struct DisassembleInfo *info) {4214const char *r;4215uint32_t offset, left;4216SectionRef S;42174218// The pointer_value can be 0 in an object file and have a relocation4219// entry for the class symbol at the ReferenceValue (the address of the4220// pointer).4221if (pointer_value == 0) {4222r = get_pointer_64(ReferenceValue, offset, left, S, info);4223if (r == nullptr || left < sizeof(uint64_t))4224return nullptr;4225uint64_t n_value;4226const char *symbol_name = get_symbol_64(offset, S, info, n_value);4227if (symbol_name == nullptr)4228return nullptr;4229const char *class_name = strrchr(symbol_name, '$');4230if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')4231return class_name + 2;4232else4233return nullptr;4234}42354236// The case were the pointer_value is non-zero and points to a class defined4237// in this Mach-O file.4238r = get_pointer_64(pointer_value, offset, left, S, info);4239if (r == nullptr || left < sizeof(struct class64_t))4240return nullptr;4241struct class64_t c;4242memcpy(&c, r, sizeof(struct class64_t));4243if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4244swapStruct(c);4245if (c.data == 0)4246return nullptr;4247r = get_pointer_64(c.data, offset, left, S, info);4248if (r == nullptr || left < sizeof(struct class_ro64_t))4249return nullptr;4250struct class_ro64_t cro;4251memcpy(&cro, r, sizeof(struct class_ro64_t));4252if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4253swapStruct(cro);4254if (cro.name == 0)4255return nullptr;4256const char *name = get_pointer_64(cro.name, offset, left, S, info);4257return name;4258}42594260// get_objc2_64bit_cfstring_name is used for disassembly and is passed a4261// pointer to a cfstring and returns its name or nullptr.4262static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,4263struct DisassembleInfo *info) {4264const char *r, *name;4265uint32_t offset, left;4266SectionRef S;4267struct cfstring64_t cfs;4268uint64_t cfs_characters;42694270r = get_pointer_64(ReferenceValue, offset, left, S, info);4271if (r == nullptr || left < sizeof(struct cfstring64_t))4272return nullptr;4273memcpy(&cfs, r, sizeof(struct cfstring64_t));4274if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4275swapStruct(cfs);4276if (cfs.characters == 0) {4277uint64_t n_value;4278const char *symbol_name = get_symbol_64(4279offset + offsetof(struct cfstring64_t, characters), S, info, n_value);4280if (symbol_name == nullptr)4281return nullptr;4282cfs_characters = n_value;4283} else4284cfs_characters = cfs.characters;4285name = get_pointer_64(cfs_characters, offset, left, S, info);42864287return name;4288}42894290// get_objc2_64bit_selref() is used for disassembly and is passed a the address4291// of a pointer to an Objective-C selector reference when the pointer value is4292// zero as in a .o file and is likely to have a external relocation entry with4293// who's symbol's n_value is the real pointer to the selector name. If that is4294// the case the real pointer to the selector name is returned else 0 is4295// returned4296static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,4297struct DisassembleInfo *info) {4298uint32_t offset, left;4299SectionRef S;43004301const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);4302if (r == nullptr || left < sizeof(uint64_t))4303return 0;4304uint64_t n_value;4305const char *symbol_name = get_symbol_64(offset, S, info, n_value);4306if (symbol_name == nullptr)4307return 0;4308return n_value;4309}43104311static const SectionRef get_section(MachOObjectFile *O, const char *segname,4312const char *sectname) {4313for (const SectionRef &Section : O->sections()) {4314StringRef SectName;4315Expected<StringRef> SecNameOrErr = Section.getName();4316if (SecNameOrErr)4317SectName = *SecNameOrErr;4318else4319consumeError(SecNameOrErr.takeError());43204321DataRefImpl Ref = Section.getRawDataRefImpl();4322StringRef SegName = O->getSectionFinalSegmentName(Ref);4323if (SegName == segname && SectName == sectname)4324return Section;4325}4326return SectionRef();4327}43284329static void4330walk_pointer_list_64(const char *listname, const SectionRef S,4331MachOObjectFile *O, struct DisassembleInfo *info,4332void (*func)(uint64_t, struct DisassembleInfo *info)) {4333if (S == SectionRef())4334return;43354336StringRef SectName;4337Expected<StringRef> SecNameOrErr = S.getName();4338if (SecNameOrErr)4339SectName = *SecNameOrErr;4340else4341consumeError(SecNameOrErr.takeError());43424343DataRefImpl Ref = S.getRawDataRefImpl();4344StringRef SegName = O->getSectionFinalSegmentName(Ref);4345outs() << "Contents of (" << SegName << "," << SectName << ") section\n";43464347StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4348const char *Contents = reinterpret_cast<const char *>(BytesStr.data());43494350for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {4351uint32_t left = S.getSize() - i;4352uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);4353uint64_t p = 0;4354memcpy(&p, Contents + i, size);4355if (i + sizeof(uint64_t) > S.getSize())4356outs() << listname << " list pointer extends past end of (" << SegName4357<< "," << SectName << ") section\n";4358outs() << format("%016" PRIx64, S.getAddress() + i) << " ";43594360if (O->isLittleEndian() != sys::IsLittleEndianHost)4361sys::swapByteOrder(p);43624363uint64_t n_value = 0;4364const char *name = get_symbol_64(i, S, info, n_value, p);4365if (name == nullptr)4366name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);43674368if (n_value != 0) {4369outs() << format("0x%" PRIx64, n_value);4370if (p != 0)4371outs() << " + " << format("0x%" PRIx64, p);4372} else4373outs() << format("0x%" PRIx64, p);4374if (name != nullptr)4375outs() << " " << name;4376outs() << "\n";43774378p += n_value;4379if (func)4380func(p, info);4381}4382}43834384static void4385walk_pointer_list_32(const char *listname, const SectionRef S,4386MachOObjectFile *O, struct DisassembleInfo *info,4387void (*func)(uint32_t, struct DisassembleInfo *info)) {4388if (S == SectionRef())4389return;43904391StringRef SectName = unwrapOrError(S.getName(), O->getFileName());4392DataRefImpl Ref = S.getRawDataRefImpl();4393StringRef SegName = O->getSectionFinalSegmentName(Ref);4394outs() << "Contents of (" << SegName << "," << SectName << ") section\n";43954396StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4397const char *Contents = reinterpret_cast<const char *>(BytesStr.data());43984399for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {4400uint32_t left = S.getSize() - i;4401uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);4402uint32_t p = 0;4403memcpy(&p, Contents + i, size);4404if (i + sizeof(uint32_t) > S.getSize())4405outs() << listname << " list pointer extends past end of (" << SegName4406<< "," << SectName << ") section\n";4407uint32_t Address = S.getAddress() + i;4408outs() << format("%08" PRIx32, Address) << " ";44094410if (O->isLittleEndian() != sys::IsLittleEndianHost)4411sys::swapByteOrder(p);4412outs() << format("0x%" PRIx32, p);44134414const char *name = get_symbol_32(i, S, info, p);4415if (name != nullptr)4416outs() << " " << name;4417outs() << "\n";44184419if (func)4420func(p, info);4421}4422}44234424static void print_layout_map(const char *layout_map, uint32_t left) {4425if (layout_map == nullptr)4426return;4427outs() << " layout map: ";4428do {4429outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";4430left--;4431layout_map++;4432} while (*layout_map != '\0' && left != 0);4433outs() << "\n";4434}44354436static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {4437uint32_t offset, left;4438SectionRef S;4439const char *layout_map;44404441if (p == 0)4442return;4443layout_map = get_pointer_64(p, offset, left, S, info);4444print_layout_map(layout_map, left);4445}44464447static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {4448uint32_t offset, left;4449SectionRef S;4450const char *layout_map;44514452if (p == 0)4453return;4454layout_map = get_pointer_32(p, offset, left, S, info);4455print_layout_map(layout_map, left);4456}44574458static void print_relative_method_list(uint32_t structSizeAndFlags,4459uint32_t structCount, uint64_t p,4460struct DisassembleInfo *info,4461const char *indent,4462uint32_t pointerBits) {4463struct method_relative_t m;4464const char *r, *name;4465uint32_t offset, xoffset, left, i;4466SectionRef S, xS;44674468assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&4469"expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");44704471outs() << indent << "\t\t entsize "4472<< (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";4473outs() << indent << "\t\t count " << structCount << "\n";44744475for (i = 0; i < structCount; i++) {4476r = get_pointer_64(p, offset, left, S, info);4477memset(&m, '\0', sizeof(struct method_relative_t));4478if (left < sizeof(struct method_relative_t)) {4479memcpy(&m, r, left);4480outs() << indent << " (method_t extends past the end of the section)\n";4481} else4482memcpy(&m, r, sizeof(struct method_relative_t));4483if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4484swapStruct(m);44854486outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);4487uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);4488uint64_t absNameRefVA = relNameRefVA + m.name;4489outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";44904491// since this is a relative list, absNameRefVA is the address of the4492// __objc_selrefs entry, so a pointer, not the actual name4493const char *nameRefPtr =4494get_pointer_64(absNameRefVA, xoffset, left, xS, info);4495if (nameRefPtr) {4496uint32_t pointerSize = pointerBits / CHAR_BIT;4497if (left < pointerSize)4498outs() << indent << " (nameRefPtr extends past the end of the section)";4499else {4500if (pointerSize == 64) {4501uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);4502if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4503sys::swapByteOrder(nameOff_64);4504name = get_pointer_64(nameOff_64, xoffset, left, xS, info);4505} else {4506uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);4507if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4508sys::swapByteOrder(nameOff_32);4509name = get_pointer_32(nameOff_32, xoffset, left, xS, info);4510}4511if (name != nullptr)4512outs() << format(" %.*s", left, name);4513}4514}4515outs() << "\n";45164517outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);4518uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);4519uint64_t absTypesVA = relTypesVA + m.types;4520outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";4521name = get_pointer_32(absTypesVA, xoffset, left, xS, info);4522if (name != nullptr)4523outs() << format(" %.*s", left, name);4524outs() << "\n";45254526outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);4527uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);4528uint64_t absImpVA = relImpVA + m.imp;4529outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";4530name = GuessSymbolName(absImpVA, info->AddrMap);4531if (name != nullptr)4532outs() << " " << name;4533outs() << "\n";45344535p += sizeof(struct method_relative_t);4536offset += sizeof(struct method_relative_t);4537}4538}45394540static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,4541const char *indent) {4542struct method_list64_t ml;4543struct method64_t m;4544const char *r;4545uint32_t offset, xoffset, left, i;4546SectionRef S, xS;4547const char *name, *sym_name;4548uint64_t n_value;45494550r = get_pointer_64(p, offset, left, S, info);4551if (r == nullptr)4552return;4553memset(&ml, '\0', sizeof(struct method_list64_t));4554if (left < sizeof(struct method_list64_t)) {4555memcpy(&ml, r, left);4556outs() << " (method_list_t entends past the end of the section)\n";4557} else4558memcpy(&ml, r, sizeof(struct method_list64_t));4559if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4560swapStruct(ml);4561p += sizeof(struct method_list64_t);45624563if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4564print_relative_method_list(ml.entsize, ml.count, p, info, indent,4565/*pointerBits=*/64);4566return;4567}45684569outs() << indent << "\t\t entsize " << ml.entsize << "\n";4570outs() << indent << "\t\t count " << ml.count << "\n";45714572offset += sizeof(struct method_list64_t);4573for (i = 0; i < ml.count; i++) {4574r = get_pointer_64(p, offset, left, S, info);4575if (r == nullptr)4576return;4577memset(&m, '\0', sizeof(struct method64_t));4578if (left < sizeof(struct method64_t)) {4579memcpy(&m, r, left);4580outs() << indent << " (method_t extends past the end of the section)\n";4581} else4582memcpy(&m, r, sizeof(struct method64_t));4583if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4584swapStruct(m);45854586outs() << indent << "\t\t name ";4587sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,4588info, n_value, m.name);4589if (n_value != 0) {4590if (info->verbose && sym_name != nullptr)4591outs() << sym_name;4592else4593outs() << format("0x%" PRIx64, n_value);4594if (m.name != 0)4595outs() << " + " << format("0x%" PRIx64, m.name);4596} else4597outs() << format("0x%" PRIx64, m.name);4598name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);4599if (name != nullptr)4600outs() << format(" %.*s", left, name);4601outs() << "\n";46024603outs() << indent << "\t\t types ";4604sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,4605info, n_value, m.types);4606if (n_value != 0) {4607if (info->verbose && sym_name != nullptr)4608outs() << sym_name;4609else4610outs() << format("0x%" PRIx64, n_value);4611if (m.types != 0)4612outs() << " + " << format("0x%" PRIx64, m.types);4613} else4614outs() << format("0x%" PRIx64, m.types);4615name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);4616if (name != nullptr)4617outs() << format(" %.*s", left, name);4618outs() << "\n";46194620outs() << indent << "\t\t imp ";4621name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,4622n_value, m.imp);4623if (info->verbose && name == nullptr) {4624if (n_value != 0) {4625outs() << format("0x%" PRIx64, n_value) << " ";4626if (m.imp != 0)4627outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";4628} else4629outs() << format("0x%" PRIx64, m.imp) << " ";4630}4631if (name != nullptr)4632outs() << name;4633outs() << "\n";46344635p += sizeof(struct method64_t);4636offset += sizeof(struct method64_t);4637}4638}46394640static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,4641const char *indent) {4642struct method_list32_t ml;4643struct method32_t m;4644const char *r, *name;4645uint32_t offset, xoffset, left, i;4646SectionRef S, xS;46474648r = get_pointer_32(p, offset, left, S, info);4649if (r == nullptr)4650return;4651memset(&ml, '\0', sizeof(struct method_list32_t));4652if (left < sizeof(struct method_list32_t)) {4653memcpy(&ml, r, left);4654outs() << " (method_list_t entends past the end of the section)\n";4655} else4656memcpy(&ml, r, sizeof(struct method_list32_t));4657if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4658swapStruct(ml);4659p += sizeof(struct method_list32_t);46604661if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4662print_relative_method_list(ml.entsize, ml.count, p, info, indent,4663/*pointerBits=*/32);4664return;4665}46664667outs() << indent << "\t\t entsize " << ml.entsize << "\n";4668outs() << indent << "\t\t count " << ml.count << "\n";46694670offset += sizeof(struct method_list32_t);4671for (i = 0; i < ml.count; i++) {4672r = get_pointer_32(p, offset, left, S, info);4673if (r == nullptr)4674return;4675memset(&m, '\0', sizeof(struct method32_t));4676if (left < sizeof(struct method32_t)) {4677memcpy(&ml, r, left);4678outs() << indent << " (method_t entends past the end of the section)\n";4679} else4680memcpy(&m, r, sizeof(struct method32_t));4681if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4682swapStruct(m);46834684outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);4685name = get_pointer_32(m.name, xoffset, left, xS, info);4686if (name != nullptr)4687outs() << format(" %.*s", left, name);4688outs() << "\n";46894690outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);4691name = get_pointer_32(m.types, xoffset, left, xS, info);4692if (name != nullptr)4693outs() << format(" %.*s", left, name);4694outs() << "\n";46954696outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);4697name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,4698m.imp);4699if (name != nullptr)4700outs() << " " << name;4701outs() << "\n";47024703p += sizeof(struct method32_t);4704offset += sizeof(struct method32_t);4705}4706}47074708static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {4709uint32_t offset, left, xleft;4710SectionRef S;4711struct objc_method_list_t method_list;4712struct objc_method_t method;4713const char *r, *methods, *name, *SymbolName;4714int32_t i;47154716r = get_pointer_32(p, offset, left, S, info, true);4717if (r == nullptr)4718return true;47194720outs() << "\n";4721if (left > sizeof(struct objc_method_list_t)) {4722memcpy(&method_list, r, sizeof(struct objc_method_list_t));4723} else {4724outs() << "\t\t objc_method_list extends past end of the section\n";4725memset(&method_list, '\0', sizeof(struct objc_method_list_t));4726memcpy(&method_list, r, left);4727}4728if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4729swapStruct(method_list);47304731outs() << "\t\t obsolete "4732<< format("0x%08" PRIx32, method_list.obsolete) << "\n";4733outs() << "\t\t method_count " << method_list.method_count << "\n";47344735methods = r + sizeof(struct objc_method_list_t);4736for (i = 0; i < method_list.method_count; i++) {4737if ((i + 1) * sizeof(struct objc_method_t) > left) {4738outs() << "\t\t remaining method's extend past the of the section\n";4739break;4740}4741memcpy(&method, methods + i * sizeof(struct objc_method_t),4742sizeof(struct objc_method_t));4743if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4744swapStruct(method);47454746outs() << "\t\t method_name "4747<< format("0x%08" PRIx32, method.method_name);4748if (info->verbose) {4749name = get_pointer_32(method.method_name, offset, xleft, S, info, true);4750if (name != nullptr)4751outs() << format(" %.*s", xleft, name);4752else4753outs() << " (not in an __OBJC section)";4754}4755outs() << "\n";47564757outs() << "\t\t method_types "4758<< format("0x%08" PRIx32, method.method_types);4759if (info->verbose) {4760name = get_pointer_32(method.method_types, offset, xleft, S, info, true);4761if (name != nullptr)4762outs() << format(" %.*s", xleft, name);4763else4764outs() << " (not in an __OBJC section)";4765}4766outs() << "\n";47674768outs() << "\t\t method_imp "4769<< format("0x%08" PRIx32, method.method_imp) << " ";4770if (info->verbose) {4771SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);4772if (SymbolName != nullptr)4773outs() << SymbolName;4774}4775outs() << "\n";4776}4777return false;4778}47794780static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {4781struct protocol_list64_t pl;4782uint64_t q, n_value;4783struct protocol64_t pc;4784const char *r;4785uint32_t offset, xoffset, left, i;4786SectionRef S, xS;4787const char *name, *sym_name;47884789r = get_pointer_64(p, offset, left, S, info);4790if (r == nullptr)4791return;4792memset(&pl, '\0', sizeof(struct protocol_list64_t));4793if (left < sizeof(struct protocol_list64_t)) {4794memcpy(&pl, r, left);4795outs() << " (protocol_list_t entends past the end of the section)\n";4796} else4797memcpy(&pl, r, sizeof(struct protocol_list64_t));4798if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4799swapStruct(pl);4800outs() << " count " << pl.count << "\n";48014802p += sizeof(struct protocol_list64_t);4803offset += sizeof(struct protocol_list64_t);4804for (i = 0; i < pl.count; i++) {4805r = get_pointer_64(p, offset, left, S, info);4806if (r == nullptr)4807return;4808q = 0;4809if (left < sizeof(uint64_t)) {4810memcpy(&q, r, left);4811outs() << " (protocol_t * entends past the end of the section)\n";4812} else4813memcpy(&q, r, sizeof(uint64_t));4814if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4815sys::swapByteOrder(q);48164817outs() << "\t\t list[" << i << "] ";4818sym_name = get_symbol_64(offset, S, info, n_value, q);4819if (n_value != 0) {4820if (info->verbose && sym_name != nullptr)4821outs() << sym_name;4822else4823outs() << format("0x%" PRIx64, n_value);4824if (q != 0)4825outs() << " + " << format("0x%" PRIx64, q);4826} else4827outs() << format("0x%" PRIx64, q);4828outs() << " (struct protocol_t *)\n";48294830r = get_pointer_64(q + n_value, offset, left, S, info);4831if (r == nullptr)4832return;4833memset(&pc, '\0', sizeof(struct protocol64_t));4834if (left < sizeof(struct protocol64_t)) {4835memcpy(&pc, r, left);4836outs() << " (protocol_t entends past the end of the section)\n";4837} else4838memcpy(&pc, r, sizeof(struct protocol64_t));4839if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4840swapStruct(pc);48414842outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";48434844outs() << "\t\t\t name ";4845sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,4846info, n_value, pc.name);4847if (n_value != 0) {4848if (info->verbose && sym_name != nullptr)4849outs() << sym_name;4850else4851outs() << format("0x%" PRIx64, n_value);4852if (pc.name != 0)4853outs() << " + " << format("0x%" PRIx64, pc.name);4854} else4855outs() << format("0x%" PRIx64, pc.name);4856name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);4857if (name != nullptr)4858outs() << format(" %.*s", left, name);4859outs() << "\n";48604861outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";48624863outs() << "\t\t instanceMethods ";4864sym_name =4865get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),4866S, info, n_value, pc.instanceMethods);4867if (n_value != 0) {4868if (info->verbose && sym_name != nullptr)4869outs() << sym_name;4870else4871outs() << format("0x%" PRIx64, n_value);4872if (pc.instanceMethods != 0)4873outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);4874} else4875outs() << format("0x%" PRIx64, pc.instanceMethods);4876outs() << " (struct method_list_t *)\n";4877if (pc.instanceMethods + n_value != 0)4878print_method_list64_t(pc.instanceMethods + n_value, info, "\t");48794880outs() << "\t\t classMethods ";4881sym_name =4882get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,4883info, n_value, pc.classMethods);4884if (n_value != 0) {4885if (info->verbose && sym_name != nullptr)4886outs() << sym_name;4887else4888outs() << format("0x%" PRIx64, n_value);4889if (pc.classMethods != 0)4890outs() << " + " << format("0x%" PRIx64, pc.classMethods);4891} else4892outs() << format("0x%" PRIx64, pc.classMethods);4893outs() << " (struct method_list_t *)\n";4894if (pc.classMethods + n_value != 0)4895print_method_list64_t(pc.classMethods + n_value, info, "\t");48964897outs() << "\t optionalInstanceMethods "4898<< format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";4899outs() << "\t optionalClassMethods "4900<< format("0x%" PRIx64, pc.optionalClassMethods) << "\n";4901outs() << "\t instanceProperties "4902<< format("0x%" PRIx64, pc.instanceProperties) << "\n";49034904p += sizeof(uint64_t);4905offset += sizeof(uint64_t);4906}4907}49084909static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {4910struct protocol_list32_t pl;4911uint32_t q;4912struct protocol32_t pc;4913const char *r;4914uint32_t offset, xoffset, left, i;4915SectionRef S, xS;4916const char *name;49174918r = get_pointer_32(p, offset, left, S, info);4919if (r == nullptr)4920return;4921memset(&pl, '\0', sizeof(struct protocol_list32_t));4922if (left < sizeof(struct protocol_list32_t)) {4923memcpy(&pl, r, left);4924outs() << " (protocol_list_t entends past the end of the section)\n";4925} else4926memcpy(&pl, r, sizeof(struct protocol_list32_t));4927if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4928swapStruct(pl);4929outs() << " count " << pl.count << "\n";49304931p += sizeof(struct protocol_list32_t);4932offset += sizeof(struct protocol_list32_t);4933for (i = 0; i < pl.count; i++) {4934r = get_pointer_32(p, offset, left, S, info);4935if (r == nullptr)4936return;4937q = 0;4938if (left < sizeof(uint32_t)) {4939memcpy(&q, r, left);4940outs() << " (protocol_t * entends past the end of the section)\n";4941} else4942memcpy(&q, r, sizeof(uint32_t));4943if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4944sys::swapByteOrder(q);4945outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)4946<< " (struct protocol_t *)\n";4947r = get_pointer_32(q, offset, left, S, info);4948if (r == nullptr)4949return;4950memset(&pc, '\0', sizeof(struct protocol32_t));4951if (left < sizeof(struct protocol32_t)) {4952memcpy(&pc, r, left);4953outs() << " (protocol_t entends past the end of the section)\n";4954} else4955memcpy(&pc, r, sizeof(struct protocol32_t));4956if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4957swapStruct(pc);4958outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";4959outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);4960name = get_pointer_32(pc.name, xoffset, left, xS, info);4961if (name != nullptr)4962outs() << format(" %.*s", left, name);4963outs() << "\n";4964outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";4965outs() << "\t\t instanceMethods "4966<< format("0x%" PRIx32, pc.instanceMethods)4967<< " (struct method_list_t *)\n";4968if (pc.instanceMethods != 0)4969print_method_list32_t(pc.instanceMethods, info, "\t");4970outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)4971<< " (struct method_list_t *)\n";4972if (pc.classMethods != 0)4973print_method_list32_t(pc.classMethods, info, "\t");4974outs() << "\t optionalInstanceMethods "4975<< format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";4976outs() << "\t optionalClassMethods "4977<< format("0x%" PRIx32, pc.optionalClassMethods) << "\n";4978outs() << "\t instanceProperties "4979<< format("0x%" PRIx32, pc.instanceProperties) << "\n";4980p += sizeof(uint32_t);4981offset += sizeof(uint32_t);4982}4983}49844985static void print_indent(uint32_t indent) {4986for (uint32_t i = 0; i < indent;) {4987if (indent - i >= 8) {4988outs() << "\t";4989i += 8;4990} else {4991for (uint32_t j = i; j < indent; j++)4992outs() << " ";4993return;4994}4995}4996}49974998static bool print_method_description_list(uint32_t p, uint32_t indent,4999struct DisassembleInfo *info) {5000uint32_t offset, left, xleft;5001SectionRef S;5002struct objc_method_description_list_t mdl;5003struct objc_method_description_t md;5004const char *r, *list, *name;5005int32_t i;50065007r = get_pointer_32(p, offset, left, S, info, true);5008if (r == nullptr)5009return true;50105011outs() << "\n";5012if (left > sizeof(struct objc_method_description_list_t)) {5013memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));5014} else {5015print_indent(indent);5016outs() << " objc_method_description_list extends past end of the section\n";5017memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));5018memcpy(&mdl, r, left);5019}5020if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5021swapStruct(mdl);50225023print_indent(indent);5024outs() << " count " << mdl.count << "\n";50255026list = r + sizeof(struct objc_method_description_list_t);5027for (i = 0; i < mdl.count; i++) {5028if ((i + 1) * sizeof(struct objc_method_description_t) > left) {5029print_indent(indent);5030outs() << " remaining list entries extend past the of the section\n";5031break;5032}5033print_indent(indent);5034outs() << " list[" << i << "]\n";5035memcpy(&md, list + i * sizeof(struct objc_method_description_t),5036sizeof(struct objc_method_description_t));5037if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5038swapStruct(md);50395040print_indent(indent);5041outs() << " name " << format("0x%08" PRIx32, md.name);5042if (info->verbose) {5043name = get_pointer_32(md.name, offset, xleft, S, info, true);5044if (name != nullptr)5045outs() << format(" %.*s", xleft, name);5046else5047outs() << " (not in an __OBJC section)";5048}5049outs() << "\n";50505051print_indent(indent);5052outs() << " types " << format("0x%08" PRIx32, md.types);5053if (info->verbose) {5054name = get_pointer_32(md.types, offset, xleft, S, info, true);5055if (name != nullptr)5056outs() << format(" %.*s", xleft, name);5057else5058outs() << " (not in an __OBJC section)";5059}5060outs() << "\n";5061}5062return false;5063}50645065static bool print_protocol_list(uint32_t p, uint32_t indent,5066struct DisassembleInfo *info);50675068static bool print_protocol(uint32_t p, uint32_t indent,5069struct DisassembleInfo *info) {5070uint32_t offset, left;5071SectionRef S;5072struct objc_protocol_t protocol;5073const char *r, *name;50745075r = get_pointer_32(p, offset, left, S, info, true);5076if (r == nullptr)5077return true;50785079outs() << "\n";5080if (left >= sizeof(struct objc_protocol_t)) {5081memcpy(&protocol, r, sizeof(struct objc_protocol_t));5082} else {5083print_indent(indent);5084outs() << " Protocol extends past end of the section\n";5085memset(&protocol, '\0', sizeof(struct objc_protocol_t));5086memcpy(&protocol, r, left);5087}5088if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5089swapStruct(protocol);50905091print_indent(indent);5092outs() << " isa " << format("0x%08" PRIx32, protocol.isa)5093<< "\n";50945095print_indent(indent);5096outs() << " protocol_name "5097<< format("0x%08" PRIx32, protocol.protocol_name);5098if (info->verbose) {5099name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);5100if (name != nullptr)5101outs() << format(" %.*s", left, name);5102else5103outs() << " (not in an __OBJC section)";5104}5105outs() << "\n";51065107print_indent(indent);5108outs() << " protocol_list "5109<< format("0x%08" PRIx32, protocol.protocol_list);5110if (print_protocol_list(protocol.protocol_list, indent + 4, info))5111outs() << " (not in an __OBJC section)\n";51125113print_indent(indent);5114outs() << " instance_methods "5115<< format("0x%08" PRIx32, protocol.instance_methods);5116if (print_method_description_list(protocol.instance_methods, indent, info))5117outs() << " (not in an __OBJC section)\n";51185119print_indent(indent);5120outs() << " class_methods "5121<< format("0x%08" PRIx32, protocol.class_methods);5122if (print_method_description_list(protocol.class_methods, indent, info))5123outs() << " (not in an __OBJC section)\n";51245125return false;5126}51275128static bool print_protocol_list(uint32_t p, uint32_t indent,5129struct DisassembleInfo *info) {5130uint32_t offset, left, l;5131SectionRef S;5132struct objc_protocol_list_t protocol_list;5133const char *r, *list;5134int32_t i;51355136r = get_pointer_32(p, offset, left, S, info, true);5137if (r == nullptr)5138return true;51395140outs() << "\n";5141if (left > sizeof(struct objc_protocol_list_t)) {5142memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));5143} else {5144outs() << "\t\t objc_protocol_list_t extends past end of the section\n";5145memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));5146memcpy(&protocol_list, r, left);5147}5148if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5149swapStruct(protocol_list);51505151print_indent(indent);5152outs() << " next " << format("0x%08" PRIx32, protocol_list.next)5153<< "\n";5154print_indent(indent);5155outs() << " count " << protocol_list.count << "\n";51565157list = r + sizeof(struct objc_protocol_list_t);5158for (i = 0; i < protocol_list.count; i++) {5159if ((i + 1) * sizeof(uint32_t) > left) {5160outs() << "\t\t remaining list entries extend past the of the section\n";5161break;5162}5163memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));5164if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5165sys::swapByteOrder(l);51665167print_indent(indent);5168outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);5169if (print_protocol(l, indent, info))5170outs() << "(not in an __OBJC section)\n";5171}5172return false;5173}51745175static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {5176struct ivar_list64_t il;5177struct ivar64_t i;5178const char *r;5179uint32_t offset, xoffset, left, j;5180SectionRef S, xS;5181const char *name, *sym_name, *ivar_offset_p;5182uint64_t ivar_offset, n_value;51835184r = get_pointer_64(p, offset, left, S, info);5185if (r == nullptr)5186return;5187memset(&il, '\0', sizeof(struct ivar_list64_t));5188if (left < sizeof(struct ivar_list64_t)) {5189memcpy(&il, r, left);5190outs() << " (ivar_list_t entends past the end of the section)\n";5191} else5192memcpy(&il, r, sizeof(struct ivar_list64_t));5193if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5194swapStruct(il);5195outs() << " entsize " << il.entsize << "\n";5196outs() << " count " << il.count << "\n";51975198p += sizeof(struct ivar_list64_t);5199offset += sizeof(struct ivar_list64_t);5200for (j = 0; j < il.count; j++) {5201r = get_pointer_64(p, offset, left, S, info);5202if (r == nullptr)5203return;5204memset(&i, '\0', sizeof(struct ivar64_t));5205if (left < sizeof(struct ivar64_t)) {5206memcpy(&i, r, left);5207outs() << " (ivar_t entends past the end of the section)\n";5208} else5209memcpy(&i, r, sizeof(struct ivar64_t));5210if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5211swapStruct(i);52125213outs() << "\t\t\t offset ";5214sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,5215info, n_value, i.offset);5216if (n_value != 0) {5217if (info->verbose && sym_name != nullptr)5218outs() << sym_name;5219else5220outs() << format("0x%" PRIx64, n_value);5221if (i.offset != 0)5222outs() << " + " << format("0x%" PRIx64, i.offset);5223} else5224outs() << format("0x%" PRIx64, i.offset);5225ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);5226if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5227memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5228if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5229sys::swapByteOrder(ivar_offset);5230outs() << " " << ivar_offset << "\n";5231} else5232outs() << "\n";52335234outs() << "\t\t\t name ";5235sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,5236n_value, i.name);5237if (n_value != 0) {5238if (info->verbose && sym_name != nullptr)5239outs() << sym_name;5240else5241outs() << format("0x%" PRIx64, n_value);5242if (i.name != 0)5243outs() << " + " << format("0x%" PRIx64, i.name);5244} else5245outs() << format("0x%" PRIx64, i.name);5246name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);5247if (name != nullptr)5248outs() << format(" %.*s", left, name);5249outs() << "\n";52505251outs() << "\t\t\t type ";5252sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,5253n_value, i.name);5254name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);5255if (n_value != 0) {5256if (info->verbose && sym_name != nullptr)5257outs() << sym_name;5258else5259outs() << format("0x%" PRIx64, n_value);5260if (i.type != 0)5261outs() << " + " << format("0x%" PRIx64, i.type);5262} else5263outs() << format("0x%" PRIx64, i.type);5264if (name != nullptr)5265outs() << format(" %.*s", left, name);5266outs() << "\n";52675268outs() << "\t\t\talignment " << i.alignment << "\n";5269outs() << "\t\t\t size " << i.size << "\n";52705271p += sizeof(struct ivar64_t);5272offset += sizeof(struct ivar64_t);5273}5274}52755276static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {5277struct ivar_list32_t il;5278struct ivar32_t i;5279const char *r;5280uint32_t offset, xoffset, left, j;5281SectionRef S, xS;5282const char *name, *ivar_offset_p;5283uint32_t ivar_offset;52845285r = get_pointer_32(p, offset, left, S, info);5286if (r == nullptr)5287return;5288memset(&il, '\0', sizeof(struct ivar_list32_t));5289if (left < sizeof(struct ivar_list32_t)) {5290memcpy(&il, r, left);5291outs() << " (ivar_list_t entends past the end of the section)\n";5292} else5293memcpy(&il, r, sizeof(struct ivar_list32_t));5294if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5295swapStruct(il);5296outs() << " entsize " << il.entsize << "\n";5297outs() << " count " << il.count << "\n";52985299p += sizeof(struct ivar_list32_t);5300offset += sizeof(struct ivar_list32_t);5301for (j = 0; j < il.count; j++) {5302r = get_pointer_32(p, offset, left, S, info);5303if (r == nullptr)5304return;5305memset(&i, '\0', sizeof(struct ivar32_t));5306if (left < sizeof(struct ivar32_t)) {5307memcpy(&i, r, left);5308outs() << " (ivar_t entends past the end of the section)\n";5309} else5310memcpy(&i, r, sizeof(struct ivar32_t));5311if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5312swapStruct(i);53135314outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);5315ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);5316if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5317memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5318if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5319sys::swapByteOrder(ivar_offset);5320outs() << " " << ivar_offset << "\n";5321} else5322outs() << "\n";53235324outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);5325name = get_pointer_32(i.name, xoffset, left, xS, info);5326if (name != nullptr)5327outs() << format(" %.*s", left, name);5328outs() << "\n";53295330outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);5331name = get_pointer_32(i.type, xoffset, left, xS, info);5332if (name != nullptr)5333outs() << format(" %.*s", left, name);5334outs() << "\n";53355336outs() << "\t\t\talignment " << i.alignment << "\n";5337outs() << "\t\t\t size " << i.size << "\n";53385339p += sizeof(struct ivar32_t);5340offset += sizeof(struct ivar32_t);5341}5342}53435344static void print_objc_property_list64(uint64_t p,5345struct DisassembleInfo *info) {5346struct objc_property_list64 opl;5347struct objc_property64 op;5348const char *r;5349uint32_t offset, xoffset, left, j;5350SectionRef S, xS;5351const char *name, *sym_name;5352uint64_t n_value;53535354r = get_pointer_64(p, offset, left, S, info);5355if (r == nullptr)5356return;5357memset(&opl, '\0', sizeof(struct objc_property_list64));5358if (left < sizeof(struct objc_property_list64)) {5359memcpy(&opl, r, left);5360outs() << " (objc_property_list entends past the end of the section)\n";5361} else5362memcpy(&opl, r, sizeof(struct objc_property_list64));5363if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5364swapStruct(opl);5365outs() << " entsize " << opl.entsize << "\n";5366outs() << " count " << opl.count << "\n";53675368p += sizeof(struct objc_property_list64);5369offset += sizeof(struct objc_property_list64);5370for (j = 0; j < opl.count; j++) {5371r = get_pointer_64(p, offset, left, S, info);5372if (r == nullptr)5373return;5374memset(&op, '\0', sizeof(struct objc_property64));5375if (left < sizeof(struct objc_property64)) {5376memcpy(&op, r, left);5377outs() << " (objc_property entends past the end of the section)\n";5378} else5379memcpy(&op, r, sizeof(struct objc_property64));5380if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5381swapStruct(op);53825383outs() << "\t\t\t name ";5384sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,5385info, n_value, op.name);5386if (n_value != 0) {5387if (info->verbose && sym_name != nullptr)5388outs() << sym_name;5389else5390outs() << format("0x%" PRIx64, n_value);5391if (op.name != 0)5392outs() << " + " << format("0x%" PRIx64, op.name);5393} else5394outs() << format("0x%" PRIx64, op.name);5395name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);5396if (name != nullptr)5397outs() << format(" %.*s", left, name);5398outs() << "\n";53995400outs() << "\t\t\tattributes ";5401sym_name =5402get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,5403info, n_value, op.attributes);5404if (n_value != 0) {5405if (info->verbose && sym_name != nullptr)5406outs() << sym_name;5407else5408outs() << format("0x%" PRIx64, n_value);5409if (op.attributes != 0)5410outs() << " + " << format("0x%" PRIx64, op.attributes);5411} else5412outs() << format("0x%" PRIx64, op.attributes);5413name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);5414if (name != nullptr)5415outs() << format(" %.*s", left, name);5416outs() << "\n";54175418p += sizeof(struct objc_property64);5419offset += sizeof(struct objc_property64);5420}5421}54225423static void print_objc_property_list32(uint32_t p,5424struct DisassembleInfo *info) {5425struct objc_property_list32 opl;5426struct objc_property32 op;5427const char *r;5428uint32_t offset, xoffset, left, j;5429SectionRef S, xS;5430const char *name;54315432r = get_pointer_32(p, offset, left, S, info);5433if (r == nullptr)5434return;5435memset(&opl, '\0', sizeof(struct objc_property_list32));5436if (left < sizeof(struct objc_property_list32)) {5437memcpy(&opl, r, left);5438outs() << " (objc_property_list entends past the end of the section)\n";5439} else5440memcpy(&opl, r, sizeof(struct objc_property_list32));5441if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5442swapStruct(opl);5443outs() << " entsize " << opl.entsize << "\n";5444outs() << " count " << opl.count << "\n";54455446p += sizeof(struct objc_property_list32);5447offset += sizeof(struct objc_property_list32);5448for (j = 0; j < opl.count; j++) {5449r = get_pointer_32(p, offset, left, S, info);5450if (r == nullptr)5451return;5452memset(&op, '\0', sizeof(struct objc_property32));5453if (left < sizeof(struct objc_property32)) {5454memcpy(&op, r, left);5455outs() << " (objc_property entends past the end of the section)\n";5456} else5457memcpy(&op, r, sizeof(struct objc_property32));5458if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5459swapStruct(op);54605461outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);5462name = get_pointer_32(op.name, xoffset, left, xS, info);5463if (name != nullptr)5464outs() << format(" %.*s", left, name);5465outs() << "\n";54665467outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);5468name = get_pointer_32(op.attributes, xoffset, left, xS, info);5469if (name != nullptr)5470outs() << format(" %.*s", left, name);5471outs() << "\n";54725473p += sizeof(struct objc_property32);5474offset += sizeof(struct objc_property32);5475}5476}54775478static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,5479bool &is_meta_class) {5480struct class_ro64_t cro;5481const char *r;5482uint32_t offset, xoffset, left;5483SectionRef S, xS;5484const char *name, *sym_name;5485uint64_t n_value;54865487r = get_pointer_64(p, offset, left, S, info);5488if (r == nullptr || left < sizeof(struct class_ro64_t))5489return false;5490memcpy(&cro, r, sizeof(struct class_ro64_t));5491if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5492swapStruct(cro);5493outs() << " flags " << format("0x%" PRIx32, cro.flags);5494if (cro.flags & RO_META)5495outs() << " RO_META";5496if (cro.flags & RO_ROOT)5497outs() << " RO_ROOT";5498if (cro.flags & RO_HAS_CXX_STRUCTORS)5499outs() << " RO_HAS_CXX_STRUCTORS";5500outs() << "\n";5501outs() << " instanceStart " << cro.instanceStart << "\n";5502outs() << " instanceSize " << cro.instanceSize << "\n";5503outs() << " reserved " << format("0x%" PRIx32, cro.reserved)5504<< "\n";5505outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)5506<< "\n";5507print_layout_map64(cro.ivarLayout, info);55085509outs() << " name ";5510sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,5511info, n_value, cro.name);5512if (n_value != 0) {5513if (info->verbose && sym_name != nullptr)5514outs() << sym_name;5515else5516outs() << format("0x%" PRIx64, n_value);5517if (cro.name != 0)5518outs() << " + " << format("0x%" PRIx64, cro.name);5519} else5520outs() << format("0x%" PRIx64, cro.name);5521name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);5522if (name != nullptr)5523outs() << format(" %.*s", left, name);5524outs() << "\n";55255526outs() << " baseMethods ";5527sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),5528S, info, n_value, cro.baseMethods);5529if (n_value != 0) {5530if (info->verbose && sym_name != nullptr)5531outs() << sym_name;5532else5533outs() << format("0x%" PRIx64, n_value);5534if (cro.baseMethods != 0)5535outs() << " + " << format("0x%" PRIx64, cro.baseMethods);5536} else5537outs() << format("0x%" PRIx64, cro.baseMethods);5538outs() << " (struct method_list_t *)\n";5539if (cro.baseMethods + n_value != 0)5540print_method_list64_t(cro.baseMethods + n_value, info, "");55415542outs() << " baseProtocols ";5543sym_name =5544get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,5545info, n_value, cro.baseProtocols);5546if (n_value != 0) {5547if (info->verbose && sym_name != nullptr)5548outs() << sym_name;5549else5550outs() << format("0x%" PRIx64, n_value);5551if (cro.baseProtocols != 0)5552outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);5553} else5554outs() << format("0x%" PRIx64, cro.baseProtocols);5555outs() << "\n";5556if (cro.baseProtocols + n_value != 0)5557print_protocol_list64_t(cro.baseProtocols + n_value, info);55585559outs() << " ivars ";5560sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,5561info, n_value, cro.ivars);5562if (n_value != 0) {5563if (info->verbose && sym_name != nullptr)5564outs() << sym_name;5565else5566outs() << format("0x%" PRIx64, n_value);5567if (cro.ivars != 0)5568outs() << " + " << format("0x%" PRIx64, cro.ivars);5569} else5570outs() << format("0x%" PRIx64, cro.ivars);5571outs() << "\n";5572if (cro.ivars + n_value != 0)5573print_ivar_list64_t(cro.ivars + n_value, info);55745575outs() << " weakIvarLayout ";5576sym_name =5577get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,5578info, n_value, cro.weakIvarLayout);5579if (n_value != 0) {5580if (info->verbose && sym_name != nullptr)5581outs() << sym_name;5582else5583outs() << format("0x%" PRIx64, n_value);5584if (cro.weakIvarLayout != 0)5585outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);5586} else5587outs() << format("0x%" PRIx64, cro.weakIvarLayout);5588outs() << "\n";5589print_layout_map64(cro.weakIvarLayout + n_value, info);55905591outs() << " baseProperties ";5592sym_name =5593get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,5594info, n_value, cro.baseProperties);5595if (n_value != 0) {5596if (info->verbose && sym_name != nullptr)5597outs() << sym_name;5598else5599outs() << format("0x%" PRIx64, n_value);5600if (cro.baseProperties != 0)5601outs() << " + " << format("0x%" PRIx64, cro.baseProperties);5602} else5603outs() << format("0x%" PRIx64, cro.baseProperties);5604outs() << "\n";5605if (cro.baseProperties + n_value != 0)5606print_objc_property_list64(cro.baseProperties + n_value, info);56075608is_meta_class = (cro.flags & RO_META) != 0;5609return true;5610}56115612static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,5613bool &is_meta_class) {5614struct class_ro32_t cro;5615const char *r;5616uint32_t offset, xoffset, left;5617SectionRef S, xS;5618const char *name;56195620r = get_pointer_32(p, offset, left, S, info);5621if (r == nullptr)5622return false;5623memset(&cro, '\0', sizeof(struct class_ro32_t));5624if (left < sizeof(struct class_ro32_t)) {5625memcpy(&cro, r, left);5626outs() << " (class_ro_t entends past the end of the section)\n";5627} else5628memcpy(&cro, r, sizeof(struct class_ro32_t));5629if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5630swapStruct(cro);5631outs() << " flags " << format("0x%" PRIx32, cro.flags);5632if (cro.flags & RO_META)5633outs() << " RO_META";5634if (cro.flags & RO_ROOT)5635outs() << " RO_ROOT";5636if (cro.flags & RO_HAS_CXX_STRUCTORS)5637outs() << " RO_HAS_CXX_STRUCTORS";5638outs() << "\n";5639outs() << " instanceStart " << cro.instanceStart << "\n";5640outs() << " instanceSize " << cro.instanceSize << "\n";5641outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)5642<< "\n";5643print_layout_map32(cro.ivarLayout, info);56445645outs() << " name " << format("0x%" PRIx32, cro.name);5646name = get_pointer_32(cro.name, xoffset, left, xS, info);5647if (name != nullptr)5648outs() << format(" %.*s", left, name);5649outs() << "\n";56505651outs() << " baseMethods "5652<< format("0x%" PRIx32, cro.baseMethods)5653<< " (struct method_list_t *)\n";5654if (cro.baseMethods != 0)5655print_method_list32_t(cro.baseMethods, info, "");56565657outs() << " baseProtocols "5658<< format("0x%" PRIx32, cro.baseProtocols) << "\n";5659if (cro.baseProtocols != 0)5660print_protocol_list32_t(cro.baseProtocols, info);5661outs() << " ivars " << format("0x%" PRIx32, cro.ivars)5662<< "\n";5663if (cro.ivars != 0)5664print_ivar_list32_t(cro.ivars, info);5665outs() << " weakIvarLayout "5666<< format("0x%" PRIx32, cro.weakIvarLayout) << "\n";5667print_layout_map32(cro.weakIvarLayout, info);5668outs() << " baseProperties "5669<< format("0x%" PRIx32, cro.baseProperties) << "\n";5670if (cro.baseProperties != 0)5671print_objc_property_list32(cro.baseProperties, info);5672is_meta_class = (cro.flags & RO_META) != 0;5673return true;5674}56755676static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {5677struct class64_t c;5678const char *r;5679uint32_t offset, left;5680SectionRef S;5681const char *name;5682uint64_t isa_n_value, n_value;56835684r = get_pointer_64(p, offset, left, S, info);5685if (r == nullptr || left < sizeof(struct class64_t))5686return;5687memcpy(&c, r, sizeof(struct class64_t));5688if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5689swapStruct(c);56905691outs() << " isa " << format("0x%" PRIx64, c.isa);5692name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,5693isa_n_value, c.isa);5694if (name != nullptr)5695outs() << " " << name;5696outs() << "\n";56975698outs() << " superclass " << format("0x%" PRIx64, c.superclass);5699name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,5700n_value, c.superclass);5701if (name != nullptr)5702outs() << " " << name;5703else {5704name = get_dyld_bind_info_symbolname(S.getAddress() +5705offset + offsetof(struct class64_t, superclass), info);5706if (name != nullptr)5707outs() << " " << name;5708}5709outs() << "\n";57105711outs() << " cache " << format("0x%" PRIx64, c.cache);5712name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,5713n_value, c.cache);5714if (name != nullptr)5715outs() << " " << name;5716outs() << "\n";57175718outs() << " vtable " << format("0x%" PRIx64, c.vtable);5719name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,5720n_value, c.vtable);5721if (name != nullptr)5722outs() << " " << name;5723outs() << "\n";57245725name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,5726n_value, c.data);5727outs() << " data ";5728if (n_value != 0) {5729if (info->verbose && name != nullptr)5730outs() << name;5731else5732outs() << format("0x%" PRIx64, n_value);5733if (c.data != 0)5734outs() << " + " << format("0x%" PRIx64, c.data);5735} else5736outs() << format("0x%" PRIx64, c.data);5737outs() << " (struct class_ro_t *)";57385739// This is a Swift class if some of the low bits of the pointer are set.5740if ((c.data + n_value) & 0x7)5741outs() << " Swift class";5742outs() << "\n";5743bool is_meta_class;5744if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))5745return;57465747if (!is_meta_class &&5748c.isa + isa_n_value != p &&5749c.isa + isa_n_value != 0 &&5750info->depth < 100) {5751info->depth++;5752outs() << "Meta Class\n";5753print_class64_t(c.isa + isa_n_value, info);5754}5755}57565757static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {5758struct class32_t c;5759const char *r;5760uint32_t offset, left;5761SectionRef S;5762const char *name;57635764r = get_pointer_32(p, offset, left, S, info);5765if (r == nullptr)5766return;5767memset(&c, '\0', sizeof(struct class32_t));5768if (left < sizeof(struct class32_t)) {5769memcpy(&c, r, left);5770outs() << " (class_t entends past the end of the section)\n";5771} else5772memcpy(&c, r, sizeof(struct class32_t));5773if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5774swapStruct(c);57755776outs() << " isa " << format("0x%" PRIx32, c.isa);5777name =5778get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);5779if (name != nullptr)5780outs() << " " << name;5781outs() << "\n";57825783outs() << " superclass " << format("0x%" PRIx32, c.superclass);5784name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,5785c.superclass);5786if (name != nullptr)5787outs() << " " << name;5788outs() << "\n";57895790outs() << " cache " << format("0x%" PRIx32, c.cache);5791name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,5792c.cache);5793if (name != nullptr)5794outs() << " " << name;5795outs() << "\n";57965797outs() << " vtable " << format("0x%" PRIx32, c.vtable);5798name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,5799c.vtable);5800if (name != nullptr)5801outs() << " " << name;5802outs() << "\n";58035804name =5805get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);5806outs() << " data " << format("0x%" PRIx32, c.data)5807<< " (struct class_ro_t *)";58085809// This is a Swift class if some of the low bits of the pointer are set.5810if (c.data & 0x3)5811outs() << " Swift class";5812outs() << "\n";5813bool is_meta_class;5814if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))5815return;58165817if (!is_meta_class) {5818outs() << "Meta Class\n";5819print_class32_t(c.isa, info);5820}5821}58225823static void print_objc_class_t(struct objc_class_t *objc_class,5824struct DisassembleInfo *info) {5825uint32_t offset, left, xleft;5826const char *name, *p, *ivar_list;5827SectionRef S;5828int32_t i;5829struct objc_ivar_list_t objc_ivar_list;5830struct objc_ivar_t ivar;58315832outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);5833if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {5834name = get_pointer_32(objc_class->isa, offset, left, S, info, true);5835if (name != nullptr)5836outs() << format(" %.*s", left, name);5837else5838outs() << " (not in an __OBJC section)";5839}5840outs() << "\n";58415842outs() << "\t super_class "5843<< format("0x%08" PRIx32, objc_class->super_class);5844if (info->verbose) {5845name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);5846if (name != nullptr)5847outs() << format(" %.*s", left, name);5848else5849outs() << " (not in an __OBJC section)";5850}5851outs() << "\n";58525853outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);5854if (info->verbose) {5855name = get_pointer_32(objc_class->name, offset, left, S, info, true);5856if (name != nullptr)5857outs() << format(" %.*s", left, name);5858else5859outs() << " (not in an __OBJC section)";5860}5861outs() << "\n";58625863outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)5864<< "\n";58655866outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);5867if (info->verbose) {5868if (CLS_GETINFO(objc_class, CLS_CLASS))5869outs() << " CLS_CLASS";5870else if (CLS_GETINFO(objc_class, CLS_META))5871outs() << " CLS_META";5872}5873outs() << "\n";58745875outs() << "\t instance_size "5876<< format("0x%08" PRIx32, objc_class->instance_size) << "\n";58775878p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);5879outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);5880if (p != nullptr) {5881if (left > sizeof(struct objc_ivar_list_t)) {5882outs() << "\n";5883memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));5884} else {5885outs() << " (entends past the end of the section)\n";5886memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));5887memcpy(&objc_ivar_list, p, left);5888}5889if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5890swapStruct(objc_ivar_list);5891outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";5892ivar_list = p + sizeof(struct objc_ivar_list_t);5893for (i = 0; i < objc_ivar_list.ivar_count; i++) {5894if ((i + 1) * sizeof(struct objc_ivar_t) > left) {5895outs() << "\t\t remaining ivar's extend past the of the section\n";5896break;5897}5898memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),5899sizeof(struct objc_ivar_t));5900if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5901swapStruct(ivar);59025903outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);5904if (info->verbose) {5905name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);5906if (name != nullptr)5907outs() << format(" %.*s", xleft, name);5908else5909outs() << " (not in an __OBJC section)";5910}5911outs() << "\n";59125913outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);5914if (info->verbose) {5915name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);5916if (name != nullptr)5917outs() << format(" %.*s", xleft, name);5918else5919outs() << " (not in an __OBJC section)";5920}5921outs() << "\n";59225923outs() << "\t\t ivar_offset "5924<< format("0x%08" PRIx32, ivar.ivar_offset) << "\n";5925}5926} else {5927outs() << " (not in an __OBJC section)\n";5928}59295930outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);5931if (print_method_list(objc_class->methodLists, info))5932outs() << " (not in an __OBJC section)\n";59335934outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)5935<< "\n";59365937outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);5938if (print_protocol_list(objc_class->protocols, 16, info))5939outs() << " (not in an __OBJC section)\n";5940}59415942static void print_objc_objc_category_t(struct objc_category_t *objc_category,5943struct DisassembleInfo *info) {5944uint32_t offset, left;5945const char *name;5946SectionRef S;59475948outs() << "\t category name "5949<< format("0x%08" PRIx32, objc_category->category_name);5950if (info->verbose) {5951name = get_pointer_32(objc_category->category_name, offset, left, S, info,5952true);5953if (name != nullptr)5954outs() << format(" %.*s", left, name);5955else5956outs() << " (not in an __OBJC section)";5957}5958outs() << "\n";59595960outs() << "\t\t class name "5961<< format("0x%08" PRIx32, objc_category->class_name);5962if (info->verbose) {5963name =5964get_pointer_32(objc_category->class_name, offset, left, S, info, true);5965if (name != nullptr)5966outs() << format(" %.*s", left, name);5967else5968outs() << " (not in an __OBJC section)";5969}5970outs() << "\n";59715972outs() << "\t instance methods "5973<< format("0x%08" PRIx32, objc_category->instance_methods);5974if (print_method_list(objc_category->instance_methods, info))5975outs() << " (not in an __OBJC section)\n";59765977outs() << "\t class methods "5978<< format("0x%08" PRIx32, objc_category->class_methods);5979if (print_method_list(objc_category->class_methods, info))5980outs() << " (not in an __OBJC section)\n";5981}59825983static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {5984struct category64_t c;5985const char *r;5986uint32_t offset, xoffset, left;5987SectionRef S, xS;5988const char *name, *sym_name;5989uint64_t n_value;59905991r = get_pointer_64(p, offset, left, S, info);5992if (r == nullptr)5993return;5994memset(&c, '\0', sizeof(struct category64_t));5995if (left < sizeof(struct category64_t)) {5996memcpy(&c, r, left);5997outs() << " (category_t entends past the end of the section)\n";5998} else5999memcpy(&c, r, sizeof(struct category64_t));6000if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6001swapStruct(c);60026003outs() << " name ";6004sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,6005info, n_value, c.name);6006if (n_value != 0) {6007if (info->verbose && sym_name != nullptr)6008outs() << sym_name;6009else6010outs() << format("0x%" PRIx64, n_value);6011if (c.name != 0)6012outs() << " + " << format("0x%" PRIx64, c.name);6013} else6014outs() << format("0x%" PRIx64, c.name);6015name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);6016if (name != nullptr)6017outs() << format(" %.*s", left, name);6018outs() << "\n";60196020outs() << " cls ";6021sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,6022n_value, c.cls);6023if (n_value != 0) {6024if (info->verbose && sym_name != nullptr)6025outs() << sym_name;6026else6027outs() << format("0x%" PRIx64, n_value);6028if (c.cls != 0)6029outs() << " + " << format("0x%" PRIx64, c.cls);6030} else6031outs() << format("0x%" PRIx64, c.cls);6032outs() << "\n";6033if (c.cls + n_value != 0)6034print_class64_t(c.cls + n_value, info);60356036outs() << " instanceMethods ";6037sym_name =6038get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,6039info, n_value, c.instanceMethods);6040if (n_value != 0) {6041if (info->verbose && sym_name != nullptr)6042outs() << sym_name;6043else6044outs() << format("0x%" PRIx64, n_value);6045if (c.instanceMethods != 0)6046outs() << " + " << format("0x%" PRIx64, c.instanceMethods);6047} else6048outs() << format("0x%" PRIx64, c.instanceMethods);6049outs() << "\n";6050if (c.instanceMethods + n_value != 0)6051print_method_list64_t(c.instanceMethods + n_value, info, "");60526053outs() << " classMethods ";6054sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),6055S, info, n_value, c.classMethods);6056if (n_value != 0) {6057if (info->verbose && sym_name != nullptr)6058outs() << sym_name;6059else6060outs() << format("0x%" PRIx64, n_value);6061if (c.classMethods != 0)6062outs() << " + " << format("0x%" PRIx64, c.classMethods);6063} else6064outs() << format("0x%" PRIx64, c.classMethods);6065outs() << "\n";6066if (c.classMethods + n_value != 0)6067print_method_list64_t(c.classMethods + n_value, info, "");60686069outs() << " protocols ";6070sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,6071info, n_value, c.protocols);6072if (n_value != 0) {6073if (info->verbose && sym_name != nullptr)6074outs() << sym_name;6075else6076outs() << format("0x%" PRIx64, n_value);6077if (c.protocols != 0)6078outs() << " + " << format("0x%" PRIx64, c.protocols);6079} else6080outs() << format("0x%" PRIx64, c.protocols);6081outs() << "\n";6082if (c.protocols + n_value != 0)6083print_protocol_list64_t(c.protocols + n_value, info);60846085outs() << "instanceProperties ";6086sym_name =6087get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),6088S, info, n_value, c.instanceProperties);6089if (n_value != 0) {6090if (info->verbose && sym_name != nullptr)6091outs() << sym_name;6092else6093outs() << format("0x%" PRIx64, n_value);6094if (c.instanceProperties != 0)6095outs() << " + " << format("0x%" PRIx64, c.instanceProperties);6096} else6097outs() << format("0x%" PRIx64, c.instanceProperties);6098outs() << "\n";6099if (c.instanceProperties + n_value != 0)6100print_objc_property_list64(c.instanceProperties + n_value, info);6101}61026103static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {6104struct category32_t c;6105const char *r;6106uint32_t offset, left;6107SectionRef S, xS;6108const char *name;61096110r = get_pointer_32(p, offset, left, S, info);6111if (r == nullptr)6112return;6113memset(&c, '\0', sizeof(struct category32_t));6114if (left < sizeof(struct category32_t)) {6115memcpy(&c, r, left);6116outs() << " (category_t entends past the end of the section)\n";6117} else6118memcpy(&c, r, sizeof(struct category32_t));6119if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6120swapStruct(c);61216122outs() << " name " << format("0x%" PRIx32, c.name);6123name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,6124c.name);6125if (name)6126outs() << " " << name;6127outs() << "\n";61286129outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";6130if (c.cls != 0)6131print_class32_t(c.cls, info);6132outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)6133<< "\n";6134if (c.instanceMethods != 0)6135print_method_list32_t(c.instanceMethods, info, "");6136outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)6137<< "\n";6138if (c.classMethods != 0)6139print_method_list32_t(c.classMethods, info, "");6140outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";6141if (c.protocols != 0)6142print_protocol_list32_t(c.protocols, info);6143outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)6144<< "\n";6145if (c.instanceProperties != 0)6146print_objc_property_list32(c.instanceProperties, info);6147}61486149static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {6150uint32_t i, left, offset, xoffset;6151uint64_t p, n_value;6152struct message_ref64 mr;6153const char *name, *sym_name;6154const char *r;6155SectionRef xS;61566157if (S == SectionRef())6158return;61596160StringRef SectName;6161Expected<StringRef> SecNameOrErr = S.getName();6162if (SecNameOrErr)6163SectName = *SecNameOrErr;6164else6165consumeError(SecNameOrErr.takeError());61666167DataRefImpl Ref = S.getRawDataRefImpl();6168StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6169outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6170offset = 0;6171for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6172p = S.getAddress() + i;6173r = get_pointer_64(p, offset, left, S, info);6174if (r == nullptr)6175return;6176memset(&mr, '\0', sizeof(struct message_ref64));6177if (left < sizeof(struct message_ref64)) {6178memcpy(&mr, r, left);6179outs() << " (message_ref entends past the end of the section)\n";6180} else6181memcpy(&mr, r, sizeof(struct message_ref64));6182if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6183swapStruct(mr);61846185outs() << " imp ";6186name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,6187n_value, mr.imp);6188if (n_value != 0) {6189outs() << format("0x%" PRIx64, n_value) << " ";6190if (mr.imp != 0)6191outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";6192} else6193outs() << format("0x%" PRIx64, mr.imp) << " ";6194if (name != nullptr)6195outs() << " " << name;6196outs() << "\n";61976198outs() << " sel ";6199sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,6200info, n_value, mr.sel);6201if (n_value != 0) {6202if (info->verbose && sym_name != nullptr)6203outs() << sym_name;6204else6205outs() << format("0x%" PRIx64, n_value);6206if (mr.sel != 0)6207outs() << " + " << format("0x%" PRIx64, mr.sel);6208} else6209outs() << format("0x%" PRIx64, mr.sel);6210name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);6211if (name != nullptr)6212outs() << format(" %.*s", left, name);6213outs() << "\n";62146215offset += sizeof(struct message_ref64);6216}6217}62186219static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {6220uint32_t i, left, offset, xoffset, p;6221struct message_ref32 mr;6222const char *name, *r;6223SectionRef xS;62246225if (S == SectionRef())6226return;62276228StringRef SectName;6229Expected<StringRef> SecNameOrErr = S.getName();6230if (SecNameOrErr)6231SectName = *SecNameOrErr;6232else6233consumeError(SecNameOrErr.takeError());62346235DataRefImpl Ref = S.getRawDataRefImpl();6236StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6237outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6238offset = 0;6239for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6240p = S.getAddress() + i;6241r = get_pointer_32(p, offset, left, S, info);6242if (r == nullptr)6243return;6244memset(&mr, '\0', sizeof(struct message_ref32));6245if (left < sizeof(struct message_ref32)) {6246memcpy(&mr, r, left);6247outs() << " (message_ref entends past the end of the section)\n";6248} else6249memcpy(&mr, r, sizeof(struct message_ref32));6250if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6251swapStruct(mr);62526253outs() << " imp " << format("0x%" PRIx32, mr.imp);6254name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,6255mr.imp);6256if (name != nullptr)6257outs() << " " << name;6258outs() << "\n";62596260outs() << " sel " << format("0x%" PRIx32, mr.sel);6261name = get_pointer_32(mr.sel, xoffset, left, xS, info);6262if (name != nullptr)6263outs() << " " << name;6264outs() << "\n";62656266offset += sizeof(struct message_ref32);6267}6268}62696270static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {6271uint32_t left, offset, swift_version;6272uint64_t p;6273struct objc_image_info64 o;6274const char *r;62756276if (S == SectionRef())6277return;62786279StringRef SectName;6280Expected<StringRef> SecNameOrErr = S.getName();6281if (SecNameOrErr)6282SectName = *SecNameOrErr;6283else6284consumeError(SecNameOrErr.takeError());62856286DataRefImpl Ref = S.getRawDataRefImpl();6287StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6288outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6289p = S.getAddress();6290r = get_pointer_64(p, offset, left, S, info);6291if (r == nullptr)6292return;6293memset(&o, '\0', sizeof(struct objc_image_info64));6294if (left < sizeof(struct objc_image_info64)) {6295memcpy(&o, r, left);6296outs() << " (objc_image_info entends past the end of the section)\n";6297} else6298memcpy(&o, r, sizeof(struct objc_image_info64));6299if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6300swapStruct(o);6301outs() << " version " << o.version << "\n";6302outs() << " flags " << format("0x%" PRIx32, o.flags);6303if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6304outs() << " OBJC_IMAGE_IS_REPLACEMENT";6305if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6306outs() << " OBJC_IMAGE_SUPPORTS_GC";6307if (o.flags & OBJC_IMAGE_IS_SIMULATED)6308outs() << " OBJC_IMAGE_IS_SIMULATED";6309if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)6310outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";6311swift_version = (o.flags >> 8) & 0xff;6312if (swift_version != 0) {6313if (swift_version == 1)6314outs() << " Swift 1.0";6315else if (swift_version == 2)6316outs() << " Swift 1.1";6317else if(swift_version == 3)6318outs() << " Swift 2.0";6319else if(swift_version == 4)6320outs() << " Swift 3.0";6321else if(swift_version == 5)6322outs() << " Swift 4.0";6323else if(swift_version == 6)6324outs() << " Swift 4.1/Swift 4.2";6325else if(swift_version == 7)6326outs() << " Swift 5 or later";6327else6328outs() << " unknown future Swift version (" << swift_version << ")";6329}6330outs() << "\n";6331}63326333static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {6334uint32_t left, offset, swift_version, p;6335struct objc_image_info32 o;6336const char *r;63376338if (S == SectionRef())6339return;63406341StringRef SectName;6342Expected<StringRef> SecNameOrErr = S.getName();6343if (SecNameOrErr)6344SectName = *SecNameOrErr;6345else6346consumeError(SecNameOrErr.takeError());63476348DataRefImpl Ref = S.getRawDataRefImpl();6349StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6350outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6351p = S.getAddress();6352r = get_pointer_32(p, offset, left, S, info);6353if (r == nullptr)6354return;6355memset(&o, '\0', sizeof(struct objc_image_info32));6356if (left < sizeof(struct objc_image_info32)) {6357memcpy(&o, r, left);6358outs() << " (objc_image_info entends past the end of the section)\n";6359} else6360memcpy(&o, r, sizeof(struct objc_image_info32));6361if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6362swapStruct(o);6363outs() << " version " << o.version << "\n";6364outs() << " flags " << format("0x%" PRIx32, o.flags);6365if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6366outs() << " OBJC_IMAGE_IS_REPLACEMENT";6367if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6368outs() << " OBJC_IMAGE_SUPPORTS_GC";6369swift_version = (o.flags >> 8) & 0xff;6370if (swift_version != 0) {6371if (swift_version == 1)6372outs() << " Swift 1.0";6373else if (swift_version == 2)6374outs() << " Swift 1.1";6375else if(swift_version == 3)6376outs() << " Swift 2.0";6377else if(swift_version == 4)6378outs() << " Swift 3.0";6379else if(swift_version == 5)6380outs() << " Swift 4.0";6381else if(swift_version == 6)6382outs() << " Swift 4.1/Swift 4.2";6383else if(swift_version == 7)6384outs() << " Swift 5 or later";6385else6386outs() << " unknown future Swift version (" << swift_version << ")";6387}6388outs() << "\n";6389}63906391static void print_image_info(SectionRef S, struct DisassembleInfo *info) {6392uint32_t left, offset, p;6393struct imageInfo_t o;6394const char *r;63956396StringRef SectName;6397Expected<StringRef> SecNameOrErr = S.getName();6398if (SecNameOrErr)6399SectName = *SecNameOrErr;6400else6401consumeError(SecNameOrErr.takeError());64026403DataRefImpl Ref = S.getRawDataRefImpl();6404StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6405outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6406p = S.getAddress();6407r = get_pointer_32(p, offset, left, S, info);6408if (r == nullptr)6409return;6410memset(&o, '\0', sizeof(struct imageInfo_t));6411if (left < sizeof(struct imageInfo_t)) {6412memcpy(&o, r, left);6413outs() << " (imageInfo entends past the end of the section)\n";6414} else6415memcpy(&o, r, sizeof(struct imageInfo_t));6416if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6417swapStruct(o);6418outs() << " version " << o.version << "\n";6419outs() << " flags " << format("0x%" PRIx32, o.flags);6420if (o.flags & 0x1)6421outs() << " F&C";6422if (o.flags & 0x2)6423outs() << " GC";6424if (o.flags & 0x4)6425outs() << " GC-only";6426else6427outs() << " RR";6428outs() << "\n";6429}64306431static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {6432SymbolAddressMap AddrMap;6433if (verbose)6434CreateSymbolAddressMap(O, &AddrMap);64356436std::vector<SectionRef> Sections;6437append_range(Sections, O->sections());64386439struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);64406441SectionRef CL = get_section(O, "__OBJC2", "__class_list");6442if (CL == SectionRef())6443CL = get_section(O, "__DATA", "__objc_classlist");6444if (CL == SectionRef())6445CL = get_section(O, "__DATA_CONST", "__objc_classlist");6446if (CL == SectionRef())6447CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6448info.S = CL;6449walk_pointer_list_64("class", CL, O, &info, print_class64_t);64506451SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6452if (CR == SectionRef())6453CR = get_section(O, "__DATA", "__objc_classrefs");6454if (CR == SectionRef())6455CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6456if (CR == SectionRef())6457CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6458info.S = CR;6459walk_pointer_list_64("class refs", CR, O, &info, nullptr);64606461SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6462if (SR == SectionRef())6463SR = get_section(O, "__DATA", "__objc_superrefs");6464if (SR == SectionRef())6465SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6466if (SR == SectionRef())6467SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6468info.S = SR;6469walk_pointer_list_64("super refs", SR, O, &info, nullptr);64706471SectionRef CA = get_section(O, "__OBJC2", "__category_list");6472if (CA == SectionRef())6473CA = get_section(O, "__DATA", "__objc_catlist");6474if (CA == SectionRef())6475CA = get_section(O, "__DATA_CONST", "__objc_catlist");6476if (CA == SectionRef())6477CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6478info.S = CA;6479walk_pointer_list_64("category", CA, O, &info, print_category64_t);64806481SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6482if (PL == SectionRef())6483PL = get_section(O, "__DATA", "__objc_protolist");6484if (PL == SectionRef())6485PL = get_section(O, "__DATA_CONST", "__objc_protolist");6486if (PL == SectionRef())6487PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6488info.S = PL;6489walk_pointer_list_64("protocol", PL, O, &info, nullptr);64906491SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6492if (MR == SectionRef())6493MR = get_section(O, "__DATA", "__objc_msgrefs");6494if (MR == SectionRef())6495MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6496if (MR == SectionRef())6497MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6498info.S = MR;6499print_message_refs64(MR, &info);65006501SectionRef II = get_section(O, "__OBJC2", "__image_info");6502if (II == SectionRef())6503II = get_section(O, "__DATA", "__objc_imageinfo");6504if (II == SectionRef())6505II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6506if (II == SectionRef())6507II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6508info.S = II;6509print_image_info64(II, &info);6510}65116512static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {6513SymbolAddressMap AddrMap;6514if (verbose)6515CreateSymbolAddressMap(O, &AddrMap);65166517std::vector<SectionRef> Sections;6518append_range(Sections, O->sections());65196520struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);65216522SectionRef CL = get_section(O, "__OBJC2", "__class_list");6523if (CL == SectionRef())6524CL = get_section(O, "__DATA", "__objc_classlist");6525if (CL == SectionRef())6526CL = get_section(O, "__DATA_CONST", "__objc_classlist");6527if (CL == SectionRef())6528CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6529info.S = CL;6530walk_pointer_list_32("class", CL, O, &info, print_class32_t);65316532SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6533if (CR == SectionRef())6534CR = get_section(O, "__DATA", "__objc_classrefs");6535if (CR == SectionRef())6536CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6537if (CR == SectionRef())6538CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6539info.S = CR;6540walk_pointer_list_32("class refs", CR, O, &info, nullptr);65416542SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6543if (SR == SectionRef())6544SR = get_section(O, "__DATA", "__objc_superrefs");6545if (SR == SectionRef())6546SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6547if (SR == SectionRef())6548SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6549info.S = SR;6550walk_pointer_list_32("super refs", SR, O, &info, nullptr);65516552SectionRef CA = get_section(O, "__OBJC2", "__category_list");6553if (CA == SectionRef())6554CA = get_section(O, "__DATA", "__objc_catlist");6555if (CA == SectionRef())6556CA = get_section(O, "__DATA_CONST", "__objc_catlist");6557if (CA == SectionRef())6558CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6559info.S = CA;6560walk_pointer_list_32("category", CA, O, &info, print_category32_t);65616562SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6563if (PL == SectionRef())6564PL = get_section(O, "__DATA", "__objc_protolist");6565if (PL == SectionRef())6566PL = get_section(O, "__DATA_CONST", "__objc_protolist");6567if (PL == SectionRef())6568PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6569info.S = PL;6570walk_pointer_list_32("protocol", PL, O, &info, nullptr);65716572SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6573if (MR == SectionRef())6574MR = get_section(O, "__DATA", "__objc_msgrefs");6575if (MR == SectionRef())6576MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6577if (MR == SectionRef())6578MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6579info.S = MR;6580print_message_refs32(MR, &info);65816582SectionRef II = get_section(O, "__OBJC2", "__image_info");6583if (II == SectionRef())6584II = get_section(O, "__DATA", "__objc_imageinfo");6585if (II == SectionRef())6586II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6587if (II == SectionRef())6588II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6589info.S = II;6590print_image_info32(II, &info);6591}65926593static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {6594uint32_t i, j, p, offset, xoffset, left, defs_left, def;6595const char *r, *name, *defs;6596struct objc_module_t module;6597SectionRef S, xS;6598struct objc_symtab_t symtab;6599struct objc_class_t objc_class;6600struct objc_category_t objc_category;66016602outs() << "Objective-C segment\n";6603S = get_section(O, "__OBJC", "__module_info");6604if (S == SectionRef())6605return false;66066607SymbolAddressMap AddrMap;6608if (verbose)6609CreateSymbolAddressMap(O, &AddrMap);66106611std::vector<SectionRef> Sections;6612append_range(Sections, O->sections());66136614struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);66156616for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {6617p = S.getAddress() + i;6618r = get_pointer_32(p, offset, left, S, &info, true);6619if (r == nullptr)6620return true;6621memset(&module, '\0', sizeof(struct objc_module_t));6622if (left < sizeof(struct objc_module_t)) {6623memcpy(&module, r, left);6624outs() << " (module extends past end of __module_info section)\n";6625} else6626memcpy(&module, r, sizeof(struct objc_module_t));6627if (O->isLittleEndian() != sys::IsLittleEndianHost)6628swapStruct(module);66296630outs() << "Module " << format("0x%" PRIx32, p) << "\n";6631outs() << " version " << module.version << "\n";6632outs() << " size " << module.size << "\n";6633outs() << " name ";6634name = get_pointer_32(module.name, xoffset, left, xS, &info, true);6635if (name != nullptr)6636outs() << format("%.*s", left, name);6637else6638outs() << format("0x%08" PRIx32, module.name)6639<< "(not in an __OBJC section)";6640outs() << "\n";66416642r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);6643if (module.symtab == 0 || r == nullptr) {6644outs() << " symtab " << format("0x%08" PRIx32, module.symtab)6645<< " (not in an __OBJC section)\n";6646continue;6647}6648outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";6649memset(&symtab, '\0', sizeof(struct objc_symtab_t));6650defs_left = 0;6651defs = nullptr;6652if (left < sizeof(struct objc_symtab_t)) {6653memcpy(&symtab, r, left);6654outs() << "\tsymtab extends past end of an __OBJC section)\n";6655} else {6656memcpy(&symtab, r, sizeof(struct objc_symtab_t));6657if (left > sizeof(struct objc_symtab_t)) {6658defs_left = left - sizeof(struct objc_symtab_t);6659defs = r + sizeof(struct objc_symtab_t);6660}6661}6662if (O->isLittleEndian() != sys::IsLittleEndianHost)6663swapStruct(symtab);66646665outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";6666r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);6667outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);6668if (r == nullptr)6669outs() << " (not in an __OBJC section)";6670outs() << "\n";6671outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";6672outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";6673if (symtab.cls_def_cnt > 0)6674outs() << "\tClass Definitions\n";6675for (j = 0; j < symtab.cls_def_cnt; j++) {6676if ((j + 1) * sizeof(uint32_t) > defs_left) {6677outs() << "\t(remaining class defs entries entends past the end of the "6678<< "section)\n";6679break;6680}6681memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));6682if (O->isLittleEndian() != sys::IsLittleEndianHost)6683sys::swapByteOrder(def);66846685r = get_pointer_32(def, xoffset, left, xS, &info, true);6686outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);6687if (r != nullptr) {6688if (left > sizeof(struct objc_class_t)) {6689outs() << "\n";6690memcpy(&objc_class, r, sizeof(struct objc_class_t));6691} else {6692outs() << " (entends past the end of the section)\n";6693memset(&objc_class, '\0', sizeof(struct objc_class_t));6694memcpy(&objc_class, r, left);6695}6696if (O->isLittleEndian() != sys::IsLittleEndianHost)6697swapStruct(objc_class);6698print_objc_class_t(&objc_class, &info);6699} else {6700outs() << "(not in an __OBJC section)\n";6701}67026703if (CLS_GETINFO(&objc_class, CLS_CLASS)) {6704outs() << "\tMeta Class";6705r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);6706if (r != nullptr) {6707if (left > sizeof(struct objc_class_t)) {6708outs() << "\n";6709memcpy(&objc_class, r, sizeof(struct objc_class_t));6710} else {6711outs() << " (entends past the end of the section)\n";6712memset(&objc_class, '\0', sizeof(struct objc_class_t));6713memcpy(&objc_class, r, left);6714}6715if (O->isLittleEndian() != sys::IsLittleEndianHost)6716swapStruct(objc_class);6717print_objc_class_t(&objc_class, &info);6718} else {6719outs() << "(not in an __OBJC section)\n";6720}6721}6722}6723if (symtab.cat_def_cnt > 0)6724outs() << "\tCategory Definitions\n";6725for (j = 0; j < symtab.cat_def_cnt; j++) {6726if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {6727outs() << "\t(remaining category defs entries entends past the end of "6728<< "the section)\n";6729break;6730}6731memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),6732sizeof(uint32_t));6733if (O->isLittleEndian() != sys::IsLittleEndianHost)6734sys::swapByteOrder(def);67356736r = get_pointer_32(def, xoffset, left, xS, &info, true);6737outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "6738<< format("0x%08" PRIx32, def);6739if (r != nullptr) {6740if (left > sizeof(struct objc_category_t)) {6741outs() << "\n";6742memcpy(&objc_category, r, sizeof(struct objc_category_t));6743} else {6744outs() << " (entends past the end of the section)\n";6745memset(&objc_category, '\0', sizeof(struct objc_category_t));6746memcpy(&objc_category, r, left);6747}6748if (O->isLittleEndian() != sys::IsLittleEndianHost)6749swapStruct(objc_category);6750print_objc_objc_category_t(&objc_category, &info);6751} else {6752outs() << "(not in an __OBJC section)\n";6753}6754}6755}6756const SectionRef II = get_section(O, "__OBJC", "__image_info");6757if (II != SectionRef())6758print_image_info(II, &info);67596760return true;6761}67626763static void DumpProtocolSection(MachOObjectFile *O, const char *sect,6764uint32_t size, uint32_t addr) {6765SymbolAddressMap AddrMap;6766CreateSymbolAddressMap(O, &AddrMap);67676768std::vector<SectionRef> Sections;6769append_range(Sections, O->sections());67706771struct DisassembleInfo info(O, &AddrMap, &Sections, true);67726773const char *p;6774struct objc_protocol_t protocol;6775uint32_t left, paddr;6776for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {6777memset(&protocol, '\0', sizeof(struct objc_protocol_t));6778left = size - (p - sect);6779if (left < sizeof(struct objc_protocol_t)) {6780outs() << "Protocol extends past end of __protocol section\n";6781memcpy(&protocol, p, left);6782} else6783memcpy(&protocol, p, sizeof(struct objc_protocol_t));6784if (O->isLittleEndian() != sys::IsLittleEndianHost)6785swapStruct(protocol);6786paddr = addr + (p - sect);6787outs() << "Protocol " << format("0x%" PRIx32, paddr);6788if (print_protocol(paddr, 0, &info))6789outs() << "(not in an __OBJC section)\n";6790}6791}67926793static void printObjcMetaData(MachOObjectFile *O, bool verbose) {6794if (O->is64Bit())6795printObjc2_64bit_MetaData(O, verbose);6796else {6797MachO::mach_header H;6798H = O->getHeader();6799if (H.cputype == MachO::CPU_TYPE_ARM)6800printObjc2_32bit_MetaData(O, verbose);6801else {6802// This is the 32-bit non-arm cputype case. Which is normally6803// the first Objective-C ABI. But it may be the case of a6804// binary for the iOS simulator which is the second Objective-C6805// ABI. In that case printObjc1_32bit_MetaData() will determine that6806// and return false.6807if (!printObjc1_32bit_MetaData(O, verbose))6808printObjc2_32bit_MetaData(O, verbose);6809}6810}6811}68126813// GuessLiteralPointer returns a string which for the item in the Mach-O file6814// for the address passed in as ReferenceValue for printing as a comment with6815// the instruction and also returns the corresponding type of that item6816// indirectly through ReferenceType.6817//6818// If ReferenceValue is an address of literal cstring then a pointer to the6819// cstring is returned and ReferenceType is set to6820// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .6821//6822// If ReferenceValue is an address of an Objective-C CFString, Selector ref or6823// Class ref that name is returned and the ReferenceType is set accordingly.6824//6825// Lastly, literals which are Symbol address in a literal pool are looked for6826// and if found the symbol name is returned and ReferenceType is set to6827// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .6828//6829// If there is no item in the Mach-O file for the address passed in as6830// ReferenceValue nullptr is returned and ReferenceType is unchanged.6831static const char *GuessLiteralPointer(uint64_t ReferenceValue,6832uint64_t ReferencePC,6833uint64_t *ReferenceType,6834struct DisassembleInfo *info) {6835// First see if there is an external relocation entry at the ReferencePC.6836if (info->O->getHeader().filetype == MachO::MH_OBJECT) {6837uint64_t sect_addr = info->S.getAddress();6838uint64_t sect_offset = ReferencePC - sect_addr;6839bool reloc_found = false;6840DataRefImpl Rel;6841MachO::any_relocation_info RE;6842bool isExtern = false;6843SymbolRef Symbol;6844for (const RelocationRef &Reloc : info->S.relocations()) {6845uint64_t RelocOffset = Reloc.getOffset();6846if (RelocOffset == sect_offset) {6847Rel = Reloc.getRawDataRefImpl();6848RE = info->O->getRelocation(Rel);6849if (info->O->isRelocationScattered(RE))6850continue;6851isExtern = info->O->getPlainRelocationExternal(RE);6852if (isExtern) {6853symbol_iterator RelocSym = Reloc.getSymbol();6854Symbol = *RelocSym;6855}6856reloc_found = true;6857break;6858}6859}6860// If there is an external relocation entry for a symbol in a section6861// then used that symbol's value for the value of the reference.6862if (reloc_found && isExtern) {6863if (info->O->getAnyRelocationPCRel(RE)) {6864unsigned Type = info->O->getAnyRelocationType(RE);6865if (Type == MachO::X86_64_RELOC_SIGNED) {6866ReferenceValue = cantFail(Symbol.getValue());6867}6868}6869}6870}68716872// Look for literals such as Objective-C CFStrings refs, Selector refs,6873// Message refs and Class refs.6874bool classref, selref, msgref, cfstring;6875uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,6876selref, msgref, cfstring);6877if (classref && pointer_value == 0) {6878// Note the ReferenceValue is a pointer into the __objc_classrefs section.6879// And the pointer_value in that section is typically zero as it will be6880// set by dyld as part of the "bind information".6881const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);6882if (name != nullptr) {6883*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6884const char *class_name = strrchr(name, '$');6885if (class_name != nullptr && class_name[1] == '_' &&6886class_name[2] != '\0') {6887info->class_name = class_name + 2;6888return name;6889}6890}6891}68926893if (classref) {6894*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6895const char *name =6896get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);6897if (name != nullptr)6898info->class_name = name;6899else6900name = "bad class ref";6901return name;6902}69036904if (cfstring) {6905*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;6906const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);6907return name;6908}69096910if (selref && pointer_value == 0)6911pointer_value = get_objc2_64bit_selref(ReferenceValue, info);69126913if (pointer_value != 0)6914ReferenceValue = pointer_value;69156916const char *name = GuessCstringPointer(ReferenceValue, info);6917if (name) {6918if (pointer_value != 0 && selref) {6919*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;6920info->selector_name = name;6921} else if (pointer_value != 0 && msgref) {6922info->class_name = nullptr;6923*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;6924info->selector_name = name;6925} else6926*ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;6927return name;6928}69296930// Lastly look for an indirect symbol with this ReferenceValue which is in6931// a literal pool. If found return that symbol name.6932name = GuessIndirectSymbol(ReferenceValue, info);6933if (name) {6934*ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;6935return name;6936}69376938return nullptr;6939}69406941// SymbolizerSymbolLookUp is the symbol lookup function passed when creating6942// the Symbolizer. It looks up the ReferenceValue using the info passed via the6943// pointer to the struct DisassembleInfo that was passed when MCSymbolizer6944// is created and returns the symbol name that matches the ReferenceValue or6945// nullptr if none. The ReferenceType is passed in for the IN type of6946// reference the instruction is making from the values in defined in the header6947// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific6948// Out type and the ReferenceName will also be set which is added as a comment6949// to the disassembled instruction.6950//6951// If the symbol name is a C++ mangled name then the demangled name is6952// returned through ReferenceName and ReferenceType is set to6953// LLVMDisassembler_ReferenceType_DeMangled_Name .6954//6955// When this is called to get a symbol name for a branch target then the6956// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then6957// SymbolValue will be looked for in the indirect symbol table to determine if6958// it is an address for a symbol stub. If so then the symbol name for that6959// stub is returned indirectly through ReferenceName and then ReferenceType is6960// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.6961//6962// When this is called with an value loaded via a PC relative load then6963// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the6964// SymbolValue is checked to be an address of literal pointer, symbol pointer,6965// or an Objective-C meta data reference. If so the output ReferenceType is6966// set to correspond to that as well as setting the ReferenceName.6967static const char *SymbolizerSymbolLookUp(void *DisInfo,6968uint64_t ReferenceValue,6969uint64_t *ReferenceType,6970uint64_t ReferencePC,6971const char **ReferenceName) {6972struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;6973// If no verbose symbolic information is wanted then just return nullptr.6974if (!info->verbose) {6975*ReferenceName = nullptr;6976*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;6977return nullptr;6978}69796980const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);69816982if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {6983*ReferenceName = GuessIndirectSymbol(ReferenceValue, info);6984if (*ReferenceName != nullptr) {6985method_reference(info, ReferenceType, ReferenceName);6986if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)6987*ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;6988} else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {6989if (info->demangled_name != nullptr)6990free(info->demangled_name);6991info->demangled_name = itaniumDemangle(SymbolName + 1);6992if (info->demangled_name != nullptr) {6993*ReferenceName = info->demangled_name;6994*ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;6995} else6996*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;6997} else6998*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;6999} else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {7000*ReferenceName =7001GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7002if (*ReferenceName)7003method_reference(info, ReferenceType, ReferenceName);7004else7005*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7006// If this is arm64 and the reference is an adrp instruction save the7007// instruction, passed in ReferenceValue and the address of the instruction7008// for use later if we see and add immediate instruction.7009} else if (info->O->getArch() == Triple::aarch64 &&7010*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {7011info->adrp_inst = ReferenceValue;7012info->adrp_addr = ReferencePC;7013SymbolName = nullptr;7014*ReferenceName = nullptr;7015*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7016// If this is arm64 and reference is an add immediate instruction and we7017// have7018// seen an adrp instruction just before it and the adrp's Xd register7019// matches7020// this add's Xn register reconstruct the value being referenced and look to7021// see if it is a literal pointer. Note the add immediate instruction is7022// passed in ReferenceValue.7023} else if (info->O->getArch() == Triple::aarch64 &&7024*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&7025ReferencePC - 4 == info->adrp_addr &&7026(info->adrp_inst & 0x9f000000) == 0x90000000 &&7027(info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7028uint32_t addxri_inst;7029uint64_t adrp_imm, addxri_imm;70307031adrp_imm =7032((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7033if (info->adrp_inst & 0x0200000)7034adrp_imm |= 0xfffffffffc000000LL;70357036addxri_inst = ReferenceValue;7037addxri_imm = (addxri_inst >> 10) & 0xfff;7038if (((addxri_inst >> 22) & 0x3) == 1)7039addxri_imm <<= 12;70407041ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7042(adrp_imm << 12) + addxri_imm;70437044*ReferenceName =7045GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7046if (*ReferenceName == nullptr)7047*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7048// If this is arm64 and the reference is a load register instruction and we7049// have seen an adrp instruction just before it and the adrp's Xd register7050// matches this add's Xn register reconstruct the value being referenced and7051// look to see if it is a literal pointer. Note the load register7052// instruction is passed in ReferenceValue.7053} else if (info->O->getArch() == Triple::aarch64 &&7054*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&7055ReferencePC - 4 == info->adrp_addr &&7056(info->adrp_inst & 0x9f000000) == 0x90000000 &&7057(info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7058uint32_t ldrxui_inst;7059uint64_t adrp_imm, ldrxui_imm;70607061adrp_imm =7062((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7063if (info->adrp_inst & 0x0200000)7064adrp_imm |= 0xfffffffffc000000LL;70657066ldrxui_inst = ReferenceValue;7067ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;70687069ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7070(adrp_imm << 12) + (ldrxui_imm << 3);70717072*ReferenceName =7073GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7074if (*ReferenceName == nullptr)7075*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7076}7077// If this arm64 and is an load register (PC-relative) instruction the7078// ReferenceValue is the PC plus the immediate value.7079else if (info->O->getArch() == Triple::aarch64 &&7080(*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||7081*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {7082*ReferenceName =7083GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7084if (*ReferenceName == nullptr)7085*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7086} else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {7087if (info->demangled_name != nullptr)7088free(info->demangled_name);7089info->demangled_name = itaniumDemangle(SymbolName + 1);7090if (info->demangled_name != nullptr) {7091*ReferenceName = info->demangled_name;7092*ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;7093}7094}7095else {7096*ReferenceName = nullptr;7097*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7098}70997100return SymbolName;7101}71027103/// Emits the comments that are stored in the CommentStream.7104/// Each comment in the CommentStream must end with a newline.7105static void emitComments(raw_svector_ostream &CommentStream,7106SmallString<128> &CommentsToEmit,7107formatted_raw_ostream &FormattedOS,7108const MCAsmInfo &MAI) {7109// Flush the stream before taking its content.7110StringRef Comments = CommentsToEmit.str();7111// Get the default information for printing a comment.7112StringRef CommentBegin = MAI.getCommentString();7113unsigned CommentColumn = MAI.getCommentColumn();7114ListSeparator LS("\n");7115while (!Comments.empty()) {7116FormattedOS << LS;7117// Emit a line of comments.7118FormattedOS.PadToColumn(CommentColumn);7119size_t Position = Comments.find('\n');7120FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);7121// Move after the newline character.7122Comments = Comments.substr(Position + 1);7123}7124FormattedOS.flush();71257126// Tell the comment stream that the vector changed underneath it.7127CommentsToEmit.clear();7128}71297130const MachOObjectFile *7131objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,7132std::unique_ptr<Binary> &DSYMBinary,7133std::unique_ptr<MemoryBuffer> &DSYMBuf) {7134const MachOObjectFile *DbgObj = MachOOF;7135std::string DSYMPath;71367137// Auto-detect w/o --dsym.7138if (DSYMFile.empty()) {7139sys::fs::file_status DSYMStatus;7140Twine FilenameDSYM = Filename + ".dSYM";7141if (!status(FilenameDSYM, DSYMStatus)) {7142if (sys::fs::is_directory(DSYMStatus)) {7143SmallString<1024> Path;7144FilenameDSYM.toVector(Path);7145sys::path::append(Path, "Contents", "Resources", "DWARF",7146sys::path::filename(Filename));7147DSYMPath = std::string(Path);7148} else if (sys::fs::is_regular_file(DSYMStatus)) {7149DSYMPath = FilenameDSYM.str();7150}7151}7152}71537154if (DSYMPath.empty() && !DSYMFile.empty()) {7155// If DSYMPath is a .dSYM directory, append the Mach-O file.7156if (sys::fs::is_directory(DSYMFile) &&7157sys::path::extension(DSYMFile) == ".dSYM") {7158SmallString<128> ShortName(sys::path::filename(DSYMFile));7159sys::path::replace_extension(ShortName, "");7160SmallString<1024> FullPath(DSYMFile);7161sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);7162DSYMPath = FullPath.str();7163} else {7164DSYMPath = DSYMFile;7165}7166}71677168if (!DSYMPath.empty()) {7169// Load the file.7170ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =7171MemoryBuffer::getFileOrSTDIN(DSYMPath);7172if (std::error_code EC = BufOrErr.getError()) {7173reportError(errorCodeToError(EC), DSYMPath);7174return nullptr;7175}71767177// We need to keep the file alive, because we're replacing DbgObj with it.7178DSYMBuf = std::move(BufOrErr.get());71797180Expected<std::unique_ptr<Binary>> BinaryOrErr =7181createBinary(DSYMBuf->getMemBufferRef());7182if (!BinaryOrErr) {7183reportError(BinaryOrErr.takeError(), DSYMPath);7184return nullptr;7185}71867187// We need to keep the Binary alive with the buffer7188DSYMBinary = std::move(BinaryOrErr.get());7189if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {7190// this is a Mach-O object file, use it7191if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {7192DbgObj = MachDSYM;7193} else {7194WithColor::error(errs(), "llvm-objdump")7195<< DSYMPath << " is not a Mach-O file type.\n";7196return nullptr;7197}7198} else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {7199// this is a Universal Binary, find a Mach-O for this architecture7200uint32_t CPUType, CPUSubType;7201const char *ArchFlag;7202if (MachOOF->is64Bit()) {7203const MachO::mach_header_64 H_64 = MachOOF->getHeader64();7204CPUType = H_64.cputype;7205CPUSubType = H_64.cpusubtype;7206} else {7207const MachO::mach_header H = MachOOF->getHeader();7208CPUType = H.cputype;7209CPUSubType = H.cpusubtype;7210}7211Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,7212&ArchFlag);7213Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =7214UB->getMachOObjectForArch(ArchFlag);7215if (!MachDSYM) {7216reportError(MachDSYM.takeError(), DSYMPath);7217return nullptr;7218}72197220// We need to keep the Binary alive with the buffer7221DbgObj = &*MachDSYM.get();7222DSYMBinary = std::move(*MachDSYM);7223} else {7224WithColor::error(errs(), "llvm-objdump")7225<< DSYMPath << " is not a Mach-O or Universal file type.\n";7226return nullptr;7227}7228}7229return DbgObj;7230}72317232static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,7233StringRef DisSegName, StringRef DisSectName) {7234const char *McpuDefault = nullptr;7235const Target *ThumbTarget = nullptr;7236const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);7237if (!TheTarget) {7238// GetTarget prints out stuff.7239return;7240}7241std::string MachOMCPU;7242if (MCPU.empty() && McpuDefault)7243MachOMCPU = McpuDefault;7244else7245MachOMCPU = MCPU;72467247#define CHECK_TARGET_INFO_CREATION(NAME) \7248do { \7249if (!NAME) { \7250WithColor::error(errs(), "llvm-objdump") \7251<< "couldn't initialize disassembler for target " << TripleName \7252<< '\n'; \7253return; \7254} \7255} while (false)7256#define CHECK_THUMB_TARGET_INFO_CREATION(NAME) \7257do { \7258if (!NAME) { \7259WithColor::error(errs(), "llvm-objdump") \7260<< "couldn't initialize disassembler for target " << ThumbTripleName \7261<< '\n'; \7262return; \7263} \7264} while (false)72657266std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());7267CHECK_TARGET_INFO_CREATION(InstrInfo);7268std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;7269if (ThumbTarget) {7270ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());7271CHECK_THUMB_TARGET_INFO_CREATION(ThumbInstrInfo);7272}72737274// Package up features to be passed to target/subtarget7275std::string FeaturesStr;7276if (!MAttrs.empty()) {7277SubtargetFeatures Features;7278for (unsigned i = 0; i != MAttrs.size(); ++i)7279Features.AddFeature(MAttrs[i]);7280FeaturesStr = Features.getString();7281}72827283MCTargetOptions MCOptions;7284// Set up disassembler.7285std::unique_ptr<const MCRegisterInfo> MRI(7286TheTarget->createMCRegInfo(TripleName));7287CHECK_TARGET_INFO_CREATION(MRI);7288std::unique_ptr<const MCAsmInfo> AsmInfo(7289TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));7290CHECK_TARGET_INFO_CREATION(AsmInfo);7291std::unique_ptr<const MCSubtargetInfo> STI(7292TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr));7293CHECK_TARGET_INFO_CREATION(STI);7294MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());7295std::unique_ptr<MCDisassembler> DisAsm(7296TheTarget->createMCDisassembler(*STI, Ctx));7297CHECK_TARGET_INFO_CREATION(DisAsm);7298std::unique_ptr<MCSymbolizer> Symbolizer;7299struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);7300std::unique_ptr<MCRelocationInfo> RelInfo(7301TheTarget->createMCRelocationInfo(TripleName, Ctx));7302if (RelInfo) {7303Symbolizer.reset(TheTarget->createMCSymbolizer(7304TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,7305&SymbolizerInfo, &Ctx, std::move(RelInfo)));7306DisAsm->setSymbolizer(std::move(Symbolizer));7307}7308int AsmPrinterVariant = AsmInfo->getAssemblerDialect();7309std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(7310Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));7311CHECK_TARGET_INFO_CREATION(IP);7312// Set the display preference for hex vs. decimal immediates.7313IP->setPrintImmHex(PrintImmHex);7314// Comment stream and backing vector.7315SmallString<128> CommentsToEmit;7316raw_svector_ostream CommentStream(CommentsToEmit);7317// FIXME: Setting the CommentStream in the InstPrinter is problematic in that7318// if it is done then arm64 comments for string literals don't get printed7319// and some constant get printed instead and not setting it causes intel7320// (32-bit and 64-bit) comments printed with different spacing before the7321// comment causing different diffs with the 'C' disassembler library API.7322// IP->setCommentStream(CommentStream);73237324// Set up separate thumb disassembler if needed.7325std::unique_ptr<const MCRegisterInfo> ThumbMRI;7326std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;7327std::unique_ptr<const MCSubtargetInfo> ThumbSTI;7328std::unique_ptr<MCDisassembler> ThumbDisAsm;7329std::unique_ptr<MCInstPrinter> ThumbIP;7330std::unique_ptr<MCContext> ThumbCtx;7331std::unique_ptr<MCSymbolizer> ThumbSymbolizer;7332struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);7333std::unique_ptr<MCRelocationInfo> ThumbRelInfo;7334if (ThumbTarget) {7335ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));7336CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);7337ThumbAsmInfo.reset(7338ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName, MCOptions));7339CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);7340ThumbSTI.reset(7341ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU,7342FeaturesStr));7343CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);7344ThumbCtx.reset(new MCContext(Triple(ThumbTripleName), ThumbAsmInfo.get(),7345ThumbMRI.get(), ThumbSTI.get()));7346ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));7347CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);7348MCContext *PtrThumbCtx = ThumbCtx.get();7349ThumbRelInfo.reset(7350ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));7351if (ThumbRelInfo) {7352ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(7353ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,7354&ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));7355ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));7356}7357int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();7358ThumbIP.reset(ThumbTarget->createMCInstPrinter(7359Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,7360*ThumbInstrInfo, *ThumbMRI));7361CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);7362// Set the display preference for hex vs. decimal immediates.7363ThumbIP->setPrintImmHex(PrintImmHex);7364}73657366#undef CHECK_TARGET_INFO_CREATION7367#undef CHECK_THUMB_TARGET_INFO_CREATION73687369MachO::mach_header Header = MachOOF->getHeader();73707371// FIXME: Using the -cfg command line option, this code used to be able to7372// annotate relocations with the referenced symbol's name, and if this was7373// inside a __[cf]string section, the data it points to. This is now replaced7374// by the upcoming MCSymbolizer, which needs the appropriate setup done above.7375std::vector<SectionRef> Sections;7376std::vector<SymbolRef> Symbols;7377SmallVector<uint64_t, 8> FoundFns;7378uint64_t BaseSegmentAddress = 0;73797380getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,7381BaseSegmentAddress);73827383// Sort the symbols by address, just in case they didn't come in that way.7384llvm::stable_sort(Symbols, SymbolSorter());73857386// Build a data in code table that is sorted on by the address of each entry.7387uint64_t BaseAddress = 0;7388if (Header.filetype == MachO::MH_OBJECT)7389BaseAddress = Sections[0].getAddress();7390else7391BaseAddress = BaseSegmentAddress;7392DiceTable Dices;7393for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();7394DI != DE; ++DI) {7395uint32_t Offset;7396DI->getOffset(Offset);7397Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));7398}7399array_pod_sort(Dices.begin(), Dices.end());74007401// Try to find debug info and set up the DIContext for it.7402std::unique_ptr<DIContext> diContext;7403std::unique_ptr<Binary> DSYMBinary;7404std::unique_ptr<MemoryBuffer> DSYMBuf;7405if (UseDbg) {7406// If separate DSym file path was specified, parse it as a macho file,7407// get the sections and supply it to the section name parsing machinery.7408if (const ObjectFile *DbgObj =7409getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf)) {7410// Setup the DIContext7411diContext = DWARFContext::create(*DbgObj);7412} else {7413return;7414}7415}74167417if (FilterSections.empty())7418outs() << "(" << DisSegName << "," << DisSectName << ") section\n";74197420for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {7421Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();7422if (!SecNameOrErr) {7423consumeError(SecNameOrErr.takeError());7424continue;7425}7426if (*SecNameOrErr != DisSectName)7427continue;74287429DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();74307431StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);7432if (SegmentName != DisSegName)7433continue;74347435StringRef BytesStr =7436unwrapOrError(Sections[SectIdx].getContents(), Filename);7437ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);7438uint64_t SectAddress = Sections[SectIdx].getAddress();74397440bool symbolTableWorked = false;74417442// Create a map of symbol addresses to symbol names for use by7443// the SymbolizerSymbolLookUp() routine.7444SymbolAddressMap AddrMap;7445bool DisSymNameFound = false;7446for (const SymbolRef &Symbol : MachOOF->symbols()) {7447SymbolRef::Type ST =7448unwrapOrError(Symbol.getType(), MachOOF->getFileName());7449if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||7450ST == SymbolRef::ST_Other) {7451uint64_t Address = cantFail(Symbol.getValue());7452StringRef SymName =7453unwrapOrError(Symbol.getName(), MachOOF->getFileName());7454AddrMap[Address] = SymName;7455if (!DisSymName.empty() && DisSymName == SymName)7456DisSymNameFound = true;7457}7458}7459if (!DisSymName.empty() && !DisSymNameFound) {7460outs() << "Can't find -dis-symname: " << DisSymName << "\n";7461return;7462}7463// Set up the block of info used by the Symbolizer call backs.7464SymbolizerInfo.verbose = SymbolicOperands;7465SymbolizerInfo.O = MachOOF;7466SymbolizerInfo.S = Sections[SectIdx];7467SymbolizerInfo.AddrMap = &AddrMap;7468SymbolizerInfo.Sections = &Sections;7469// Same for the ThumbSymbolizer7470ThumbSymbolizerInfo.verbose = SymbolicOperands;7471ThumbSymbolizerInfo.O = MachOOF;7472ThumbSymbolizerInfo.S = Sections[SectIdx];7473ThumbSymbolizerInfo.AddrMap = &AddrMap;7474ThumbSymbolizerInfo.Sections = &Sections;74757476unsigned int Arch = MachOOF->getArch();74777478// Skip all symbols if this is a stubs file.7479if (Bytes.empty())7480return;74817482// If the section has symbols but no symbol at the start of the section7483// these are used to make sure the bytes before the first symbol are7484// disassembled.7485bool FirstSymbol = true;7486bool FirstSymbolAtSectionStart = true;74877488// Disassemble symbol by symbol.7489for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {7490StringRef SymName =7491unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());7492SymbolRef::Type ST =7493unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());7494if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)7495continue;74967497// Make sure the symbol is defined in this section.7498bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);7499if (!containsSym) {7500if (!DisSymName.empty() && DisSymName == SymName) {7501outs() << "-dis-symname: " << DisSymName << " not in the section\n";7502return;7503}7504continue;7505}7506// The __mh_execute_header is special and we need to deal with that fact7507// this symbol is before the start of the (__TEXT,__text) section and at the7508// address of the start of the __TEXT segment. This is because this symbol7509// is an N_SECT symbol in the (__TEXT,__text) but its address is before the7510// start of the section in a standard MH_EXECUTE filetype.7511if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {7512outs() << "-dis-symname: __mh_execute_header not in any section\n";7513return;7514}7515// When this code is trying to disassemble a symbol at a time and in the7516// case there is only the __mh_execute_header symbol left as in a stripped7517// executable, we need to deal with this by ignoring this symbol so the7518// whole section is disassembled and this symbol is then not displayed.7519if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||7520SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||7521SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")7522continue;75237524// If we are only disassembling one symbol see if this is that symbol.7525if (!DisSymName.empty() && DisSymName != SymName)7526continue;75277528// Start at the address of the symbol relative to the section's address.7529uint64_t SectSize = Sections[SectIdx].getSize();7530uint64_t Start = cantFail(Symbols[SymIdx].getValue());7531uint64_t SectionAddress = Sections[SectIdx].getAddress();7532Start -= SectionAddress;75337534if (Start > SectSize) {7535outs() << "section data ends, " << SymName7536<< " lies outside valid range\n";7537return;7538}75397540// Stop disassembling either at the beginning of the next symbol or at7541// the end of the section.7542bool containsNextSym = false;7543uint64_t NextSym = 0;7544uint64_t NextSymIdx = SymIdx + 1;7545while (Symbols.size() > NextSymIdx) {7546SymbolRef::Type NextSymType = unwrapOrError(7547Symbols[NextSymIdx].getType(), MachOOF->getFileName());7548if (NextSymType == SymbolRef::ST_Function) {7549containsNextSym =7550Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);7551NextSym = cantFail(Symbols[NextSymIdx].getValue());7552NextSym -= SectionAddress;7553break;7554}7555++NextSymIdx;7556}75577558uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;7559uint64_t Size;75607561symbolTableWorked = true;75627563DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();7564uint32_t SymbolFlags = cantFail(MachOOF->getSymbolFlags(Symb));7565bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;75667567// We only need the dedicated Thumb target if there's a real choice7568// (i.e. we're not targeting M-class) and the function is Thumb.7569bool UseThumbTarget = IsThumb && ThumbTarget;75707571// If we are not specifying a symbol to start disassembly with and this7572// is the first symbol in the section but not at the start of the section7573// then move the disassembly index to the start of the section and7574// don't print the symbol name just yet. This is so the bytes before the7575// first symbol are disassembled.7576uint64_t SymbolStart = Start;7577if (DisSymName.empty() && FirstSymbol && Start != 0) {7578FirstSymbolAtSectionStart = false;7579Start = 0;7580}7581else7582outs() << SymName << ":\n";75837584DILineInfo lastLine;7585for (uint64_t Index = Start; Index < End; Index += Size) {7586MCInst Inst;75877588// If this is the first symbol in the section and it was not at the7589// start of the section, see if we are at its Index now and if so print7590// the symbol name.7591if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)7592outs() << SymName << ":\n";75937594uint64_t PC = SectAddress + Index;7595if (LeadingAddr) {7596if (FullLeadingAddr) {7597if (MachOOF->is64Bit())7598outs() << format("%016" PRIx64, PC);7599else7600outs() << format("%08" PRIx64, PC);7601} else {7602outs() << format("%8" PRIx64 ":", PC);7603}7604}7605if (ShowRawInsn || Arch == Triple::arm)7606outs() << "\t";76077608if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))7609continue;76107611SmallVector<char, 64> AnnotationsBytes;7612raw_svector_ostream Annotations(AnnotationsBytes);76137614bool gotInst;7615if (UseThumbTarget)7616gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),7617PC, Annotations);7618else7619gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,7620Annotations);7621if (gotInst) {7622if (ShowRawInsn || Arch == Triple::arm) {7623dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());7624}7625formatted_raw_ostream FormattedOS(outs());7626StringRef AnnotationsStr = Annotations.str();7627if (UseThumbTarget)7628ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI,7629FormattedOS);7630else7631IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);7632emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);76337634// Print debug info.7635if (diContext) {7636DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});7637// Print valid line info if it changed.7638if (dli != lastLine && dli.Line != 0)7639outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'7640<< dli.Column;7641lastLine = dli;7642}7643outs() << "\n";7644} else {7645if (MachOOF->getArchTriple().isX86()) {7646outs() << format("\t.byte 0x%02x #bad opcode\n",7647*(Bytes.data() + Index) & 0xff);7648Size = 1; // skip exactly one illegible byte and move on.7649} else if (Arch == Triple::aarch64 ||7650(Arch == Triple::arm && !IsThumb)) {7651uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7652(*(Bytes.data() + Index + 1) & 0xff) << 8 |7653(*(Bytes.data() + Index + 2) & 0xff) << 16 |7654(*(Bytes.data() + Index + 3) & 0xff) << 24;7655outs() << format("\t.long\t0x%08x\n", opcode);7656Size = 4;7657} else if (Arch == Triple::arm) {7658assert(IsThumb && "ARM mode should have been dealt with above");7659uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7660(*(Bytes.data() + Index + 1) & 0xff) << 8;7661outs() << format("\t.short\t0x%04x\n", opcode);7662Size = 2;7663} else{7664WithColor::warning(errs(), "llvm-objdump")7665<< "invalid instruction encoding\n";7666if (Size == 0)7667Size = 1; // skip illegible bytes7668}7669}7670}7671// Now that we are done disassembled the first symbol set the bool that7672// were doing this to false.7673FirstSymbol = false;7674}7675if (!symbolTableWorked) {7676// Reading the symbol table didn't work, disassemble the whole section.7677uint64_t SectAddress = Sections[SectIdx].getAddress();7678uint64_t SectSize = Sections[SectIdx].getSize();7679uint64_t InstSize;7680for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {7681MCInst Inst;76827683uint64_t PC = SectAddress + Index;76847685if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize))7686continue;76877688SmallVector<char, 64> AnnotationsBytes;7689raw_svector_ostream Annotations(AnnotationsBytes);7690if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,7691Annotations)) {7692if (LeadingAddr) {7693if (FullLeadingAddr) {7694if (MachOOF->is64Bit())7695outs() << format("%016" PRIx64, PC);7696else7697outs() << format("%08" PRIx64, PC);7698} else {7699outs() << format("%8" PRIx64 ":", PC);7700}7701}7702if (ShowRawInsn || Arch == Triple::arm) {7703outs() << "\t";7704dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());7705}7706StringRef AnnotationsStr = Annotations.str();7707IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());7708outs() << "\n";7709} else {7710if (MachOOF->getArchTriple().isX86()) {7711outs() << format("\t.byte 0x%02x #bad opcode\n",7712*(Bytes.data() + Index) & 0xff);7713InstSize = 1; // skip exactly one illegible byte and move on.7714} else {7715WithColor::warning(errs(), "llvm-objdump")7716<< "invalid instruction encoding\n";7717if (InstSize == 0)7718InstSize = 1; // skip illegible bytes7719}7720}7721}7722}7723// The TripleName's need to be reset if we are called again for a different7724// architecture.7725TripleName = "";7726ThumbTripleName = "";77277728if (SymbolizerInfo.demangled_name != nullptr)7729free(SymbolizerInfo.demangled_name);7730if (ThumbSymbolizerInfo.demangled_name != nullptr)7731free(ThumbSymbolizerInfo.demangled_name);7732}7733}77347735//===----------------------------------------------------------------------===//7736// __compact_unwind section dumping7737//===----------------------------------------------------------------------===//77387739namespace {77407741template <typename T>7742static uint64_t read(StringRef Contents, ptrdiff_t Offset) {7743if (Offset + sizeof(T) > Contents.size()) {7744outs() << "warning: attempt to read past end of buffer\n";7745return T();7746}77477748uint64_t Val = support::endian::read<T, llvm::endianness::little>(7749Contents.data() + Offset);7750return Val;7751}77527753template <typename T>7754static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {7755T Val = read<T>(Contents, Offset);7756Offset += sizeof(T);7757return Val;7758}77597760struct CompactUnwindEntry {7761uint32_t OffsetInSection;77627763uint64_t FunctionAddr;7764uint32_t Length;7765uint32_t CompactEncoding;7766uint64_t PersonalityAddr;7767uint64_t LSDAAddr;77687769RelocationRef FunctionReloc;7770RelocationRef PersonalityReloc;7771RelocationRef LSDAReloc;77727773CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)7774: OffsetInSection(Offset) {7775if (Is64)7776read<uint64_t>(Contents, Offset);7777else7778read<uint32_t>(Contents, Offset);7779}77807781private:7782template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {7783FunctionAddr = readNext<UIntPtr>(Contents, Offset);7784Length = readNext<uint32_t>(Contents, Offset);7785CompactEncoding = readNext<uint32_t>(Contents, Offset);7786PersonalityAddr = readNext<UIntPtr>(Contents, Offset);7787LSDAAddr = readNext<UIntPtr>(Contents, Offset);7788}7789};7790}77917792/// Given a relocation from __compact_unwind, consisting of the RelocationRef7793/// and data being relocated, determine the best base Name and Addend to use for7794/// display purposes.7795///7796/// 1. An Extern relocation will directly reference a symbol (and the data is7797/// then already an addend), so use that.7798/// 2. Otherwise the data is an offset in the object file's layout; try to find7799// a symbol before it in the same section, and use the offset from there.7800/// 3. Finally, if all that fails, fall back to an offset from the start of the7801/// referenced section.7802static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,7803std::map<uint64_t, SymbolRef> &Symbols,7804const RelocationRef &Reloc, uint64_t Addr,7805StringRef &Name, uint64_t &Addend) {7806if (Reloc.getSymbol() != Obj->symbol_end()) {7807Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());7808Addend = Addr;7809return;7810}78117812auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());7813SectionRef RelocSection = Obj->getAnyRelocationSection(RE);78147815uint64_t SectionAddr = RelocSection.getAddress();78167817auto Sym = Symbols.upper_bound(Addr);7818if (Sym == Symbols.begin()) {7819// The first symbol in the object is after this reference, the best we can7820// do is section-relative notation.7821if (Expected<StringRef> NameOrErr = RelocSection.getName())7822Name = *NameOrErr;7823else7824consumeError(NameOrErr.takeError());78257826Addend = Addr - SectionAddr;7827return;7828}78297830// Go back one so that SymbolAddress <= Addr.7831--Sym;78327833section_iterator SymSection =7834unwrapOrError(Sym->second.getSection(), Obj->getFileName());7835if (RelocSection == *SymSection) {7836// There's a valid symbol in the same section before this reference.7837Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());7838Addend = Addr - Sym->first;7839return;7840}78417842// There is a symbol before this reference, but it's in a different7843// section. Probably not helpful to mention it, so use the section name.7844if (Expected<StringRef> NameOrErr = RelocSection.getName())7845Name = *NameOrErr;7846else7847consumeError(NameOrErr.takeError());78487849Addend = Addr - SectionAddr;7850}78517852static void printUnwindRelocDest(const MachOObjectFile *Obj,7853std::map<uint64_t, SymbolRef> &Symbols,7854const RelocationRef &Reloc, uint64_t Addr) {7855StringRef Name;7856uint64_t Addend;78577858if (!Reloc.getObject())7859return;78607861findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);78627863outs() << Name;7864if (Addend)7865outs() << " + " << format("0x%" PRIx64, Addend);7866}78677868static void7869printMachOCompactUnwindSection(const MachOObjectFile *Obj,7870std::map<uint64_t, SymbolRef> &Symbols,7871const SectionRef &CompactUnwind) {78727873if (!Obj->isLittleEndian()) {7874outs() << "Skipping big-endian __compact_unwind section\n";7875return;7876}78777878bool Is64 = Obj->is64Bit();7879uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);7880uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);78817882StringRef Contents =7883unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());7884SmallVector<CompactUnwindEntry, 4> CompactUnwinds;78857886// First populate the initial raw offsets, encodings and so on from the entry.7887for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {7888CompactUnwindEntry Entry(Contents, Offset, Is64);7889CompactUnwinds.push_back(Entry);7890}78917892// Next we need to look at the relocations to find out what objects are7893// actually being referred to.7894for (const RelocationRef &Reloc : CompactUnwind.relocations()) {7895uint64_t RelocAddress = Reloc.getOffset();78967897uint32_t EntryIdx = RelocAddress / EntrySize;7898uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;7899CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];79007901if (OffsetInEntry == 0)7902Entry.FunctionReloc = Reloc;7903else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))7904Entry.PersonalityReloc = Reloc;7905else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))7906Entry.LSDAReloc = Reloc;7907else {7908outs() << "Invalid relocation in __compact_unwind section\n";7909return;7910}7911}79127913// Finally, we're ready to print the data we've gathered.7914outs() << "Contents of __compact_unwind section:\n";7915for (auto &Entry : CompactUnwinds) {7916outs() << " Entry at offset "7917<< format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";79187919// 1. Start of the region this entry applies to.7920outs() << " start: " << format("0x%" PRIx64,7921Entry.FunctionAddr) << ' ';7922printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);7923outs() << '\n';79247925// 2. Length of the region this entry applies to.7926outs() << " length: " << format("0x%" PRIx32, Entry.Length)7927<< '\n';7928// 3. The 32-bit compact encoding.7929outs() << " compact encoding: "7930<< format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';79317932// 4. The personality function, if present.7933if (Entry.PersonalityReloc.getObject()) {7934outs() << " personality function: "7935<< format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';7936printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,7937Entry.PersonalityAddr);7938outs() << '\n';7939}79407941// 5. This entry's language-specific data area.7942if (Entry.LSDAReloc.getObject()) {7943outs() << " LSDA: " << format("0x%" PRIx64,7944Entry.LSDAAddr) << ' ';7945printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);7946outs() << '\n';7947}7948}7949}79507951//===----------------------------------------------------------------------===//7952// __unwind_info section dumping7953//===----------------------------------------------------------------------===//79547955static void printRegularSecondLevelUnwindPage(StringRef PageData) {7956ptrdiff_t Pos = 0;7957uint32_t Kind = readNext<uint32_t>(PageData, Pos);7958(void)Kind;7959assert(Kind == 2 && "kind for a regular 2nd level index should be 2");79607961uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);7962uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);79637964Pos = EntriesStart;7965for (unsigned i = 0; i < NumEntries; ++i) {7966uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);7967uint32_t Encoding = readNext<uint32_t>(PageData, Pos);79687969outs() << " [" << i << "]: "7970<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)7971<< ", "7972<< "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';7973}7974}79757976static void printCompressedSecondLevelUnwindPage(7977StringRef PageData, uint32_t FunctionBase,7978const SmallVectorImpl<uint32_t> &CommonEncodings) {7979ptrdiff_t Pos = 0;7980uint32_t Kind = readNext<uint32_t>(PageData, Pos);7981(void)Kind;7982assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");79837984uint32_t NumCommonEncodings = CommonEncodings.size();7985uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);7986uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);79877988uint16_t PageEncodingsStart = readNext<uint16_t>(PageData, Pos);7989uint16_t NumPageEncodings = readNext<uint16_t>(PageData, Pos);7990SmallVector<uint32_t, 64> PageEncodings;7991if (NumPageEncodings) {7992outs() << " Page encodings: (count = " << NumPageEncodings << ")\n";7993Pos = PageEncodingsStart;7994for (unsigned i = 0; i < NumPageEncodings; ++i) {7995uint32_t Encoding = readNext<uint32_t>(PageData, Pos);7996PageEncodings.push_back(Encoding);7997outs() << " encoding[" << (i + NumCommonEncodings)7998<< "]: " << format("0x%08" PRIx32, Encoding) << '\n';7999}8000}80018002Pos = EntriesStart;8003for (unsigned i = 0; i < NumEntries; ++i) {8004uint32_t Entry = readNext<uint32_t>(PageData, Pos);8005uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);8006uint32_t EncodingIdx = Entry >> 24;80078008uint32_t Encoding;8009if (EncodingIdx < NumCommonEncodings)8010Encoding = CommonEncodings[EncodingIdx];8011else8012Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];80138014outs() << " [" << i << "]: "8015<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)8016<< ", "8017<< "encoding[" << EncodingIdx8018<< "]=" << format("0x%08" PRIx32, Encoding) << '\n';8019}8020}80218022static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,8023std::map<uint64_t, SymbolRef> &Symbols,8024const SectionRef &UnwindInfo) {80258026if (!Obj->isLittleEndian()) {8027outs() << "Skipping big-endian __unwind_info section\n";8028return;8029}80308031outs() << "Contents of __unwind_info section:\n";80328033StringRef Contents =8034unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());8035ptrdiff_t Pos = 0;80368037//===----------------------------------8038// Section header8039//===----------------------------------80408041uint32_t Version = readNext<uint32_t>(Contents, Pos);8042outs() << " Version: "8043<< format("0x%" PRIx32, Version) << '\n';8044if (Version != 1) {8045outs() << " Skipping section with unknown version\n";8046return;8047}80488049uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);8050outs() << " Common encodings array section offset: "8051<< format("0x%" PRIx32, CommonEncodingsStart) << '\n';8052uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);8053outs() << " Number of common encodings in array: "8054<< format("0x%" PRIx32, NumCommonEncodings) << '\n';80558056uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);8057outs() << " Personality function array section offset: "8058<< format("0x%" PRIx32, PersonalitiesStart) << '\n';8059uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);8060outs() << " Number of personality functions in array: "8061<< format("0x%" PRIx32, NumPersonalities) << '\n';80628063uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);8064outs() << " Index array section offset: "8065<< format("0x%" PRIx32, IndicesStart) << '\n';8066uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);8067outs() << " Number of indices in array: "8068<< format("0x%" PRIx32, NumIndices) << '\n';80698070//===----------------------------------8071// A shared list of common encodings8072//===----------------------------------80738074// These occupy indices in the range [0, N] whenever an encoding is referenced8075// from a compressed 2nd level index table. In practice the linker only8076// creates ~128 of these, so that indices are available to embed encodings in8077// the 2nd level index.80788079SmallVector<uint32_t, 64> CommonEncodings;8080outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";8081Pos = CommonEncodingsStart;8082for (unsigned i = 0; i < NumCommonEncodings; ++i) {8083uint32_t Encoding = readNext<uint32_t>(Contents, Pos);8084CommonEncodings.push_back(Encoding);80858086outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)8087<< '\n';8088}80898090//===----------------------------------8091// Personality functions used in this executable8092//===----------------------------------80938094// There should be only a handful of these (one per source language,8095// roughly). Particularly since they only get 2 bits in the compact encoding.80968097outs() << " Personality functions: (count = " << NumPersonalities << ")\n";8098Pos = PersonalitiesStart;8099for (unsigned i = 0; i < NumPersonalities; ++i) {8100uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);8101outs() << " personality[" << i + 18102<< "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';8103}81048105//===----------------------------------8106// The level 1 index entries8107//===----------------------------------81088109// These specify an approximate place to start searching for the more detailed8110// information, sorted by PC.81118112struct IndexEntry {8113uint32_t FunctionOffset;8114uint32_t SecondLevelPageStart;8115uint32_t LSDAStart;8116};81178118SmallVector<IndexEntry, 4> IndexEntries;81198120outs() << " Top level indices: (count = " << NumIndices << ")\n";8121Pos = IndicesStart;8122for (unsigned i = 0; i < NumIndices; ++i) {8123IndexEntry Entry;81248125Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);8126Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);8127Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);8128IndexEntries.push_back(Entry);81298130outs() << " [" << i << "]: "8131<< "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)8132<< ", "8133<< "2nd level page offset="8134<< format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "8135<< "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';8136}81378138//===----------------------------------8139// Next come the LSDA tables8140//===----------------------------------81418142// The LSDA layout is rather implicit: it's a contiguous array of entries from8143// the first top-level index's LSDAOffset to the last (sentinel).81448145outs() << " LSDA descriptors:\n";8146Pos = IndexEntries[0].LSDAStart;8147const uint32_t LSDASize = 2 * sizeof(uint32_t);8148int NumLSDAs =8149(IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;81508151for (int i = 0; i < NumLSDAs; ++i) {8152uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);8153uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);8154outs() << " [" << i << "]: "8155<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)8156<< ", "8157<< "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';8158}81598160//===----------------------------------8161// Finally, the 2nd level indices8162//===----------------------------------81638164// Generally these are 4K in size, and have 2 possible forms:8165// + Regular stores up to 511 entries with disparate encodings8166// + Compressed stores up to 1021 entries if few enough compact encoding8167// values are used.8168outs() << " Second level indices:\n";8169for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {8170// The final sentinel top-level index has no associated 2nd level page8171if (IndexEntries[i].SecondLevelPageStart == 0)8172break;81738174outs() << " Second level index[" << i << "]: "8175<< "offset in section="8176<< format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)8177<< ", "8178<< "base function offset="8179<< format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';81808181Pos = IndexEntries[i].SecondLevelPageStart;8182if (Pos + sizeof(uint32_t) > Contents.size()) {8183outs() << "warning: invalid offset for second level page: " << Pos << '\n';8184continue;8185}81868187uint32_t Kind =8188*reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);8189if (Kind == 2)8190printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));8191else if (Kind == 3)8192printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),8193IndexEntries[i].FunctionOffset,8194CommonEncodings);8195else8196outs() << " Skipping 2nd level page with unknown kind " << Kind8197<< '\n';8198}8199}82008201void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {8202std::map<uint64_t, SymbolRef> Symbols;8203for (const SymbolRef &SymRef : Obj->symbols()) {8204// Discard any undefined or absolute symbols. They're not going to take part8205// in the convenience lookup for unwind info and just take up resources.8206auto SectOrErr = SymRef.getSection();8207if (!SectOrErr) {8208// TODO: Actually report errors helpfully.8209consumeError(SectOrErr.takeError());8210continue;8211}8212section_iterator Section = *SectOrErr;8213if (Section == Obj->section_end())8214continue;82158216uint64_t Addr = cantFail(SymRef.getValue());8217Symbols.insert(std::make_pair(Addr, SymRef));8218}82198220for (const SectionRef &Section : Obj->sections()) {8221StringRef SectName;8222if (Expected<StringRef> NameOrErr = Section.getName())8223SectName = *NameOrErr;8224else8225consumeError(NameOrErr.takeError());82268227if (SectName == "__compact_unwind")8228printMachOCompactUnwindSection(Obj, Symbols, Section);8229else if (SectName == "__unwind_info")8230printMachOUnwindInfoSection(Obj, Symbols, Section);8231}8232}82338234static void PrintMachHeader(uint32_t magic, uint32_t cputype,8235uint32_t cpusubtype, uint32_t filetype,8236uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,8237bool verbose) {8238outs() << "Mach header\n";8239outs() << " magic cputype cpusubtype caps filetype ncmds "8240"sizeofcmds flags\n";8241if (verbose) {8242if (magic == MachO::MH_MAGIC)8243outs() << " MH_MAGIC";8244else if (magic == MachO::MH_MAGIC_64)8245outs() << "MH_MAGIC_64";8246else8247outs() << format(" 0x%08" PRIx32, magic);8248switch (cputype) {8249case MachO::CPU_TYPE_I386:8250outs() << " I386";8251switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8252case MachO::CPU_SUBTYPE_I386_ALL:8253outs() << " ALL";8254break;8255default:8256outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8257break;8258}8259break;8260case MachO::CPU_TYPE_X86_64:8261outs() << " X86_64";8262switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8263case MachO::CPU_SUBTYPE_X86_64_ALL:8264outs() << " ALL";8265break;8266case MachO::CPU_SUBTYPE_X86_64_H:8267outs() << " Haswell";8268break;8269default:8270outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8271break;8272}8273break;8274case MachO::CPU_TYPE_ARM:8275outs() << " ARM";8276switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8277case MachO::CPU_SUBTYPE_ARM_ALL:8278outs() << " ALL";8279break;8280case MachO::CPU_SUBTYPE_ARM_V4T:8281outs() << " V4T";8282break;8283case MachO::CPU_SUBTYPE_ARM_V5TEJ:8284outs() << " V5TEJ";8285break;8286case MachO::CPU_SUBTYPE_ARM_XSCALE:8287outs() << " XSCALE";8288break;8289case MachO::CPU_SUBTYPE_ARM_V6:8290outs() << " V6";8291break;8292case MachO::CPU_SUBTYPE_ARM_V6M:8293outs() << " V6M";8294break;8295case MachO::CPU_SUBTYPE_ARM_V7:8296outs() << " V7";8297break;8298case MachO::CPU_SUBTYPE_ARM_V7EM:8299outs() << " V7EM";8300break;8301case MachO::CPU_SUBTYPE_ARM_V7K:8302outs() << " V7K";8303break;8304case MachO::CPU_SUBTYPE_ARM_V7M:8305outs() << " V7M";8306break;8307case MachO::CPU_SUBTYPE_ARM_V7S:8308outs() << " V7S";8309break;8310default:8311outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8312break;8313}8314break;8315case MachO::CPU_TYPE_ARM64:8316outs() << " ARM64";8317switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8318case MachO::CPU_SUBTYPE_ARM64_ALL:8319outs() << " ALL";8320break;8321case MachO::CPU_SUBTYPE_ARM64_V8:8322outs() << " V8";8323break;8324case MachO::CPU_SUBTYPE_ARM64E:8325outs() << " E";8326break;8327default:8328outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8329break;8330}8331break;8332case MachO::CPU_TYPE_ARM64_32:8333outs() << " ARM64_32";8334switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8335case MachO::CPU_SUBTYPE_ARM64_32_V8:8336outs() << " V8";8337break;8338default:8339outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8340break;8341}8342break;8343case MachO::CPU_TYPE_POWERPC:8344outs() << " PPC";8345switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8346case MachO::CPU_SUBTYPE_POWERPC_ALL:8347outs() << " ALL";8348break;8349default:8350outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8351break;8352}8353break;8354case MachO::CPU_TYPE_POWERPC64:8355outs() << " PPC64";8356switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8357case MachO::CPU_SUBTYPE_POWERPC_ALL:8358outs() << " ALL";8359break;8360default:8361outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8362break;8363}8364break;8365default:8366outs() << format(" %7d", cputype);8367outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8368break;8369}8370if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {8371outs() << " LIB64";8372} else {8373outs() << format(" 0x%02" PRIx32,8374(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8375}8376switch (filetype) {8377case MachO::MH_OBJECT:8378outs() << " OBJECT";8379break;8380case MachO::MH_EXECUTE:8381outs() << " EXECUTE";8382break;8383case MachO::MH_FVMLIB:8384outs() << " FVMLIB";8385break;8386case MachO::MH_CORE:8387outs() << " CORE";8388break;8389case MachO::MH_PRELOAD:8390outs() << " PRELOAD";8391break;8392case MachO::MH_DYLIB:8393outs() << " DYLIB";8394break;8395case MachO::MH_DYLIB_STUB:8396outs() << " DYLIB_STUB";8397break;8398case MachO::MH_DYLINKER:8399outs() << " DYLINKER";8400break;8401case MachO::MH_BUNDLE:8402outs() << " BUNDLE";8403break;8404case MachO::MH_DSYM:8405outs() << " DSYM";8406break;8407case MachO::MH_KEXT_BUNDLE:8408outs() << " KEXTBUNDLE";8409break;8410case MachO::MH_FILESET:8411outs() << " FILESET";8412break;8413default:8414outs() << format(" %10u", filetype);8415break;8416}8417outs() << format(" %5u", ncmds);8418outs() << format(" %10u", sizeofcmds);8419uint32_t f = flags;8420if (f & MachO::MH_NOUNDEFS) {8421outs() << " NOUNDEFS";8422f &= ~MachO::MH_NOUNDEFS;8423}8424if (f & MachO::MH_INCRLINK) {8425outs() << " INCRLINK";8426f &= ~MachO::MH_INCRLINK;8427}8428if (f & MachO::MH_DYLDLINK) {8429outs() << " DYLDLINK";8430f &= ~MachO::MH_DYLDLINK;8431}8432if (f & MachO::MH_BINDATLOAD) {8433outs() << " BINDATLOAD";8434f &= ~MachO::MH_BINDATLOAD;8435}8436if (f & MachO::MH_PREBOUND) {8437outs() << " PREBOUND";8438f &= ~MachO::MH_PREBOUND;8439}8440if (f & MachO::MH_SPLIT_SEGS) {8441outs() << " SPLIT_SEGS";8442f &= ~MachO::MH_SPLIT_SEGS;8443}8444if (f & MachO::MH_LAZY_INIT) {8445outs() << " LAZY_INIT";8446f &= ~MachO::MH_LAZY_INIT;8447}8448if (f & MachO::MH_TWOLEVEL) {8449outs() << " TWOLEVEL";8450f &= ~MachO::MH_TWOLEVEL;8451}8452if (f & MachO::MH_FORCE_FLAT) {8453outs() << " FORCE_FLAT";8454f &= ~MachO::MH_FORCE_FLAT;8455}8456if (f & MachO::MH_NOMULTIDEFS) {8457outs() << " NOMULTIDEFS";8458f &= ~MachO::MH_NOMULTIDEFS;8459}8460if (f & MachO::MH_NOFIXPREBINDING) {8461outs() << " NOFIXPREBINDING";8462f &= ~MachO::MH_NOFIXPREBINDING;8463}8464if (f & MachO::MH_PREBINDABLE) {8465outs() << " PREBINDABLE";8466f &= ~MachO::MH_PREBINDABLE;8467}8468if (f & MachO::MH_ALLMODSBOUND) {8469outs() << " ALLMODSBOUND";8470f &= ~MachO::MH_ALLMODSBOUND;8471}8472if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {8473outs() << " SUBSECTIONS_VIA_SYMBOLS";8474f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;8475}8476if (f & MachO::MH_CANONICAL) {8477outs() << " CANONICAL";8478f &= ~MachO::MH_CANONICAL;8479}8480if (f & MachO::MH_WEAK_DEFINES) {8481outs() << " WEAK_DEFINES";8482f &= ~MachO::MH_WEAK_DEFINES;8483}8484if (f & MachO::MH_BINDS_TO_WEAK) {8485outs() << " BINDS_TO_WEAK";8486f &= ~MachO::MH_BINDS_TO_WEAK;8487}8488if (f & MachO::MH_ALLOW_STACK_EXECUTION) {8489outs() << " ALLOW_STACK_EXECUTION";8490f &= ~MachO::MH_ALLOW_STACK_EXECUTION;8491}8492if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {8493outs() << " DEAD_STRIPPABLE_DYLIB";8494f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;8495}8496if (f & MachO::MH_PIE) {8497outs() << " PIE";8498f &= ~MachO::MH_PIE;8499}8500if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {8501outs() << " NO_REEXPORTED_DYLIBS";8502f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;8503}8504if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {8505outs() << " MH_HAS_TLV_DESCRIPTORS";8506f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;8507}8508if (f & MachO::MH_NO_HEAP_EXECUTION) {8509outs() << " MH_NO_HEAP_EXECUTION";8510f &= ~MachO::MH_NO_HEAP_EXECUTION;8511}8512if (f & MachO::MH_APP_EXTENSION_SAFE) {8513outs() << " APP_EXTENSION_SAFE";8514f &= ~MachO::MH_APP_EXTENSION_SAFE;8515}8516if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {8517outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";8518f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;8519}8520if (f != 0 || flags == 0)8521outs() << format(" 0x%08" PRIx32, f);8522} else {8523outs() << format(" 0x%08" PRIx32, magic);8524outs() << format(" %7d", cputype);8525outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8526outs() << format(" 0x%02" PRIx32,8527(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8528outs() << format(" %10u", filetype);8529outs() << format(" %5u", ncmds);8530outs() << format(" %10u", sizeofcmds);8531outs() << format(" 0x%08" PRIx32, flags);8532}8533outs() << "\n";8534}85358536static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,8537StringRef SegName, uint64_t vmaddr,8538uint64_t vmsize, uint64_t fileoff,8539uint64_t filesize, uint32_t maxprot,8540uint32_t initprot, uint32_t nsects,8541uint32_t flags, uint32_t object_size,8542bool verbose) {8543uint64_t expected_cmdsize;8544if (cmd == MachO::LC_SEGMENT) {8545outs() << " cmd LC_SEGMENT\n";8546expected_cmdsize = nsects;8547expected_cmdsize *= sizeof(struct MachO::section);8548expected_cmdsize += sizeof(struct MachO::segment_command);8549} else {8550outs() << " cmd LC_SEGMENT_64\n";8551expected_cmdsize = nsects;8552expected_cmdsize *= sizeof(struct MachO::section_64);8553expected_cmdsize += sizeof(struct MachO::segment_command_64);8554}8555outs() << " cmdsize " << cmdsize;8556if (cmdsize != expected_cmdsize)8557outs() << " Inconsistent size\n";8558else8559outs() << "\n";8560outs() << " segname " << SegName << "\n";8561if (cmd == MachO::LC_SEGMENT_64) {8562outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";8563outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";8564} else {8565outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";8566outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";8567}8568outs() << " fileoff " << fileoff;8569if (fileoff > object_size)8570outs() << " (past end of file)\n";8571else8572outs() << "\n";8573outs() << " filesize " << filesize;8574if (fileoff + filesize > object_size)8575outs() << " (past end of file)\n";8576else8577outs() << "\n";8578if (verbose) {8579if ((maxprot &8580~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8581MachO::VM_PROT_EXECUTE)) != 0)8582outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";8583else {8584outs() << " maxprot ";8585outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");8586outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");8587outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8588}8589if ((initprot &8590~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8591MachO::VM_PROT_EXECUTE)) != 0)8592outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";8593else {8594outs() << " initprot ";8595outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");8596outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");8597outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8598}8599} else {8600outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";8601outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";8602}8603outs() << " nsects " << nsects << "\n";8604if (verbose) {8605outs() << " flags";8606if (flags == 0)8607outs() << " (none)\n";8608else {8609if (flags & MachO::SG_HIGHVM) {8610outs() << " HIGHVM";8611flags &= ~MachO::SG_HIGHVM;8612}8613if (flags & MachO::SG_FVMLIB) {8614outs() << " FVMLIB";8615flags &= ~MachO::SG_FVMLIB;8616}8617if (flags & MachO::SG_NORELOC) {8618outs() << " NORELOC";8619flags &= ~MachO::SG_NORELOC;8620}8621if (flags & MachO::SG_PROTECTED_VERSION_1) {8622outs() << " PROTECTED_VERSION_1";8623flags &= ~MachO::SG_PROTECTED_VERSION_1;8624}8625if (flags & MachO::SG_READ_ONLY) {8626// Apple's otool prints the SG_ prefix for this flag, but not for the8627// others.8628outs() << " SG_READ_ONLY";8629flags &= ~MachO::SG_READ_ONLY;8630}8631if (flags)8632outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";8633else8634outs() << "\n";8635}8636} else {8637outs() << " flags " << format("0x%" PRIx32, flags) << "\n";8638}8639}86408641static void PrintSection(const char *sectname, const char *segname,8642uint64_t addr, uint64_t size, uint32_t offset,8643uint32_t align, uint32_t reloff, uint32_t nreloc,8644uint32_t flags, uint32_t reserved1, uint32_t reserved2,8645uint32_t cmd, const char *sg_segname,8646uint32_t filetype, uint32_t object_size,8647bool verbose) {8648outs() << "Section\n";8649outs() << " sectname " << format("%.16s\n", sectname);8650outs() << " segname " << format("%.16s", segname);8651if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)8652outs() << " (does not match segment)\n";8653else8654outs() << "\n";8655if (cmd == MachO::LC_SEGMENT_64) {8656outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";8657outs() << " size " << format("0x%016" PRIx64, size);8658} else {8659outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";8660outs() << " size " << format("0x%08" PRIx64, size);8661}8662if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)8663outs() << " (past end of file)\n";8664else8665outs() << "\n";8666outs() << " offset " << offset;8667if (offset > object_size)8668outs() << " (past end of file)\n";8669else8670outs() << "\n";8671uint32_t align_shifted = 1 << align;8672outs() << " align 2^" << align << " (" << align_shifted << ")\n";8673outs() << " reloff " << reloff;8674if (reloff > object_size)8675outs() << " (past end of file)\n";8676else8677outs() << "\n";8678outs() << " nreloc " << nreloc;8679if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)8680outs() << " (past end of file)\n";8681else8682outs() << "\n";8683uint32_t section_type = flags & MachO::SECTION_TYPE;8684if (verbose) {8685outs() << " type";8686if (section_type == MachO::S_REGULAR)8687outs() << " S_REGULAR\n";8688else if (section_type == MachO::S_ZEROFILL)8689outs() << " S_ZEROFILL\n";8690else if (section_type == MachO::S_CSTRING_LITERALS)8691outs() << " S_CSTRING_LITERALS\n";8692else if (section_type == MachO::S_4BYTE_LITERALS)8693outs() << " S_4BYTE_LITERALS\n";8694else if (section_type == MachO::S_8BYTE_LITERALS)8695outs() << " S_8BYTE_LITERALS\n";8696else if (section_type == MachO::S_16BYTE_LITERALS)8697outs() << " S_16BYTE_LITERALS\n";8698else if (section_type == MachO::S_LITERAL_POINTERS)8699outs() << " S_LITERAL_POINTERS\n";8700else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)8701outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";8702else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)8703outs() << " S_LAZY_SYMBOL_POINTERS\n";8704else if (section_type == MachO::S_SYMBOL_STUBS)8705outs() << " S_SYMBOL_STUBS\n";8706else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)8707outs() << " S_MOD_INIT_FUNC_POINTERS\n";8708else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)8709outs() << " S_MOD_TERM_FUNC_POINTERS\n";8710else if (section_type == MachO::S_COALESCED)8711outs() << " S_COALESCED\n";8712else if (section_type == MachO::S_INTERPOSING)8713outs() << " S_INTERPOSING\n";8714else if (section_type == MachO::S_DTRACE_DOF)8715outs() << " S_DTRACE_DOF\n";8716else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)8717outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";8718else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)8719outs() << " S_THREAD_LOCAL_REGULAR\n";8720else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)8721outs() << " S_THREAD_LOCAL_ZEROFILL\n";8722else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)8723outs() << " S_THREAD_LOCAL_VARIABLES\n";8724else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8725outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";8726else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)8727outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";8728else if (section_type == MachO::S_INIT_FUNC_OFFSETS)8729outs() << " S_INIT_FUNC_OFFSETS\n";8730else8731outs() << format("0x%08" PRIx32, section_type) << "\n";8732outs() << "attributes";8733uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;8734if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)8735outs() << " PURE_INSTRUCTIONS";8736if (section_attributes & MachO::S_ATTR_NO_TOC)8737outs() << " NO_TOC";8738if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)8739outs() << " STRIP_STATIC_SYMS";8740if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)8741outs() << " NO_DEAD_STRIP";8742if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)8743outs() << " LIVE_SUPPORT";8744if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)8745outs() << " SELF_MODIFYING_CODE";8746if (section_attributes & MachO::S_ATTR_DEBUG)8747outs() << " DEBUG";8748if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)8749outs() << " SOME_INSTRUCTIONS";8750if (section_attributes & MachO::S_ATTR_EXT_RELOC)8751outs() << " EXT_RELOC";8752if (section_attributes & MachO::S_ATTR_LOC_RELOC)8753outs() << " LOC_RELOC";8754if (section_attributes == 0)8755outs() << " (none)";8756outs() << "\n";8757} else8758outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";8759outs() << " reserved1 " << reserved1;8760if (section_type == MachO::S_SYMBOL_STUBS ||8761section_type == MachO::S_LAZY_SYMBOL_POINTERS ||8762section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||8763section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||8764section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8765outs() << " (index into indirect symbol table)\n";8766else8767outs() << "\n";8768outs() << " reserved2 " << reserved2;8769if (section_type == MachO::S_SYMBOL_STUBS)8770outs() << " (size of stubs)\n";8771else8772outs() << "\n";8773}87748775static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,8776uint32_t object_size) {8777outs() << " cmd LC_SYMTAB\n";8778outs() << " cmdsize " << st.cmdsize;8779if (st.cmdsize != sizeof(struct MachO::symtab_command))8780outs() << " Incorrect size\n";8781else8782outs() << "\n";8783outs() << " symoff " << st.symoff;8784if (st.symoff > object_size)8785outs() << " (past end of file)\n";8786else8787outs() << "\n";8788outs() << " nsyms " << st.nsyms;8789uint64_t big_size;8790if (Is64Bit) {8791big_size = st.nsyms;8792big_size *= sizeof(struct MachO::nlist_64);8793big_size += st.symoff;8794if (big_size > object_size)8795outs() << " (past end of file)\n";8796else8797outs() << "\n";8798} else {8799big_size = st.nsyms;8800big_size *= sizeof(struct MachO::nlist);8801big_size += st.symoff;8802if (big_size > object_size)8803outs() << " (past end of file)\n";8804else8805outs() << "\n";8806}8807outs() << " stroff " << st.stroff;8808if (st.stroff > object_size)8809outs() << " (past end of file)\n";8810else8811outs() << "\n";8812outs() << " strsize " << st.strsize;8813big_size = st.stroff;8814big_size += st.strsize;8815if (big_size > object_size)8816outs() << " (past end of file)\n";8817else8818outs() << "\n";8819}88208821static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,8822uint32_t nsyms, uint32_t object_size,8823bool Is64Bit) {8824outs() << " cmd LC_DYSYMTAB\n";8825outs() << " cmdsize " << dyst.cmdsize;8826if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))8827outs() << " Incorrect size\n";8828else8829outs() << "\n";8830outs() << " ilocalsym " << dyst.ilocalsym;8831if (dyst.ilocalsym > nsyms)8832outs() << " (greater than the number of symbols)\n";8833else8834outs() << "\n";8835outs() << " nlocalsym " << dyst.nlocalsym;8836uint64_t big_size;8837big_size = dyst.ilocalsym;8838big_size += dyst.nlocalsym;8839if (big_size > nsyms)8840outs() << " (past the end of the symbol table)\n";8841else8842outs() << "\n";8843outs() << " iextdefsym " << dyst.iextdefsym;8844if (dyst.iextdefsym > nsyms)8845outs() << " (greater than the number of symbols)\n";8846else8847outs() << "\n";8848outs() << " nextdefsym " << dyst.nextdefsym;8849big_size = dyst.iextdefsym;8850big_size += dyst.nextdefsym;8851if (big_size > nsyms)8852outs() << " (past the end of the symbol table)\n";8853else8854outs() << "\n";8855outs() << " iundefsym " << dyst.iundefsym;8856if (dyst.iundefsym > nsyms)8857outs() << " (greater than the number of symbols)\n";8858else8859outs() << "\n";8860outs() << " nundefsym " << dyst.nundefsym;8861big_size = dyst.iundefsym;8862big_size += dyst.nundefsym;8863if (big_size > nsyms)8864outs() << " (past the end of the symbol table)\n";8865else8866outs() << "\n";8867outs() << " tocoff " << dyst.tocoff;8868if (dyst.tocoff > object_size)8869outs() << " (past end of file)\n";8870else8871outs() << "\n";8872outs() << " ntoc " << dyst.ntoc;8873big_size = dyst.ntoc;8874big_size *= sizeof(struct MachO::dylib_table_of_contents);8875big_size += dyst.tocoff;8876if (big_size > object_size)8877outs() << " (past end of file)\n";8878else8879outs() << "\n";8880outs() << " modtaboff " << dyst.modtaboff;8881if (dyst.modtaboff > object_size)8882outs() << " (past end of file)\n";8883else8884outs() << "\n";8885outs() << " nmodtab " << dyst.nmodtab;8886uint64_t modtabend;8887if (Is64Bit) {8888modtabend = dyst.nmodtab;8889modtabend *= sizeof(struct MachO::dylib_module_64);8890modtabend += dyst.modtaboff;8891} else {8892modtabend = dyst.nmodtab;8893modtabend *= sizeof(struct MachO::dylib_module);8894modtabend += dyst.modtaboff;8895}8896if (modtabend > object_size)8897outs() << " (past end of file)\n";8898else8899outs() << "\n";8900outs() << " extrefsymoff " << dyst.extrefsymoff;8901if (dyst.extrefsymoff > object_size)8902outs() << " (past end of file)\n";8903else8904outs() << "\n";8905outs() << " nextrefsyms " << dyst.nextrefsyms;8906big_size = dyst.nextrefsyms;8907big_size *= sizeof(struct MachO::dylib_reference);8908big_size += dyst.extrefsymoff;8909if (big_size > object_size)8910outs() << " (past end of file)\n";8911else8912outs() << "\n";8913outs() << " indirectsymoff " << dyst.indirectsymoff;8914if (dyst.indirectsymoff > object_size)8915outs() << " (past end of file)\n";8916else8917outs() << "\n";8918outs() << " nindirectsyms " << dyst.nindirectsyms;8919big_size = dyst.nindirectsyms;8920big_size *= sizeof(uint32_t);8921big_size += dyst.indirectsymoff;8922if (big_size > object_size)8923outs() << " (past end of file)\n";8924else8925outs() << "\n";8926outs() << " extreloff " << dyst.extreloff;8927if (dyst.extreloff > object_size)8928outs() << " (past end of file)\n";8929else8930outs() << "\n";8931outs() << " nextrel " << dyst.nextrel;8932big_size = dyst.nextrel;8933big_size *= sizeof(struct MachO::relocation_info);8934big_size += dyst.extreloff;8935if (big_size > object_size)8936outs() << " (past end of file)\n";8937else8938outs() << "\n";8939outs() << " locreloff " << dyst.locreloff;8940if (dyst.locreloff > object_size)8941outs() << " (past end of file)\n";8942else8943outs() << "\n";8944outs() << " nlocrel " << dyst.nlocrel;8945big_size = dyst.nlocrel;8946big_size *= sizeof(struct MachO::relocation_info);8947big_size += dyst.locreloff;8948if (big_size > object_size)8949outs() << " (past end of file)\n";8950else8951outs() << "\n";8952}89538954static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,8955uint32_t object_size) {8956if (dc.cmd == MachO::LC_DYLD_INFO)8957outs() << " cmd LC_DYLD_INFO\n";8958else8959outs() << " cmd LC_DYLD_INFO_ONLY\n";8960outs() << " cmdsize " << dc.cmdsize;8961if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))8962outs() << " Incorrect size\n";8963else8964outs() << "\n";8965outs() << " rebase_off " << dc.rebase_off;8966if (dc.rebase_off > object_size)8967outs() << " (past end of file)\n";8968else8969outs() << "\n";8970outs() << " rebase_size " << dc.rebase_size;8971uint64_t big_size;8972big_size = dc.rebase_off;8973big_size += dc.rebase_size;8974if (big_size > object_size)8975outs() << " (past end of file)\n";8976else8977outs() << "\n";8978outs() << " bind_off " << dc.bind_off;8979if (dc.bind_off > object_size)8980outs() << " (past end of file)\n";8981else8982outs() << "\n";8983outs() << " bind_size " << dc.bind_size;8984big_size = dc.bind_off;8985big_size += dc.bind_size;8986if (big_size > object_size)8987outs() << " (past end of file)\n";8988else8989outs() << "\n";8990outs() << " weak_bind_off " << dc.weak_bind_off;8991if (dc.weak_bind_off > object_size)8992outs() << " (past end of file)\n";8993else8994outs() << "\n";8995outs() << " weak_bind_size " << dc.weak_bind_size;8996big_size = dc.weak_bind_off;8997big_size += dc.weak_bind_size;8998if (big_size > object_size)8999outs() << " (past end of file)\n";9000else9001outs() << "\n";9002outs() << " lazy_bind_off " << dc.lazy_bind_off;9003if (dc.lazy_bind_off > object_size)9004outs() << " (past end of file)\n";9005else9006outs() << "\n";9007outs() << " lazy_bind_size " << dc.lazy_bind_size;9008big_size = dc.lazy_bind_off;9009big_size += dc.lazy_bind_size;9010if (big_size > object_size)9011outs() << " (past end of file)\n";9012else9013outs() << "\n";9014outs() << " export_off " << dc.export_off;9015if (dc.export_off > object_size)9016outs() << " (past end of file)\n";9017else9018outs() << "\n";9019outs() << " export_size " << dc.export_size;9020big_size = dc.export_off;9021big_size += dc.export_size;9022if (big_size > object_size)9023outs() << " (past end of file)\n";9024else9025outs() << "\n";9026}90279028static void PrintDyldLoadCommand(MachO::dylinker_command dyld,9029const char *Ptr) {9030if (dyld.cmd == MachO::LC_ID_DYLINKER)9031outs() << " cmd LC_ID_DYLINKER\n";9032else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)9033outs() << " cmd LC_LOAD_DYLINKER\n";9034else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)9035outs() << " cmd LC_DYLD_ENVIRONMENT\n";9036else9037outs() << " cmd ?(" << dyld.cmd << ")\n";9038outs() << " cmdsize " << dyld.cmdsize;9039if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))9040outs() << " Incorrect size\n";9041else9042outs() << "\n";9043if (dyld.name >= dyld.cmdsize)9044outs() << " name ?(bad offset " << dyld.name << ")\n";9045else {9046const char *P = (const char *)(Ptr) + dyld.name;9047outs() << " name " << P << " (offset " << dyld.name << ")\n";9048}9049}90509051static void PrintUuidLoadCommand(MachO::uuid_command uuid) {9052outs() << " cmd LC_UUID\n";9053outs() << " cmdsize " << uuid.cmdsize;9054if (uuid.cmdsize != sizeof(struct MachO::uuid_command))9055outs() << " Incorrect size\n";9056else9057outs() << "\n";9058outs() << " uuid ";9059for (int i = 0; i < 16; ++i) {9060outs() << format("%02" PRIX32, uuid.uuid[i]);9061if (i == 3 || i == 5 || i == 7 || i == 9)9062outs() << "-";9063}9064outs() << "\n";9065}90669067static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {9068outs() << " cmd LC_RPATH\n";9069outs() << " cmdsize " << rpath.cmdsize;9070if (rpath.cmdsize < sizeof(struct MachO::rpath_command))9071outs() << " Incorrect size\n";9072else9073outs() << "\n";9074if (rpath.path >= rpath.cmdsize)9075outs() << " path ?(bad offset " << rpath.path << ")\n";9076else {9077const char *P = (const char *)(Ptr) + rpath.path;9078outs() << " path " << P << " (offset " << rpath.path << ")\n";9079}9080}90819082static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {9083StringRef LoadCmdName;9084switch (vd.cmd) {9085case MachO::LC_VERSION_MIN_MACOSX:9086LoadCmdName = "LC_VERSION_MIN_MACOSX";9087break;9088case MachO::LC_VERSION_MIN_IPHONEOS:9089LoadCmdName = "LC_VERSION_MIN_IPHONEOS";9090break;9091case MachO::LC_VERSION_MIN_TVOS:9092LoadCmdName = "LC_VERSION_MIN_TVOS";9093break;9094case MachO::LC_VERSION_MIN_WATCHOS:9095LoadCmdName = "LC_VERSION_MIN_WATCHOS";9096break;9097default:9098llvm_unreachable("Unknown version min load command");9099}91009101outs() << " cmd " << LoadCmdName << '\n';9102outs() << " cmdsize " << vd.cmdsize;9103if (vd.cmdsize != sizeof(struct MachO::version_min_command))9104outs() << " Incorrect size\n";9105else9106outs() << "\n";9107outs() << " version "9108<< MachOObjectFile::getVersionMinMajor(vd, false) << "."9109<< MachOObjectFile::getVersionMinMinor(vd, false);9110uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);9111if (Update != 0)9112outs() << "." << Update;9113outs() << "\n";9114if (vd.sdk == 0)9115outs() << " sdk n/a";9116else {9117outs() << " sdk "9118<< MachOObjectFile::getVersionMinMajor(vd, true) << "."9119<< MachOObjectFile::getVersionMinMinor(vd, true);9120}9121Update = MachOObjectFile::getVersionMinUpdate(vd, true);9122if (Update != 0)9123outs() << "." << Update;9124outs() << "\n";9125}91269127static void PrintNoteLoadCommand(MachO::note_command Nt) {9128outs() << " cmd LC_NOTE\n";9129outs() << " cmdsize " << Nt.cmdsize;9130if (Nt.cmdsize != sizeof(struct MachO::note_command))9131outs() << " Incorrect size\n";9132else9133outs() << "\n";9134const char *d = Nt.data_owner;9135outs() << "data_owner " << format("%.16s\n", d);9136outs() << " offset " << Nt.offset << "\n";9137outs() << " size " << Nt.size << "\n";9138}91399140static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {9141outs() << " tool ";9142if (verbose)9143outs() << MachOObjectFile::getBuildTool(bv.tool);9144else9145outs() << bv.tool;9146outs() << "\n";9147outs() << " version " << MachOObjectFile::getVersionString(bv.version)9148<< "\n";9149}91509151static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,9152MachO::build_version_command bd,9153bool verbose) {9154outs() << " cmd LC_BUILD_VERSION\n";9155outs() << " cmdsize " << bd.cmdsize;9156if (bd.cmdsize !=9157sizeof(struct MachO::build_version_command) +9158bd.ntools * sizeof(struct MachO::build_tool_version))9159outs() << " Incorrect size\n";9160else9161outs() << "\n";9162outs() << " platform ";9163if (verbose)9164outs() << MachOObjectFile::getBuildPlatform(bd.platform);9165else9166outs() << bd.platform;9167outs() << "\n";9168if (bd.sdk)9169outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)9170<< "\n";9171else9172outs() << " sdk n/a\n";9173outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)9174<< "\n";9175outs() << " ntools " << bd.ntools << "\n";9176for (unsigned i = 0; i < bd.ntools; ++i) {9177MachO::build_tool_version bv = obj->getBuildToolVersion(i);9178PrintBuildToolVersion(bv, verbose);9179}9180}91819182static void PrintSourceVersionCommand(MachO::source_version_command sd) {9183outs() << " cmd LC_SOURCE_VERSION\n";9184outs() << " cmdsize " << sd.cmdsize;9185if (sd.cmdsize != sizeof(struct MachO::source_version_command))9186outs() << " Incorrect size\n";9187else9188outs() << "\n";9189uint64_t a = (sd.version >> 40) & 0xffffff;9190uint64_t b = (sd.version >> 30) & 0x3ff;9191uint64_t c = (sd.version >> 20) & 0x3ff;9192uint64_t d = (sd.version >> 10) & 0x3ff;9193uint64_t e = sd.version & 0x3ff;9194outs() << " version " << a << "." << b;9195if (e != 0)9196outs() << "." << c << "." << d << "." << e;9197else if (d != 0)9198outs() << "." << c << "." << d;9199else if (c != 0)9200outs() << "." << c;9201outs() << "\n";9202}92039204static void PrintEntryPointCommand(MachO::entry_point_command ep) {9205outs() << " cmd LC_MAIN\n";9206outs() << " cmdsize " << ep.cmdsize;9207if (ep.cmdsize != sizeof(struct MachO::entry_point_command))9208outs() << " Incorrect size\n";9209else9210outs() << "\n";9211outs() << " entryoff " << ep.entryoff << "\n";9212outs() << " stacksize " << ep.stacksize << "\n";9213}92149215static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,9216uint32_t object_size) {9217outs() << " cmd LC_ENCRYPTION_INFO\n";9218outs() << " cmdsize " << ec.cmdsize;9219if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))9220outs() << " Incorrect size\n";9221else9222outs() << "\n";9223outs() << " cryptoff " << ec.cryptoff;9224if (ec.cryptoff > object_size)9225outs() << " (past end of file)\n";9226else9227outs() << "\n";9228outs() << " cryptsize " << ec.cryptsize;9229if (ec.cryptsize > object_size)9230outs() << " (past end of file)\n";9231else9232outs() << "\n";9233outs() << " cryptid " << ec.cryptid << "\n";9234}92359236static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,9237uint32_t object_size) {9238outs() << " cmd LC_ENCRYPTION_INFO_64\n";9239outs() << " cmdsize " << ec.cmdsize;9240if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))9241outs() << " Incorrect size\n";9242else9243outs() << "\n";9244outs() << " cryptoff " << ec.cryptoff;9245if (ec.cryptoff > object_size)9246outs() << " (past end of file)\n";9247else9248outs() << "\n";9249outs() << " cryptsize " << ec.cryptsize;9250if (ec.cryptsize > object_size)9251outs() << " (past end of file)\n";9252else9253outs() << "\n";9254outs() << " cryptid " << ec.cryptid << "\n";9255outs() << " pad " << ec.pad << "\n";9256}92579258static void PrintLinkerOptionCommand(MachO::linker_option_command lo,9259const char *Ptr) {9260outs() << " cmd LC_LINKER_OPTION\n";9261outs() << " cmdsize " << lo.cmdsize;9262if (lo.cmdsize < sizeof(struct MachO::linker_option_command))9263outs() << " Incorrect size\n";9264else9265outs() << "\n";9266outs() << " count " << lo.count << "\n";9267const char *string = Ptr + sizeof(struct MachO::linker_option_command);9268uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);9269uint32_t i = 0;9270while (left > 0) {9271while (*string == '\0' && left > 0) {9272string++;9273left--;9274}9275if (left > 0) {9276i++;9277outs() << " string #" << i << " " << format("%.*s\n", left, string);9278uint32_t NullPos = StringRef(string, left).find('\0');9279uint32_t len = std::min(NullPos, left) + 1;9280string += len;9281left -= len;9282}9283}9284if (lo.count != i)9285outs() << " count " << lo.count << " does not match number of strings "9286<< i << "\n";9287}92889289static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,9290const char *Ptr) {9291outs() << " cmd LC_SUB_FRAMEWORK\n";9292outs() << " cmdsize " << sub.cmdsize;9293if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))9294outs() << " Incorrect size\n";9295else9296outs() << "\n";9297if (sub.umbrella < sub.cmdsize) {9298const char *P = Ptr + sub.umbrella;9299outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";9300} else {9301outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";9302}9303}93049305static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,9306const char *Ptr) {9307outs() << " cmd LC_SUB_UMBRELLA\n";9308outs() << " cmdsize " << sub.cmdsize;9309if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))9310outs() << " Incorrect size\n";9311else9312outs() << "\n";9313if (sub.sub_umbrella < sub.cmdsize) {9314const char *P = Ptr + sub.sub_umbrella;9315outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";9316} else {9317outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";9318}9319}93209321static void PrintSubLibraryCommand(MachO::sub_library_command sub,9322const char *Ptr) {9323outs() << " cmd LC_SUB_LIBRARY\n";9324outs() << " cmdsize " << sub.cmdsize;9325if (sub.cmdsize < sizeof(struct MachO::sub_library_command))9326outs() << " Incorrect size\n";9327else9328outs() << "\n";9329if (sub.sub_library < sub.cmdsize) {9330const char *P = Ptr + sub.sub_library;9331outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";9332} else {9333outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";9334}9335}93369337static void PrintSubClientCommand(MachO::sub_client_command sub,9338const char *Ptr) {9339outs() << " cmd LC_SUB_CLIENT\n";9340outs() << " cmdsize " << sub.cmdsize;9341if (sub.cmdsize < sizeof(struct MachO::sub_client_command))9342outs() << " Incorrect size\n";9343else9344outs() << "\n";9345if (sub.client < sub.cmdsize) {9346const char *P = Ptr + sub.client;9347outs() << " client " << P << " (offset " << sub.client << ")\n";9348} else {9349outs() << " client ?(bad offset " << sub.client << ")\n";9350}9351}93529353static void PrintRoutinesCommand(MachO::routines_command r) {9354outs() << " cmd LC_ROUTINES\n";9355outs() << " cmdsize " << r.cmdsize;9356if (r.cmdsize != sizeof(struct MachO::routines_command))9357outs() << " Incorrect size\n";9358else9359outs() << "\n";9360outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";9361outs() << " init_module " << r.init_module << "\n";9362outs() << " reserved1 " << r.reserved1 << "\n";9363outs() << " reserved2 " << r.reserved2 << "\n";9364outs() << " reserved3 " << r.reserved3 << "\n";9365outs() << " reserved4 " << r.reserved4 << "\n";9366outs() << " reserved5 " << r.reserved5 << "\n";9367outs() << " reserved6 " << r.reserved6 << "\n";9368}93699370static void PrintRoutinesCommand64(MachO::routines_command_64 r) {9371outs() << " cmd LC_ROUTINES_64\n";9372outs() << " cmdsize " << r.cmdsize;9373if (r.cmdsize != sizeof(struct MachO::routines_command_64))9374outs() << " Incorrect size\n";9375else9376outs() << "\n";9377outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";9378outs() << " init_module " << r.init_module << "\n";9379outs() << " reserved1 " << r.reserved1 << "\n";9380outs() << " reserved2 " << r.reserved2 << "\n";9381outs() << " reserved3 " << r.reserved3 << "\n";9382outs() << " reserved4 " << r.reserved4 << "\n";9383outs() << " reserved5 " << r.reserved5 << "\n";9384outs() << " reserved6 " << r.reserved6 << "\n";9385}93869387static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {9388outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);9389outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);9390outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);9391outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";9392outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);9393outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);9394outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);9395outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";9396outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);9397outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);9398outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);9399outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";9400outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);9401outs() << " es " << format("0x%08" PRIx32, cpu32.es);9402outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);9403outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";9404}94059406static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {9407outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);9408outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);9409outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";9410outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);9411outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);9412outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";9413outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);9414outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);9415outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";9416outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);9417outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);9418outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";9419outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);9420outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);9421outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";9422outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);9423outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";9424outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);9425outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);9426outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";9427outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";9428}94299430static void Print_mmst_reg(MachO::mmst_reg_t &r) {9431uint32_t f;9432outs() << "\t mmst_reg ";9433for (f = 0; f < 10; f++)9434outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";9435outs() << "\n";9436outs() << "\t mmst_rsrv ";9437for (f = 0; f < 6; f++)9438outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";9439outs() << "\n";9440}94419442static void Print_xmm_reg(MachO::xmm_reg_t &r) {9443uint32_t f;9444outs() << "\t xmm_reg ";9445for (f = 0; f < 16; f++)9446outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";9447outs() << "\n";9448}94499450static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {9451outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];9452outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";9453outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;9454outs() << " denorm " << fpu.fpu_fcw.denorm;9455outs() << " zdiv " << fpu.fpu_fcw.zdiv;9456outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;9457outs() << " undfl " << fpu.fpu_fcw.undfl;9458outs() << " precis " << fpu.fpu_fcw.precis << "\n";9459outs() << "\t\t pc ";9460if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)9461outs() << "FP_PREC_24B ";9462else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)9463outs() << "FP_PREC_53B ";9464else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)9465outs() << "FP_PREC_64B ";9466else9467outs() << fpu.fpu_fcw.pc << " ";9468outs() << "rc ";9469if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)9470outs() << "FP_RND_NEAR ";9471else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)9472outs() << "FP_RND_DOWN ";9473else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)9474outs() << "FP_RND_UP ";9475else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)9476outs() << "FP_CHOP ";9477outs() << "\n";9478outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;9479outs() << " denorm " << fpu.fpu_fsw.denorm;9480outs() << " zdiv " << fpu.fpu_fsw.zdiv;9481outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;9482outs() << " undfl " << fpu.fpu_fsw.undfl;9483outs() << " precis " << fpu.fpu_fsw.precis;9484outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";9485outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;9486outs() << " c0 " << fpu.fpu_fsw.c0;9487outs() << " c1 " << fpu.fpu_fsw.c1;9488outs() << " c2 " << fpu.fpu_fsw.c2;9489outs() << " tos " << fpu.fpu_fsw.tos;9490outs() << " c3 " << fpu.fpu_fsw.c3;9491outs() << " busy " << fpu.fpu_fsw.busy << "\n";9492outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);9493outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);9494outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);9495outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";9496outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);9497outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);9498outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);9499outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";9500outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);9501outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);9502outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);9503outs() << "\n";9504outs() << "\t fpu_stmm0:\n";9505Print_mmst_reg(fpu.fpu_stmm0);9506outs() << "\t fpu_stmm1:\n";9507Print_mmst_reg(fpu.fpu_stmm1);9508outs() << "\t fpu_stmm2:\n";9509Print_mmst_reg(fpu.fpu_stmm2);9510outs() << "\t fpu_stmm3:\n";9511Print_mmst_reg(fpu.fpu_stmm3);9512outs() << "\t fpu_stmm4:\n";9513Print_mmst_reg(fpu.fpu_stmm4);9514outs() << "\t fpu_stmm5:\n";9515Print_mmst_reg(fpu.fpu_stmm5);9516outs() << "\t fpu_stmm6:\n";9517Print_mmst_reg(fpu.fpu_stmm6);9518outs() << "\t fpu_stmm7:\n";9519Print_mmst_reg(fpu.fpu_stmm7);9520outs() << "\t fpu_xmm0:\n";9521Print_xmm_reg(fpu.fpu_xmm0);9522outs() << "\t fpu_xmm1:\n";9523Print_xmm_reg(fpu.fpu_xmm1);9524outs() << "\t fpu_xmm2:\n";9525Print_xmm_reg(fpu.fpu_xmm2);9526outs() << "\t fpu_xmm3:\n";9527Print_xmm_reg(fpu.fpu_xmm3);9528outs() << "\t fpu_xmm4:\n";9529Print_xmm_reg(fpu.fpu_xmm4);9530outs() << "\t fpu_xmm5:\n";9531Print_xmm_reg(fpu.fpu_xmm5);9532outs() << "\t fpu_xmm6:\n";9533Print_xmm_reg(fpu.fpu_xmm6);9534outs() << "\t fpu_xmm7:\n";9535Print_xmm_reg(fpu.fpu_xmm7);9536outs() << "\t fpu_xmm8:\n";9537Print_xmm_reg(fpu.fpu_xmm8);9538outs() << "\t fpu_xmm9:\n";9539Print_xmm_reg(fpu.fpu_xmm9);9540outs() << "\t fpu_xmm10:\n";9541Print_xmm_reg(fpu.fpu_xmm10);9542outs() << "\t fpu_xmm11:\n";9543Print_xmm_reg(fpu.fpu_xmm11);9544outs() << "\t fpu_xmm12:\n";9545Print_xmm_reg(fpu.fpu_xmm12);9546outs() << "\t fpu_xmm13:\n";9547Print_xmm_reg(fpu.fpu_xmm13);9548outs() << "\t fpu_xmm14:\n";9549Print_xmm_reg(fpu.fpu_xmm14);9550outs() << "\t fpu_xmm15:\n";9551Print_xmm_reg(fpu.fpu_xmm15);9552outs() << "\t fpu_rsrv4:\n";9553for (uint32_t f = 0; f < 6; f++) {9554outs() << "\t ";9555for (uint32_t g = 0; g < 16; g++)9556outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";9557outs() << "\n";9558}9559outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);9560outs() << "\n";9561}95629563static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {9564outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);9565outs() << " err " << format("0x%08" PRIx32, exc64.err);9566outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";9567}95689569static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {9570outs() << "\t r0 " << format("0x%08" PRIx32, cpu32.r[0]);9571outs() << " r1 " << format("0x%08" PRIx32, cpu32.r[1]);9572outs() << " r2 " << format("0x%08" PRIx32, cpu32.r[2]);9573outs() << " r3 " << format("0x%08" PRIx32, cpu32.r[3]) << "\n";9574outs() << "\t r4 " << format("0x%08" PRIx32, cpu32.r[4]);9575outs() << " r5 " << format("0x%08" PRIx32, cpu32.r[5]);9576outs() << " r6 " << format("0x%08" PRIx32, cpu32.r[6]);9577outs() << " r7 " << format("0x%08" PRIx32, cpu32.r[7]) << "\n";9578outs() << "\t r8 " << format("0x%08" PRIx32, cpu32.r[8]);9579outs() << " r9 " << format("0x%08" PRIx32, cpu32.r[9]);9580outs() << " r10 " << format("0x%08" PRIx32, cpu32.r[10]);9581outs() << " r11 " << format("0x%08" PRIx32, cpu32.r[11]) << "\n";9582outs() << "\t r12 " << format("0x%08" PRIx32, cpu32.r[12]);9583outs() << " sp " << format("0x%08" PRIx32, cpu32.sp);9584outs() << " lr " << format("0x%08" PRIx32, cpu32.lr);9585outs() << " pc " << format("0x%08" PRIx32, cpu32.pc) << "\n";9586outs() << "\t cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";9587}95889589static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {9590outs() << "\t x0 " << format("0x%016" PRIx64, cpu64.x[0]);9591outs() << " x1 " << format("0x%016" PRIx64, cpu64.x[1]);9592outs() << " x2 " << format("0x%016" PRIx64, cpu64.x[2]) << "\n";9593outs() << "\t x3 " << format("0x%016" PRIx64, cpu64.x[3]);9594outs() << " x4 " << format("0x%016" PRIx64, cpu64.x[4]);9595outs() << " x5 " << format("0x%016" PRIx64, cpu64.x[5]) << "\n";9596outs() << "\t x6 " << format("0x%016" PRIx64, cpu64.x[6]);9597outs() << " x7 " << format("0x%016" PRIx64, cpu64.x[7]);9598outs() << " x8 " << format("0x%016" PRIx64, cpu64.x[8]) << "\n";9599outs() << "\t x9 " << format("0x%016" PRIx64, cpu64.x[9]);9600outs() << " x10 " << format("0x%016" PRIx64, cpu64.x[10]);9601outs() << " x11 " << format("0x%016" PRIx64, cpu64.x[11]) << "\n";9602outs() << "\t x12 " << format("0x%016" PRIx64, cpu64.x[12]);9603outs() << " x13 " << format("0x%016" PRIx64, cpu64.x[13]);9604outs() << " x14 " << format("0x%016" PRIx64, cpu64.x[14]) << "\n";9605outs() << "\t x15 " << format("0x%016" PRIx64, cpu64.x[15]);9606outs() << " x16 " << format("0x%016" PRIx64, cpu64.x[16]);9607outs() << " x17 " << format("0x%016" PRIx64, cpu64.x[17]) << "\n";9608outs() << "\t x18 " << format("0x%016" PRIx64, cpu64.x[18]);9609outs() << " x19 " << format("0x%016" PRIx64, cpu64.x[19]);9610outs() << " x20 " << format("0x%016" PRIx64, cpu64.x[20]) << "\n";9611outs() << "\t x21 " << format("0x%016" PRIx64, cpu64.x[21]);9612outs() << " x22 " << format("0x%016" PRIx64, cpu64.x[22]);9613outs() << " x23 " << format("0x%016" PRIx64, cpu64.x[23]) << "\n";9614outs() << "\t x24 " << format("0x%016" PRIx64, cpu64.x[24]);9615outs() << " x25 " << format("0x%016" PRIx64, cpu64.x[25]);9616outs() << " x26 " << format("0x%016" PRIx64, cpu64.x[26]) << "\n";9617outs() << "\t x27 " << format("0x%016" PRIx64, cpu64.x[27]);9618outs() << " x28 " << format("0x%016" PRIx64, cpu64.x[28]);9619outs() << " fp " << format("0x%016" PRIx64, cpu64.fp) << "\n";9620outs() << "\t lr " << format("0x%016" PRIx64, cpu64.lr);9621outs() << " sp " << format("0x%016" PRIx64, cpu64.sp);9622outs() << " pc " << format("0x%016" PRIx64, cpu64.pc) << "\n";9623outs() << "\t cpsr " << format("0x%08" PRIx32, cpu64.cpsr) << "\n";9624}96259626static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,9627bool isLittleEndian, uint32_t cputype) {9628if (t.cmd == MachO::LC_THREAD)9629outs() << " cmd LC_THREAD\n";9630else if (t.cmd == MachO::LC_UNIXTHREAD)9631outs() << " cmd LC_UNIXTHREAD\n";9632else9633outs() << " cmd " << t.cmd << " (unknown)\n";9634outs() << " cmdsize " << t.cmdsize;9635if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))9636outs() << " Incorrect size\n";9637else9638outs() << "\n";96399640const char *begin = Ptr + sizeof(struct MachO::thread_command);9641const char *end = Ptr + t.cmdsize;9642uint32_t flavor, count, left;9643if (cputype == MachO::CPU_TYPE_I386) {9644while (begin < end) {9645if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9646memcpy((char *)&flavor, begin, sizeof(uint32_t));9647begin += sizeof(uint32_t);9648} else {9649flavor = 0;9650begin = end;9651}9652if (isLittleEndian != sys::IsLittleEndianHost)9653sys::swapByteOrder(flavor);9654if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9655memcpy((char *)&count, begin, sizeof(uint32_t));9656begin += sizeof(uint32_t);9657} else {9658count = 0;9659begin = end;9660}9661if (isLittleEndian != sys::IsLittleEndianHost)9662sys::swapByteOrder(count);9663if (flavor == MachO::x86_THREAD_STATE32) {9664outs() << " flavor i386_THREAD_STATE\n";9665if (count == MachO::x86_THREAD_STATE32_COUNT)9666outs() << " count i386_THREAD_STATE_COUNT\n";9667else9668outs() << " count " << count9669<< " (not x86_THREAD_STATE32_COUNT)\n";9670MachO::x86_thread_state32_t cpu32;9671left = end - begin;9672if (left >= sizeof(MachO::x86_thread_state32_t)) {9673memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));9674begin += sizeof(MachO::x86_thread_state32_t);9675} else {9676memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));9677memcpy(&cpu32, begin, left);9678begin += left;9679}9680if (isLittleEndian != sys::IsLittleEndianHost)9681swapStruct(cpu32);9682Print_x86_thread_state32_t(cpu32);9683} else if (flavor == MachO::x86_THREAD_STATE) {9684outs() << " flavor x86_THREAD_STATE\n";9685if (count == MachO::x86_THREAD_STATE_COUNT)9686outs() << " count x86_THREAD_STATE_COUNT\n";9687else9688outs() << " count " << count9689<< " (not x86_THREAD_STATE_COUNT)\n";9690struct MachO::x86_thread_state_t ts;9691left = end - begin;9692if (left >= sizeof(MachO::x86_thread_state_t)) {9693memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9694begin += sizeof(MachO::x86_thread_state_t);9695} else {9696memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9697memcpy(&ts, begin, left);9698begin += left;9699}9700if (isLittleEndian != sys::IsLittleEndianHost)9701swapStruct(ts);9702if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {9703outs() << "\t tsh.flavor x86_THREAD_STATE32 ";9704if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)9705outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";9706else9707outs() << "tsh.count " << ts.tsh.count9708<< " (not x86_THREAD_STATE32_COUNT\n";9709Print_x86_thread_state32_t(ts.uts.ts32);9710} else {9711outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "9712<< ts.tsh.count << "\n";9713}9714} else {9715outs() << " flavor " << flavor << " (unknown)\n";9716outs() << " count " << count << "\n";9717outs() << " state (unknown)\n";9718begin += count * sizeof(uint32_t);9719}9720}9721} else if (cputype == MachO::CPU_TYPE_X86_64) {9722while (begin < end) {9723if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9724memcpy((char *)&flavor, begin, sizeof(uint32_t));9725begin += sizeof(uint32_t);9726} else {9727flavor = 0;9728begin = end;9729}9730if (isLittleEndian != sys::IsLittleEndianHost)9731sys::swapByteOrder(flavor);9732if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9733memcpy((char *)&count, begin, sizeof(uint32_t));9734begin += sizeof(uint32_t);9735} else {9736count = 0;9737begin = end;9738}9739if (isLittleEndian != sys::IsLittleEndianHost)9740sys::swapByteOrder(count);9741if (flavor == MachO::x86_THREAD_STATE64) {9742outs() << " flavor x86_THREAD_STATE64\n";9743if (count == MachO::x86_THREAD_STATE64_COUNT)9744outs() << " count x86_THREAD_STATE64_COUNT\n";9745else9746outs() << " count " << count9747<< " (not x86_THREAD_STATE64_COUNT)\n";9748MachO::x86_thread_state64_t cpu64;9749left = end - begin;9750if (left >= sizeof(MachO::x86_thread_state64_t)) {9751memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));9752begin += sizeof(MachO::x86_thread_state64_t);9753} else {9754memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));9755memcpy(&cpu64, begin, left);9756begin += left;9757}9758if (isLittleEndian != sys::IsLittleEndianHost)9759swapStruct(cpu64);9760Print_x86_thread_state64_t(cpu64);9761} else if (flavor == MachO::x86_THREAD_STATE) {9762outs() << " flavor x86_THREAD_STATE\n";9763if (count == MachO::x86_THREAD_STATE_COUNT)9764outs() << " count x86_THREAD_STATE_COUNT\n";9765else9766outs() << " count " << count9767<< " (not x86_THREAD_STATE_COUNT)\n";9768struct MachO::x86_thread_state_t ts;9769left = end - begin;9770if (left >= sizeof(MachO::x86_thread_state_t)) {9771memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9772begin += sizeof(MachO::x86_thread_state_t);9773} else {9774memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9775memcpy(&ts, begin, left);9776begin += left;9777}9778if (isLittleEndian != sys::IsLittleEndianHost)9779swapStruct(ts);9780if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {9781outs() << "\t tsh.flavor x86_THREAD_STATE64 ";9782if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)9783outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";9784else9785outs() << "tsh.count " << ts.tsh.count9786<< " (not x86_THREAD_STATE64_COUNT\n";9787Print_x86_thread_state64_t(ts.uts.ts64);9788} else {9789outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "9790<< ts.tsh.count << "\n";9791}9792} else if (flavor == MachO::x86_FLOAT_STATE) {9793outs() << " flavor x86_FLOAT_STATE\n";9794if (count == MachO::x86_FLOAT_STATE_COUNT)9795outs() << " count x86_FLOAT_STATE_COUNT\n";9796else9797outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";9798struct MachO::x86_float_state_t fs;9799left = end - begin;9800if (left >= sizeof(MachO::x86_float_state_t)) {9801memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));9802begin += sizeof(MachO::x86_float_state_t);9803} else {9804memset(&fs, '\0', sizeof(MachO::x86_float_state_t));9805memcpy(&fs, begin, left);9806begin += left;9807}9808if (isLittleEndian != sys::IsLittleEndianHost)9809swapStruct(fs);9810if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {9811outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";9812if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)9813outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";9814else9815outs() << "fsh.count " << fs.fsh.count9816<< " (not x86_FLOAT_STATE64_COUNT\n";9817Print_x86_float_state_t(fs.ufs.fs64);9818} else {9819outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "9820<< fs.fsh.count << "\n";9821}9822} else if (flavor == MachO::x86_EXCEPTION_STATE) {9823outs() << " flavor x86_EXCEPTION_STATE\n";9824if (count == MachO::x86_EXCEPTION_STATE_COUNT)9825outs() << " count x86_EXCEPTION_STATE_COUNT\n";9826else9827outs() << " count " << count9828<< " (not x86_EXCEPTION_STATE_COUNT)\n";9829struct MachO::x86_exception_state_t es;9830left = end - begin;9831if (left >= sizeof(MachO::x86_exception_state_t)) {9832memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));9833begin += sizeof(MachO::x86_exception_state_t);9834} else {9835memset(&es, '\0', sizeof(MachO::x86_exception_state_t));9836memcpy(&es, begin, left);9837begin += left;9838}9839if (isLittleEndian != sys::IsLittleEndianHost)9840swapStruct(es);9841if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {9842outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";9843if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)9844outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";9845else9846outs() << "\t esh.count " << es.esh.count9847<< " (not x86_EXCEPTION_STATE64_COUNT\n";9848Print_x86_exception_state_t(es.ues.es64);9849} else {9850outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "9851<< es.esh.count << "\n";9852}9853} else if (flavor == MachO::x86_EXCEPTION_STATE64) {9854outs() << " flavor x86_EXCEPTION_STATE64\n";9855if (count == MachO::x86_EXCEPTION_STATE64_COUNT)9856outs() << " count x86_EXCEPTION_STATE64_COUNT\n";9857else9858outs() << " count " << count9859<< " (not x86_EXCEPTION_STATE64_COUNT)\n";9860struct MachO::x86_exception_state64_t es64;9861left = end - begin;9862if (left >= sizeof(MachO::x86_exception_state64_t)) {9863memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));9864begin += sizeof(MachO::x86_exception_state64_t);9865} else {9866memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));9867memcpy(&es64, begin, left);9868begin += left;9869}9870if (isLittleEndian != sys::IsLittleEndianHost)9871swapStruct(es64);9872Print_x86_exception_state_t(es64);9873} else {9874outs() << " flavor " << flavor << " (unknown)\n";9875outs() << " count " << count << "\n";9876outs() << " state (unknown)\n";9877begin += count * sizeof(uint32_t);9878}9879}9880} else if (cputype == MachO::CPU_TYPE_ARM) {9881while (begin < end) {9882if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9883memcpy((char *)&flavor, begin, sizeof(uint32_t));9884begin += sizeof(uint32_t);9885} else {9886flavor = 0;9887begin = end;9888}9889if (isLittleEndian != sys::IsLittleEndianHost)9890sys::swapByteOrder(flavor);9891if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9892memcpy((char *)&count, begin, sizeof(uint32_t));9893begin += sizeof(uint32_t);9894} else {9895count = 0;9896begin = end;9897}9898if (isLittleEndian != sys::IsLittleEndianHost)9899sys::swapByteOrder(count);9900if (flavor == MachO::ARM_THREAD_STATE) {9901outs() << " flavor ARM_THREAD_STATE\n";9902if (count == MachO::ARM_THREAD_STATE_COUNT)9903outs() << " count ARM_THREAD_STATE_COUNT\n";9904else9905outs() << " count " << count9906<< " (not ARM_THREAD_STATE_COUNT)\n";9907MachO::arm_thread_state32_t cpu32;9908left = end - begin;9909if (left >= sizeof(MachO::arm_thread_state32_t)) {9910memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));9911begin += sizeof(MachO::arm_thread_state32_t);9912} else {9913memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));9914memcpy(&cpu32, begin, left);9915begin += left;9916}9917if (isLittleEndian != sys::IsLittleEndianHost)9918swapStruct(cpu32);9919Print_arm_thread_state32_t(cpu32);9920} else {9921outs() << " flavor " << flavor << " (unknown)\n";9922outs() << " count " << count << "\n";9923outs() << " state (unknown)\n";9924begin += count * sizeof(uint32_t);9925}9926}9927} else if (cputype == MachO::CPU_TYPE_ARM64 ||9928cputype == MachO::CPU_TYPE_ARM64_32) {9929while (begin < end) {9930if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9931memcpy((char *)&flavor, begin, sizeof(uint32_t));9932begin += sizeof(uint32_t);9933} else {9934flavor = 0;9935begin = end;9936}9937if (isLittleEndian != sys::IsLittleEndianHost)9938sys::swapByteOrder(flavor);9939if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9940memcpy((char *)&count, begin, sizeof(uint32_t));9941begin += sizeof(uint32_t);9942} else {9943count = 0;9944begin = end;9945}9946if (isLittleEndian != sys::IsLittleEndianHost)9947sys::swapByteOrder(count);9948if (flavor == MachO::ARM_THREAD_STATE64) {9949outs() << " flavor ARM_THREAD_STATE64\n";9950if (count == MachO::ARM_THREAD_STATE64_COUNT)9951outs() << " count ARM_THREAD_STATE64_COUNT\n";9952else9953outs() << " count " << count9954<< " (not ARM_THREAD_STATE64_COUNT)\n";9955MachO::arm_thread_state64_t cpu64;9956left = end - begin;9957if (left >= sizeof(MachO::arm_thread_state64_t)) {9958memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));9959begin += sizeof(MachO::arm_thread_state64_t);9960} else {9961memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));9962memcpy(&cpu64, begin, left);9963begin += left;9964}9965if (isLittleEndian != sys::IsLittleEndianHost)9966swapStruct(cpu64);9967Print_arm_thread_state64_t(cpu64);9968} else {9969outs() << " flavor " << flavor << " (unknown)\n";9970outs() << " count " << count << "\n";9971outs() << " state (unknown)\n";9972begin += count * sizeof(uint32_t);9973}9974}9975} else {9976while (begin < end) {9977if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9978memcpy((char *)&flavor, begin, sizeof(uint32_t));9979begin += sizeof(uint32_t);9980} else {9981flavor = 0;9982begin = end;9983}9984if (isLittleEndian != sys::IsLittleEndianHost)9985sys::swapByteOrder(flavor);9986if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9987memcpy((char *)&count, begin, sizeof(uint32_t));9988begin += sizeof(uint32_t);9989} else {9990count = 0;9991begin = end;9992}9993if (isLittleEndian != sys::IsLittleEndianHost)9994sys::swapByteOrder(count);9995outs() << " flavor " << flavor << "\n";9996outs() << " count " << count << "\n";9997outs() << " state (Unknown cputype/cpusubtype)\n";9998begin += count * sizeof(uint32_t);9999}10000}10001}1000210003static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {10004if (dl.cmd == MachO::LC_ID_DYLIB)10005outs() << " cmd LC_ID_DYLIB\n";10006else if (dl.cmd == MachO::LC_LOAD_DYLIB)10007outs() << " cmd LC_LOAD_DYLIB\n";10008else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)10009outs() << " cmd LC_LOAD_WEAK_DYLIB\n";10010else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)10011outs() << " cmd LC_REEXPORT_DYLIB\n";10012else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)10013outs() << " cmd LC_LAZY_LOAD_DYLIB\n";10014else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)10015outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";10016else10017outs() << " cmd " << dl.cmd << " (unknown)\n";10018outs() << " cmdsize " << dl.cmdsize;10019if (dl.cmdsize < sizeof(struct MachO::dylib_command))10020outs() << " Incorrect size\n";10021else10022outs() << "\n";10023if (dl.dylib.name < dl.cmdsize) {10024const char *P = (const char *)(Ptr) + dl.dylib.name;10025outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";10026} else {10027outs() << " name ?(bad offset " << dl.dylib.name << ")\n";10028}10029outs() << " time stamp " << dl.dylib.timestamp << " ";10030time_t t = dl.dylib.timestamp;10031outs() << ctime(&t);10032outs() << " current version ";10033if (dl.dylib.current_version == 0xffffffff)10034outs() << "n/a\n";10035else10036outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."10037<< ((dl.dylib.current_version >> 8) & 0xff) << "."10038<< (dl.dylib.current_version & 0xff) << "\n";10039outs() << "compatibility version ";10040if (dl.dylib.compatibility_version == 0xffffffff)10041outs() << "n/a\n";10042else10043outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."10044<< ((dl.dylib.compatibility_version >> 8) & 0xff) << "."10045<< (dl.dylib.compatibility_version & 0xff) << "\n";10046}1004710048static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,10049uint32_t object_size) {10050if (ld.cmd == MachO::LC_CODE_SIGNATURE)10051outs() << " cmd LC_CODE_SIGNATURE\n";10052else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)10053outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";10054else if (ld.cmd == MachO::LC_FUNCTION_STARTS)10055outs() << " cmd LC_FUNCTION_STARTS\n";10056else if (ld.cmd == MachO::LC_DATA_IN_CODE)10057outs() << " cmd LC_DATA_IN_CODE\n";10058else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)10059outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";10060else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)10061outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";10062else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)10063outs() << " cmd LC_DYLD_EXPORTS_TRIE\n";10064else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)10065outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n";10066else if (ld.cmd == MachO::LC_ATOM_INFO)10067outs() << " cmd LC_ATOM_INFO\n";10068else10069outs() << " cmd " << ld.cmd << " (?)\n";10070outs() << " cmdsize " << ld.cmdsize;10071if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))10072outs() << " Incorrect size\n";10073else10074outs() << "\n";10075outs() << " dataoff " << ld.dataoff;10076if (ld.dataoff > object_size)10077outs() << " (past end of file)\n";10078else10079outs() << "\n";10080outs() << " datasize " << ld.datasize;10081uint64_t big_size = ld.dataoff;10082big_size += ld.datasize;10083if (big_size > object_size)10084outs() << " (past end of file)\n";10085else10086outs() << "\n";10087}1008810089static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,10090uint32_t cputype, bool verbose) {10091StringRef Buf = Obj->getData();10092unsigned Index = 0;10093for (const auto &Command : Obj->load_commands()) {10094outs() << "Load command " << Index++ << "\n";10095if (Command.C.cmd == MachO::LC_SEGMENT) {10096MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);10097const char *sg_segname = SLC.segname;10098PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,10099SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,10100SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),10101verbose);10102for (unsigned j = 0; j < SLC.nsects; j++) {10103MachO::section S = Obj->getSection(Command, j);10104PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,10105S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,10106SLC.cmd, sg_segname, filetype, Buf.size(), verbose);10107}10108} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10109MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);10110const char *sg_segname = SLC_64.segname;10111PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,10112SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,10113SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,10114SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);10115for (unsigned j = 0; j < SLC_64.nsects; j++) {10116MachO::section_64 S_64 = Obj->getSection64(Command, j);10117PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,10118S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,10119S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,10120sg_segname, filetype, Buf.size(), verbose);10121}10122} else if (Command.C.cmd == MachO::LC_SYMTAB) {10123MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10124PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());10125} else if (Command.C.cmd == MachO::LC_DYSYMTAB) {10126MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();10127MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10128PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),10129Obj->is64Bit());10130} else if (Command.C.cmd == MachO::LC_DYLD_INFO ||10131Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {10132MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);10133PrintDyldInfoLoadCommand(DyldInfo, Buf.size());10134} else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||10135Command.C.cmd == MachO::LC_ID_DYLINKER ||10136Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {10137MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);10138PrintDyldLoadCommand(Dyld, Command.Ptr);10139} else if (Command.C.cmd == MachO::LC_UUID) {10140MachO::uuid_command Uuid = Obj->getUuidCommand(Command);10141PrintUuidLoadCommand(Uuid);10142} else if (Command.C.cmd == MachO::LC_RPATH) {10143MachO::rpath_command Rpath = Obj->getRpathCommand(Command);10144PrintRpathLoadCommand(Rpath, Command.Ptr);10145} else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||10146Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||10147Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||10148Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {10149MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);10150PrintVersionMinLoadCommand(Vd);10151} else if (Command.C.cmd == MachO::LC_NOTE) {10152MachO::note_command Nt = Obj->getNoteLoadCommand(Command);10153PrintNoteLoadCommand(Nt);10154} else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {10155MachO::build_version_command Bv =10156Obj->getBuildVersionLoadCommand(Command);10157PrintBuildVersionLoadCommand(Obj, Bv, verbose);10158} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {10159MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);10160PrintSourceVersionCommand(Sd);10161} else if (Command.C.cmd == MachO::LC_MAIN) {10162MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);10163PrintEntryPointCommand(Ep);10164} else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {10165MachO::encryption_info_command Ei =10166Obj->getEncryptionInfoCommand(Command);10167PrintEncryptionInfoCommand(Ei, Buf.size());10168} else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {10169MachO::encryption_info_command_64 Ei =10170Obj->getEncryptionInfoCommand64(Command);10171PrintEncryptionInfoCommand64(Ei, Buf.size());10172} else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {10173MachO::linker_option_command Lo =10174Obj->getLinkerOptionLoadCommand(Command);10175PrintLinkerOptionCommand(Lo, Command.Ptr);10176} else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {10177MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);10178PrintSubFrameworkCommand(Sf, Command.Ptr);10179} else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {10180MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);10181PrintSubUmbrellaCommand(Sf, Command.Ptr);10182} else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {10183MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);10184PrintSubLibraryCommand(Sl, Command.Ptr);10185} else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {10186MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);10187PrintSubClientCommand(Sc, Command.Ptr);10188} else if (Command.C.cmd == MachO::LC_ROUTINES) {10189MachO::routines_command Rc = Obj->getRoutinesCommand(Command);10190PrintRoutinesCommand(Rc);10191} else if (Command.C.cmd == MachO::LC_ROUTINES_64) {10192MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);10193PrintRoutinesCommand64(Rc);10194} else if (Command.C.cmd == MachO::LC_THREAD ||10195Command.C.cmd == MachO::LC_UNIXTHREAD) {10196MachO::thread_command Tc = Obj->getThreadCommand(Command);10197PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);10198} else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||10199Command.C.cmd == MachO::LC_ID_DYLIB ||10200Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||10201Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||10202Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||10203Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {10204MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);10205PrintDylibCommand(Dl, Command.Ptr);10206} else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||10207Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||10208Command.C.cmd == MachO::LC_FUNCTION_STARTS ||10209Command.C.cmd == MachO::LC_DATA_IN_CODE ||10210Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||10211Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||10212Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||10213Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||10214Command.C.cmd == MachO::LC_ATOM_INFO) {10215MachO::linkedit_data_command Ld =10216Obj->getLinkeditDataLoadCommand(Command);10217PrintLinkEditDataCommand(Ld, Buf.size());10218} else {10219outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)10220<< ")\n";10221outs() << " cmdsize " << Command.C.cmdsize << "\n";10222// TODO: get and print the raw bytes of the load command.10223}10224// TODO: print all the other kinds of load commands.10225}10226}1022710228static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {10229if (Obj->is64Bit()) {10230MachO::mach_header_64 H_64;10231H_64 = Obj->getHeader64();10232PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,10233H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);10234} else {10235MachO::mach_header H;10236H = Obj->getHeader();10237PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,10238H.sizeofcmds, H.flags, verbose);10239}10240}1024110242void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {10243const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10244PrintMachHeader(file, Verbose);10245}1024610247void MachODumper::printPrivateHeaders() {10248printMachOFileHeader(&Obj);10249if (!FirstPrivateHeader)10250printMachOLoadCommands(&Obj);10251}1025210253void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {10254const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10255uint32_t filetype = 0;10256uint32_t cputype = 0;10257if (file->is64Bit()) {10258MachO::mach_header_64 H_64;10259H_64 = file->getHeader64();10260filetype = H_64.filetype;10261cputype = H_64.cputype;10262} else {10263MachO::mach_header H;10264H = file->getHeader();10265filetype = H.filetype;10266cputype = H.cputype;10267}10268PrintLoadCommands(file, filetype, cputype, Verbose);10269}1027010271//===----------------------------------------------------------------------===//10272// export trie dumping10273//===----------------------------------------------------------------------===//1027410275static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {10276uint64_t BaseSegmentAddress = 0;10277for (const auto &Command : Obj->load_commands()) {10278if (Command.C.cmd == MachO::LC_SEGMENT) {10279MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);10280if (Seg.fileoff == 0 && Seg.filesize != 0) {10281BaseSegmentAddress = Seg.vmaddr;10282break;10283}10284} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10285MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);10286if (Seg.fileoff == 0 && Seg.filesize != 0) {10287BaseSegmentAddress = Seg.vmaddr;10288break;10289}10290}10291}10292Error Err = Error::success();10293for (const object::ExportEntry &Entry : Obj->exports(Err)) {10294uint64_t Flags = Entry.flags();10295bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);10296bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);10297bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10298MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);10299bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10300MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);10301bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);10302if (ReExport)10303outs() << "[re-export] ";10304else10305outs() << format("0x%08llX ",10306Entry.address() + BaseSegmentAddress);10307outs() << Entry.name();10308if (WeakDef || ThreadLocal || Resolver || Abs) {10309ListSeparator LS;10310outs() << " [";10311if (WeakDef)10312outs() << LS << "weak_def";10313if (ThreadLocal)10314outs() << LS << "per-thread";10315if (Abs)10316outs() << LS << "absolute";10317if (Resolver)10318outs() << LS << format("resolver=0x%08llX", Entry.other());10319outs() << "]";10320}10321if (ReExport) {10322StringRef DylibName = "unknown";10323int Ordinal = Entry.other() - 1;10324Obj->getLibraryShortNameByIndex(Ordinal, DylibName);10325if (Entry.otherName().empty())10326outs() << " (from " << DylibName << ")";10327else10328outs() << " (" << Entry.otherName() << " from " << DylibName << ")";10329}10330outs() << "\n";10331}10332if (Err)10333reportError(std::move(Err), Obj->getFileName());10334}1033510336//===----------------------------------------------------------------------===//10337// rebase table dumping10338//===----------------------------------------------------------------------===//1033910340static void printMachORebaseTable(object::MachOObjectFile *Obj) {10341outs() << "segment section address type\n";10342Error Err = Error::success();10343for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {10344StringRef SegmentName = Entry.segmentName();10345StringRef SectionName = Entry.sectionName();10346uint64_t Address = Entry.address();1034710348// Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer10349outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",10350SegmentName.str().c_str(), SectionName.str().c_str(),10351Address, Entry.typeName().str().c_str());10352}10353if (Err)10354reportError(std::move(Err), Obj->getFileName());10355}1035610357static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {10358StringRef DylibName;10359switch (Ordinal) {10360case MachO::BIND_SPECIAL_DYLIB_SELF:10361return "this-image";10362case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:10363return "main-executable";10364case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:10365return "flat-namespace";10366case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:10367return "weak";10368default:10369if (Ordinal > 0) {10370std::error_code EC =10371Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);10372if (EC)10373return "<<bad library ordinal>>";10374return DylibName;10375}10376}10377return "<<unknown special ordinal>>";10378}1037910380//===----------------------------------------------------------------------===//10381// bind table dumping10382//===----------------------------------------------------------------------===//1038310384static void printMachOBindTable(object::MachOObjectFile *Obj) {10385// Build table of sections so names can used in final output.10386outs() << "segment section address type "10387"addend dylib symbol\n";10388Error Err = Error::success();10389for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {10390StringRef SegmentName = Entry.segmentName();10391StringRef SectionName = Entry.sectionName();10392uint64_t Address = Entry.address();1039310394// Table lines look like:10395// __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard10396StringRef Attr;10397if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)10398Attr = " (weak_import)";10399outs() << left_justify(SegmentName, 8) << " "10400<< left_justify(SectionName, 18) << " "10401<< format_hex(Address, 10, true) << " "10402<< left_justify(Entry.typeName(), 8) << " "10403<< format_decimal(Entry.addend(), 8) << " "10404<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10405<< Entry.symbolName() << Attr << "\n";10406}10407if (Err)10408reportError(std::move(Err), Obj->getFileName());10409}1041010411//===----------------------------------------------------------------------===//10412// lazy bind table dumping10413//===----------------------------------------------------------------------===//1041410415static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {10416outs() << "segment section address "10417"dylib symbol\n";10418Error Err = Error::success();10419for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {10420StringRef SegmentName = Entry.segmentName();10421StringRef SectionName = Entry.sectionName();10422uint64_t Address = Entry.address();1042310424// Table lines look like:10425// __DATA __got 0x00012010 libSystem ___stack_chk_guard10426outs() << left_justify(SegmentName, 8) << " "10427<< left_justify(SectionName, 18) << " "10428<< format_hex(Address, 10, true) << " "10429<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10430<< Entry.symbolName() << "\n";10431}10432if (Err)10433reportError(std::move(Err), Obj->getFileName());10434}1043510436//===----------------------------------------------------------------------===//10437// weak bind table dumping10438//===----------------------------------------------------------------------===//1043910440static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {10441outs() << "segment section address "10442"type addend symbol\n";10443Error Err = Error::success();10444for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {10445// Strong symbols don't have a location to update.10446if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {10447outs() << " strong "10448<< Entry.symbolName() << "\n";10449continue;10450}10451StringRef SegmentName = Entry.segmentName();10452StringRef SectionName = Entry.sectionName();10453uint64_t Address = Entry.address();1045410455// Table lines look like:10456// __DATA __data 0x00001000 pointer 0 _foo10457outs() << left_justify(SegmentName, 8) << " "10458<< left_justify(SectionName, 18) << " "10459<< format_hex(Address, 10, true) << " "10460<< left_justify(Entry.typeName(), 8) << " "10461<< format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()10462<< "\n";10463}10464if (Err)10465reportError(std::move(Err), Obj->getFileName());10466}1046710468// get_dyld_bind_info_symbolname() is used for disassembly and passed an10469// address, ReferenceValue, in the Mach-O file and looks in the dyld bind10470// information for that address. If the address is found its binding symbol10471// name is returned. If not nullptr is returned.10472static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,10473struct DisassembleInfo *info) {10474if (info->bindtable == nullptr) {10475info->bindtable = std::make_unique<SymbolAddressMap>();10476Error Err = Error::success();10477for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {10478uint64_t Address = Entry.address();10479StringRef name = Entry.symbolName();10480if (!name.empty())10481(*info->bindtable)[Address] = name;10482}10483if (Err)10484reportError(std::move(Err), info->O->getFileName());10485}10486auto name = info->bindtable->lookup(ReferenceValue);10487return !name.empty() ? name.data() : nullptr;10488}1048910490void objdump::printLazyBindTable(ObjectFile *o) {10491outs() << "\nLazy bind table:\n";10492if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10493printMachOLazyBindTable(MachO);10494else10495WithColor::error()10496<< "This operation is only currently supported "10497"for Mach-O executable files.\n";10498}1049910500void objdump::printWeakBindTable(ObjectFile *o) {10501outs() << "\nWeak bind table:\n";10502if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10503printMachOWeakBindTable(MachO);10504else10505WithColor::error()10506<< "This operation is only currently supported "10507"for Mach-O executable files.\n";10508}1050910510void objdump::printExportsTrie(const ObjectFile *o) {10511outs() << "\nExports trie:\n";10512if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10513printMachOExportsTrie(MachO);10514else10515WithColor::error()10516<< "This operation is only currently supported "10517"for Mach-O executable files.\n";10518}1051910520void objdump::printRebaseTable(ObjectFile *o) {10521outs() << "\nRebase table:\n";10522if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10523printMachORebaseTable(MachO);10524else10525WithColor::error()10526<< "This operation is only currently supported "10527"for Mach-O executable files.\n";10528}1052910530void objdump::printBindTable(ObjectFile *o) {10531outs() << "\nBind table:\n";10532if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10533printMachOBindTable(MachO);10534else10535WithColor::error()10536<< "This operation is only currently supported "10537"for Mach-O executable files.\n";10538}105391054010541