10585 lines · cpp
1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the MachO-specific dumper for llvm-objdump.10//11//===----------------------------------------------------------------------===//12 13#include "MachODump.h"14 15#include "ObjdumpOptID.h"16#include "SourcePrinter.h"17#include "llvm-objdump.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/BinaryFormat/MachO.h"21#include "llvm/Config/config.h"22#include "llvm/DebugInfo/DIContext.h"23#include "llvm/DebugInfo/DWARF/DWARFContext.h"24#include "llvm/Demangle/Demangle.h"25#include "llvm/MC/MCAsmInfo.h"26#include "llvm/MC/MCContext.h"27#include "llvm/MC/MCDisassembler/MCDisassembler.h"28#include "llvm/MC/MCInst.h"29#include "llvm/MC/MCInstPrinter.h"30#include "llvm/MC/MCInstrDesc.h"31#include "llvm/MC/MCInstrInfo.h"32#include "llvm/MC/MCRegisterInfo.h"33#include "llvm/MC/MCSubtargetInfo.h"34#include "llvm/MC/MCTargetOptions.h"35#include "llvm/MC/TargetRegistry.h"36#include "llvm/Object/MachO.h"37#include "llvm/Object/MachOUniversal.h"38#include "llvm/Option/ArgList.h"39#include "llvm/Support/Casting.h"40#include "llvm/Support/Debug.h"41#include "llvm/Support/Endian.h"42#include "llvm/Support/Format.h"43#include "llvm/Support/FormattedStream.h"44#include "llvm/Support/LEB128.h"45#include "llvm/Support/MemoryBuffer.h"46#include "llvm/Support/WithColor.h"47#include "llvm/Support/raw_ostream.h"48#include "llvm/TargetParser/Triple.h"49#include <algorithm>50#include <cstring>51#include <system_error>52 53using namespace llvm;54using namespace llvm::object;55using namespace llvm::objdump;56 57bool objdump::FirstPrivateHeader;58bool objdump::ExportsTrie;59bool objdump::Rebase;60bool objdump::Rpaths;61bool objdump::Bind;62bool objdump::LazyBind;63bool objdump::WeakBind;64static bool UseDbg;65static std::string DSYMFile;66bool objdump::FullLeadingAddr;67bool objdump::LeadingHeaders;68bool objdump::UniversalHeaders;69static bool ArchiveMemberOffsets;70bool objdump::IndirectSymbols;71bool objdump::DataInCode;72FunctionStartsMode objdump::FunctionStartsType =73 objdump::FunctionStartsMode::None;74bool objdump::LinkOptHints;75bool objdump::InfoPlist;76bool objdump::ChainedFixups;77bool objdump::DyldInfo;78bool objdump::DylibsUsed;79bool objdump::DylibId;80bool objdump::Verbose;81bool objdump::ObjcMetaData;82std::string objdump::DisSymName;83bool objdump::SymbolicOperands;84static std::vector<std::string> ArchFlags;85 86static bool ArchAll = false;87static std::string ThumbTripleName;88 89static StringRef ordinalName(const object::MachOObjectFile *, int);90 91void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {92 FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);93 ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);94 Rebase = InputArgs.hasArg(OBJDUMP_rebase);95 Rpaths = InputArgs.hasArg(OBJDUMP_rpaths);96 Bind = InputArgs.hasArg(OBJDUMP_bind);97 LazyBind = InputArgs.hasArg(OBJDUMP_lazy_bind);98 WeakBind = InputArgs.hasArg(OBJDUMP_weak_bind);99 UseDbg = InputArgs.hasArg(OBJDUMP_g);100 DSYMFile = InputArgs.getLastArgValue(OBJDUMP_dsym_EQ).str();101 FullLeadingAddr = InputArgs.hasArg(OBJDUMP_full_leading_addr);102 LeadingHeaders = !InputArgs.hasArg(OBJDUMP_no_leading_headers);103 UniversalHeaders = InputArgs.hasArg(OBJDUMP_universal_headers);104 ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);105 IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);106 DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);107 if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {108 FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())109 .Case("addrs", FunctionStartsMode::Addrs)110 .Case("names", FunctionStartsMode::Names)111 .Case("both", FunctionStartsMode::Both)112 .Default(FunctionStartsMode::None);113 if (FunctionStartsType == FunctionStartsMode::None)114 invalidArgValue(A);115 }116 LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);117 InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);118 ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);119 DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);120 DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);121 DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);122 Verbose = !InputArgs.hasArg(OBJDUMP_non_verbose);123 ObjcMetaData = InputArgs.hasArg(OBJDUMP_objc_meta_data);124 DisSymName = InputArgs.getLastArgValue(OBJDUMP_dis_symname).str();125 SymbolicOperands = !InputArgs.hasArg(OBJDUMP_no_symbolic_operands);126 ArchFlags = InputArgs.getAllArgValues(OBJDUMP_arch_EQ);127}128 129static const Target *GetTarget(const MachOObjectFile *MachOObj,130 const char **McpuDefault,131 const Target **ThumbTarget,132 Triple &ThumbTriple) {133 // Figure out the target triple.134 Triple TT(TripleName);135 if (TripleName.empty()) {136 TT = MachOObj->getArchTriple(McpuDefault);137 TripleName = TT.str();138 }139 140 if (TT.getArch() == Triple::arm) {141 // We've inferred a 32-bit ARM target from the object file. All MachO CPUs142 // that support ARM are also capable of Thumb mode.143 std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();144 ThumbTriple = TT;145 ThumbTriple.setArchName(ThumbName);146 ThumbTripleName = ThumbTriple.str();147 }148 149 // Get the target specific parser.150 std::string Error;151 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);152 if (TheTarget && ThumbTripleName.empty())153 return TheTarget;154 155 *ThumbTarget = TargetRegistry::lookupTarget(ThumbTriple, Error);156 if (*ThumbTarget)157 return TheTarget;158 159 WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";160 if (!TheTarget)161 errs() << TripleName;162 else163 errs() << ThumbTripleName;164 errs() << "', see --version and --triple.\n";165 return nullptr;166}167 168namespace {169struct SymbolSorter {170 bool operator()(const SymbolRef &A, const SymbolRef &B) {171 Expected<SymbolRef::Type> ATypeOrErr = A.getType();172 if (!ATypeOrErr)173 reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());174 SymbolRef::Type AType = *ATypeOrErr;175 Expected<SymbolRef::Type> BTypeOrErr = B.getType();176 if (!BTypeOrErr)177 reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());178 SymbolRef::Type BType = *BTypeOrErr;179 uint64_t AAddr =180 (AType != SymbolRef::ST_Function) ? 0 : cantFail(A.getValue());181 uint64_t BAddr =182 (BType != SymbolRef::ST_Function) ? 0 : cantFail(B.getValue());183 return AAddr < BAddr;184 }185};186 187class MachODumper : public Dumper {188 const object::MachOObjectFile &Obj;189 190public:191 MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}192 void printPrivateHeaders() override;193};194} // namespace195 196std::unique_ptr<Dumper>197objdump::createMachODumper(const object::MachOObjectFile &Obj) {198 return std::make_unique<MachODumper>(Obj);199}200 201// Types for the storted data in code table that is built before disassembly202// and the predicate function to sort them.203typedef std::pair<uint64_t, DiceRef> DiceTableEntry;204typedef std::vector<DiceTableEntry> DiceTable;205typedef DiceTable::iterator dice_table_iterator;206 207// This is used to search for a data in code table entry for the PC being208// disassembled. The j parameter has the PC in j.first. A single data in code209// table entry can cover many bytes for each of its Kind's. So if the offset,210// aka the i.first value, of the data in code table entry plus its Length211// covers the PC being searched for this will return true. If not it will212// return false.213static bool compareDiceTableEntries(const DiceTableEntry &i,214 const DiceTableEntry &j) {215 uint16_t Length;216 i.second.getLength(Length);217 218 return j.first >= i.first && j.first < i.first + Length;219}220 221static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,222 unsigned short Kind) {223 uint32_t Value, Size = 1;224 225 switch (Kind) {226 default:227 case MachO::DICE_KIND_DATA:228 if (Length >= 4) {229 if (ShowRawInsn)230 dumpBytes(ArrayRef(bytes, 4), outs());231 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];232 outs() << "\t.long " << Value;233 Size = 4;234 } else if (Length >= 2) {235 if (ShowRawInsn)236 dumpBytes(ArrayRef(bytes, 2), outs());237 Value = bytes[1] << 8 | bytes[0];238 outs() << "\t.short " << Value;239 Size = 2;240 } else {241 if (ShowRawInsn)242 dumpBytes(ArrayRef(bytes, 2), outs());243 Value = bytes[0];244 outs() << "\t.byte " << Value;245 Size = 1;246 }247 if (Kind == MachO::DICE_KIND_DATA)248 outs() << "\t@ KIND_DATA\n";249 else250 outs() << "\t@ data in code kind = " << Kind << "\n";251 break;252 case MachO::DICE_KIND_JUMP_TABLE8:253 if (ShowRawInsn)254 dumpBytes(ArrayRef(bytes, 1), outs());255 Value = bytes[0];256 outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";257 Size = 1;258 break;259 case MachO::DICE_KIND_JUMP_TABLE16:260 if (ShowRawInsn)261 dumpBytes(ArrayRef(bytes, 2), outs());262 Value = bytes[1] << 8 | bytes[0];263 outs() << "\t.short " << format("%5u", Value & 0xffff)264 << "\t@ KIND_JUMP_TABLE16\n";265 Size = 2;266 break;267 case MachO::DICE_KIND_JUMP_TABLE32:268 case MachO::DICE_KIND_ABS_JUMP_TABLE32:269 if (ShowRawInsn)270 dumpBytes(ArrayRef(bytes, 4), outs());271 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];272 outs() << "\t.long " << Value;273 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)274 outs() << "\t@ KIND_JUMP_TABLE32\n";275 else276 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";277 Size = 4;278 break;279 }280 return Size;281}282 283static void getSectionsAndSymbols(MachOObjectFile *MachOObj,284 std::vector<SectionRef> &Sections,285 std::vector<SymbolRef> &Symbols,286 SmallVectorImpl<uint64_t> &FoundFns,287 uint64_t &BaseSegmentAddress) {288 const StringRef FileName = MachOObj->getFileName();289 for (const SymbolRef &Symbol : MachOObj->symbols()) {290 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);291 if (!SymName.starts_with("ltmp"))292 Symbols.push_back(Symbol);293 }294 295 append_range(Sections, MachOObj->sections());296 297 bool BaseSegmentAddressSet = false;298 for (const auto &Command : MachOObj->load_commands()) {299 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {300 // We found a function starts segment, parse the addresses for later301 // consumption.302 MachO::linkedit_data_command LLC =303 MachOObj->getLinkeditDataLoadCommand(Command);304 305 MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);306 } else if (Command.C.cmd == MachO::LC_SEGMENT) {307 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);308 StringRef SegName = SLC.segname;309 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {310 BaseSegmentAddressSet = true;311 BaseSegmentAddress = SLC.vmaddr;312 }313 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {314 MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command);315 StringRef SegName = SLC.segname;316 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {317 BaseSegmentAddressSet = true;318 BaseSegmentAddress = SLC.vmaddr;319 }320 }321 }322}323 324static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,325 DiceTable &Dices, uint64_t &InstSize) {326 // Check the data in code table here to see if this is data not an327 // instruction to be disassembled.328 DiceTable Dice;329 Dice.push_back(std::make_pair(PC, DiceRef()));330 dice_table_iterator DTI =331 std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),332 compareDiceTableEntries);333 if (DTI != Dices.end()) {334 uint16_t Length;335 DTI->second.getLength(Length);336 uint16_t Kind;337 DTI->second.getKind(Kind);338 InstSize = DumpDataInCode(bytes, Length, Kind);339 if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&340 (PC == (DTI->first + Length - 1)) && (Length & 1))341 InstSize++;342 return true;343 }344 return false;345}346 347static void printRelocationTargetName(const MachOObjectFile *O,348 const MachO::any_relocation_info &RE,349 raw_string_ostream &Fmt) {350 // Target of a scattered relocation is an address. In the interest of351 // generating pretty output, scan through the symbol table looking for a352 // symbol that aligns with that address. If we find one, print it.353 // Otherwise, we just print the hex address of the target.354 const StringRef FileName = O->getFileName();355 if (O->isRelocationScattered(RE)) {356 uint32_t Val = O->getPlainRelocationSymbolNum(RE);357 358 for (const SymbolRef &Symbol : O->symbols()) {359 uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);360 if (Addr != Val)361 continue;362 Fmt << unwrapOrError(Symbol.getName(), FileName);363 return;364 }365 366 // If we couldn't find a symbol that this relocation refers to, try367 // to find a section beginning instead.368 for (const SectionRef &Section : ToolSectionFilter(*O)) {369 uint64_t Addr = Section.getAddress();370 if (Addr != Val)371 continue;372 StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName());373 Fmt << NameOrErr;374 return;375 }376 377 Fmt << format("0x%x", Val);378 return;379 }380 381 StringRef S;382 bool isExtern = O->getPlainRelocationExternal(RE);383 uint64_t Val = O->getPlainRelocationSymbolNum(RE);384 385 if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&386 (O->getArch() == Triple::aarch64 || O->getArch() == Triple::aarch64_be)) {387 Fmt << format("0x%0" PRIx64, Val);388 return;389 }390 391 if (isExtern) {392 symbol_iterator SI = O->symbol_begin();393 std::advance(SI, Val);394 S = unwrapOrError(SI->getName(), FileName);395 } else {396 section_iterator SI = O->section_begin();397 // Adjust for the fact that sections are 1-indexed.398 if (Val == 0) {399 Fmt << "0 (?,?)";400 return;401 }402 uint32_t I = Val - 1;403 while (I != 0 && SI != O->section_end()) {404 --I;405 std::advance(SI, 1);406 }407 if (SI == O->section_end()) {408 Fmt << Val << " (?,?)";409 } else {410 if (Expected<StringRef> NameOrErr = SI->getName())411 S = *NameOrErr;412 else413 consumeError(NameOrErr.takeError());414 }415 }416 417 Fmt << S;418}419 420Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,421 const RelocationRef &RelRef,422 SmallVectorImpl<char> &Result) {423 DataRefImpl Rel = RelRef.getRawDataRefImpl();424 MachO::any_relocation_info RE = Obj->getRelocation(Rel);425 426 unsigned Arch = Obj->getArch();427 428 std::string FmtBuf;429 raw_string_ostream Fmt(FmtBuf);430 unsigned Type = Obj->getAnyRelocationType(RE);431 bool IsPCRel = Obj->getAnyRelocationPCRel(RE);432 433 // Determine any addends that should be displayed with the relocation.434 // These require decoding the relocation type, which is triple-specific.435 436 // X86_64 has entirely custom relocation types.437 if (Arch == Triple::x86_64) {438 switch (Type) {439 case MachO::X86_64_RELOC_GOT_LOAD:440 case MachO::X86_64_RELOC_GOT: {441 printRelocationTargetName(Obj, RE, Fmt);442 Fmt << "@GOT";443 if (IsPCRel)444 Fmt << "PCREL";445 break;446 }447 case MachO::X86_64_RELOC_SUBTRACTOR: {448 DataRefImpl RelNext = Rel;449 Obj->moveRelocationNext(RelNext);450 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);451 452 // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type453 // X86_64_RELOC_UNSIGNED.454 // NOTE: Scattered relocations don't exist on x86_64.455 unsigned RType = Obj->getAnyRelocationType(RENext);456 if (RType != MachO::X86_64_RELOC_UNSIGNED)457 reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "458 "X86_64_RELOC_SUBTRACTOR.");459 460 // The X86_64_RELOC_UNSIGNED contains the minuend symbol;461 // X86_64_RELOC_SUBTRACTOR contains the subtrahend.462 printRelocationTargetName(Obj, RENext, Fmt);463 Fmt << "-";464 printRelocationTargetName(Obj, RE, Fmt);465 break;466 }467 case MachO::X86_64_RELOC_TLV:468 printRelocationTargetName(Obj, RE, Fmt);469 Fmt << "@TLV";470 if (IsPCRel)471 Fmt << "P";472 break;473 case MachO::X86_64_RELOC_SIGNED_1:474 printRelocationTargetName(Obj, RE, Fmt);475 Fmt << "-1";476 break;477 case MachO::X86_64_RELOC_SIGNED_2:478 printRelocationTargetName(Obj, RE, Fmt);479 Fmt << "-2";480 break;481 case MachO::X86_64_RELOC_SIGNED_4:482 printRelocationTargetName(Obj, RE, Fmt);483 Fmt << "-4";484 break;485 default:486 printRelocationTargetName(Obj, RE, Fmt);487 break;488 }489 // X86 and ARM share some relocation types in common.490 } else if (Arch == Triple::x86 || Arch == Triple::arm ||491 Arch == Triple::ppc) {492 // Generic relocation types...493 switch (Type) {494 case MachO::GENERIC_RELOC_PAIR: // prints no info495 return Error::success();496 case MachO::GENERIC_RELOC_SECTDIFF: {497 DataRefImpl RelNext = Rel;498 Obj->moveRelocationNext(RelNext);499 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);500 501 // X86 sect diff's must be followed by a relocation of type502 // GENERIC_RELOC_PAIR.503 unsigned RType = Obj->getAnyRelocationType(RENext);504 505 if (RType != MachO::GENERIC_RELOC_PAIR)506 reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "507 "GENERIC_RELOC_SECTDIFF.");508 509 printRelocationTargetName(Obj, RE, Fmt);510 Fmt << "-";511 printRelocationTargetName(Obj, RENext, Fmt);512 break;513 }514 }515 516 if (Arch == Triple::x86 || Arch == Triple::ppc) {517 switch (Type) {518 case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {519 DataRefImpl RelNext = Rel;520 Obj->moveRelocationNext(RelNext);521 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);522 523 // X86 sect diff's must be followed by a relocation of type524 // GENERIC_RELOC_PAIR.525 unsigned RType = Obj->getAnyRelocationType(RENext);526 if (RType != MachO::GENERIC_RELOC_PAIR)527 reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "528 "GENERIC_RELOC_LOCAL_SECTDIFF.");529 530 printRelocationTargetName(Obj, RE, Fmt);531 Fmt << "-";532 printRelocationTargetName(Obj, RENext, Fmt);533 break;534 }535 case MachO::GENERIC_RELOC_TLV: {536 printRelocationTargetName(Obj, RE, Fmt);537 Fmt << "@TLV";538 if (IsPCRel)539 Fmt << "P";540 break;541 }542 default:543 printRelocationTargetName(Obj, RE, Fmt);544 }545 } else { // ARM-specific relocations546 switch (Type) {547 case MachO::ARM_RELOC_HALF:548 case MachO::ARM_RELOC_HALF_SECTDIFF: {549 // Half relocations steal a bit from the length field to encode550 // whether this is an upper16 or a lower16 relocation.551 bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;552 553 if (isUpper)554 Fmt << ":upper16:(";555 else556 Fmt << ":lower16:(";557 printRelocationTargetName(Obj, RE, Fmt);558 559 DataRefImpl RelNext = Rel;560 Obj->moveRelocationNext(RelNext);561 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);562 563 // ARM half relocs must be followed by a relocation of type564 // ARM_RELOC_PAIR.565 unsigned RType = Obj->getAnyRelocationType(RENext);566 if (RType != MachO::ARM_RELOC_PAIR)567 reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "568 "ARM_RELOC_HALF");569 570 // NOTE: The half of the target virtual address is stashed in the571 // address field of the secondary relocation, but we can't reverse572 // engineer the constant offset from it without decoding the movw/movt573 // instruction to find the other half in its immediate field.574 575 // ARM_RELOC_HALF_SECTDIFF encodes the second section in the576 // symbol/section pointer of the follow-on relocation.577 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {578 Fmt << "-";579 printRelocationTargetName(Obj, RENext, Fmt);580 }581 582 Fmt << ")";583 break;584 }585 default: {586 printRelocationTargetName(Obj, RE, Fmt);587 }588 }589 }590 } else591 printRelocationTargetName(Obj, RE, Fmt);592 593 Fmt.flush();594 Result.append(FmtBuf.begin(), FmtBuf.end());595 return Error::success();596}597 598static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,599 uint32_t n, uint32_t count,600 uint32_t stride, uint64_t addr) {601 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();602 uint32_t nindirectsyms = Dysymtab.nindirectsyms;603 if (n > nindirectsyms)604 outs() << " (entries start past the end of the indirect symbol "605 "table) (reserved1 field greater than the table size)";606 else if (n + count > nindirectsyms)607 outs() << " (entries extends past the end of the indirect symbol "608 "table)";609 outs() << "\n";610 uint32_t cputype = O->getHeader().cputype;611 if (cputype & MachO::CPU_ARCH_ABI64)612 outs() << "address index";613 else614 outs() << "address index";615 if (verbose)616 outs() << " name\n";617 else618 outs() << "\n";619 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {620 if (cputype & MachO::CPU_ARCH_ABI64)621 outs() << format("0x%016" PRIx64, addr + j * stride) << " ";622 else623 outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";624 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();625 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);626 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {627 outs() << "LOCAL\n";628 continue;629 }630 if (indirect_symbol ==631 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {632 outs() << "LOCAL ABSOLUTE\n";633 continue;634 }635 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {636 outs() << "ABSOLUTE\n";637 continue;638 }639 outs() << format("%5u ", indirect_symbol);640 if (verbose) {641 MachO::symtab_command Symtab = O->getSymtabLoadCommand();642 if (indirect_symbol < Symtab.nsyms) {643 symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);644 SymbolRef Symbol = *Sym;645 outs() << unwrapOrError(Symbol.getName(), O->getFileName());646 } else {647 outs() << "?";648 }649 }650 outs() << "\n";651 }652}653 654static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {655 for (const auto &Load : O->load_commands()) {656 if (Load.C.cmd == MachO::LC_SEGMENT_64) {657 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);658 for (unsigned J = 0; J < Seg.nsects; ++J) {659 MachO::section_64 Sec = O->getSection64(Load, J);660 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;661 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||662 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||663 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||664 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||665 section_type == MachO::S_SYMBOL_STUBS) {666 uint32_t stride;667 if (section_type == MachO::S_SYMBOL_STUBS)668 stride = Sec.reserved2;669 else670 stride = 8;671 if (stride == 0) {672 outs() << "Can't print indirect symbols for (" << Sec.segname << ","673 << Sec.sectname << ") "674 << "(size of stubs in reserved2 field is zero)\n";675 continue;676 }677 uint32_t count = Sec.size / stride;678 outs() << "Indirect symbols for (" << Sec.segname << ","679 << Sec.sectname << ") " << count << " entries";680 uint32_t n = Sec.reserved1;681 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);682 }683 }684 } else if (Load.C.cmd == MachO::LC_SEGMENT) {685 MachO::segment_command Seg = O->getSegmentLoadCommand(Load);686 for (unsigned J = 0; J < Seg.nsects; ++J) {687 MachO::section Sec = O->getSection(Load, J);688 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;689 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||690 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||691 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||692 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||693 section_type == MachO::S_SYMBOL_STUBS) {694 uint32_t stride;695 if (section_type == MachO::S_SYMBOL_STUBS)696 stride = Sec.reserved2;697 else698 stride = 4;699 if (stride == 0) {700 outs() << "Can't print indirect symbols for (" << Sec.segname << ","701 << Sec.sectname << ") "702 << "(size of stubs in reserved2 field is zero)\n";703 continue;704 }705 uint32_t count = Sec.size / stride;706 outs() << "Indirect symbols for (" << Sec.segname << ","707 << Sec.sectname << ") " << count << " entries";708 uint32_t n = Sec.reserved1;709 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);710 }711 }712 }713 }714}715 716static void PrintRType(const uint64_t cputype, const unsigned r_type) {717 static char const *generic_r_types[] = {718 "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",719 " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",720 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "721 };722 static char const *x86_64_r_types[] = {723 "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",724 "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",725 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "726 };727 static char const *arm_r_types[] = {728 "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",729 "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",730 " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "731 };732 static char const *arm64_r_types[] = {733 "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",734 "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",735 "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "736 };737 738 if (r_type > 0xf){739 outs() << format("%-7u", r_type) << " ";740 return;741 }742 switch (cputype) {743 case MachO::CPU_TYPE_I386:744 outs() << generic_r_types[r_type];745 break;746 case MachO::CPU_TYPE_X86_64:747 outs() << x86_64_r_types[r_type];748 break;749 case MachO::CPU_TYPE_ARM:750 outs() << arm_r_types[r_type];751 break;752 case MachO::CPU_TYPE_ARM64:753 case MachO::CPU_TYPE_ARM64_32:754 outs() << arm64_r_types[r_type];755 break;756 default:757 outs() << format("%-7u ", r_type);758 }759}760 761static void PrintRLength(const uint64_t cputype, const unsigned r_type,762 const unsigned r_length, const bool previous_arm_half){763 if (cputype == MachO::CPU_TYPE_ARM &&764 (r_type == MachO::ARM_RELOC_HALF ||765 r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {766 if ((r_length & 0x1) == 0)767 outs() << "lo/";768 else769 outs() << "hi/";770 if ((r_length & 0x1) == 0)771 outs() << "arm ";772 else773 outs() << "thm ";774 } else {775 switch (r_length) {776 case 0:777 outs() << "byte ";778 break;779 case 1:780 outs() << "word ";781 break;782 case 2:783 outs() << "long ";784 break;785 case 3:786 if (cputype == MachO::CPU_TYPE_X86_64)787 outs() << "quad ";788 else789 outs() << format("?(%2d) ", r_length);790 break;791 default:792 outs() << format("?(%2d) ", r_length);793 }794 }795}796 797static void PrintRelocationEntries(const MachOObjectFile *O,798 const relocation_iterator Begin,799 const relocation_iterator End,800 const uint64_t cputype,801 const bool verbose) {802 const MachO::symtab_command Symtab = O->getSymtabLoadCommand();803 bool previous_arm_half = false;804 bool previous_sectdiff = false;805 uint32_t sectdiff_r_type = 0;806 807 for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {808 const DataRefImpl Rel = Reloc->getRawDataRefImpl();809 const MachO::any_relocation_info RE = O->getRelocation(Rel);810 const unsigned r_type = O->getAnyRelocationType(RE);811 const bool r_scattered = O->isRelocationScattered(RE);812 const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);813 const unsigned r_length = O->getAnyRelocationLength(RE);814 const unsigned r_address = O->getAnyRelocationAddress(RE);815 const bool r_extern = (r_scattered ? false :816 O->getPlainRelocationExternal(RE));817 const uint32_t r_value = (r_scattered ?818 O->getScatteredRelocationValue(RE) : 0);819 const unsigned r_symbolnum = (r_scattered ? 0 :820 O->getPlainRelocationSymbolNum(RE));821 822 if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {823 if (verbose) {824 // scattered: address825 if ((cputype == MachO::CPU_TYPE_I386 &&826 r_type == MachO::GENERIC_RELOC_PAIR) ||827 (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))828 outs() << " ";829 else830 outs() << format("%08x ", (unsigned int)r_address);831 832 // scattered: pcrel833 if (r_pcrel)834 outs() << "True ";835 else836 outs() << "False ";837 838 // scattered: length839 PrintRLength(cputype, r_type, r_length, previous_arm_half);840 841 // scattered: extern & type842 outs() << "n/a ";843 PrintRType(cputype, r_type);844 845 // scattered: scattered & value846 outs() << format("True 0x%08x", (unsigned int)r_value);847 if (previous_sectdiff == false) {848 if ((cputype == MachO::CPU_TYPE_ARM &&849 r_type == MachO::ARM_RELOC_PAIR))850 outs() << format(" half = 0x%04x ", (unsigned int)r_address);851 } else if (cputype == MachO::CPU_TYPE_ARM &&852 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)853 outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);854 if ((cputype == MachO::CPU_TYPE_I386 &&855 (r_type == MachO::GENERIC_RELOC_SECTDIFF ||856 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||857 (cputype == MachO::CPU_TYPE_ARM &&858 (sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||859 sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||860 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {861 previous_sectdiff = true;862 sectdiff_r_type = r_type;863 } else {864 previous_sectdiff = false;865 sectdiff_r_type = 0;866 }867 if (cputype == MachO::CPU_TYPE_ARM &&868 (r_type == MachO::ARM_RELOC_HALF ||869 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))870 previous_arm_half = true;871 else872 previous_arm_half = false;873 outs() << "\n";874 }875 else {876 // scattered: address pcrel length extern type scattered value877 outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",878 (unsigned int)r_address, r_pcrel, r_length, r_type,879 (unsigned int)r_value);880 }881 }882 else {883 if (verbose) {884 // plain: address885 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)886 outs() << " ";887 else888 outs() << format("%08x ", (unsigned int)r_address);889 890 // plain: pcrel891 if (r_pcrel)892 outs() << "True ";893 else894 outs() << "False ";895 896 // plain: length897 PrintRLength(cputype, r_type, r_length, previous_arm_half);898 899 if (r_extern) {900 // plain: extern & type & scattered901 outs() << "True ";902 PrintRType(cputype, r_type);903 outs() << "False ";904 905 // plain: symbolnum/value906 if (r_symbolnum > Symtab.nsyms)907 outs() << format("?(%d)\n", r_symbolnum);908 else {909 SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);910 Expected<StringRef> SymNameNext = Symbol.getName();911 const char *name = nullptr;912 if (SymNameNext)913 name = SymNameNext->data();914 if (name == nullptr)915 outs() << format("?(%d)\n", r_symbolnum);916 else917 outs() << name << "\n";918 }919 }920 else {921 // plain: extern & type & scattered922 outs() << "False ";923 PrintRType(cputype, r_type);924 outs() << "False ";925 926 // plain: symbolnum/value927 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)928 outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);929 else if ((cputype == MachO::CPU_TYPE_ARM64 ||930 cputype == MachO::CPU_TYPE_ARM64_32) &&931 r_type == MachO::ARM64_RELOC_ADDEND)932 outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);933 else {934 outs() << format("%d ", r_symbolnum);935 if (r_symbolnum == MachO::R_ABS)936 outs() << "R_ABS\n";937 else {938 // in this case, r_symbolnum is actually a 1-based section number939 uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;940 if (r_symbolnum > 0 && r_symbolnum <= nsects) {941 object::DataRefImpl DRI;942 DRI.d.a = r_symbolnum-1;943 StringRef SegName = O->getSectionFinalSegmentName(DRI);944 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))945 outs() << "(" << SegName << "," << *NameOrErr << ")\n";946 else947 outs() << "(?,?)\n";948 }949 else {950 outs() << "(?,?)\n";951 }952 }953 }954 }955 if (cputype == MachO::CPU_TYPE_ARM &&956 (r_type == MachO::ARM_RELOC_HALF ||957 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))958 previous_arm_half = true;959 else960 previous_arm_half = false;961 }962 else {963 // plain: address pcrel length extern type scattered symbolnum/section964 outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",965 (unsigned int)r_address, r_pcrel, r_length, r_extern,966 r_type, r_symbolnum);967 }968 }969 }970}971 972static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {973 const uint64_t cputype = O->getHeader().cputype;974 const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();975 if (Dysymtab.nextrel != 0) {976 outs() << "External relocation information " << Dysymtab.nextrel977 << " entries";978 outs() << "\naddress pcrel length extern type scattered "979 "symbolnum/value\n";980 PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,981 verbose);982 }983 if (Dysymtab.nlocrel != 0) {984 outs() << format("Local relocation information %u entries",985 Dysymtab.nlocrel);986 outs() << "\naddress pcrel length extern type scattered "987 "symbolnum/value\n";988 PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,989 verbose);990 }991 for (const auto &Load : O->load_commands()) {992 if (Load.C.cmd == MachO::LC_SEGMENT_64) {993 const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);994 for (unsigned J = 0; J < Seg.nsects; ++J) {995 const MachO::section_64 Sec = O->getSection64(Load, J);996 if (Sec.nreloc != 0) {997 DataRefImpl DRI;998 DRI.d.a = J;999 const StringRef SegName = O->getSectionFinalSegmentName(DRI);1000 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1001 outs() << "Relocation information (" << SegName << "," << *NameOrErr1002 << format(") %u entries", Sec.nreloc);1003 else1004 outs() << "Relocation information (" << SegName << ",?) "1005 << format("%u entries", Sec.nreloc);1006 outs() << "\naddress pcrel length extern type scattered "1007 "symbolnum/value\n";1008 PrintRelocationEntries(O, O->section_rel_begin(DRI),1009 O->section_rel_end(DRI), cputype, verbose);1010 }1011 }1012 } else if (Load.C.cmd == MachO::LC_SEGMENT) {1013 const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);1014 for (unsigned J = 0; J < Seg.nsects; ++J) {1015 const MachO::section Sec = O->getSection(Load, J);1016 if (Sec.nreloc != 0) {1017 DataRefImpl DRI;1018 DRI.d.a = J;1019 const StringRef SegName = O->getSectionFinalSegmentName(DRI);1020 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))1021 outs() << "Relocation information (" << SegName << "," << *NameOrErr1022 << format(") %u entries", Sec.nreloc);1023 else1024 outs() << "Relocation information (" << SegName << ",?) "1025 << format("%u entries", Sec.nreloc);1026 outs() << "\naddress pcrel length extern type scattered "1027 "symbolnum/value\n";1028 PrintRelocationEntries(O, O->section_rel_begin(DRI),1029 O->section_rel_end(DRI), cputype, verbose);1030 }1031 }1032 }1033 }1034}1035 1036static void PrintFunctionStarts(MachOObjectFile *O) {1037 uint64_t BaseSegmentAddress = 0;1038 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1039 if (Command.C.cmd == MachO::LC_SEGMENT) {1040 MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1041 if (StringRef(SLC.segname) == "__TEXT") {1042 BaseSegmentAddress = SLC.vmaddr;1043 break;1044 }1045 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1046 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1047 if (StringRef(SLC.segname) == "__TEXT") {1048 BaseSegmentAddress = SLC.vmaddr;1049 break;1050 }1051 }1052 }1053 1054 SmallVector<uint64_t, 8> FunctionStarts;1055 for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {1056 if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {1057 MachO::linkedit_data_command FunctionStartsLC =1058 O->getLinkeditDataLoadCommand(LC);1059 O->ReadULEB128s(FunctionStartsLC.dataoff, FunctionStarts);1060 break;1061 }1062 }1063 1064 DenseMap<uint64_t, StringRef> SymbolNames;1065 if (FunctionStartsType == FunctionStartsMode::Names ||1066 FunctionStartsType == FunctionStartsMode::Both) {1067 for (SymbolRef Sym : O->symbols()) {1068 if (Expected<uint64_t> Addr = Sym.getAddress()) {1069 if (Expected<StringRef> Name = Sym.getName()) {1070 SymbolNames[*Addr] = *Name;1071 }1072 }1073 }1074 }1075 1076 for (uint64_t S : FunctionStarts) {1077 uint64_t Addr = BaseSegmentAddress + S;1078 if (FunctionStartsType == FunctionStartsMode::Names) {1079 auto It = SymbolNames.find(Addr);1080 if (It != SymbolNames.end())1081 outs() << It->second << "\n";1082 } else {1083 if (O->is64Bit())1084 outs() << format("%016" PRIx64, Addr);1085 else1086 outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));1087 1088 if (FunctionStartsType == FunctionStartsMode::Both) {1089 auto It = SymbolNames.find(Addr);1090 if (It != SymbolNames.end())1091 outs() << " " << It->second;1092 else1093 outs() << " ?";1094 }1095 outs() << "\n";1096 }1097 }1098}1099 1100static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {1101 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();1102 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);1103 outs() << "Data in code table (" << nentries << " entries)\n";1104 outs() << "offset length kind\n";1105 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;1106 ++DI) {1107 uint32_t Offset;1108 DI->getOffset(Offset);1109 outs() << format("0x%08" PRIx32, Offset) << " ";1110 uint16_t Length;1111 DI->getLength(Length);1112 outs() << format("%6u", Length) << " ";1113 uint16_t Kind;1114 DI->getKind(Kind);1115 if (verbose) {1116 switch (Kind) {1117 case MachO::DICE_KIND_DATA:1118 outs() << "DATA";1119 break;1120 case MachO::DICE_KIND_JUMP_TABLE8:1121 outs() << "JUMP_TABLE8";1122 break;1123 case MachO::DICE_KIND_JUMP_TABLE16:1124 outs() << "JUMP_TABLE16";1125 break;1126 case MachO::DICE_KIND_JUMP_TABLE32:1127 outs() << "JUMP_TABLE32";1128 break;1129 case MachO::DICE_KIND_ABS_JUMP_TABLE32:1130 outs() << "ABS_JUMP_TABLE32";1131 break;1132 default:1133 outs() << format("0x%04" PRIx32, Kind);1134 break;1135 }1136 } else1137 outs() << format("0x%04" PRIx32, Kind);1138 outs() << "\n";1139 }1140}1141 1142static void PrintLinkOptHints(MachOObjectFile *O) {1143 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();1144 const char *loh = O->getData().substr(LohLC.dataoff, 1).data();1145 uint32_t nloh = LohLC.datasize;1146 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";1147 for (uint32_t i = 0; i < nloh;) {1148 unsigned n;1149 uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);1150 i += n;1151 outs() << " identifier " << identifier << " ";1152 if (i >= nloh)1153 return;1154 switch (identifier) {1155 case 1:1156 outs() << "AdrpAdrp\n";1157 break;1158 case 2:1159 outs() << "AdrpLdr\n";1160 break;1161 case 3:1162 outs() << "AdrpAddLdr\n";1163 break;1164 case 4:1165 outs() << "AdrpLdrGotLdr\n";1166 break;1167 case 5:1168 outs() << "AdrpAddStr\n";1169 break;1170 case 6:1171 outs() << "AdrpLdrGotStr\n";1172 break;1173 case 7:1174 outs() << "AdrpAdd\n";1175 break;1176 case 8:1177 outs() << "AdrpLdrGot\n";1178 break;1179 default:1180 outs() << "Unknown identifier value\n";1181 break;1182 }1183 uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);1184 i += n;1185 outs() << " narguments " << narguments << "\n";1186 if (i >= nloh)1187 return;1188 1189 for (uint32_t j = 0; j < narguments; j++) {1190 uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);1191 i += n;1192 outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";1193 if (i >= nloh)1194 return;1195 }1196 }1197}1198 1199static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {1200 SmallVector<std::string> Ret;1201 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {1202 if (Command.C.cmd == MachO::LC_SEGMENT) {1203 MachO::segment_command SLC = O->getSegmentLoadCommand(Command);1204 Ret.push_back(SLC.segname);1205 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {1206 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);1207 Ret.push_back(SLC.segname);1208 }1209 }1210 return Ret;1211}1212 1213static void1214PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {1215 outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";1216 outs() << " fixups_version = " << H.fixups_version << '\n';1217 outs() << " starts_offset = " << H.starts_offset << '\n';1218 outs() << " imports_offset = " << H.imports_offset << '\n';1219 outs() << " symbols_offset = " << H.symbols_offset << '\n';1220 outs() << " imports_count = " << H.imports_count << '\n';1221 1222 outs() << " imports_format = " << H.imports_format;1223 switch (H.imports_format) {1224 case llvm::MachO::DYLD_CHAINED_IMPORT:1225 outs() << " (DYLD_CHAINED_IMPORT)";1226 break;1227 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:1228 outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";1229 break;1230 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:1231 outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";1232 break;1233 }1234 outs() << '\n';1235 1236 outs() << " symbols_format = " << H.symbols_format;1237 if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)1238 outs() << " (zlib compressed)";1239 outs() << '\n';1240}1241 1242static constexpr std::array<StringRef, 13> PointerFormats{1243 "DYLD_CHAINED_PTR_ARM64E",1244 "DYLD_CHAINED_PTR_64",1245 "DYLD_CHAINED_PTR_32",1246 "DYLD_CHAINED_PTR_32_CACHE",1247 "DYLD_CHAINED_PTR_32_FIRMWARE",1248 "DYLD_CHAINED_PTR_64_OFFSET",1249 "DYLD_CHAINED_PTR_ARM64E_KERNEL",1250 "DYLD_CHAINED_PTR_64_KERNEL_CACHE",1251 "DYLD_CHAINED_PTR_ARM64E_USERLAND",1252 "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",1253 "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",1254 "DYLD_CHAINED_PTR_ARM64E_USERLAND24",1255};1256 1257static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,1258 StringRef SegName) {1259 outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName1260 << ")\n";1261 outs() << " size = " << Segment.Header.size << '\n';1262 outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)1263 << '\n';1264 1265 outs() << " pointer_format = " << Segment.Header.pointer_format;1266 if ((Segment.Header.pointer_format - 1) <1267 MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)1268 outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";1269 outs() << '\n';1270 1271 outs() << " segment_offset = "1272 << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';1273 outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer1274 << '\n';1275 outs() << " page_count = " << Segment.Header.page_count << '\n';1276 for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {1277 outs() << " page_start[" << Index << "] = " << PageStart;1278 // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)1279 if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)1280 outs() << " (DYLD_CHAINED_PTR_START_NONE)";1281 outs() << '\n';1282 }1283}1284 1285static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,1286 int Format, MachOObjectFile *O) {1287 if (Format == MachO::DYLD_CHAINED_IMPORT)1288 outs() << "dyld chained import";1289 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)1290 outs() << "dyld chained import addend";1291 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)1292 outs() << "dyld chained import addend64";1293 // FIXME: otool prints the encoded value as well.1294 outs() << '[' << Idx << "]\n";1295 1296 outs() << " lib_ordinal = " << Target.libOrdinal() << " ("1297 << ordinalName(O, Target.libOrdinal()) << ")\n";1298 outs() << " weak_import = " << Target.weakImport() << '\n';1299 outs() << " name_offset = " << Target.nameOffset() << " ("1300 << Target.symbolName() << ")\n";1301 if (Format != MachO::DYLD_CHAINED_IMPORT)1302 outs() << " addend = " << (int64_t)Target.addend() << '\n';1303}1304 1305static void PrintChainedFixups(MachOObjectFile *O) {1306 // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.1307 // FIXME: Support chained fixups in __TEXT,__chain_starts section too.1308 auto ChainedFixupHeader =1309 unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());1310 if (!ChainedFixupHeader)1311 return;1312 1313 PrintChainedFixupsHeader(*ChainedFixupHeader);1314 1315 auto [SegCount, Segments] =1316 unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());1317 1318 auto SegNames = GetSegmentNames(O);1319 1320 size_t StartsIdx = 0;1321 outs() << "chained starts in image\n";1322 outs() << " seg_count = " << SegCount << '\n';1323 for (size_t I = 0; I < SegCount; ++I) {1324 uint64_t SegOffset = 0;1325 if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {1326 SegOffset = Segments[StartsIdx].Offset;1327 ++StartsIdx;1328 }1329 1330 outs() << " seg_offset[" << I << "] = " << SegOffset << " ("1331 << SegNames[I] << ")\n";1332 }1333 1334 for (const ChainedFixupsSegment &S : Segments)1335 PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);1336 1337 auto FixupTargets =1338 unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());1339 1340 uint32_t ImportsFormat = ChainedFixupHeader->imports_format;1341 for (auto [Idx, Target] : enumerate(FixupTargets))1342 PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);1343}1344 1345static void PrintDyldInfo(MachOObjectFile *O) {1346 Error Err = Error::success();1347 1348 size_t SegmentWidth = strlen("segment");1349 size_t SectionWidth = strlen("section");1350 size_t AddressWidth = strlen("address");1351 size_t AddendWidth = strlen("addend");1352 size_t DylibWidth = strlen("dylib");1353 const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;1354 1355 auto HexLength = [](uint64_t Num) {1356 return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;1357 };1358 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1359 SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());1360 SectionWidth = std::max(SectionWidth, Entry.sectionName().size());1361 AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);1362 if (Entry.isBind()) {1363 AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);1364 DylibWidth = std::max(DylibWidth, Entry.symbolName().size());1365 }1366 }1367 // Errors will be handled when printing the table.1368 if (Err)1369 consumeError(std::move(Err));1370 1371 outs() << "dyld information:\n";1372 outs() << left_justify("segment", SegmentWidth) << ' '1373 << left_justify("section", SectionWidth) << ' '1374 << left_justify("address", AddressWidth) << ' '1375 << left_justify("pointer", PointerWidth) << " type "1376 << left_justify("addend", AddendWidth) << ' '1377 << left_justify("dylib", DylibWidth) << " symbol/vm address\n";1378 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {1379 outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '1380 << left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"1381 << left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '1382 << format_hex(Entry.rawValue(), PointerWidth, true) << ' ';1383 if (Entry.isBind()) {1384 outs() << "bind "1385 << "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)1386 << ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)1387 << ' ' << Entry.symbolName();1388 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)1389 outs() << " (weak import)";1390 outs() << '\n';1391 } else {1392 assert(Entry.isRebase());1393 outs() << "rebase";1394 outs().indent(AddendWidth + DylibWidth + 2);1395 outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';1396 }1397 }1398 if (Err)1399 reportError(std::move(Err), O->getFileName());1400 1401 // TODO: Print opcode-based fixups if the object uses those.1402}1403 1404static void PrintDylibs(MachOObjectFile *O, bool JustId) {1405 unsigned Index = 0;1406 for (const auto &Load : O->load_commands()) {1407 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||1408 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||1409 Load.C.cmd == MachO::LC_LOAD_DYLIB ||1410 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||1411 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||1412 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||1413 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {1414 MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);1415 if (dl.dylib.name < dl.cmdsize) {1416 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;1417 if (JustId)1418 outs() << p << "\n";1419 else {1420 outs() << "\t" << p;1421 outs() << " (compatibility version "1422 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."1423 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."1424 << (dl.dylib.compatibility_version & 0xff) << ",";1425 outs() << " current version "1426 << ((dl.dylib.current_version >> 16) & 0xffff) << "."1427 << ((dl.dylib.current_version >> 8) & 0xff) << "."1428 << (dl.dylib.current_version & 0xff);1429 if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1430 outs() << ", weak";1431 if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1432 outs() << ", reexport";1433 if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1434 outs() << ", upward";1435 if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1436 outs() << ", lazy";1437 outs() << ")\n";1438 }1439 } else {1440 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";1441 if (Load.C.cmd == MachO::LC_ID_DYLIB)1442 outs() << "LC_ID_DYLIB ";1443 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)1444 outs() << "LC_LOAD_DYLIB ";1445 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)1446 outs() << "LC_LOAD_WEAK_DYLIB ";1447 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)1448 outs() << "LC_LAZY_LOAD_DYLIB ";1449 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)1450 outs() << "LC_REEXPORT_DYLIB ";1451 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)1452 outs() << "LC_LOAD_UPWARD_DYLIB ";1453 else1454 outs() << "LC_??? ";1455 outs() << "command " << Index++ << "\n";1456 }1457 }1458 }1459}1460 1461static void printRpaths(MachOObjectFile *O) {1462 for (const auto &Command : O->load_commands()) {1463 if (Command.C.cmd == MachO::LC_RPATH) {1464 auto Rpath = O->getRpathCommand(Command);1465 const char *P = (const char *)(Command.Ptr) + Rpath.path;1466 outs() << P << "\n";1467 }1468 }1469}1470 1471typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;1472 1473static void CreateSymbolAddressMap(MachOObjectFile *O,1474 SymbolAddressMap *AddrMap) {1475 // Create a map of symbol addresses to symbol names.1476 const StringRef FileName = O->getFileName();1477 for (const SymbolRef &Symbol : O->symbols()) {1478 SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);1479 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||1480 ST == SymbolRef::ST_Other) {1481 uint64_t Address = cantFail(Symbol.getValue());1482 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);1483 if (!SymName.starts_with(".objc"))1484 (*AddrMap)[Address] = SymName;1485 }1486 }1487}1488 1489// GuessSymbolName is passed the address of what might be a symbol and a1490// pointer to the SymbolAddressMap. It returns the name of a symbol1491// with that address or nullptr if no symbol is found with that address.1492static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {1493 const char *SymbolName = nullptr;1494 // A DenseMap can't lookup up some values.1495 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {1496 StringRef name = AddrMap->lookup(value);1497 if (!name.empty())1498 SymbolName = name.data();1499 }1500 return SymbolName;1501}1502 1503static void DumpCstringChar(const char c) {1504 char p[2];1505 p[0] = c;1506 p[1] = '\0';1507 outs().write_escaped(p);1508}1509 1510static void DumpCstringSection(MachOObjectFile *O, const char *sect,1511 uint32_t sect_size, uint64_t sect_addr,1512 bool print_addresses) {1513 for (uint32_t i = 0; i < sect_size; i++) {1514 if (print_addresses) {1515 if (O->is64Bit())1516 outs() << format("%016" PRIx64, sect_addr + i) << " ";1517 else1518 outs() << format("%08" PRIx64, sect_addr + i) << " ";1519 }1520 for (; i < sect_size && sect[i] != '\0'; i++)1521 DumpCstringChar(sect[i]);1522 if (i < sect_size && sect[i] == '\0')1523 outs() << "\n";1524 }1525}1526 1527static void DumpLiteral4(uint32_t l, float f) {1528 outs() << format("0x%08" PRIx32, l);1529 if ((l & 0x7f800000) != 0x7f800000)1530 outs() << format(" (%.16e)\n", f);1531 else {1532 if (l == 0x7f800000)1533 outs() << " (+Infinity)\n";1534 else if (l == 0xff800000)1535 outs() << " (-Infinity)\n";1536 else if ((l & 0x00400000) == 0x00400000)1537 outs() << " (non-signaling Not-a-Number)\n";1538 else1539 outs() << " (signaling Not-a-Number)\n";1540 }1541}1542 1543static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,1544 uint32_t sect_size, uint64_t sect_addr,1545 bool print_addresses) {1546 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {1547 if (print_addresses) {1548 if (O->is64Bit())1549 outs() << format("%016" PRIx64, sect_addr + i) << " ";1550 else1551 outs() << format("%08" PRIx64, sect_addr + i) << " ";1552 }1553 float f;1554 memcpy(&f, sect + i, sizeof(float));1555 if (O->isLittleEndian() != sys::IsLittleEndianHost)1556 sys::swapByteOrder(f);1557 uint32_t l;1558 memcpy(&l, sect + i, sizeof(uint32_t));1559 if (O->isLittleEndian() != sys::IsLittleEndianHost)1560 sys::swapByteOrder(l);1561 DumpLiteral4(l, f);1562 }1563}1564 1565static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,1566 double d) {1567 outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);1568 uint32_t Hi, Lo;1569 Hi = (O->isLittleEndian()) ? l1 : l0;1570 Lo = (O->isLittleEndian()) ? l0 : l1;1571 1572 // Hi is the high word, so this is equivalent to if(isfinite(d))1573 if ((Hi & 0x7ff00000) != 0x7ff00000)1574 outs() << format(" (%.16e)\n", d);1575 else {1576 if (Hi == 0x7ff00000 && Lo == 0)1577 outs() << " (+Infinity)\n";1578 else if (Hi == 0xfff00000 && Lo == 0)1579 outs() << " (-Infinity)\n";1580 else if ((Hi & 0x00080000) == 0x00080000)1581 outs() << " (non-signaling Not-a-Number)\n";1582 else1583 outs() << " (signaling Not-a-Number)\n";1584 }1585}1586 1587static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,1588 uint32_t sect_size, uint64_t sect_addr,1589 bool print_addresses) {1590 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {1591 if (print_addresses) {1592 if (O->is64Bit())1593 outs() << format("%016" PRIx64, sect_addr + i) << " ";1594 else1595 outs() << format("%08" PRIx64, sect_addr + i) << " ";1596 }1597 double d;1598 memcpy(&d, sect + i, sizeof(double));1599 if (O->isLittleEndian() != sys::IsLittleEndianHost)1600 sys::swapByteOrder(d);1601 uint32_t l0, l1;1602 memcpy(&l0, sect + i, sizeof(uint32_t));1603 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1604 if (O->isLittleEndian() != sys::IsLittleEndianHost) {1605 sys::swapByteOrder(l0);1606 sys::swapByteOrder(l1);1607 }1608 DumpLiteral8(O, l0, l1, d);1609 }1610}1611 1612static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {1613 outs() << format("0x%08" PRIx32, l0) << " ";1614 outs() << format("0x%08" PRIx32, l1) << " ";1615 outs() << format("0x%08" PRIx32, l2) << " ";1616 outs() << format("0x%08" PRIx32, l3) << "\n";1617}1618 1619static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,1620 uint32_t sect_size, uint64_t sect_addr,1621 bool print_addresses) {1622 for (uint32_t i = 0; i < sect_size; i += 16) {1623 if (print_addresses) {1624 if (O->is64Bit())1625 outs() << format("%016" PRIx64, sect_addr + i) << " ";1626 else1627 outs() << format("%08" PRIx64, sect_addr + i) << " ";1628 }1629 uint32_t l0, l1, l2, l3;1630 memcpy(&l0, sect + i, sizeof(uint32_t));1631 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));1632 memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));1633 memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));1634 if (O->isLittleEndian() != sys::IsLittleEndianHost) {1635 sys::swapByteOrder(l0);1636 sys::swapByteOrder(l1);1637 sys::swapByteOrder(l2);1638 sys::swapByteOrder(l3);1639 }1640 DumpLiteral16(l0, l1, l2, l3);1641 }1642}1643 1644static void DumpLiteralPointerSection(MachOObjectFile *O,1645 const SectionRef &Section,1646 const char *sect, uint32_t sect_size,1647 uint64_t sect_addr,1648 bool print_addresses) {1649 // Collect the literal sections in this Mach-O file.1650 std::vector<SectionRef> LiteralSections;1651 for (const SectionRef &Section : O->sections()) {1652 DataRefImpl Ref = Section.getRawDataRefImpl();1653 uint32_t section_type;1654 if (O->is64Bit()) {1655 const MachO::section_64 Sec = O->getSection64(Ref);1656 section_type = Sec.flags & MachO::SECTION_TYPE;1657 } else {1658 const MachO::section Sec = O->getSection(Ref);1659 section_type = Sec.flags & MachO::SECTION_TYPE;1660 }1661 if (section_type == MachO::S_CSTRING_LITERALS ||1662 section_type == MachO::S_4BYTE_LITERALS ||1663 section_type == MachO::S_8BYTE_LITERALS ||1664 section_type == MachO::S_16BYTE_LITERALS)1665 LiteralSections.push_back(Section);1666 }1667 1668 // Set the size of the literal pointer.1669 uint32_t lp_size = O->is64Bit() ? 8 : 4;1670 1671 // Collect the external relocation symbols for the literal pointers.1672 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1673 for (const RelocationRef &Reloc : Section.relocations()) {1674 DataRefImpl Rel;1675 MachO::any_relocation_info RE;1676 bool isExtern = false;1677 Rel = Reloc.getRawDataRefImpl();1678 RE = O->getRelocation(Rel);1679 isExtern = O->getPlainRelocationExternal(RE);1680 if (isExtern) {1681 uint64_t RelocOffset = Reloc.getOffset();1682 symbol_iterator RelocSym = Reloc.getSymbol();1683 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1684 }1685 }1686 array_pod_sort(Relocs.begin(), Relocs.end());1687 1688 // Dump each literal pointer.1689 for (uint32_t i = 0; i < sect_size; i += lp_size) {1690 if (print_addresses) {1691 if (O->is64Bit())1692 outs() << format("%016" PRIx64, sect_addr + i) << " ";1693 else1694 outs() << format("%08" PRIx64, sect_addr + i) << " ";1695 }1696 uint64_t lp;1697 if (O->is64Bit()) {1698 memcpy(&lp, sect + i, sizeof(uint64_t));1699 if (O->isLittleEndian() != sys::IsLittleEndianHost)1700 sys::swapByteOrder(lp);1701 } else {1702 uint32_t li;1703 memcpy(&li, sect + i, sizeof(uint32_t));1704 if (O->isLittleEndian() != sys::IsLittleEndianHost)1705 sys::swapByteOrder(li);1706 lp = li;1707 }1708 1709 // First look for an external relocation entry for this literal pointer.1710 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1711 return P.first == i;1712 });1713 if (Reloc != Relocs.end()) {1714 symbol_iterator RelocSym = Reloc->second;1715 StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());1716 outs() << "external relocation entry for symbol:" << SymName << "\n";1717 continue;1718 }1719 1720 // For local references see what the section the literal pointer points to.1721 auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {1722 return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();1723 });1724 if (Sect == LiteralSections.end()) {1725 outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";1726 continue;1727 }1728 1729 uint64_t SectAddress = Sect->getAddress();1730 uint64_t SectSize = Sect->getSize();1731 1732 StringRef SectName;1733 Expected<StringRef> SectNameOrErr = Sect->getName();1734 if (SectNameOrErr)1735 SectName = *SectNameOrErr;1736 else1737 consumeError(SectNameOrErr.takeError());1738 1739 DataRefImpl Ref = Sect->getRawDataRefImpl();1740 StringRef SegmentName = O->getSectionFinalSegmentName(Ref);1741 outs() << SegmentName << ":" << SectName << ":";1742 1743 uint32_t section_type;1744 if (O->is64Bit()) {1745 const MachO::section_64 Sec = O->getSection64(Ref);1746 section_type = Sec.flags & MachO::SECTION_TYPE;1747 } else {1748 const MachO::section Sec = O->getSection(Ref);1749 section_type = Sec.flags & MachO::SECTION_TYPE;1750 }1751 1752 StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());1753 1754 const char *Contents = BytesStr.data();1755 1756 switch (section_type) {1757 case MachO::S_CSTRING_LITERALS:1758 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';1759 i++) {1760 DumpCstringChar(Contents[i]);1761 }1762 outs() << "\n";1763 break;1764 case MachO::S_4BYTE_LITERALS:1765 float f;1766 memcpy(&f, Contents + (lp - SectAddress), sizeof(float));1767 uint32_t l;1768 memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));1769 if (O->isLittleEndian() != sys::IsLittleEndianHost) {1770 sys::swapByteOrder(f);1771 sys::swapByteOrder(l);1772 }1773 DumpLiteral4(l, f);1774 break;1775 case MachO::S_8BYTE_LITERALS: {1776 double d;1777 memcpy(&d, Contents + (lp - SectAddress), sizeof(double));1778 uint32_t l0, l1;1779 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1780 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1781 sizeof(uint32_t));1782 if (O->isLittleEndian() != sys::IsLittleEndianHost) {1783 sys::swapByteOrder(f);1784 sys::swapByteOrder(l0);1785 sys::swapByteOrder(l1);1786 }1787 DumpLiteral8(O, l0, l1, d);1788 break;1789 }1790 case MachO::S_16BYTE_LITERALS: {1791 uint32_t l0, l1, l2, l3;1792 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));1793 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),1794 sizeof(uint32_t));1795 memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),1796 sizeof(uint32_t));1797 memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),1798 sizeof(uint32_t));1799 if (O->isLittleEndian() != sys::IsLittleEndianHost) {1800 sys::swapByteOrder(l0);1801 sys::swapByteOrder(l1);1802 sys::swapByteOrder(l2);1803 sys::swapByteOrder(l3);1804 }1805 DumpLiteral16(l0, l1, l2, l3);1806 break;1807 }1808 }1809 }1810}1811 1812static void DumpInitTermPointerSection(MachOObjectFile *O,1813 const SectionRef &Section,1814 const char *sect,1815 uint32_t sect_size, uint64_t sect_addr,1816 SymbolAddressMap *AddrMap,1817 bool verbose) {1818 uint32_t stride;1819 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);1820 1821 // Collect the external relocation symbols for the pointers.1822 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;1823 for (const RelocationRef &Reloc : Section.relocations()) {1824 DataRefImpl Rel;1825 MachO::any_relocation_info RE;1826 bool isExtern = false;1827 Rel = Reloc.getRawDataRefImpl();1828 RE = O->getRelocation(Rel);1829 isExtern = O->getPlainRelocationExternal(RE);1830 if (isExtern) {1831 uint64_t RelocOffset = Reloc.getOffset();1832 symbol_iterator RelocSym = Reloc.getSymbol();1833 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));1834 }1835 }1836 array_pod_sort(Relocs.begin(), Relocs.end());1837 1838 for (uint32_t i = 0; i < sect_size; i += stride) {1839 const char *SymbolName = nullptr;1840 uint64_t p;1841 if (O->is64Bit()) {1842 outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";1843 uint64_t pointer_value;1844 memcpy(&pointer_value, sect + i, stride);1845 if (O->isLittleEndian() != sys::IsLittleEndianHost)1846 sys::swapByteOrder(pointer_value);1847 outs() << format("0x%016" PRIx64, pointer_value);1848 p = pointer_value;1849 } else {1850 outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";1851 uint32_t pointer_value;1852 memcpy(&pointer_value, sect + i, stride);1853 if (O->isLittleEndian() != sys::IsLittleEndianHost)1854 sys::swapByteOrder(pointer_value);1855 outs() << format("0x%08" PRIx32, pointer_value);1856 p = pointer_value;1857 }1858 if (verbose) {1859 // First look for an external relocation entry for this pointer.1860 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {1861 return P.first == i;1862 });1863 if (Reloc != Relocs.end()) {1864 symbol_iterator RelocSym = Reloc->second;1865 outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());1866 } else {1867 SymbolName = GuessSymbolName(p, AddrMap);1868 if (SymbolName)1869 outs() << " " << SymbolName;1870 }1871 }1872 outs() << "\n";1873 }1874}1875 1876static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,1877 uint32_t size, uint64_t addr) {1878 uint32_t cputype = O->getHeader().cputype;1879 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {1880 uint32_t j;1881 for (uint32_t i = 0; i < size; i += j, addr += j) {1882 if (O->is64Bit())1883 outs() << format("%016" PRIx64, addr) << "\t";1884 else1885 outs() << format("%08" PRIx64, addr) << "\t";1886 for (j = 0; j < 16 && i + j < size; j++) {1887 uint8_t byte_word = *(sect + i + j);1888 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1889 }1890 outs() << "\n";1891 }1892 } else {1893 uint32_t j;1894 for (uint32_t i = 0; i < size; i += j, addr += j) {1895 if (O->is64Bit())1896 outs() << format("%016" PRIx64, addr) << "\t";1897 else1898 outs() << format("%08" PRIx64, addr) << "\t";1899 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;1900 j += sizeof(int32_t)) {1901 if (i + j + sizeof(int32_t) <= size) {1902 uint32_t long_word;1903 memcpy(&long_word, sect + i + j, sizeof(int32_t));1904 if (O->isLittleEndian() != sys::IsLittleEndianHost)1905 sys::swapByteOrder(long_word);1906 outs() << format("%08" PRIx32, long_word) << " ";1907 } else {1908 for (uint32_t k = 0; i + j + k < size; k++) {1909 uint8_t byte_word = *(sect + i + j + k);1910 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";1911 }1912 }1913 }1914 outs() << "\n";1915 }1916 }1917}1918 1919static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,1920 StringRef DisSegName, StringRef DisSectName);1921static void DumpProtocolSection(MachOObjectFile *O, const char *sect,1922 uint32_t size, uint32_t addr);1923static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,1924 bool verbose) {1925 SymbolAddressMap AddrMap;1926 if (verbose)1927 CreateSymbolAddressMap(O, &AddrMap);1928 1929 for (unsigned i = 0; i < FilterSections.size(); ++i) {1930 StringRef DumpSection = FilterSections[i];1931 std::pair<StringRef, StringRef> DumpSegSectName;1932 DumpSegSectName = DumpSection.split(',');1933 StringRef DumpSegName, DumpSectName;1934 if (!DumpSegSectName.second.empty()) {1935 DumpSegName = DumpSegSectName.first;1936 DumpSectName = DumpSegSectName.second;1937 } else {1938 DumpSegName = "";1939 DumpSectName = DumpSegSectName.first;1940 }1941 for (const SectionRef &Section : O->sections()) {1942 StringRef SectName;1943 Expected<StringRef> SecNameOrErr = Section.getName();1944 if (SecNameOrErr)1945 SectName = *SecNameOrErr;1946 else1947 consumeError(SecNameOrErr.takeError());1948 1949 if (!DumpSection.empty())1950 FoundSectionSet.insert(DumpSection);1951 1952 DataRefImpl Ref = Section.getRawDataRefImpl();1953 StringRef SegName = O->getSectionFinalSegmentName(Ref);1954 if ((DumpSegName.empty() || SegName == DumpSegName) &&1955 (SectName == DumpSectName)) {1956 1957 uint32_t section_flags;1958 if (O->is64Bit()) {1959 const MachO::section_64 Sec = O->getSection64(Ref);1960 section_flags = Sec.flags;1961 1962 } else {1963 const MachO::section Sec = O->getSection(Ref);1964 section_flags = Sec.flags;1965 }1966 uint32_t section_type = section_flags & MachO::SECTION_TYPE;1967 1968 StringRef BytesStr =1969 unwrapOrError(Section.getContents(), O->getFileName());1970 const char *sect = BytesStr.data();1971 uint32_t sect_size = BytesStr.size();1972 uint64_t sect_addr = Section.getAddress();1973 1974 if (LeadingHeaders)1975 outs() << "Contents of (" << SegName << "," << SectName1976 << ") section\n";1977 1978 if (verbose) {1979 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||1980 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {1981 DisassembleMachO(Filename, O, SegName, SectName);1982 continue;1983 }1984 if (SegName == "__TEXT" && SectName == "__info_plist") {1985 outs() << sect;1986 continue;1987 }1988 if (SegName == "__OBJC" && SectName == "__protocol") {1989 DumpProtocolSection(O, sect, sect_size, sect_addr);1990 continue;1991 }1992 switch (section_type) {1993 case MachO::S_REGULAR:1994 DumpRawSectionContents(O, sect, sect_size, sect_addr);1995 break;1996 case MachO::S_ZEROFILL:1997 outs() << "zerofill section and has no contents in the file\n";1998 break;1999 case MachO::S_CSTRING_LITERALS:2000 DumpCstringSection(O, sect, sect_size, sect_addr, LeadingAddr);2001 break;2002 case MachO::S_4BYTE_LITERALS:2003 DumpLiteral4Section(O, sect, sect_size, sect_addr, LeadingAddr);2004 break;2005 case MachO::S_8BYTE_LITERALS:2006 DumpLiteral8Section(O, sect, sect_size, sect_addr, LeadingAddr);2007 break;2008 case MachO::S_16BYTE_LITERALS:2009 DumpLiteral16Section(O, sect, sect_size, sect_addr, LeadingAddr);2010 break;2011 case MachO::S_LITERAL_POINTERS:2012 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,2013 LeadingAddr);2014 break;2015 case MachO::S_MOD_INIT_FUNC_POINTERS:2016 case MachO::S_MOD_TERM_FUNC_POINTERS:2017 DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,2018 &AddrMap, verbose);2019 break;2020 default:2021 outs() << "Unknown section type ("2022 << format("0x%08" PRIx32, section_type) << ")\n";2023 DumpRawSectionContents(O, sect, sect_size, sect_addr);2024 break;2025 }2026 } else {2027 if (section_type == MachO::S_ZEROFILL)2028 outs() << "zerofill section and has no contents in the file\n";2029 else2030 DumpRawSectionContents(O, sect, sect_size, sect_addr);2031 }2032 }2033 }2034 }2035}2036 2037static void DumpInfoPlistSectionContents(StringRef Filename,2038 MachOObjectFile *O) {2039 for (const SectionRef &Section : O->sections()) {2040 StringRef SectName;2041 Expected<StringRef> SecNameOrErr = Section.getName();2042 if (SecNameOrErr)2043 SectName = *SecNameOrErr;2044 else2045 consumeError(SecNameOrErr.takeError());2046 2047 DataRefImpl Ref = Section.getRawDataRefImpl();2048 StringRef SegName = O->getSectionFinalSegmentName(Ref);2049 if (SegName == "__TEXT" && SectName == "__info_plist") {2050 if (LeadingHeaders)2051 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";2052 StringRef BytesStr =2053 unwrapOrError(Section.getContents(), O->getFileName());2054 const char *sect = BytesStr.data();2055 outs() << format("%.*s", BytesStr.size(), sect) << "\n";2056 return;2057 }2058 }2059}2060 2061// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file2062// and if it is and there is a list of architecture flags is specified then2063// check to make sure this Mach-O file is one of those architectures or all2064// architectures were specified. If not then an error is generated and this2065// routine returns false. Else it returns true.2066static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {2067 auto *MachO = dyn_cast<MachOObjectFile>(O);2068 2069 if (!MachO || ArchAll || ArchFlags.empty())2070 return true;2071 2072 MachO::mach_header H;2073 MachO::mach_header_64 H_64;2074 Triple T;2075 const char *McpuDefault, *ArchFlag;2076 if (MachO->is64Bit()) {2077 H_64 = MachO->MachOObjectFile::getHeader64();2078 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,2079 &McpuDefault, &ArchFlag);2080 } else {2081 H = MachO->MachOObjectFile::getHeader();2082 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,2083 &McpuDefault, &ArchFlag);2084 }2085 const std::string ArchFlagName(ArchFlag);2086 if (!llvm::is_contained(ArchFlags, ArchFlagName)) {2087 WithColor::error(errs(), "llvm-objdump")2088 << Filename << ": no architecture specified.\n";2089 return false;2090 }2091 return true;2092}2093 2094static void printObjcMetaData(MachOObjectFile *O, bool verbose);2095 2096// ProcessMachO() is passed a single opened Mach-O file, which may be an2097// archive member and or in a slice of a universal file. It prints the2098// the file name and header info and then processes it according to the2099// command line options.2100static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,2101 StringRef ArchiveMemberName = StringRef(),2102 StringRef ArchitectureName = StringRef()) {2103 std::unique_ptr<Dumper> D = createMachODumper(*MachOOF);2104 2105 // If we are doing some processing here on the Mach-O file print the header2106 // info. And don't print it otherwise like in the case of printing the2107 // UniversalHeaders or ArchiveHeaders.2108 if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||2109 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||2110 DataInCode || FunctionStartsType != FunctionStartsMode::None ||2111 LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||2112 Rpaths || ObjcMetaData || (!FilterSections.empty())) {2113 if (LeadingHeaders) {2114 outs() << Name;2115 if (!ArchiveMemberName.empty())2116 outs() << '(' << ArchiveMemberName << ')';2117 if (!ArchitectureName.empty())2118 outs() << " (architecture " << ArchitectureName << ")";2119 outs() << ":\n";2120 }2121 }2122 // To use the report_error() form with an ArchiveName and FileName set2123 // these up based on what is passed for Name and ArchiveMemberName.2124 StringRef ArchiveName;2125 StringRef FileName;2126 if (!ArchiveMemberName.empty()) {2127 ArchiveName = Name;2128 FileName = ArchiveMemberName;2129 } else {2130 ArchiveName = StringRef();2131 FileName = Name;2132 }2133 2134 // If we need the symbol table to do the operation then check it here to2135 // produce a good error message as to where the Mach-O file comes from in2136 // the error message.2137 if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)2138 if (Error Err = MachOOF->checkSymbolTable())2139 reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);2140 2141 if (DisassembleAll) {2142 for (const SectionRef &Section : MachOOF->sections()) {2143 StringRef SectName;2144 if (Expected<StringRef> NameOrErr = Section.getName())2145 SectName = *NameOrErr;2146 else2147 consumeError(NameOrErr.takeError());2148 2149 if (SectName == "__text") {2150 DataRefImpl Ref = Section.getRawDataRefImpl();2151 StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);2152 DisassembleMachO(FileName, MachOOF, SegName, SectName);2153 }2154 }2155 }2156 else if (Disassemble) {2157 if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&2158 MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)2159 DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");2160 else2161 DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");2162 }2163 if (IndirectSymbols)2164 PrintIndirectSymbols(MachOOF, Verbose);2165 if (DataInCode)2166 PrintDataInCodeTable(MachOOF, Verbose);2167 if (FunctionStartsType != FunctionStartsMode::None)2168 PrintFunctionStarts(MachOOF);2169 if (LinkOptHints)2170 PrintLinkOptHints(MachOOF);2171 if (Relocations)2172 PrintRelocations(MachOOF, Verbose);2173 if (SectionHeaders)2174 printSectionHeaders(*MachOOF);2175 if (SectionContents)2176 printSectionContents(MachOOF);2177 if (!FilterSections.empty())2178 DumpSectionContents(FileName, MachOOF, Verbose);2179 if (InfoPlist)2180 DumpInfoPlistSectionContents(FileName, MachOOF);2181 if (DyldInfo)2182 PrintDyldInfo(MachOOF);2183 if (ChainedFixups)2184 PrintChainedFixups(MachOOF);2185 if (DylibsUsed)2186 PrintDylibs(MachOOF, false);2187 if (DylibId)2188 PrintDylibs(MachOOF, true);2189 if (SymbolTable)2190 D->printSymbolTable(ArchiveName, ArchitectureName);2191 if (UnwindInfo)2192 printMachOUnwindInfo(MachOOF);2193 if (PrivateHeaders) {2194 printMachOFileHeader(MachOOF);2195 printMachOLoadCommands(MachOOF);2196 }2197 if (FirstPrivateHeader)2198 printMachOFileHeader(MachOOF);2199 if (ObjcMetaData)2200 printObjcMetaData(MachOOF, Verbose);2201 if (ExportsTrie)2202 printExportsTrie(MachOOF);2203 if (Rebase)2204 printRebaseTable(MachOOF);2205 if (Rpaths)2206 printRpaths(MachOOF);2207 if (Bind)2208 printBindTable(MachOOF);2209 if (LazyBind)2210 printLazyBindTable(MachOOF);2211 if (WeakBind)2212 printWeakBindTable(MachOOF);2213 2214 if (DwarfDumpType != DIDT_Null) {2215 std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);2216 // Dump the complete DWARF structure.2217 DIDumpOptions DumpOpts;2218 DumpOpts.DumpType = DwarfDumpType;2219 DICtx->dump(outs(), DumpOpts);2220 }2221}2222 2223// printUnknownCPUType() helps print_fat_headers for unknown CPU's.2224static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {2225 outs() << " cputype (" << cputype << ")\n";2226 outs() << " cpusubtype (" << cpusubtype << ")\n";2227}2228 2229// printCPUType() helps print_fat_headers by printing the cputype and2230// pusubtype (symbolically for the one's it knows about).2231static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {2232 switch (cputype) {2233 case MachO::CPU_TYPE_I386:2234 switch (cpusubtype) {2235 case MachO::CPU_SUBTYPE_I386_ALL:2236 outs() << " cputype CPU_TYPE_I386\n";2237 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";2238 break;2239 default:2240 printUnknownCPUType(cputype, cpusubtype);2241 break;2242 }2243 break;2244 case MachO::CPU_TYPE_X86_64:2245 switch (cpusubtype) {2246 case MachO::CPU_SUBTYPE_X86_64_ALL:2247 outs() << " cputype CPU_TYPE_X86_64\n";2248 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";2249 break;2250 case MachO::CPU_SUBTYPE_X86_64_H:2251 outs() << " cputype CPU_TYPE_X86_64\n";2252 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";2253 break;2254 default:2255 printUnknownCPUType(cputype, cpusubtype);2256 break;2257 }2258 break;2259 case MachO::CPU_TYPE_ARM:2260 switch (cpusubtype) {2261 case MachO::CPU_SUBTYPE_ARM_ALL:2262 outs() << " cputype CPU_TYPE_ARM\n";2263 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";2264 break;2265 case MachO::CPU_SUBTYPE_ARM_V4T:2266 outs() << " cputype CPU_TYPE_ARM\n";2267 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";2268 break;2269 case MachO::CPU_SUBTYPE_ARM_V5TEJ:2270 outs() << " cputype CPU_TYPE_ARM\n";2271 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";2272 break;2273 case MachO::CPU_SUBTYPE_ARM_XSCALE:2274 outs() << " cputype CPU_TYPE_ARM\n";2275 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";2276 break;2277 case MachO::CPU_SUBTYPE_ARM_V6:2278 outs() << " cputype CPU_TYPE_ARM\n";2279 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";2280 break;2281 case MachO::CPU_SUBTYPE_ARM_V6M:2282 outs() << " cputype CPU_TYPE_ARM\n";2283 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";2284 break;2285 case MachO::CPU_SUBTYPE_ARM_V7:2286 outs() << " cputype CPU_TYPE_ARM\n";2287 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";2288 break;2289 case MachO::CPU_SUBTYPE_ARM_V7EM:2290 outs() << " cputype CPU_TYPE_ARM\n";2291 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";2292 break;2293 case MachO::CPU_SUBTYPE_ARM_V7K:2294 outs() << " cputype CPU_TYPE_ARM\n";2295 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";2296 break;2297 case MachO::CPU_SUBTYPE_ARM_V7M:2298 outs() << " cputype CPU_TYPE_ARM\n";2299 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";2300 break;2301 case MachO::CPU_SUBTYPE_ARM_V7S:2302 outs() << " cputype CPU_TYPE_ARM\n";2303 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";2304 break;2305 default:2306 printUnknownCPUType(cputype, cpusubtype);2307 break;2308 }2309 break;2310 case MachO::CPU_TYPE_ARM64:2311 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2312 case MachO::CPU_SUBTYPE_ARM64_ALL:2313 outs() << " cputype CPU_TYPE_ARM64\n";2314 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";2315 break;2316 case MachO::CPU_SUBTYPE_ARM64_V8:2317 outs() << " cputype CPU_TYPE_ARM64\n";2318 outs() << " cpusubtype CPU_SUBTYPE_ARM64_V8\n";2319 break;2320 case MachO::CPU_SUBTYPE_ARM64E:2321 outs() << " cputype CPU_TYPE_ARM64\n";2322 outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";2323 break;2324 default:2325 printUnknownCPUType(cputype, cpusubtype);2326 break;2327 }2328 break;2329 case MachO::CPU_TYPE_ARM64_32:2330 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {2331 case MachO::CPU_SUBTYPE_ARM64_32_V8:2332 outs() << " cputype CPU_TYPE_ARM64_32\n";2333 outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";2334 break;2335 default:2336 printUnknownCPUType(cputype, cpusubtype);2337 break;2338 }2339 break;2340 default:2341 printUnknownCPUType(cputype, cpusubtype);2342 break;2343 }2344}2345 2346static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,2347 bool verbose) {2348 outs() << "Fat headers\n";2349 if (verbose) {2350 if (UB->getMagic() == MachO::FAT_MAGIC)2351 outs() << "fat_magic FAT_MAGIC\n";2352 else // UB->getMagic() == MachO::FAT_MAGIC_642353 outs() << "fat_magic FAT_MAGIC_64\n";2354 } else2355 outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";2356 2357 uint32_t nfat_arch = UB->getNumberOfObjects();2358 StringRef Buf = UB->getData();2359 uint64_t size = Buf.size();2360 uint64_t big_size = sizeof(struct MachO::fat_header) +2361 nfat_arch * sizeof(struct MachO::fat_arch);2362 outs() << "nfat_arch " << UB->getNumberOfObjects();2363 if (nfat_arch == 0)2364 outs() << " (malformed, contains zero architecture types)\n";2365 else if (big_size > size)2366 outs() << " (malformed, architectures past end of file)\n";2367 else2368 outs() << "\n";2369 2370 for (uint32_t i = 0; i < nfat_arch; ++i) {2371 MachOUniversalBinary::ObjectForArch OFA(UB, i);2372 uint32_t cputype = OFA.getCPUType();2373 uint32_t cpusubtype = OFA.getCPUSubType();2374 outs() << "architecture ";2375 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {2376 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);2377 uint32_t other_cputype = other_OFA.getCPUType();2378 uint32_t other_cpusubtype = other_OFA.getCPUSubType();2379 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&2380 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==2381 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {2382 outs() << "(illegal duplicate architecture) ";2383 break;2384 }2385 }2386 if (verbose) {2387 outs() << OFA.getArchFlagName() << "\n";2388 printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);2389 } else {2390 outs() << i << "\n";2391 outs() << " cputype " << cputype << "\n";2392 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)2393 << "\n";2394 }2395 if (verbose && cputype == MachO::CPU_TYPE_ARM64 &&2396 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {2397 outs() << " capabilities CPU_SUBTYPE_ARM64E_";2398 if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype))2399 outs() << "KERNEL_";2400 outs() << format("PTRAUTH_VERSION %d",2401 MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype))2402 << "\n";2403 } else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) ==2404 MachO::CPU_SUBTYPE_LIB64)2405 outs() << " capabilities CPU_SUBTYPE_LIB64\n";2406 else2407 outs() << " capabilities "2408 << format("0x%" PRIx32,2409 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";2410 outs() << " offset " << OFA.getOffset();2411 if (OFA.getOffset() > size)2412 outs() << " (past end of file)";2413 if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)2414 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";2415 outs() << "\n";2416 outs() << " size " << OFA.getSize();2417 big_size = OFA.getOffset() + OFA.getSize();2418 if (big_size > size)2419 outs() << " (past end of file)";2420 outs() << "\n";2421 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())2422 << ")\n";2423 }2424}2425 2426static void printArchiveChild(StringRef Filename, const Archive::Child &C,2427 size_t ChildIndex, bool verbose,2428 bool print_offset,2429 StringRef ArchitectureName = StringRef()) {2430 if (print_offset)2431 outs() << C.getChildOffset() << "\t";2432 sys::fs::perms Mode =2433 unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex),2434 Filename, ArchitectureName);2435 if (verbose) {2436 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.2437 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.2438 outs() << "-";2439 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");2440 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");2441 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");2442 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");2443 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");2444 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");2445 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");2446 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");2447 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");2448 } else {2449 outs() << format("0%o ", Mode);2450 }2451 2452 outs() << format("%3d/%-3d %5" PRId64 " ",2453 unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex),2454 Filename, ArchitectureName),2455 unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex),2456 Filename, ArchitectureName),2457 unwrapOrError(C.getRawSize(),2458 getFileNameForError(C, ChildIndex), Filename,2459 ArchitectureName));2460 2461 StringRef RawLastModified = C.getRawLastModified();2462 if (verbose) {2463 unsigned Seconds;2464 if (RawLastModified.getAsInteger(10, Seconds))2465 outs() << "(date: \"" << RawLastModified2466 << "\" contains non-decimal chars) ";2467 else {2468 // Since cime(3) returns a 26 character string of the form:2469 // "Sun Sep 16 01:03:52 1973\n\0"2470 // just print 24 characters.2471 time_t t = Seconds;2472 outs() << format("%.24s ", ctime(&t));2473 }2474 } else {2475 outs() << RawLastModified << " ";2476 }2477 2478 if (verbose) {2479 Expected<StringRef> NameOrErr = C.getName();2480 if (!NameOrErr) {2481 consumeError(NameOrErr.takeError());2482 outs() << unwrapOrError(C.getRawName(),2483 getFileNameForError(C, ChildIndex), Filename,2484 ArchitectureName)2485 << "\n";2486 } else {2487 StringRef Name = NameOrErr.get();2488 outs() << Name << "\n";2489 }2490 } else {2491 outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex),2492 Filename, ArchitectureName)2493 << "\n";2494 }2495}2496 2497static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,2498 bool print_offset,2499 StringRef ArchitectureName = StringRef()) {2500 Error Err = Error::success();2501 size_t I = 0;2502 for (const auto &C : A->children(Err, false))2503 printArchiveChild(Filename, C, I++, verbose, print_offset,2504 ArchitectureName);2505 2506 if (Err)2507 reportError(std::move(Err), Filename, "", ArchitectureName);2508}2509 2510static bool ValidateArchFlags() {2511 // Check for -arch all and verifiy the -arch flags are valid.2512 for (unsigned i = 0; i < ArchFlags.size(); ++i) {2513 if (ArchFlags[i] == "all") {2514 ArchAll = true;2515 } else {2516 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {2517 WithColor::error(errs(), "llvm-objdump")2518 << "unknown architecture named '" + ArchFlags[i] +2519 "'for the -arch option\n";2520 return false;2521 }2522 }2523 }2524 return true;2525}2526 2527// ParseInputMachO() parses the named Mach-O file in Filename and handles the2528// -arch flags selecting just those slices as specified by them and also parses2529// archive files. Then for each individual Mach-O file ProcessMachO() is2530// called to process the file based on the command line options.2531void objdump::parseInputMachO(StringRef Filename) {2532 if (!ValidateArchFlags())2533 return;2534 2535 // Attempt to open the binary.2536 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);2537 if (!BinaryOrErr) {2538 if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))2539 reportError(std::move(E), Filename);2540 else2541 outs() << Filename << ": is not an object file\n";2542 return;2543 }2544 Binary &Bin = *BinaryOrErr.get().getBinary();2545 2546 if (Archive *A = dyn_cast<Archive>(&Bin)) {2547 outs() << "Archive : " << Filename << "\n";2548 if (ArchiveHeaders)2549 printArchiveHeaders(Filename, A, Verbose, ArchiveMemberOffsets);2550 2551 Error Err = Error::success();2552 unsigned I = -1;2553 for (auto &C : A->children(Err)) {2554 ++I;2555 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2556 if (!ChildOrErr) {2557 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2558 reportError(std::move(E), getFileNameForError(C, I), Filename);2559 continue;2560 }2561 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2562 if (!checkMachOAndArchFlags(O, Filename))2563 return;2564 ProcessMachO(Filename, O, O->getFileName());2565 }2566 }2567 if (Err)2568 reportError(std::move(Err), Filename);2569 return;2570 }2571 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {2572 parseInputMachO(UB);2573 return;2574 }2575 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {2576 if (!checkMachOAndArchFlags(O, Filename))2577 return;2578 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))2579 ProcessMachO(Filename, MachOOF);2580 else2581 WithColor::error(errs(), "llvm-objdump")2582 << Filename << "': "2583 << "object is not a Mach-O file type.\n";2584 return;2585 }2586 llvm_unreachable("Input object can't be invalid at this point");2587}2588 2589void objdump::parseInputMachO(MachOUniversalBinary *UB) {2590 if (!ValidateArchFlags())2591 return;2592 2593 auto Filename = UB->getFileName();2594 2595 if (UniversalHeaders)2596 printMachOUniversalHeaders(UB, Verbose);2597 2598 // If we have a list of architecture flags specified dump only those.2599 if (!ArchAll && !ArchFlags.empty()) {2600 // Look for a slice in the universal binary that matches each ArchFlag.2601 bool ArchFound;2602 for (unsigned i = 0; i < ArchFlags.size(); ++i) {2603 ArchFound = false;2604 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2605 E = UB->end_objects();2606 I != E; ++I) {2607 if (ArchFlags[i] == I->getArchFlagName()) {2608 ArchFound = true;2609 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =2610 I->getAsObjectFile();2611 std::string ArchitectureName;2612 if (ArchFlags.size() > 1)2613 ArchitectureName = I->getArchFlagName();2614 if (ObjOrErr) {2615 ObjectFile &O = *ObjOrErr.get();2616 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2617 ProcessMachO(Filename, MachOOF, "", ArchitectureName);2618 } else if (Error E = isNotObjectErrorInvalidFileType(2619 ObjOrErr.takeError())) {2620 reportError(std::move(E), "", Filename, ArchitectureName);2621 continue;2622 } else if (Expected<std::unique_ptr<Archive>> AOrErr =2623 I->getAsArchive()) {2624 std::unique_ptr<Archive> &A = *AOrErr;2625 outs() << "Archive : " << Filename;2626 if (!ArchitectureName.empty())2627 outs() << " (architecture " << ArchitectureName << ")";2628 outs() << "\n";2629 if (ArchiveHeaders)2630 printArchiveHeaders(Filename, A.get(), Verbose,2631 ArchiveMemberOffsets, ArchitectureName);2632 Error Err = Error::success();2633 unsigned I = -1;2634 for (auto &C : A->children(Err)) {2635 ++I;2636 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2637 if (!ChildOrErr) {2638 if (Error E =2639 isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2640 reportError(std::move(E), getFileNameForError(C, I), Filename,2641 ArchitectureName);2642 continue;2643 }2644 if (MachOObjectFile *O =2645 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2646 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);2647 }2648 if (Err)2649 reportError(std::move(Err), Filename);2650 } else {2651 consumeError(AOrErr.takeError());2652 reportError(Filename,2653 "Mach-O universal file for architecture " +2654 StringRef(I->getArchFlagName()) +2655 " is not a Mach-O file or an archive file");2656 }2657 }2658 }2659 if (!ArchFound) {2660 WithColor::error(errs(), "llvm-objdump")2661 << "file: " + Filename + " does not contain "2662 << "architecture: " + ArchFlags[i] + "\n";2663 return;2664 }2665 }2666 return;2667 }2668 // No architecture flags were specified so if this contains a slice that2669 // matches the host architecture dump only that.2670 if (!ArchAll) {2671 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2672 E = UB->end_objects();2673 I != E; ++I) {2674 if (MachOObjectFile::getHostArch().getArchName() ==2675 I->getArchFlagName()) {2676 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2677 std::string ArchiveName;2678 ArchiveName.clear();2679 if (ObjOrErr) {2680 ObjectFile &O = *ObjOrErr.get();2681 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))2682 ProcessMachO(Filename, MachOOF);2683 } else if (Error E =2684 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2685 reportError(std::move(E), Filename);2686 } else if (Expected<std::unique_ptr<Archive>> AOrErr =2687 I->getAsArchive()) {2688 std::unique_ptr<Archive> &A = *AOrErr;2689 outs() << "Archive : " << Filename << "\n";2690 if (ArchiveHeaders)2691 printArchiveHeaders(Filename, A.get(), Verbose,2692 ArchiveMemberOffsets);2693 Error Err = Error::success();2694 unsigned I = -1;2695 for (auto &C : A->children(Err)) {2696 ++I;2697 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2698 if (!ChildOrErr) {2699 if (Error E =2700 isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2701 reportError(std::move(E), getFileNameForError(C, I), Filename);2702 continue;2703 }2704 if (MachOObjectFile *O =2705 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))2706 ProcessMachO(Filename, O, O->getFileName());2707 }2708 if (Err)2709 reportError(std::move(Err), Filename);2710 } else {2711 consumeError(AOrErr.takeError());2712 reportError(Filename, "Mach-O universal file for architecture " +2713 StringRef(I->getArchFlagName()) +2714 " is not a Mach-O file or an archive file");2715 }2716 return;2717 }2718 }2719 }2720 // Either all architectures have been specified or none have been specified2721 // and this does not contain the host architecture so dump all the slices.2722 bool moreThanOneArch = UB->getNumberOfObjects() > 1;2723 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),2724 E = UB->end_objects();2725 I != E; ++I) {2726 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();2727 std::string ArchitectureName;2728 if (moreThanOneArch)2729 ArchitectureName = I->getArchFlagName();2730 if (ObjOrErr) {2731 ObjectFile &Obj = *ObjOrErr.get();2732 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))2733 ProcessMachO(Filename, MachOOF, "", ArchitectureName);2734 } else if (Error E =2735 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {2736 reportError(std::move(E), Filename, "", ArchitectureName);2737 } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {2738 std::unique_ptr<Archive> &A = *AOrErr;2739 outs() << "Archive : " << Filename;2740 if (!ArchitectureName.empty())2741 outs() << " (architecture " << ArchitectureName << ")";2742 outs() << "\n";2743 if (ArchiveHeaders)2744 printArchiveHeaders(Filename, A.get(), Verbose, ArchiveMemberOffsets,2745 ArchitectureName);2746 Error Err = Error::success();2747 unsigned I = -1;2748 for (auto &C : A->children(Err)) {2749 ++I;2750 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();2751 if (!ChildOrErr) {2752 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))2753 reportError(std::move(E), getFileNameForError(C, I), Filename,2754 ArchitectureName);2755 continue;2756 }2757 if (MachOObjectFile *O =2758 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {2759 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))2760 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),2761 ArchitectureName);2762 }2763 }2764 if (Err)2765 reportError(std::move(Err), Filename);2766 } else {2767 consumeError(AOrErr.takeError());2768 reportError(Filename, "Mach-O universal file for architecture " +2769 StringRef(I->getArchFlagName()) +2770 " is not a Mach-O file or an archive file");2771 }2772 }2773}2774 2775namespace {2776// The block of info used by the Symbolizer call backs.2777struct DisassembleInfo {2778 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,2779 std::vector<SectionRef> *Sections, bool verbose)2780 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}2781 bool verbose;2782 MachOObjectFile *O;2783 SectionRef S;2784 SymbolAddressMap *AddrMap;2785 std::vector<SectionRef> *Sections;2786 const char *class_name = nullptr;2787 const char *selector_name = nullptr;2788 std::unique_ptr<char[]> method = nullptr;2789 char *demangled_name = nullptr;2790 uint64_t adrp_addr = 0;2791 uint32_t adrp_inst = 0;2792 std::unique_ptr<SymbolAddressMap> bindtable;2793 uint32_t depth = 0;2794};2795} // namespace2796 2797// SymbolizerGetOpInfo() is the operand information call back function.2798// This is called to get the symbolic information for operand(s) of an2799// instruction when it is being done. This routine does this from2800// the relocation information, symbol table, etc. That block of information2801// is a pointer to the struct DisassembleInfo that was passed when the2802// disassembler context was created and passed to back to here when2803// called back by the disassembler for instruction operands that could have2804// relocation information. The address of the instruction containing operand is2805// at the Pc parameter. The immediate value the operand has is passed in2806// op_info->Value and is at Offset past the start of the instruction and has a2807// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the2808// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol2809// names and addends of the symbolic expression to add for the operand. The2810// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic2811// information is returned then this function returns 1 else it returns 0.2812static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,2813 uint64_t OpSize, uint64_t InstSize, int TagType,2814 void *TagBuf) {2815 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;2816 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;2817 uint64_t value = op_info->Value;2818 2819 // Make sure all fields returned are zero if we don't set them.2820 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));2821 op_info->Value = value;2822 2823 // If the TagType is not the value 1 which it code knows about or if no2824 // verbose symbolic information is wanted then just return 0, indicating no2825 // information is being returned.2826 if (TagType != 1 || !info->verbose)2827 return 0;2828 2829 unsigned int Arch = info->O->getArch();2830 if (Arch == Triple::x86) {2831 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2832 return 0;2833 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2834 // TODO:2835 // Search the external relocation entries of a fully linked image2836 // (if any) for an entry that matches this segment offset.2837 // uint32_t seg_offset = (Pc + Offset);2838 return 0;2839 }2840 // In MH_OBJECT filetypes search the section's relocation entries (if any)2841 // for an entry for this section offset.2842 uint32_t sect_addr = info->S.getAddress();2843 uint32_t sect_offset = (Pc + Offset) - sect_addr;2844 bool reloc_found = false;2845 DataRefImpl Rel;2846 MachO::any_relocation_info RE;2847 bool isExtern = false;2848 SymbolRef Symbol;2849 bool r_scattered = false;2850 uint32_t r_value, pair_r_value, r_type;2851 for (const RelocationRef &Reloc : info->S.relocations()) {2852 uint64_t RelocOffset = Reloc.getOffset();2853 if (RelocOffset == sect_offset) {2854 Rel = Reloc.getRawDataRefImpl();2855 RE = info->O->getRelocation(Rel);2856 r_type = info->O->getAnyRelocationType(RE);2857 r_scattered = info->O->isRelocationScattered(RE);2858 if (r_scattered) {2859 r_value = info->O->getScatteredRelocationValue(RE);2860 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2861 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {2862 DataRefImpl RelNext = Rel;2863 info->O->moveRelocationNext(RelNext);2864 MachO::any_relocation_info RENext;2865 RENext = info->O->getRelocation(RelNext);2866 if (info->O->isRelocationScattered(RENext))2867 pair_r_value = info->O->getScatteredRelocationValue(RENext);2868 else2869 return 0;2870 }2871 } else {2872 isExtern = info->O->getPlainRelocationExternal(RE);2873 if (isExtern) {2874 symbol_iterator RelocSym = Reloc.getSymbol();2875 Symbol = *RelocSym;2876 }2877 }2878 reloc_found = true;2879 break;2880 }2881 }2882 if (reloc_found && isExtern) {2883 op_info->AddSymbol.Present = 1;2884 op_info->AddSymbol.Name =2885 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2886 // For i386 extern relocation entries the value in the instruction is2887 // the offset from the symbol, and value is already set in op_info->Value.2888 return 1;2889 }2890 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||2891 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {2892 const char *add = GuessSymbolName(r_value, info->AddrMap);2893 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);2894 uint32_t offset = value - (r_value - pair_r_value);2895 op_info->AddSymbol.Present = 1;2896 if (add != nullptr)2897 op_info->AddSymbol.Name = add;2898 else2899 op_info->AddSymbol.Value = r_value;2900 op_info->SubtractSymbol.Present = 1;2901 if (sub != nullptr)2902 op_info->SubtractSymbol.Name = sub;2903 else2904 op_info->SubtractSymbol.Value = pair_r_value;2905 op_info->Value = offset;2906 return 1;2907 }2908 return 0;2909 }2910 if (Arch == Triple::x86_64) {2911 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)2912 return 0;2913 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external2914 // relocation entries of a linked image (if any) for an entry that matches2915 // this segment offset.2916 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {2917 uint64_t seg_offset = Pc + Offset;2918 bool reloc_found = false;2919 DataRefImpl Rel;2920 MachO::any_relocation_info RE;2921 bool isExtern = false;2922 SymbolRef Symbol;2923 for (const RelocationRef &Reloc : info->O->external_relocations()) {2924 uint64_t RelocOffset = Reloc.getOffset();2925 if (RelocOffset == seg_offset) {2926 Rel = Reloc.getRawDataRefImpl();2927 RE = info->O->getRelocation(Rel);2928 // external relocation entries should always be external.2929 isExtern = info->O->getPlainRelocationExternal(RE);2930 if (isExtern) {2931 symbol_iterator RelocSym = Reloc.getSymbol();2932 Symbol = *RelocSym;2933 }2934 reloc_found = true;2935 break;2936 }2937 }2938 if (reloc_found && isExtern) {2939 // The Value passed in will be adjusted by the Pc if the instruction2940 // adds the Pc. But for x86_64 external relocation entries the Value2941 // is the offset from the external symbol.2942 if (info->O->getAnyRelocationPCRel(RE))2943 op_info->Value -= Pc + InstSize;2944 const char *name =2945 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2946 op_info->AddSymbol.Present = 1;2947 op_info->AddSymbol.Name = name;2948 return 1;2949 }2950 return 0;2951 }2952 // In MH_OBJECT filetypes search the section's relocation entries (if any)2953 // for an entry for this section offset.2954 uint64_t sect_addr = info->S.getAddress();2955 uint64_t sect_offset = (Pc + Offset) - sect_addr;2956 bool reloc_found = false;2957 DataRefImpl Rel;2958 MachO::any_relocation_info RE;2959 bool isExtern = false;2960 SymbolRef Symbol;2961 for (const RelocationRef &Reloc : info->S.relocations()) {2962 uint64_t RelocOffset = Reloc.getOffset();2963 if (RelocOffset == sect_offset) {2964 Rel = Reloc.getRawDataRefImpl();2965 RE = info->O->getRelocation(Rel);2966 // NOTE: Scattered relocations don't exist on x86_64.2967 isExtern = info->O->getPlainRelocationExternal(RE);2968 if (isExtern) {2969 symbol_iterator RelocSym = Reloc.getSymbol();2970 Symbol = *RelocSym;2971 }2972 reloc_found = true;2973 break;2974 }2975 }2976 if (reloc_found && isExtern) {2977 // The Value passed in will be adjusted by the Pc if the instruction2978 // adds the Pc. But for x86_64 external relocation entries the Value2979 // is the offset from the external symbol.2980 if (info->O->getAnyRelocationPCRel(RE))2981 op_info->Value -= Pc + InstSize;2982 const char *name =2983 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2984 unsigned Type = info->O->getAnyRelocationType(RE);2985 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {2986 DataRefImpl RelNext = Rel;2987 info->O->moveRelocationNext(RelNext);2988 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);2989 unsigned TypeNext = info->O->getAnyRelocationType(RENext);2990 bool isExternNext = info->O->getPlainRelocationExternal(RENext);2991 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);2992 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {2993 op_info->SubtractSymbol.Present = 1;2994 op_info->SubtractSymbol.Name = name;2995 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);2996 Symbol = *RelocSymNext;2997 name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();2998 }2999 }3000 // TODO: add the VariantKinds to op_info->VariantKind for relocation types3001 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.3002 op_info->AddSymbol.Present = 1;3003 op_info->AddSymbol.Name = name;3004 return 1;3005 }3006 return 0;3007 }3008 if (Arch == Triple::arm) {3009 if (Offset != 0 || (InstSize != 4 && InstSize != 2))3010 return 0;3011 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3012 // TODO:3013 // Search the external relocation entries of a fully linked image3014 // (if any) for an entry that matches this segment offset.3015 // uint32_t seg_offset = (Pc + Offset);3016 return 0;3017 }3018 // In MH_OBJECT filetypes search the section's relocation entries (if any)3019 // for an entry for this section offset.3020 uint32_t sect_addr = info->S.getAddress();3021 uint32_t sect_offset = (Pc + Offset) - sect_addr;3022 DataRefImpl Rel;3023 MachO::any_relocation_info RE;3024 bool isExtern = false;3025 SymbolRef Symbol;3026 bool r_scattered = false;3027 uint32_t r_value, pair_r_value, r_type, r_length, other_half;3028 auto Reloc =3029 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3030 uint64_t RelocOffset = Reloc.getOffset();3031 return RelocOffset == sect_offset;3032 });3033 3034 if (Reloc == info->S.relocations().end())3035 return 0;3036 3037 Rel = Reloc->getRawDataRefImpl();3038 RE = info->O->getRelocation(Rel);3039 r_length = info->O->getAnyRelocationLength(RE);3040 r_scattered = info->O->isRelocationScattered(RE);3041 if (r_scattered) {3042 r_value = info->O->getScatteredRelocationValue(RE);3043 r_type = info->O->getScatteredRelocationType(RE);3044 } else {3045 r_type = info->O->getAnyRelocationType(RE);3046 isExtern = info->O->getPlainRelocationExternal(RE);3047 if (isExtern) {3048 symbol_iterator RelocSym = Reloc->getSymbol();3049 Symbol = *RelocSym;3050 }3051 }3052 if (r_type == MachO::ARM_RELOC_HALF ||3053 r_type == MachO::ARM_RELOC_SECTDIFF ||3054 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||3055 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3056 DataRefImpl RelNext = Rel;3057 info->O->moveRelocationNext(RelNext);3058 MachO::any_relocation_info RENext;3059 RENext = info->O->getRelocation(RelNext);3060 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;3061 if (info->O->isRelocationScattered(RENext))3062 pair_r_value = info->O->getScatteredRelocationValue(RENext);3063 }3064 3065 if (isExtern) {3066 const char *name =3067 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();3068 op_info->AddSymbol.Present = 1;3069 op_info->AddSymbol.Name = name;3070 switch (r_type) {3071 case MachO::ARM_RELOC_HALF:3072 if ((r_length & 0x1) == 1) {3073 op_info->Value = value << 16 | other_half;3074 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3075 } else {3076 op_info->Value = other_half << 16 | value;3077 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3078 }3079 break;3080 default:3081 break;3082 }3083 return 1;3084 }3085 // If we have a branch that is not an external relocation entry then3086 // return 0 so the code in tryAddingSymbolicOperand() can use the3087 // SymbolLookUp call back with the branch target address to look up the3088 // symbol and possibility add an annotation for a symbol stub.3089 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||3090 r_type == MachO::ARM_THUMB_RELOC_BR22))3091 return 0;3092 3093 uint32_t offset = 0;3094 if (r_type == MachO::ARM_RELOC_HALF ||3095 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3096 if ((r_length & 0x1) == 1)3097 value = value << 16 | other_half;3098 else3099 value = other_half << 16 | value;3100 }3101 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&3102 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {3103 offset = value - r_value;3104 value = r_value;3105 }3106 3107 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {3108 if ((r_length & 0x1) == 1)3109 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3110 else3111 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3112 const char *add = GuessSymbolName(r_value, info->AddrMap);3113 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);3114 int32_t offset = value - (r_value - pair_r_value);3115 op_info->AddSymbol.Present = 1;3116 if (add != nullptr)3117 op_info->AddSymbol.Name = add;3118 else3119 op_info->AddSymbol.Value = r_value;3120 op_info->SubtractSymbol.Present = 1;3121 if (sub != nullptr)3122 op_info->SubtractSymbol.Name = sub;3123 else3124 op_info->SubtractSymbol.Value = pair_r_value;3125 op_info->Value = offset;3126 return 1;3127 }3128 3129 op_info->AddSymbol.Present = 1;3130 op_info->Value = offset;3131 if (r_type == MachO::ARM_RELOC_HALF) {3132 if ((r_length & 0x1) == 1)3133 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;3134 else3135 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;3136 }3137 const char *add = GuessSymbolName(value, info->AddrMap);3138 if (add != nullptr) {3139 op_info->AddSymbol.Name = add;3140 return 1;3141 }3142 op_info->AddSymbol.Value = value;3143 return 1;3144 }3145 if (Arch == Triple::aarch64) {3146 if (Offset != 0 || InstSize != 4)3147 return 0;3148 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {3149 // TODO:3150 // Search the external relocation entries of a fully linked image3151 // (if any) for an entry that matches this segment offset.3152 // uint64_t seg_offset = (Pc + Offset);3153 return 0;3154 }3155 // In MH_OBJECT filetypes search the section's relocation entries (if any)3156 // for an entry for this section offset.3157 uint64_t sect_addr = info->S.getAddress();3158 uint64_t sect_offset = (Pc + Offset) - sect_addr;3159 auto Reloc =3160 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {3161 uint64_t RelocOffset = Reloc.getOffset();3162 return RelocOffset == sect_offset;3163 });3164 3165 if (Reloc == info->S.relocations().end())3166 return 0;3167 3168 DataRefImpl Rel = Reloc->getRawDataRefImpl();3169 MachO::any_relocation_info RE = info->O->getRelocation(Rel);3170 uint32_t r_type = info->O->getAnyRelocationType(RE);3171 if (r_type == MachO::ARM64_RELOC_ADDEND) {3172 DataRefImpl RelNext = Rel;3173 info->O->moveRelocationNext(RelNext);3174 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);3175 if (value == 0) {3176 value = info->O->getPlainRelocationSymbolNum(RENext);3177 op_info->Value = value;3178 }3179 }3180 // NOTE: Scattered relocations don't exist on arm64.3181 if (!info->O->getPlainRelocationExternal(RE))3182 return 0;3183 const char *name =3184 unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())3185 .data();3186 op_info->AddSymbol.Present = 1;3187 op_info->AddSymbol.Name = name;3188 3189 switch (r_type) {3190 case MachO::ARM64_RELOC_PAGE21:3191 /* @page */3192 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;3193 break;3194 case MachO::ARM64_RELOC_PAGEOFF12:3195 /* @pageoff */3196 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;3197 break;3198 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:3199 /* @gotpage */3200 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;3201 break;3202 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:3203 /* @gotpageoff */3204 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;3205 break;3206 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:3207 /* @tvlppage is not implemented in llvm-mc */3208 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;3209 break;3210 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:3211 /* @tvlppageoff is not implemented in llvm-mc */3212 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;3213 break;3214 default:3215 case MachO::ARM64_RELOC_BRANCH26:3216 op_info->VariantKind = LLVMDisassembler_VariantKind_None;3217 break;3218 }3219 return 1;3220 }3221 return 0;3222}3223 3224// GuessCstringPointer is passed the address of what might be a pointer to a3225// literal string in a cstring section. If that address is in a cstring section3226// it returns a pointer to that string. Else it returns nullptr.3227static const char *GuessCstringPointer(uint64_t ReferenceValue,3228 struct DisassembleInfo *info) {3229 for (const auto &Load : info->O->load_commands()) {3230 if (Load.C.cmd == MachO::LC_SEGMENT_64) {3231 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3232 for (unsigned J = 0; J < Seg.nsects; ++J) {3233 MachO::section_64 Sec = info->O->getSection64(Load, J);3234 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3235 if (section_type == MachO::S_CSTRING_LITERALS &&3236 ReferenceValue >= Sec.addr &&3237 ReferenceValue < Sec.addr + Sec.size) {3238 uint64_t sect_offset = ReferenceValue - Sec.addr;3239 uint64_t object_offset = Sec.offset + sect_offset;3240 StringRef MachOContents = info->O->getData();3241 uint64_t object_size = MachOContents.size();3242 const char *object_addr = MachOContents.data();3243 if (object_offset < object_size) {3244 const char *name = object_addr + object_offset;3245 return name;3246 } else {3247 return nullptr;3248 }3249 }3250 }3251 } else if (Load.C.cmd == MachO::LC_SEGMENT) {3252 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3253 for (unsigned J = 0; J < Seg.nsects; ++J) {3254 MachO::section Sec = info->O->getSection(Load, J);3255 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3256 if (section_type == MachO::S_CSTRING_LITERALS &&3257 ReferenceValue >= Sec.addr &&3258 ReferenceValue < Sec.addr + Sec.size) {3259 uint64_t sect_offset = ReferenceValue - Sec.addr;3260 uint64_t object_offset = Sec.offset + sect_offset;3261 StringRef MachOContents = info->O->getData();3262 uint64_t object_size = MachOContents.size();3263 const char *object_addr = MachOContents.data();3264 if (object_offset < object_size) {3265 const char *name = object_addr + object_offset;3266 return name;3267 } else {3268 return nullptr;3269 }3270 }3271 }3272 }3273 }3274 return nullptr;3275}3276 3277// GuessIndirectSymbol returns the name of the indirect symbol for the3278// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe3279// an address of a symbol stub or a lazy or non-lazy pointer to associate the3280// symbol name being referenced by the stub or pointer.3281static const char *GuessIndirectSymbol(uint64_t ReferenceValue,3282 struct DisassembleInfo *info) {3283 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();3284 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();3285 for (const auto &Load : info->O->load_commands()) {3286 if (Load.C.cmd == MachO::LC_SEGMENT_64) {3287 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3288 for (unsigned J = 0; J < Seg.nsects; ++J) {3289 MachO::section_64 Sec = info->O->getSection64(Load, J);3290 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3291 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3292 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3293 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3294 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3295 section_type == MachO::S_SYMBOL_STUBS) &&3296 ReferenceValue >= Sec.addr &&3297 ReferenceValue < Sec.addr + Sec.size) {3298 uint32_t stride;3299 if (section_type == MachO::S_SYMBOL_STUBS)3300 stride = Sec.reserved2;3301 else3302 stride = 8;3303 if (stride == 0)3304 return nullptr;3305 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3306 if (index < Dysymtab.nindirectsyms) {3307 uint32_t indirect_symbol =3308 info->O->getIndirectSymbolTableEntry(Dysymtab, index);3309 if (indirect_symbol < Symtab.nsyms) {3310 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3311 return unwrapOrError(Sym->getName(), info->O->getFileName())3312 .data();3313 }3314 }3315 }3316 }3317 } else if (Load.C.cmd == MachO::LC_SEGMENT) {3318 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);3319 for (unsigned J = 0; J < Seg.nsects; ++J) {3320 MachO::section Sec = info->O->getSection(Load, J);3321 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;3322 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||3323 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||3324 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||3325 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||3326 section_type == MachO::S_SYMBOL_STUBS) &&3327 ReferenceValue >= Sec.addr &&3328 ReferenceValue < Sec.addr + Sec.size) {3329 uint32_t stride;3330 if (section_type == MachO::S_SYMBOL_STUBS)3331 stride = Sec.reserved2;3332 else3333 stride = 4;3334 if (stride == 0)3335 return nullptr;3336 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;3337 if (index < Dysymtab.nindirectsyms) {3338 uint32_t indirect_symbol =3339 info->O->getIndirectSymbolTableEntry(Dysymtab, index);3340 if (indirect_symbol < Symtab.nsyms) {3341 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);3342 return unwrapOrError(Sym->getName(), info->O->getFileName())3343 .data();3344 }3345 }3346 }3347 }3348 }3349 }3350 return nullptr;3351}3352 3353// method_reference() is called passing it the ReferenceName that might be3354// a reference it to an Objective-C method call. If so then it allocates and3355// assembles a method call string with the values last seen and saved in3356// the DisassembleInfo's class_name and selector_name fields. This is saved3357// into the method field of the info and any previous string is free'ed.3358// Then the class_name field in the info is set to nullptr. The method call3359// string is set into ReferenceName and ReferenceType is set to3360// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call3361// then both ReferenceType and ReferenceName are left unchanged.3362static void method_reference(struct DisassembleInfo *info,3363 uint64_t *ReferenceType,3364 const char **ReferenceName) {3365 unsigned int Arch = info->O->getArch();3366 if (*ReferenceName != nullptr) {3367 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {3368 if (info->selector_name != nullptr) {3369 if (info->class_name != nullptr) {3370 info->method = std::make_unique<char[]>(3371 5 + strlen(info->class_name) + strlen(info->selector_name));3372 char *method = info->method.get();3373 if (method != nullptr) {3374 strcpy(method, "+[");3375 strcat(method, info->class_name);3376 strcat(method, " ");3377 strcat(method, info->selector_name);3378 strcat(method, "]");3379 *ReferenceName = method;3380 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3381 }3382 } else {3383 info->method =3384 std::make_unique<char[]>(9 + strlen(info->selector_name));3385 char *method = info->method.get();3386 if (method != nullptr) {3387 if (Arch == Triple::x86_64)3388 strcpy(method, "-[%rdi ");3389 else if (Arch == Triple::aarch64)3390 strcpy(method, "-[x0 ");3391 else3392 strcpy(method, "-[r? ");3393 strcat(method, info->selector_name);3394 strcat(method, "]");3395 *ReferenceName = method;3396 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3397 }3398 }3399 info->class_name = nullptr;3400 }3401 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {3402 if (info->selector_name != nullptr) {3403 info->method =3404 std::make_unique<char[]>(17 + strlen(info->selector_name));3405 char *method = info->method.get();3406 if (method != nullptr) {3407 if (Arch == Triple::x86_64)3408 strcpy(method, "-[[%rdi super] ");3409 else if (Arch == Triple::aarch64)3410 strcpy(method, "-[[x0 super] ");3411 else3412 strcpy(method, "-[[r? super] ");3413 strcat(method, info->selector_name);3414 strcat(method, "]");3415 *ReferenceName = method;3416 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;3417 }3418 info->class_name = nullptr;3419 }3420 }3421 }3422}3423 3424// GuessPointerPointer() is passed the address of what might be a pointer to3425// a reference to an Objective-C class, selector, message ref or cfstring.3426// If so the value of the pointer is returned and one of the booleans are set3427// to true. If not zero is returned and all the booleans are set to false.3428static uint64_t GuessPointerPointer(uint64_t ReferenceValue,3429 struct DisassembleInfo *info,3430 bool &classref, bool &selref, bool &msgref,3431 bool &cfstring) {3432 classref = false;3433 selref = false;3434 msgref = false;3435 cfstring = false;3436 for (const auto &Load : info->O->load_commands()) {3437 if (Load.C.cmd == MachO::LC_SEGMENT_64) {3438 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);3439 for (unsigned J = 0; J < Seg.nsects; ++J) {3440 MachO::section_64 Sec = info->O->getSection64(Load, J);3441 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||3442 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3443 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||3444 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||3445 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&3446 ReferenceValue >= Sec.addr &&3447 ReferenceValue < Sec.addr + Sec.size) {3448 uint64_t sect_offset = ReferenceValue - Sec.addr;3449 uint64_t object_offset = Sec.offset + sect_offset;3450 StringRef MachOContents = info->O->getData();3451 uint64_t object_size = MachOContents.size();3452 const char *object_addr = MachOContents.data();3453 if (object_offset < object_size) {3454 uint64_t pointer_value;3455 memcpy(&pointer_value, object_addr + object_offset,3456 sizeof(uint64_t));3457 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3458 sys::swapByteOrder(pointer_value);3459 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)3460 selref = true;3461 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||3462 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)3463 classref = true;3464 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&3465 ReferenceValue + 8 < Sec.addr + Sec.size) {3466 msgref = true;3467 memcpy(&pointer_value, object_addr + object_offset + 8,3468 sizeof(uint64_t));3469 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)3470 sys::swapByteOrder(pointer_value);3471 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)3472 cfstring = true;3473 return pointer_value;3474 } else {3475 return 0;3476 }3477 }3478 }3479 }3480 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.3481 }3482 return 0;3483}3484 3485// get_pointer_64 returns a pointer to the bytes in the object file at the3486// Address from a section in the Mach-O file. And indirectly returns the3487// offset into the section, number of bytes left in the section past the offset3488// and which section is was being referenced. If the Address is not in a3489// section nullptr is returned.3490static const char *get_pointer_64(uint64_t Address, uint32_t &offset,3491 uint32_t &left, SectionRef &S,3492 DisassembleInfo *info,3493 bool objc_only = false) {3494 offset = 0;3495 left = 0;3496 S = SectionRef();3497 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {3498 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();3499 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();3500 if (SectSize == 0)3501 continue;3502 if (objc_only) {3503 StringRef SectName;3504 Expected<StringRef> SecNameOrErr =3505 ((*(info->Sections))[SectIdx]).getName();3506 if (SecNameOrErr)3507 SectName = *SecNameOrErr;3508 else3509 consumeError(SecNameOrErr.takeError());3510 3511 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();3512 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);3513 if (SegName != "__OBJC" && SectName != "__cstring")3514 continue;3515 }3516 if (Address >= SectAddress && Address < SectAddress + SectSize) {3517 S = (*(info->Sections))[SectIdx];3518 offset = Address - SectAddress;3519 left = SectSize - offset;3520 StringRef SectContents = unwrapOrError(3521 ((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());3522 return SectContents.data() + offset;3523 }3524 }3525 return nullptr;3526}3527 3528static const char *get_pointer_32(uint32_t Address, uint32_t &offset,3529 uint32_t &left, SectionRef &S,3530 DisassembleInfo *info,3531 bool objc_only = false) {3532 return get_pointer_64(Address, offset, left, S, info, objc_only);3533}3534 3535// get_symbol_64() returns the name of a symbol (or nullptr) and the address of3536// the symbol indirectly through n_value. Based on the relocation information3537// for the specified section offset in the specified section reference.3538// If no relocation information is found and a non-zero ReferenceValue for the3539// symbol is passed, look up that address in the info's AddrMap.3540static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,3541 DisassembleInfo *info, uint64_t &n_value,3542 uint64_t ReferenceValue = 0) {3543 n_value = 0;3544 if (!info->verbose)3545 return nullptr;3546 3547 // See if there is an external relocation entry at the sect_offset.3548 bool reloc_found = false;3549 DataRefImpl Rel;3550 MachO::any_relocation_info RE;3551 bool isExtern = false;3552 SymbolRef Symbol;3553 for (const RelocationRef &Reloc : S.relocations()) {3554 uint64_t RelocOffset = Reloc.getOffset();3555 if (RelocOffset == sect_offset) {3556 Rel = Reloc.getRawDataRefImpl();3557 RE = info->O->getRelocation(Rel);3558 if (info->O->isRelocationScattered(RE))3559 continue;3560 isExtern = info->O->getPlainRelocationExternal(RE);3561 if (isExtern) {3562 symbol_iterator RelocSym = Reloc.getSymbol();3563 Symbol = *RelocSym;3564 }3565 reloc_found = true;3566 break;3567 }3568 }3569 // If there is an external relocation entry for a symbol in this section3570 // at this section_offset then use that symbol's value for the n_value3571 // and return its name.3572 const char *SymbolName = nullptr;3573 if (reloc_found && isExtern) {3574 n_value = cantFail(Symbol.getValue());3575 StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());3576 if (!Name.empty()) {3577 SymbolName = Name.data();3578 return SymbolName;3579 }3580 }3581 3582 // TODO: For fully linked images, look through the external relocation3583 // entries off the dynamic symtab command. For these the r_offset is from the3584 // start of the first writeable segment in the Mach-O file. So the offset3585 // to this section from that segment is passed to this routine by the caller,3586 // as the database_offset. Which is the difference of the section's starting3587 // address and the first writable segment.3588 //3589 // NOTE: need add passing the database_offset to this routine.3590 3591 // We did not find an external relocation entry so look up the ReferenceValue3592 // as an address of a symbol and if found return that symbol's name.3593 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);3594 3595 return SymbolName;3596}3597 3598static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,3599 DisassembleInfo *info,3600 uint32_t ReferenceValue) {3601 uint64_t n_value64;3602 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);3603}3604 3605namespace {3606 3607// These are structs in the Objective-C meta data and read to produce the3608// comments for disassembly. While these are part of the ABI they are no3609// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h3610// .3611 3612// The cfstring object in a 64-bit Mach-O file.3613struct cfstring64_t {3614 uint64_t isa; // class64_t * (64-bit pointer)3615 uint64_t flags; // flag bits3616 uint64_t characters; // char * (64-bit pointer)3617 uint64_t length; // number of non-NULL characters in above3618};3619 3620// The class object in a 64-bit Mach-O file.3621struct class64_t {3622 uint64_t isa; // class64_t * (64-bit pointer)3623 uint64_t superclass; // class64_t * (64-bit pointer)3624 uint64_t cache; // Cache (64-bit pointer)3625 uint64_t vtable; // IMP * (64-bit pointer)3626 uint64_t data; // class_ro64_t * (64-bit pointer)3627};3628 3629struct class32_t {3630 uint32_t isa; /* class32_t * (32-bit pointer) */3631 uint32_t superclass; /* class32_t * (32-bit pointer) */3632 uint32_t cache; /* Cache (32-bit pointer) */3633 uint32_t vtable; /* IMP * (32-bit pointer) */3634 uint32_t data; /* class_ro32_t * (32-bit pointer) */3635};3636 3637struct class_ro64_t {3638 uint32_t flags;3639 uint32_t instanceStart;3640 uint32_t instanceSize;3641 uint32_t reserved;3642 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)3643 uint64_t name; // const char * (64-bit pointer)3644 uint64_t baseMethods; // const method_list_t * (64-bit pointer)3645 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)3646 uint64_t ivars; // const ivar_list_t * (64-bit pointer)3647 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)3648 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)3649};3650 3651struct class_ro32_t {3652 uint32_t flags;3653 uint32_t instanceStart;3654 uint32_t instanceSize;3655 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */3656 uint32_t name; /* const char * (32-bit pointer) */3657 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */3658 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */3659 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */3660 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */3661 uint32_t baseProperties; /* const struct objc_property_list *3662 (32-bit pointer) */3663};3664 3665/* Values for class_ro{64,32}_t->flags */3666#define RO_META (1 << 0)3667#define RO_ROOT (1 << 1)3668#define RO_HAS_CXX_STRUCTORS (1 << 2)3669 3670/* Values for method_list{64,32}_t->entsize */3671#define ML_HAS_RELATIVE_PTRS (1 << 31)3672#define ML_ENTSIZE_MASK 0xFFFF3673 3674struct method_list64_t {3675 uint32_t entsize;3676 uint32_t count;3677 /* struct method64_t first; These structures follow inline */3678};3679 3680struct method_list32_t {3681 uint32_t entsize;3682 uint32_t count;3683 /* struct method32_t first; These structures follow inline */3684};3685 3686struct method64_t {3687 uint64_t name; /* SEL (64-bit pointer) */3688 uint64_t types; /* const char * (64-bit pointer) */3689 uint64_t imp; /* IMP (64-bit pointer) */3690};3691 3692struct method32_t {3693 uint32_t name; /* SEL (32-bit pointer) */3694 uint32_t types; /* const char * (32-bit pointer) */3695 uint32_t imp; /* IMP (32-bit pointer) */3696};3697 3698struct method_relative_t {3699 int32_t name; /* SEL (32-bit relative) */3700 int32_t types; /* const char * (32-bit relative) */3701 int32_t imp; /* IMP (32-bit relative) */3702};3703 3704struct protocol_list64_t {3705 uint64_t count; /* uintptr_t (a 64-bit value) */3706 /* struct protocol64_t * list[0]; These pointers follow inline */3707};3708 3709struct protocol_list32_t {3710 uint32_t count; /* uintptr_t (a 32-bit value) */3711 /* struct protocol32_t * list[0]; These pointers follow inline */3712};3713 3714struct protocol64_t {3715 uint64_t isa; /* id * (64-bit pointer) */3716 uint64_t name; /* const char * (64-bit pointer) */3717 uint64_t protocols; /* struct protocol_list64_t *3718 (64-bit pointer) */3719 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */3720 uint64_t classMethods; /* method_list_t * (64-bit pointer) */3721 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */3722 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */3723 uint64_t instanceProperties; /* struct objc_property_list *3724 (64-bit pointer) */3725};3726 3727struct protocol32_t {3728 uint32_t isa; /* id * (32-bit pointer) */3729 uint32_t name; /* const char * (32-bit pointer) */3730 uint32_t protocols; /* struct protocol_list_t *3731 (32-bit pointer) */3732 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */3733 uint32_t classMethods; /* method_list_t * (32-bit pointer) */3734 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */3735 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */3736 uint32_t instanceProperties; /* struct objc_property_list *3737 (32-bit pointer) */3738};3739 3740struct ivar_list64_t {3741 uint32_t entsize;3742 uint32_t count;3743 /* struct ivar64_t first; These structures follow inline */3744};3745 3746struct ivar_list32_t {3747 uint32_t entsize;3748 uint32_t count;3749 /* struct ivar32_t first; These structures follow inline */3750};3751 3752struct ivar64_t {3753 uint64_t offset; /* uintptr_t * (64-bit pointer) */3754 uint64_t name; /* const char * (64-bit pointer) */3755 uint64_t type; /* const char * (64-bit pointer) */3756 uint32_t alignment;3757 uint32_t size;3758};3759 3760struct ivar32_t {3761 uint32_t offset; /* uintptr_t * (32-bit pointer) */3762 uint32_t name; /* const char * (32-bit pointer) */3763 uint32_t type; /* const char * (32-bit pointer) */3764 uint32_t alignment;3765 uint32_t size;3766};3767 3768struct objc_property_list64 {3769 uint32_t entsize;3770 uint32_t count;3771 /* struct objc_property64 first; These structures follow inline */3772};3773 3774struct objc_property_list32 {3775 uint32_t entsize;3776 uint32_t count;3777 /* struct objc_property32 first; These structures follow inline */3778};3779 3780struct objc_property64 {3781 uint64_t name; /* const char * (64-bit pointer) */3782 uint64_t attributes; /* const char * (64-bit pointer) */3783};3784 3785struct objc_property32 {3786 uint32_t name; /* const char * (32-bit pointer) */3787 uint32_t attributes; /* const char * (32-bit pointer) */3788};3789 3790struct category64_t {3791 uint64_t name; /* const char * (64-bit pointer) */3792 uint64_t cls; /* struct class_t * (64-bit pointer) */3793 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */3794 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */3795 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */3796 uint64_t instanceProperties; /* struct objc_property_list *3797 (64-bit pointer) */3798};3799 3800struct category32_t {3801 uint32_t name; /* const char * (32-bit pointer) */3802 uint32_t cls; /* struct class_t * (32-bit pointer) */3803 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */3804 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */3805 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */3806 uint32_t instanceProperties; /* struct objc_property_list *3807 (32-bit pointer) */3808};3809 3810struct objc_image_info64 {3811 uint32_t version;3812 uint32_t flags;3813};3814struct objc_image_info32 {3815 uint32_t version;3816 uint32_t flags;3817};3818struct imageInfo_t {3819 uint32_t version;3820 uint32_t flags;3821};3822/* masks for objc_image_info.flags */3823#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)3824#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)3825#define OBJC_IMAGE_IS_SIMULATED (1 << 5)3826#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)3827 3828struct message_ref64 {3829 uint64_t imp; /* IMP (64-bit pointer) */3830 uint64_t sel; /* SEL (64-bit pointer) */3831};3832 3833struct message_ref32 {3834 uint32_t imp; /* IMP (32-bit pointer) */3835 uint32_t sel; /* SEL (32-bit pointer) */3836};3837 3838// Objective-C 1 (32-bit only) meta data structs.3839 3840struct objc_module_t {3841 uint32_t version;3842 uint32_t size;3843 uint32_t name; /* char * (32-bit pointer) */3844 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */3845};3846 3847struct objc_symtab_t {3848 uint32_t sel_ref_cnt;3849 uint32_t refs; /* SEL * (32-bit pointer) */3850 uint16_t cls_def_cnt;3851 uint16_t cat_def_cnt;3852 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */3853};3854 3855struct objc_class_t {3856 uint32_t isa; /* struct objc_class * (32-bit pointer) */3857 uint32_t super_class; /* struct objc_class * (32-bit pointer) */3858 uint32_t name; /* const char * (32-bit pointer) */3859 int32_t version;3860 int32_t info;3861 int32_t instance_size;3862 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */3863 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */3864 uint32_t cache; /* struct objc_cache * (32-bit pointer) */3865 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */3866};3867 3868#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))3869// class is not a metaclass3870#define CLS_CLASS 0x13871// class is a metaclass3872#define CLS_META 0x23873 3874struct objc_category_t {3875 uint32_t category_name; /* char * (32-bit pointer) */3876 uint32_t class_name; /* char * (32-bit pointer) */3877 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */3878 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */3879 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */3880};3881 3882struct objc_ivar_t {3883 uint32_t ivar_name; /* char * (32-bit pointer) */3884 uint32_t ivar_type; /* char * (32-bit pointer) */3885 int32_t ivar_offset;3886};3887 3888struct objc_ivar_list_t {3889 int32_t ivar_count;3890 // struct objc_ivar_t ivar_list[1]; /* variable length structure */3891};3892 3893struct objc_method_list_t {3894 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */3895 int32_t method_count;3896 // struct objc_method_t method_list[1]; /* variable length structure */3897};3898 3899struct objc_method_t {3900 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */3901 uint32_t method_types; /* char * (32-bit pointer) */3902 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)3903 (32-bit pointer) */3904};3905 3906struct objc_protocol_list_t {3907 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */3908 int32_t count;3909 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *3910 // (32-bit pointer) */3911};3912 3913struct objc_protocol_t {3914 uint32_t isa; /* struct objc_class * (32-bit pointer) */3915 uint32_t protocol_name; /* char * (32-bit pointer) */3916 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */3917 uint32_t instance_methods; /* struct objc_method_description_list *3918 (32-bit pointer) */3919 uint32_t class_methods; /* struct objc_method_description_list *3920 (32-bit pointer) */3921};3922 3923struct objc_method_description_list_t {3924 int32_t count;3925 // struct objc_method_description_t list[1];3926};3927 3928struct objc_method_description_t {3929 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */3930 uint32_t types; /* char * (32-bit pointer) */3931};3932 3933inline void swapStruct(struct cfstring64_t &cfs) {3934 sys::swapByteOrder(cfs.isa);3935 sys::swapByteOrder(cfs.flags);3936 sys::swapByteOrder(cfs.characters);3937 sys::swapByteOrder(cfs.length);3938}3939 3940inline void swapStruct(struct class64_t &c) {3941 sys::swapByteOrder(c.isa);3942 sys::swapByteOrder(c.superclass);3943 sys::swapByteOrder(c.cache);3944 sys::swapByteOrder(c.vtable);3945 sys::swapByteOrder(c.data);3946}3947 3948inline void swapStruct(struct class32_t &c) {3949 sys::swapByteOrder(c.isa);3950 sys::swapByteOrder(c.superclass);3951 sys::swapByteOrder(c.cache);3952 sys::swapByteOrder(c.vtable);3953 sys::swapByteOrder(c.data);3954}3955 3956inline void swapStruct(struct class_ro64_t &cro) {3957 sys::swapByteOrder(cro.flags);3958 sys::swapByteOrder(cro.instanceStart);3959 sys::swapByteOrder(cro.instanceSize);3960 sys::swapByteOrder(cro.reserved);3961 sys::swapByteOrder(cro.ivarLayout);3962 sys::swapByteOrder(cro.name);3963 sys::swapByteOrder(cro.baseMethods);3964 sys::swapByteOrder(cro.baseProtocols);3965 sys::swapByteOrder(cro.ivars);3966 sys::swapByteOrder(cro.weakIvarLayout);3967 sys::swapByteOrder(cro.baseProperties);3968}3969 3970inline void swapStruct(struct class_ro32_t &cro) {3971 sys::swapByteOrder(cro.flags);3972 sys::swapByteOrder(cro.instanceStart);3973 sys::swapByteOrder(cro.instanceSize);3974 sys::swapByteOrder(cro.ivarLayout);3975 sys::swapByteOrder(cro.name);3976 sys::swapByteOrder(cro.baseMethods);3977 sys::swapByteOrder(cro.baseProtocols);3978 sys::swapByteOrder(cro.ivars);3979 sys::swapByteOrder(cro.weakIvarLayout);3980 sys::swapByteOrder(cro.baseProperties);3981}3982 3983inline void swapStruct(struct method_list64_t &ml) {3984 sys::swapByteOrder(ml.entsize);3985 sys::swapByteOrder(ml.count);3986}3987 3988inline void swapStruct(struct method_list32_t &ml) {3989 sys::swapByteOrder(ml.entsize);3990 sys::swapByteOrder(ml.count);3991}3992 3993inline void swapStruct(struct method64_t &m) {3994 sys::swapByteOrder(m.name);3995 sys::swapByteOrder(m.types);3996 sys::swapByteOrder(m.imp);3997}3998 3999inline void swapStruct(struct method32_t &m) {4000 sys::swapByteOrder(m.name);4001 sys::swapByteOrder(m.types);4002 sys::swapByteOrder(m.imp);4003}4004 4005inline void swapStruct(struct method_relative_t &m) {4006 sys::swapByteOrder(m.name);4007 sys::swapByteOrder(m.types);4008 sys::swapByteOrder(m.imp);4009}4010 4011inline void swapStruct(struct protocol_list64_t &pl) {4012 sys::swapByteOrder(pl.count);4013}4014 4015inline void swapStruct(struct protocol_list32_t &pl) {4016 sys::swapByteOrder(pl.count);4017}4018 4019inline void swapStruct(struct protocol64_t &p) {4020 sys::swapByteOrder(p.isa);4021 sys::swapByteOrder(p.name);4022 sys::swapByteOrder(p.protocols);4023 sys::swapByteOrder(p.instanceMethods);4024 sys::swapByteOrder(p.classMethods);4025 sys::swapByteOrder(p.optionalInstanceMethods);4026 sys::swapByteOrder(p.optionalClassMethods);4027 sys::swapByteOrder(p.instanceProperties);4028}4029 4030inline void swapStruct(struct protocol32_t &p) {4031 sys::swapByteOrder(p.isa);4032 sys::swapByteOrder(p.name);4033 sys::swapByteOrder(p.protocols);4034 sys::swapByteOrder(p.instanceMethods);4035 sys::swapByteOrder(p.classMethods);4036 sys::swapByteOrder(p.optionalInstanceMethods);4037 sys::swapByteOrder(p.optionalClassMethods);4038 sys::swapByteOrder(p.instanceProperties);4039}4040 4041inline void swapStruct(struct ivar_list64_t &il) {4042 sys::swapByteOrder(il.entsize);4043 sys::swapByteOrder(il.count);4044}4045 4046inline void swapStruct(struct ivar_list32_t &il) {4047 sys::swapByteOrder(il.entsize);4048 sys::swapByteOrder(il.count);4049}4050 4051inline void swapStruct(struct ivar64_t &i) {4052 sys::swapByteOrder(i.offset);4053 sys::swapByteOrder(i.name);4054 sys::swapByteOrder(i.type);4055 sys::swapByteOrder(i.alignment);4056 sys::swapByteOrder(i.size);4057}4058 4059inline void swapStruct(struct ivar32_t &i) {4060 sys::swapByteOrder(i.offset);4061 sys::swapByteOrder(i.name);4062 sys::swapByteOrder(i.type);4063 sys::swapByteOrder(i.alignment);4064 sys::swapByteOrder(i.size);4065}4066 4067inline void swapStruct(struct objc_property_list64 &pl) {4068 sys::swapByteOrder(pl.entsize);4069 sys::swapByteOrder(pl.count);4070}4071 4072inline void swapStruct(struct objc_property_list32 &pl) {4073 sys::swapByteOrder(pl.entsize);4074 sys::swapByteOrder(pl.count);4075}4076 4077inline void swapStruct(struct objc_property64 &op) {4078 sys::swapByteOrder(op.name);4079 sys::swapByteOrder(op.attributes);4080}4081 4082inline void swapStruct(struct objc_property32 &op) {4083 sys::swapByteOrder(op.name);4084 sys::swapByteOrder(op.attributes);4085}4086 4087inline void swapStruct(struct category64_t &c) {4088 sys::swapByteOrder(c.name);4089 sys::swapByteOrder(c.cls);4090 sys::swapByteOrder(c.instanceMethods);4091 sys::swapByteOrder(c.classMethods);4092 sys::swapByteOrder(c.protocols);4093 sys::swapByteOrder(c.instanceProperties);4094}4095 4096inline void swapStruct(struct category32_t &c) {4097 sys::swapByteOrder(c.name);4098 sys::swapByteOrder(c.cls);4099 sys::swapByteOrder(c.instanceMethods);4100 sys::swapByteOrder(c.classMethods);4101 sys::swapByteOrder(c.protocols);4102 sys::swapByteOrder(c.instanceProperties);4103}4104 4105inline void swapStruct(struct objc_image_info64 &o) {4106 sys::swapByteOrder(o.version);4107 sys::swapByteOrder(o.flags);4108}4109 4110inline void swapStruct(struct objc_image_info32 &o) {4111 sys::swapByteOrder(o.version);4112 sys::swapByteOrder(o.flags);4113}4114 4115inline void swapStruct(struct imageInfo_t &o) {4116 sys::swapByteOrder(o.version);4117 sys::swapByteOrder(o.flags);4118}4119 4120inline void swapStruct(struct message_ref64 &mr) {4121 sys::swapByteOrder(mr.imp);4122 sys::swapByteOrder(mr.sel);4123}4124 4125inline void swapStruct(struct message_ref32 &mr) {4126 sys::swapByteOrder(mr.imp);4127 sys::swapByteOrder(mr.sel);4128}4129 4130inline void swapStruct(struct objc_module_t &module) {4131 sys::swapByteOrder(module.version);4132 sys::swapByteOrder(module.size);4133 sys::swapByteOrder(module.name);4134 sys::swapByteOrder(module.symtab);4135}4136 4137inline void swapStruct(struct objc_symtab_t &symtab) {4138 sys::swapByteOrder(symtab.sel_ref_cnt);4139 sys::swapByteOrder(symtab.refs);4140 sys::swapByteOrder(symtab.cls_def_cnt);4141 sys::swapByteOrder(symtab.cat_def_cnt);4142}4143 4144inline void swapStruct(struct objc_class_t &objc_class) {4145 sys::swapByteOrder(objc_class.isa);4146 sys::swapByteOrder(objc_class.super_class);4147 sys::swapByteOrder(objc_class.name);4148 sys::swapByteOrder(objc_class.version);4149 sys::swapByteOrder(objc_class.info);4150 sys::swapByteOrder(objc_class.instance_size);4151 sys::swapByteOrder(objc_class.ivars);4152 sys::swapByteOrder(objc_class.methodLists);4153 sys::swapByteOrder(objc_class.cache);4154 sys::swapByteOrder(objc_class.protocols);4155}4156 4157inline void swapStruct(struct objc_category_t &objc_category) {4158 sys::swapByteOrder(objc_category.category_name);4159 sys::swapByteOrder(objc_category.class_name);4160 sys::swapByteOrder(objc_category.instance_methods);4161 sys::swapByteOrder(objc_category.class_methods);4162 sys::swapByteOrder(objc_category.protocols);4163}4164 4165inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {4166 sys::swapByteOrder(objc_ivar_list.ivar_count);4167}4168 4169inline void swapStruct(struct objc_ivar_t &objc_ivar) {4170 sys::swapByteOrder(objc_ivar.ivar_name);4171 sys::swapByteOrder(objc_ivar.ivar_type);4172 sys::swapByteOrder(objc_ivar.ivar_offset);4173}4174 4175inline void swapStruct(struct objc_method_list_t &method_list) {4176 sys::swapByteOrder(method_list.obsolete);4177 sys::swapByteOrder(method_list.method_count);4178}4179 4180inline void swapStruct(struct objc_method_t &method) {4181 sys::swapByteOrder(method.method_name);4182 sys::swapByteOrder(method.method_types);4183 sys::swapByteOrder(method.method_imp);4184}4185 4186inline void swapStruct(struct objc_protocol_list_t &protocol_list) {4187 sys::swapByteOrder(protocol_list.next);4188 sys::swapByteOrder(protocol_list.count);4189}4190 4191inline void swapStruct(struct objc_protocol_t &protocol) {4192 sys::swapByteOrder(protocol.isa);4193 sys::swapByteOrder(protocol.protocol_name);4194 sys::swapByteOrder(protocol.protocol_list);4195 sys::swapByteOrder(protocol.instance_methods);4196 sys::swapByteOrder(protocol.class_methods);4197}4198 4199inline void swapStruct(struct objc_method_description_list_t &mdl) {4200 sys::swapByteOrder(mdl.count);4201}4202 4203inline void swapStruct(struct objc_method_description_t &md) {4204 sys::swapByteOrder(md.name);4205 sys::swapByteOrder(md.types);4206}4207 4208} // namespace4209 4210static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,4211 struct DisassembleInfo *info);4212 4213// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer4214// to an Objective-C class and returns the class name. It is also passed the4215// address of the pointer, so when the pointer is zero as it can be in an .o4216// file, that is used to look for an external relocation entry with a symbol4217// name.4218static const char *get_objc2_64bit_class_name(uint64_t pointer_value,4219 uint64_t ReferenceValue,4220 struct DisassembleInfo *info) {4221 const char *r;4222 uint32_t offset, left;4223 SectionRef S;4224 4225 // The pointer_value can be 0 in an object file and have a relocation4226 // entry for the class symbol at the ReferenceValue (the address of the4227 // pointer).4228 if (pointer_value == 0) {4229 r = get_pointer_64(ReferenceValue, offset, left, S, info);4230 if (r == nullptr || left < sizeof(uint64_t))4231 return nullptr;4232 uint64_t n_value;4233 const char *symbol_name = get_symbol_64(offset, S, info, n_value);4234 if (symbol_name == nullptr)4235 return nullptr;4236 const char *class_name = strrchr(symbol_name, '$');4237 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')4238 return class_name + 2;4239 else4240 return nullptr;4241 }4242 4243 // The case were the pointer_value is non-zero and points to a class defined4244 // in this Mach-O file.4245 r = get_pointer_64(pointer_value, offset, left, S, info);4246 if (r == nullptr || left < sizeof(struct class64_t))4247 return nullptr;4248 struct class64_t c;4249 memcpy(&c, r, sizeof(struct class64_t));4250 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4251 swapStruct(c);4252 if (c.data == 0)4253 return nullptr;4254 r = get_pointer_64(c.data, offset, left, S, info);4255 if (r == nullptr || left < sizeof(struct class_ro64_t))4256 return nullptr;4257 struct class_ro64_t cro;4258 memcpy(&cro, r, sizeof(struct class_ro64_t));4259 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4260 swapStruct(cro);4261 if (cro.name == 0)4262 return nullptr;4263 const char *name = get_pointer_64(cro.name, offset, left, S, info);4264 return name;4265}4266 4267// get_objc2_64bit_cfstring_name is used for disassembly and is passed a4268// pointer to a cfstring and returns its name or nullptr.4269static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,4270 struct DisassembleInfo *info) {4271 const char *r, *name;4272 uint32_t offset, left;4273 SectionRef S;4274 struct cfstring64_t cfs;4275 uint64_t cfs_characters;4276 4277 r = get_pointer_64(ReferenceValue, offset, left, S, info);4278 if (r == nullptr || left < sizeof(struct cfstring64_t))4279 return nullptr;4280 memcpy(&cfs, r, sizeof(struct cfstring64_t));4281 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4282 swapStruct(cfs);4283 if (cfs.characters == 0) {4284 uint64_t n_value;4285 const char *symbol_name = get_symbol_64(4286 offset + offsetof(struct cfstring64_t, characters), S, info, n_value);4287 if (symbol_name == nullptr)4288 return nullptr;4289 cfs_characters = n_value;4290 } else4291 cfs_characters = cfs.characters;4292 name = get_pointer_64(cfs_characters, offset, left, S, info);4293 4294 return name;4295}4296 4297// get_objc2_64bit_selref() is used for disassembly and is passed a the address4298// of a pointer to an Objective-C selector reference when the pointer value is4299// zero as in a .o file and is likely to have a external relocation entry with4300// who's symbol's n_value is the real pointer to the selector name. If that is4301// the case the real pointer to the selector name is returned else 0 is4302// returned4303static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,4304 struct DisassembleInfo *info) {4305 uint32_t offset, left;4306 SectionRef S;4307 4308 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);4309 if (r == nullptr || left < sizeof(uint64_t))4310 return 0;4311 uint64_t n_value;4312 const char *symbol_name = get_symbol_64(offset, S, info, n_value);4313 if (symbol_name == nullptr)4314 return 0;4315 return n_value;4316}4317 4318static const SectionRef get_section(MachOObjectFile *O, const char *segname,4319 const char *sectname) {4320 for (const SectionRef &Section : O->sections()) {4321 StringRef SectName;4322 Expected<StringRef> SecNameOrErr = Section.getName();4323 if (SecNameOrErr)4324 SectName = *SecNameOrErr;4325 else4326 consumeError(SecNameOrErr.takeError());4327 4328 DataRefImpl Ref = Section.getRawDataRefImpl();4329 StringRef SegName = O->getSectionFinalSegmentName(Ref);4330 if (SegName == segname && SectName == sectname)4331 return Section;4332 }4333 return SectionRef();4334}4335 4336static void4337walk_pointer_list_64(const char *listname, const SectionRef S,4338 MachOObjectFile *O, struct DisassembleInfo *info,4339 void (*func)(uint64_t, struct DisassembleInfo *info)) {4340 if (S == SectionRef())4341 return;4342 4343 StringRef SectName;4344 Expected<StringRef> SecNameOrErr = S.getName();4345 if (SecNameOrErr)4346 SectName = *SecNameOrErr;4347 else4348 consumeError(SecNameOrErr.takeError());4349 4350 DataRefImpl Ref = S.getRawDataRefImpl();4351 StringRef SegName = O->getSectionFinalSegmentName(Ref);4352 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";4353 4354 StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4355 const char *Contents = BytesStr.data();4356 4357 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {4358 uint32_t left = S.getSize() - i;4359 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);4360 uint64_t p = 0;4361 memcpy(&p, Contents + i, size);4362 if (i + sizeof(uint64_t) > S.getSize())4363 outs() << listname << " list pointer extends past end of (" << SegName4364 << "," << SectName << ") section\n";4365 outs() << format("%016" PRIx64, S.getAddress() + i) << " ";4366 4367 if (O->isLittleEndian() != sys::IsLittleEndianHost)4368 sys::swapByteOrder(p);4369 4370 uint64_t n_value = 0;4371 const char *name = get_symbol_64(i, S, info, n_value, p);4372 if (name == nullptr)4373 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);4374 4375 if (n_value != 0) {4376 outs() << format("0x%" PRIx64, n_value);4377 if (p != 0)4378 outs() << " + " << format("0x%" PRIx64, p);4379 } else4380 outs() << format("0x%" PRIx64, p);4381 if (name != nullptr)4382 outs() << " " << name;4383 outs() << "\n";4384 4385 p += n_value;4386 if (func)4387 func(p, info);4388 }4389}4390 4391static void4392walk_pointer_list_32(const char *listname, const SectionRef S,4393 MachOObjectFile *O, struct DisassembleInfo *info,4394 void (*func)(uint32_t, struct DisassembleInfo *info)) {4395 if (S == SectionRef())4396 return;4397 4398 StringRef SectName = unwrapOrError(S.getName(), O->getFileName());4399 DataRefImpl Ref = S.getRawDataRefImpl();4400 StringRef SegName = O->getSectionFinalSegmentName(Ref);4401 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";4402 4403 StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());4404 const char *Contents = BytesStr.data();4405 4406 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {4407 uint32_t left = S.getSize() - i;4408 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);4409 uint32_t p = 0;4410 memcpy(&p, Contents + i, size);4411 if (i + sizeof(uint32_t) > S.getSize())4412 outs() << listname << " list pointer extends past end of (" << SegName4413 << "," << SectName << ") section\n";4414 uint32_t Address = S.getAddress() + i;4415 outs() << format("%08" PRIx32, Address) << " ";4416 4417 if (O->isLittleEndian() != sys::IsLittleEndianHost)4418 sys::swapByteOrder(p);4419 outs() << format("0x%" PRIx32, p);4420 4421 const char *name = get_symbol_32(i, S, info, p);4422 if (name != nullptr)4423 outs() << " " << name;4424 outs() << "\n";4425 4426 if (func)4427 func(p, info);4428 }4429}4430 4431static void print_layout_map(const char *layout_map, uint32_t left) {4432 if (layout_map == nullptr)4433 return;4434 outs() << " layout map: ";4435 do {4436 outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";4437 left--;4438 layout_map++;4439 } while (*layout_map != '\0' && left != 0);4440 outs() << "\n";4441}4442 4443static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {4444 uint32_t offset, left;4445 SectionRef S;4446 const char *layout_map;4447 4448 if (p == 0)4449 return;4450 layout_map = get_pointer_64(p, offset, left, S, info);4451 print_layout_map(layout_map, left);4452}4453 4454static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {4455 uint32_t offset, left;4456 SectionRef S;4457 const char *layout_map;4458 4459 if (p == 0)4460 return;4461 layout_map = get_pointer_32(p, offset, left, S, info);4462 print_layout_map(layout_map, left);4463}4464 4465static void print_relative_method_list(uint32_t structSizeAndFlags,4466 uint32_t structCount, uint64_t p,4467 struct DisassembleInfo *info,4468 const char *indent,4469 uint32_t pointerBits) {4470 struct method_relative_t m;4471 const char *r, *name;4472 uint32_t offset, xoffset, left, i;4473 SectionRef S, xS;4474 4475 assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&4476 "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");4477 4478 outs() << indent << "\t\t entsize "4479 << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";4480 outs() << indent << "\t\t count " << structCount << "\n";4481 4482 for (i = 0; i < structCount; i++) {4483 r = get_pointer_64(p, offset, left, S, info);4484 memset(&m, '\0', sizeof(struct method_relative_t));4485 if (left < sizeof(struct method_relative_t)) {4486 memcpy(&m, r, left);4487 outs() << indent << " (method_t extends past the end of the section)\n";4488 } else4489 memcpy(&m, r, sizeof(struct method_relative_t));4490 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4491 swapStruct(m);4492 4493 outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);4494 uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);4495 uint64_t absNameRefVA = relNameRefVA + m.name;4496 outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";4497 4498 // since this is a relative list, absNameRefVA is the address of the4499 // __objc_selrefs entry, so a pointer, not the actual name4500 const char *nameRefPtr =4501 get_pointer_64(absNameRefVA, xoffset, left, xS, info);4502 if (nameRefPtr) {4503 uint32_t pointerSize = pointerBits / CHAR_BIT;4504 if (left < pointerSize)4505 outs() << indent << " (nameRefPtr extends past the end of the section)";4506 else {4507 if (pointerSize == 64) {4508 uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);4509 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4510 sys::swapByteOrder(nameOff_64);4511 name = get_pointer_64(nameOff_64, xoffset, left, xS, info);4512 } else {4513 uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);4514 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4515 sys::swapByteOrder(nameOff_32);4516 name = get_pointer_32(nameOff_32, xoffset, left, xS, info);4517 }4518 if (name != nullptr)4519 outs() << format(" %.*s", left, name);4520 }4521 }4522 outs() << "\n";4523 4524 outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);4525 uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);4526 uint64_t absTypesVA = relTypesVA + m.types;4527 outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";4528 name = get_pointer_32(absTypesVA, xoffset, left, xS, info);4529 if (name != nullptr)4530 outs() << format(" %.*s", left, name);4531 outs() << "\n";4532 4533 outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);4534 uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);4535 uint64_t absImpVA = relImpVA + m.imp;4536 outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";4537 name = GuessSymbolName(absImpVA, info->AddrMap);4538 if (name != nullptr)4539 outs() << " " << name;4540 outs() << "\n";4541 4542 p += sizeof(struct method_relative_t);4543 offset += sizeof(struct method_relative_t);4544 }4545}4546 4547static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,4548 const char *indent) {4549 struct method_list64_t ml;4550 struct method64_t m;4551 const char *r;4552 uint32_t offset, xoffset, left, i;4553 SectionRef S, xS;4554 const char *name, *sym_name;4555 uint64_t n_value;4556 4557 r = get_pointer_64(p, offset, left, S, info);4558 if (r == nullptr)4559 return;4560 memset(&ml, '\0', sizeof(struct method_list64_t));4561 if (left < sizeof(struct method_list64_t)) {4562 memcpy(&ml, r, left);4563 outs() << " (method_list_t entends past the end of the section)\n";4564 } else4565 memcpy(&ml, r, sizeof(struct method_list64_t));4566 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4567 swapStruct(ml);4568 p += sizeof(struct method_list64_t);4569 4570 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4571 print_relative_method_list(ml.entsize, ml.count, p, info, indent,4572 /*pointerBits=*/64);4573 return;4574 }4575 4576 outs() << indent << "\t\t entsize " << ml.entsize << "\n";4577 outs() << indent << "\t\t count " << ml.count << "\n";4578 4579 offset += sizeof(struct method_list64_t);4580 for (i = 0; i < ml.count; i++) {4581 r = get_pointer_64(p, offset, left, S, info);4582 if (r == nullptr)4583 return;4584 memset(&m, '\0', sizeof(struct method64_t));4585 if (left < sizeof(struct method64_t)) {4586 memcpy(&m, r, left);4587 outs() << indent << " (method_t extends past the end of the section)\n";4588 } else4589 memcpy(&m, r, sizeof(struct method64_t));4590 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4591 swapStruct(m);4592 4593 outs() << indent << "\t\t name ";4594 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,4595 info, n_value, m.name);4596 if (n_value != 0) {4597 if (info->verbose && sym_name != nullptr)4598 outs() << sym_name;4599 else4600 outs() << format("0x%" PRIx64, n_value);4601 if (m.name != 0)4602 outs() << " + " << format("0x%" PRIx64, m.name);4603 } else4604 outs() << format("0x%" PRIx64, m.name);4605 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);4606 if (name != nullptr)4607 outs() << format(" %.*s", left, name);4608 outs() << "\n";4609 4610 outs() << indent << "\t\t types ";4611 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,4612 info, n_value, m.types);4613 if (n_value != 0) {4614 if (info->verbose && sym_name != nullptr)4615 outs() << sym_name;4616 else4617 outs() << format("0x%" PRIx64, n_value);4618 if (m.types != 0)4619 outs() << " + " << format("0x%" PRIx64, m.types);4620 } else4621 outs() << format("0x%" PRIx64, m.types);4622 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);4623 if (name != nullptr)4624 outs() << format(" %.*s", left, name);4625 outs() << "\n";4626 4627 outs() << indent << "\t\t imp ";4628 name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,4629 n_value, m.imp);4630 if (info->verbose && name == nullptr) {4631 if (n_value != 0) {4632 outs() << format("0x%" PRIx64, n_value) << " ";4633 if (m.imp != 0)4634 outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";4635 } else4636 outs() << format("0x%" PRIx64, m.imp) << " ";4637 }4638 if (name != nullptr)4639 outs() << name;4640 outs() << "\n";4641 4642 p += sizeof(struct method64_t);4643 offset += sizeof(struct method64_t);4644 }4645}4646 4647static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,4648 const char *indent) {4649 struct method_list32_t ml;4650 struct method32_t m;4651 const char *r, *name;4652 uint32_t offset, xoffset, left, i;4653 SectionRef S, xS;4654 4655 r = get_pointer_32(p, offset, left, S, info);4656 if (r == nullptr)4657 return;4658 memset(&ml, '\0', sizeof(struct method_list32_t));4659 if (left < sizeof(struct method_list32_t)) {4660 memcpy(&ml, r, left);4661 outs() << " (method_list_t entends past the end of the section)\n";4662 } else4663 memcpy(&ml, r, sizeof(struct method_list32_t));4664 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4665 swapStruct(ml);4666 p += sizeof(struct method_list32_t);4667 4668 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {4669 print_relative_method_list(ml.entsize, ml.count, p, info, indent,4670 /*pointerBits=*/32);4671 return;4672 }4673 4674 outs() << indent << "\t\t entsize " << ml.entsize << "\n";4675 outs() << indent << "\t\t count " << ml.count << "\n";4676 4677 offset += sizeof(struct method_list32_t);4678 for (i = 0; i < ml.count; i++) {4679 r = get_pointer_32(p, offset, left, S, info);4680 if (r == nullptr)4681 return;4682 memset(&m, '\0', sizeof(struct method32_t));4683 if (left < sizeof(struct method32_t)) {4684 memcpy(&ml, r, left);4685 outs() << indent << " (method_t entends past the end of the section)\n";4686 } else4687 memcpy(&m, r, sizeof(struct method32_t));4688 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4689 swapStruct(m);4690 4691 outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);4692 name = get_pointer_32(m.name, xoffset, left, xS, info);4693 if (name != nullptr)4694 outs() << format(" %.*s", left, name);4695 outs() << "\n";4696 4697 outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);4698 name = get_pointer_32(m.types, xoffset, left, xS, info);4699 if (name != nullptr)4700 outs() << format(" %.*s", left, name);4701 outs() << "\n";4702 4703 outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);4704 name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,4705 m.imp);4706 if (name != nullptr)4707 outs() << " " << name;4708 outs() << "\n";4709 4710 p += sizeof(struct method32_t);4711 offset += sizeof(struct method32_t);4712 }4713}4714 4715static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {4716 uint32_t offset, left, xleft;4717 SectionRef S;4718 struct objc_method_list_t method_list;4719 struct objc_method_t method;4720 const char *r, *methods, *name, *SymbolName;4721 int32_t i;4722 4723 r = get_pointer_32(p, offset, left, S, info, true);4724 if (r == nullptr)4725 return true;4726 4727 outs() << "\n";4728 if (left > sizeof(struct objc_method_list_t)) {4729 memcpy(&method_list, r, sizeof(struct objc_method_list_t));4730 } else {4731 outs() << "\t\t objc_method_list extends past end of the section\n";4732 memset(&method_list, '\0', sizeof(struct objc_method_list_t));4733 memcpy(&method_list, r, left);4734 }4735 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4736 swapStruct(method_list);4737 4738 outs() << "\t\t obsolete "4739 << format("0x%08" PRIx32, method_list.obsolete) << "\n";4740 outs() << "\t\t method_count " << method_list.method_count << "\n";4741 4742 methods = r + sizeof(struct objc_method_list_t);4743 for (i = 0; i < method_list.method_count; i++) {4744 if ((i + 1) * sizeof(struct objc_method_t) > left) {4745 outs() << "\t\t remaining method's extend past the of the section\n";4746 break;4747 }4748 memcpy(&method, methods + i * sizeof(struct objc_method_t),4749 sizeof(struct objc_method_t));4750 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4751 swapStruct(method);4752 4753 outs() << "\t\t method_name "4754 << format("0x%08" PRIx32, method.method_name);4755 if (info->verbose) {4756 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);4757 if (name != nullptr)4758 outs() << format(" %.*s", xleft, name);4759 else4760 outs() << " (not in an __OBJC section)";4761 }4762 outs() << "\n";4763 4764 outs() << "\t\t method_types "4765 << format("0x%08" PRIx32, method.method_types);4766 if (info->verbose) {4767 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);4768 if (name != nullptr)4769 outs() << format(" %.*s", xleft, name);4770 else4771 outs() << " (not in an __OBJC section)";4772 }4773 outs() << "\n";4774 4775 outs() << "\t\t method_imp "4776 << format("0x%08" PRIx32, method.method_imp) << " ";4777 if (info->verbose) {4778 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);4779 if (SymbolName != nullptr)4780 outs() << SymbolName;4781 }4782 outs() << "\n";4783 }4784 return false;4785}4786 4787static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {4788 struct protocol_list64_t pl;4789 uint64_t q, n_value;4790 struct protocol64_t pc;4791 const char *r;4792 uint32_t offset, xoffset, left, i;4793 SectionRef S, xS;4794 const char *name, *sym_name;4795 4796 r = get_pointer_64(p, offset, left, S, info);4797 if (r == nullptr)4798 return;4799 memset(&pl, '\0', sizeof(struct protocol_list64_t));4800 if (left < sizeof(struct protocol_list64_t)) {4801 memcpy(&pl, r, left);4802 outs() << " (protocol_list_t entends past the end of the section)\n";4803 } else4804 memcpy(&pl, r, sizeof(struct protocol_list64_t));4805 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4806 swapStruct(pl);4807 outs() << " count " << pl.count << "\n";4808 4809 p += sizeof(struct protocol_list64_t);4810 offset += sizeof(struct protocol_list64_t);4811 for (i = 0; i < pl.count; i++) {4812 r = get_pointer_64(p, offset, left, S, info);4813 if (r == nullptr)4814 return;4815 q = 0;4816 if (left < sizeof(uint64_t)) {4817 memcpy(&q, r, left);4818 outs() << " (protocol_t * entends past the end of the section)\n";4819 } else4820 memcpy(&q, r, sizeof(uint64_t));4821 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4822 sys::swapByteOrder(q);4823 4824 outs() << "\t\t list[" << i << "] ";4825 sym_name = get_symbol_64(offset, S, info, n_value, q);4826 if (n_value != 0) {4827 if (info->verbose && sym_name != nullptr)4828 outs() << sym_name;4829 else4830 outs() << format("0x%" PRIx64, n_value);4831 if (q != 0)4832 outs() << " + " << format("0x%" PRIx64, q);4833 } else4834 outs() << format("0x%" PRIx64, q);4835 outs() << " (struct protocol_t *)\n";4836 4837 r = get_pointer_64(q + n_value, offset, left, S, info);4838 if (r == nullptr)4839 return;4840 memset(&pc, '\0', sizeof(struct protocol64_t));4841 if (left < sizeof(struct protocol64_t)) {4842 memcpy(&pc, r, left);4843 outs() << " (protocol_t entends past the end of the section)\n";4844 } else4845 memcpy(&pc, r, sizeof(struct protocol64_t));4846 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4847 swapStruct(pc);4848 4849 outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";4850 4851 outs() << "\t\t\t name ";4852 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,4853 info, n_value, pc.name);4854 if (n_value != 0) {4855 if (info->verbose && sym_name != nullptr)4856 outs() << sym_name;4857 else4858 outs() << format("0x%" PRIx64, n_value);4859 if (pc.name != 0)4860 outs() << " + " << format("0x%" PRIx64, pc.name);4861 } else4862 outs() << format("0x%" PRIx64, pc.name);4863 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);4864 if (name != nullptr)4865 outs() << format(" %.*s", left, name);4866 outs() << "\n";4867 4868 outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";4869 4870 outs() << "\t\t instanceMethods ";4871 sym_name =4872 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),4873 S, info, n_value, pc.instanceMethods);4874 if (n_value != 0) {4875 if (info->verbose && sym_name != nullptr)4876 outs() << sym_name;4877 else4878 outs() << format("0x%" PRIx64, n_value);4879 if (pc.instanceMethods != 0)4880 outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);4881 } else4882 outs() << format("0x%" PRIx64, pc.instanceMethods);4883 outs() << " (struct method_list_t *)\n";4884 if (pc.instanceMethods + n_value != 0)4885 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");4886 4887 outs() << "\t\t classMethods ";4888 sym_name =4889 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,4890 info, n_value, pc.classMethods);4891 if (n_value != 0) {4892 if (info->verbose && sym_name != nullptr)4893 outs() << sym_name;4894 else4895 outs() << format("0x%" PRIx64, n_value);4896 if (pc.classMethods != 0)4897 outs() << " + " << format("0x%" PRIx64, pc.classMethods);4898 } else4899 outs() << format("0x%" PRIx64, pc.classMethods);4900 outs() << " (struct method_list_t *)\n";4901 if (pc.classMethods + n_value != 0)4902 print_method_list64_t(pc.classMethods + n_value, info, "\t");4903 4904 outs() << "\t optionalInstanceMethods "4905 << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";4906 outs() << "\t optionalClassMethods "4907 << format("0x%" PRIx64, pc.optionalClassMethods) << "\n";4908 outs() << "\t instanceProperties "4909 << format("0x%" PRIx64, pc.instanceProperties) << "\n";4910 4911 p += sizeof(uint64_t);4912 offset += sizeof(uint64_t);4913 }4914}4915 4916static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {4917 struct protocol_list32_t pl;4918 uint32_t q;4919 struct protocol32_t pc;4920 const char *r;4921 uint32_t offset, xoffset, left, i;4922 SectionRef S, xS;4923 const char *name;4924 4925 r = get_pointer_32(p, offset, left, S, info);4926 if (r == nullptr)4927 return;4928 memset(&pl, '\0', sizeof(struct protocol_list32_t));4929 if (left < sizeof(struct protocol_list32_t)) {4930 memcpy(&pl, r, left);4931 outs() << " (protocol_list_t entends past the end of the section)\n";4932 } else4933 memcpy(&pl, r, sizeof(struct protocol_list32_t));4934 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4935 swapStruct(pl);4936 outs() << " count " << pl.count << "\n";4937 4938 p += sizeof(struct protocol_list32_t);4939 offset += sizeof(struct protocol_list32_t);4940 for (i = 0; i < pl.count; i++) {4941 r = get_pointer_32(p, offset, left, S, info);4942 if (r == nullptr)4943 return;4944 q = 0;4945 if (left < sizeof(uint32_t)) {4946 memcpy(&q, r, left);4947 outs() << " (protocol_t * entends past the end of the section)\n";4948 } else4949 memcpy(&q, r, sizeof(uint32_t));4950 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4951 sys::swapByteOrder(q);4952 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)4953 << " (struct protocol_t *)\n";4954 r = get_pointer_32(q, offset, left, S, info);4955 if (r == nullptr)4956 return;4957 memset(&pc, '\0', sizeof(struct protocol32_t));4958 if (left < sizeof(struct protocol32_t)) {4959 memcpy(&pc, r, left);4960 outs() << " (protocol_t entends past the end of the section)\n";4961 } else4962 memcpy(&pc, r, sizeof(struct protocol32_t));4963 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)4964 swapStruct(pc);4965 outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";4966 outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);4967 name = get_pointer_32(pc.name, xoffset, left, xS, info);4968 if (name != nullptr)4969 outs() << format(" %.*s", left, name);4970 outs() << "\n";4971 outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";4972 outs() << "\t\t instanceMethods "4973 << format("0x%" PRIx32, pc.instanceMethods)4974 << " (struct method_list_t *)\n";4975 if (pc.instanceMethods != 0)4976 print_method_list32_t(pc.instanceMethods, info, "\t");4977 outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)4978 << " (struct method_list_t *)\n";4979 if (pc.classMethods != 0)4980 print_method_list32_t(pc.classMethods, info, "\t");4981 outs() << "\t optionalInstanceMethods "4982 << format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";4983 outs() << "\t optionalClassMethods "4984 << format("0x%" PRIx32, pc.optionalClassMethods) << "\n";4985 outs() << "\t instanceProperties "4986 << format("0x%" PRIx32, pc.instanceProperties) << "\n";4987 p += sizeof(uint32_t);4988 offset += sizeof(uint32_t);4989 }4990}4991 4992static void print_indent(uint32_t indent) {4993 for (uint32_t i = 0; i < indent;) {4994 if (indent - i >= 8) {4995 outs() << "\t";4996 i += 8;4997 } else {4998 for (uint32_t j = i; j < indent; j++)4999 outs() << " ";5000 return;5001 }5002 }5003}5004 5005static bool print_method_description_list(uint32_t p, uint32_t indent,5006 struct DisassembleInfo *info) {5007 uint32_t offset, left, xleft;5008 SectionRef S;5009 struct objc_method_description_list_t mdl;5010 struct objc_method_description_t md;5011 const char *r, *list, *name;5012 int32_t i;5013 5014 r = get_pointer_32(p, offset, left, S, info, true);5015 if (r == nullptr)5016 return true;5017 5018 outs() << "\n";5019 if (left > sizeof(struct objc_method_description_list_t)) {5020 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));5021 } else {5022 print_indent(indent);5023 outs() << " objc_method_description_list extends past end of the section\n";5024 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));5025 memcpy(&mdl, r, left);5026 }5027 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5028 swapStruct(mdl);5029 5030 print_indent(indent);5031 outs() << " count " << mdl.count << "\n";5032 5033 list = r + sizeof(struct objc_method_description_list_t);5034 for (i = 0; i < mdl.count; i++) {5035 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {5036 print_indent(indent);5037 outs() << " remaining list entries extend past the of the section\n";5038 break;5039 }5040 print_indent(indent);5041 outs() << " list[" << i << "]\n";5042 memcpy(&md, list + i * sizeof(struct objc_method_description_t),5043 sizeof(struct objc_method_description_t));5044 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5045 swapStruct(md);5046 5047 print_indent(indent);5048 outs() << " name " << format("0x%08" PRIx32, md.name);5049 if (info->verbose) {5050 name = get_pointer_32(md.name, offset, xleft, S, info, true);5051 if (name != nullptr)5052 outs() << format(" %.*s", xleft, name);5053 else5054 outs() << " (not in an __OBJC section)";5055 }5056 outs() << "\n";5057 5058 print_indent(indent);5059 outs() << " types " << format("0x%08" PRIx32, md.types);5060 if (info->verbose) {5061 name = get_pointer_32(md.types, offset, xleft, S, info, true);5062 if (name != nullptr)5063 outs() << format(" %.*s", xleft, name);5064 else5065 outs() << " (not in an __OBJC section)";5066 }5067 outs() << "\n";5068 }5069 return false;5070}5071 5072static bool print_protocol_list(uint32_t p, uint32_t indent,5073 struct DisassembleInfo *info);5074 5075static bool print_protocol(uint32_t p, uint32_t indent,5076 struct DisassembleInfo *info) {5077 uint32_t offset, left;5078 SectionRef S;5079 struct objc_protocol_t protocol;5080 const char *r, *name;5081 5082 r = get_pointer_32(p, offset, left, S, info, true);5083 if (r == nullptr)5084 return true;5085 5086 outs() << "\n";5087 if (left >= sizeof(struct objc_protocol_t)) {5088 memcpy(&protocol, r, sizeof(struct objc_protocol_t));5089 } else {5090 print_indent(indent);5091 outs() << " Protocol extends past end of the section\n";5092 memset(&protocol, '\0', sizeof(struct objc_protocol_t));5093 memcpy(&protocol, r, left);5094 }5095 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5096 swapStruct(protocol);5097 5098 print_indent(indent);5099 outs() << " isa " << format("0x%08" PRIx32, protocol.isa)5100 << "\n";5101 5102 print_indent(indent);5103 outs() << " protocol_name "5104 << format("0x%08" PRIx32, protocol.protocol_name);5105 if (info->verbose) {5106 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);5107 if (name != nullptr)5108 outs() << format(" %.*s", left, name);5109 else5110 outs() << " (not in an __OBJC section)";5111 }5112 outs() << "\n";5113 5114 print_indent(indent);5115 outs() << " protocol_list "5116 << format("0x%08" PRIx32, protocol.protocol_list);5117 if (print_protocol_list(protocol.protocol_list, indent + 4, info))5118 outs() << " (not in an __OBJC section)\n";5119 5120 print_indent(indent);5121 outs() << " instance_methods "5122 << format("0x%08" PRIx32, protocol.instance_methods);5123 if (print_method_description_list(protocol.instance_methods, indent, info))5124 outs() << " (not in an __OBJC section)\n";5125 5126 print_indent(indent);5127 outs() << " class_methods "5128 << format("0x%08" PRIx32, protocol.class_methods);5129 if (print_method_description_list(protocol.class_methods, indent, info))5130 outs() << " (not in an __OBJC section)\n";5131 5132 return false;5133}5134 5135static bool print_protocol_list(uint32_t p, uint32_t indent,5136 struct DisassembleInfo *info) {5137 uint32_t offset, left, l;5138 SectionRef S;5139 struct objc_protocol_list_t protocol_list;5140 const char *r, *list;5141 int32_t i;5142 5143 r = get_pointer_32(p, offset, left, S, info, true);5144 if (r == nullptr)5145 return true;5146 5147 outs() << "\n";5148 if (left > sizeof(struct objc_protocol_list_t)) {5149 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));5150 } else {5151 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";5152 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));5153 memcpy(&protocol_list, r, left);5154 }5155 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5156 swapStruct(protocol_list);5157 5158 print_indent(indent);5159 outs() << " next " << format("0x%08" PRIx32, protocol_list.next)5160 << "\n";5161 print_indent(indent);5162 outs() << " count " << protocol_list.count << "\n";5163 5164 list = r + sizeof(struct objc_protocol_list_t);5165 for (i = 0; i < protocol_list.count; i++) {5166 if ((i + 1) * sizeof(uint32_t) > left) {5167 outs() << "\t\t remaining list entries extend past the of the section\n";5168 break;5169 }5170 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));5171 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5172 sys::swapByteOrder(l);5173 5174 print_indent(indent);5175 outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);5176 if (print_protocol(l, indent, info))5177 outs() << "(not in an __OBJC section)\n";5178 }5179 return false;5180}5181 5182static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {5183 struct ivar_list64_t il;5184 struct ivar64_t i;5185 const char *r;5186 uint32_t offset, xoffset, left, j;5187 SectionRef S, xS;5188 const char *name, *sym_name, *ivar_offset_p;5189 uint64_t ivar_offset, n_value;5190 5191 r = get_pointer_64(p, offset, left, S, info);5192 if (r == nullptr)5193 return;5194 memset(&il, '\0', sizeof(struct ivar_list64_t));5195 if (left < sizeof(struct ivar_list64_t)) {5196 memcpy(&il, r, left);5197 outs() << " (ivar_list_t entends past the end of the section)\n";5198 } else5199 memcpy(&il, r, sizeof(struct ivar_list64_t));5200 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5201 swapStruct(il);5202 outs() << " entsize " << il.entsize << "\n";5203 outs() << " count " << il.count << "\n";5204 5205 p += sizeof(struct ivar_list64_t);5206 offset += sizeof(struct ivar_list64_t);5207 for (j = 0; j < il.count; j++) {5208 r = get_pointer_64(p, offset, left, S, info);5209 if (r == nullptr)5210 return;5211 memset(&i, '\0', sizeof(struct ivar64_t));5212 if (left < sizeof(struct ivar64_t)) {5213 memcpy(&i, r, left);5214 outs() << " (ivar_t entends past the end of the section)\n";5215 } else5216 memcpy(&i, r, sizeof(struct ivar64_t));5217 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5218 swapStruct(i);5219 5220 outs() << "\t\t\t offset ";5221 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,5222 info, n_value, i.offset);5223 if (n_value != 0) {5224 if (info->verbose && sym_name != nullptr)5225 outs() << sym_name;5226 else5227 outs() << format("0x%" PRIx64, n_value);5228 if (i.offset != 0)5229 outs() << " + " << format("0x%" PRIx64, i.offset);5230 } else5231 outs() << format("0x%" PRIx64, i.offset);5232 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);5233 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5234 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5235 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5236 sys::swapByteOrder(ivar_offset);5237 outs() << " " << ivar_offset << "\n";5238 } else5239 outs() << "\n";5240 5241 outs() << "\t\t\t name ";5242 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,5243 n_value, i.name);5244 if (n_value != 0) {5245 if (info->verbose && sym_name != nullptr)5246 outs() << sym_name;5247 else5248 outs() << format("0x%" PRIx64, n_value);5249 if (i.name != 0)5250 outs() << " + " << format("0x%" PRIx64, i.name);5251 } else5252 outs() << format("0x%" PRIx64, i.name);5253 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);5254 if (name != nullptr)5255 outs() << format(" %.*s", left, name);5256 outs() << "\n";5257 5258 outs() << "\t\t\t type ";5259 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,5260 n_value, i.name);5261 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);5262 if (n_value != 0) {5263 if (info->verbose && sym_name != nullptr)5264 outs() << sym_name;5265 else5266 outs() << format("0x%" PRIx64, n_value);5267 if (i.type != 0)5268 outs() << " + " << format("0x%" PRIx64, i.type);5269 } else5270 outs() << format("0x%" PRIx64, i.type);5271 if (name != nullptr)5272 outs() << format(" %.*s", left, name);5273 outs() << "\n";5274 5275 outs() << "\t\t\talignment " << i.alignment << "\n";5276 outs() << "\t\t\t size " << i.size << "\n";5277 5278 p += sizeof(struct ivar64_t);5279 offset += sizeof(struct ivar64_t);5280 }5281}5282 5283static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {5284 struct ivar_list32_t il;5285 struct ivar32_t i;5286 const char *r;5287 uint32_t offset, xoffset, left, j;5288 SectionRef S, xS;5289 const char *name, *ivar_offset_p;5290 uint32_t ivar_offset;5291 5292 r = get_pointer_32(p, offset, left, S, info);5293 if (r == nullptr)5294 return;5295 memset(&il, '\0', sizeof(struct ivar_list32_t));5296 if (left < sizeof(struct ivar_list32_t)) {5297 memcpy(&il, r, left);5298 outs() << " (ivar_list_t entends past the end of the section)\n";5299 } else5300 memcpy(&il, r, sizeof(struct ivar_list32_t));5301 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5302 swapStruct(il);5303 outs() << " entsize " << il.entsize << "\n";5304 outs() << " count " << il.count << "\n";5305 5306 p += sizeof(struct ivar_list32_t);5307 offset += sizeof(struct ivar_list32_t);5308 for (j = 0; j < il.count; j++) {5309 r = get_pointer_32(p, offset, left, S, info);5310 if (r == nullptr)5311 return;5312 memset(&i, '\0', sizeof(struct ivar32_t));5313 if (left < sizeof(struct ivar32_t)) {5314 memcpy(&i, r, left);5315 outs() << " (ivar_t entends past the end of the section)\n";5316 } else5317 memcpy(&i, r, sizeof(struct ivar32_t));5318 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5319 swapStruct(i);5320 5321 outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);5322 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);5323 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {5324 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));5325 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5326 sys::swapByteOrder(ivar_offset);5327 outs() << " " << ivar_offset << "\n";5328 } else5329 outs() << "\n";5330 5331 outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);5332 name = get_pointer_32(i.name, xoffset, left, xS, info);5333 if (name != nullptr)5334 outs() << format(" %.*s", left, name);5335 outs() << "\n";5336 5337 outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);5338 name = get_pointer_32(i.type, xoffset, left, xS, info);5339 if (name != nullptr)5340 outs() << format(" %.*s", left, name);5341 outs() << "\n";5342 5343 outs() << "\t\t\talignment " << i.alignment << "\n";5344 outs() << "\t\t\t size " << i.size << "\n";5345 5346 p += sizeof(struct ivar32_t);5347 offset += sizeof(struct ivar32_t);5348 }5349}5350 5351static void print_objc_property_list64(uint64_t p,5352 struct DisassembleInfo *info) {5353 struct objc_property_list64 opl;5354 struct objc_property64 op;5355 const char *r;5356 uint32_t offset, xoffset, left, j;5357 SectionRef S, xS;5358 const char *name, *sym_name;5359 uint64_t n_value;5360 5361 r = get_pointer_64(p, offset, left, S, info);5362 if (r == nullptr)5363 return;5364 memset(&opl, '\0', sizeof(struct objc_property_list64));5365 if (left < sizeof(struct objc_property_list64)) {5366 memcpy(&opl, r, left);5367 outs() << " (objc_property_list entends past the end of the section)\n";5368 } else5369 memcpy(&opl, r, sizeof(struct objc_property_list64));5370 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5371 swapStruct(opl);5372 outs() << " entsize " << opl.entsize << "\n";5373 outs() << " count " << opl.count << "\n";5374 5375 p += sizeof(struct objc_property_list64);5376 offset += sizeof(struct objc_property_list64);5377 for (j = 0; j < opl.count; j++) {5378 r = get_pointer_64(p, offset, left, S, info);5379 if (r == nullptr)5380 return;5381 memset(&op, '\0', sizeof(struct objc_property64));5382 if (left < sizeof(struct objc_property64)) {5383 memcpy(&op, r, left);5384 outs() << " (objc_property entends past the end of the section)\n";5385 } else5386 memcpy(&op, r, sizeof(struct objc_property64));5387 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5388 swapStruct(op);5389 5390 outs() << "\t\t\t name ";5391 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,5392 info, n_value, op.name);5393 if (n_value != 0) {5394 if (info->verbose && sym_name != nullptr)5395 outs() << sym_name;5396 else5397 outs() << format("0x%" PRIx64, n_value);5398 if (op.name != 0)5399 outs() << " + " << format("0x%" PRIx64, op.name);5400 } else5401 outs() << format("0x%" PRIx64, op.name);5402 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);5403 if (name != nullptr)5404 outs() << format(" %.*s", left, name);5405 outs() << "\n";5406 5407 outs() << "\t\t\tattributes ";5408 sym_name =5409 get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,5410 info, n_value, op.attributes);5411 if (n_value != 0) {5412 if (info->verbose && sym_name != nullptr)5413 outs() << sym_name;5414 else5415 outs() << format("0x%" PRIx64, n_value);5416 if (op.attributes != 0)5417 outs() << " + " << format("0x%" PRIx64, op.attributes);5418 } else5419 outs() << format("0x%" PRIx64, op.attributes);5420 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);5421 if (name != nullptr)5422 outs() << format(" %.*s", left, name);5423 outs() << "\n";5424 5425 p += sizeof(struct objc_property64);5426 offset += sizeof(struct objc_property64);5427 }5428}5429 5430static void print_objc_property_list32(uint32_t p,5431 struct DisassembleInfo *info) {5432 struct objc_property_list32 opl;5433 struct objc_property32 op;5434 const char *r;5435 uint32_t offset, xoffset, left, j;5436 SectionRef S, xS;5437 const char *name;5438 5439 r = get_pointer_32(p, offset, left, S, info);5440 if (r == nullptr)5441 return;5442 memset(&opl, '\0', sizeof(struct objc_property_list32));5443 if (left < sizeof(struct objc_property_list32)) {5444 memcpy(&opl, r, left);5445 outs() << " (objc_property_list entends past the end of the section)\n";5446 } else5447 memcpy(&opl, r, sizeof(struct objc_property_list32));5448 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5449 swapStruct(opl);5450 outs() << " entsize " << opl.entsize << "\n";5451 outs() << " count " << opl.count << "\n";5452 5453 p += sizeof(struct objc_property_list32);5454 offset += sizeof(struct objc_property_list32);5455 for (j = 0; j < opl.count; j++) {5456 r = get_pointer_32(p, offset, left, S, info);5457 if (r == nullptr)5458 return;5459 memset(&op, '\0', sizeof(struct objc_property32));5460 if (left < sizeof(struct objc_property32)) {5461 memcpy(&op, r, left);5462 outs() << " (objc_property entends past the end of the section)\n";5463 } else5464 memcpy(&op, r, sizeof(struct objc_property32));5465 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5466 swapStruct(op);5467 5468 outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);5469 name = get_pointer_32(op.name, xoffset, left, xS, info);5470 if (name != nullptr)5471 outs() << format(" %.*s", left, name);5472 outs() << "\n";5473 5474 outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);5475 name = get_pointer_32(op.attributes, xoffset, left, xS, info);5476 if (name != nullptr)5477 outs() << format(" %.*s", left, name);5478 outs() << "\n";5479 5480 p += sizeof(struct objc_property32);5481 offset += sizeof(struct objc_property32);5482 }5483}5484 5485static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,5486 bool &is_meta_class) {5487 struct class_ro64_t cro;5488 const char *r;5489 uint32_t offset, xoffset, left;5490 SectionRef S, xS;5491 const char *name, *sym_name;5492 uint64_t n_value;5493 5494 r = get_pointer_64(p, offset, left, S, info);5495 if (r == nullptr || left < sizeof(struct class_ro64_t))5496 return false;5497 memcpy(&cro, r, sizeof(struct class_ro64_t));5498 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5499 swapStruct(cro);5500 outs() << " flags " << format("0x%" PRIx32, cro.flags);5501 if (cro.flags & RO_META)5502 outs() << " RO_META";5503 if (cro.flags & RO_ROOT)5504 outs() << " RO_ROOT";5505 if (cro.flags & RO_HAS_CXX_STRUCTORS)5506 outs() << " RO_HAS_CXX_STRUCTORS";5507 outs() << "\n";5508 outs() << " instanceStart " << cro.instanceStart << "\n";5509 outs() << " instanceSize " << cro.instanceSize << "\n";5510 outs() << " reserved " << format("0x%" PRIx32, cro.reserved)5511 << "\n";5512 outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)5513 << "\n";5514 print_layout_map64(cro.ivarLayout, info);5515 5516 outs() << " name ";5517 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,5518 info, n_value, cro.name);5519 if (n_value != 0) {5520 if (info->verbose && sym_name != nullptr)5521 outs() << sym_name;5522 else5523 outs() << format("0x%" PRIx64, n_value);5524 if (cro.name != 0)5525 outs() << " + " << format("0x%" PRIx64, cro.name);5526 } else5527 outs() << format("0x%" PRIx64, cro.name);5528 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);5529 if (name != nullptr)5530 outs() << format(" %.*s", left, name);5531 outs() << "\n";5532 5533 outs() << " baseMethods ";5534 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),5535 S, info, n_value, cro.baseMethods);5536 if (n_value != 0) {5537 if (info->verbose && sym_name != nullptr)5538 outs() << sym_name;5539 else5540 outs() << format("0x%" PRIx64, n_value);5541 if (cro.baseMethods != 0)5542 outs() << " + " << format("0x%" PRIx64, cro.baseMethods);5543 } else5544 outs() << format("0x%" PRIx64, cro.baseMethods);5545 outs() << " (struct method_list_t *)\n";5546 if (cro.baseMethods + n_value != 0)5547 print_method_list64_t(cro.baseMethods + n_value, info, "");5548 5549 outs() << " baseProtocols ";5550 sym_name =5551 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,5552 info, n_value, cro.baseProtocols);5553 if (n_value != 0) {5554 if (info->verbose && sym_name != nullptr)5555 outs() << sym_name;5556 else5557 outs() << format("0x%" PRIx64, n_value);5558 if (cro.baseProtocols != 0)5559 outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);5560 } else5561 outs() << format("0x%" PRIx64, cro.baseProtocols);5562 outs() << "\n";5563 if (cro.baseProtocols + n_value != 0)5564 print_protocol_list64_t(cro.baseProtocols + n_value, info);5565 5566 outs() << " ivars ";5567 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,5568 info, n_value, cro.ivars);5569 if (n_value != 0) {5570 if (info->verbose && sym_name != nullptr)5571 outs() << sym_name;5572 else5573 outs() << format("0x%" PRIx64, n_value);5574 if (cro.ivars != 0)5575 outs() << " + " << format("0x%" PRIx64, cro.ivars);5576 } else5577 outs() << format("0x%" PRIx64, cro.ivars);5578 outs() << "\n";5579 if (cro.ivars + n_value != 0)5580 print_ivar_list64_t(cro.ivars + n_value, info);5581 5582 outs() << " weakIvarLayout ";5583 sym_name =5584 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,5585 info, n_value, cro.weakIvarLayout);5586 if (n_value != 0) {5587 if (info->verbose && sym_name != nullptr)5588 outs() << sym_name;5589 else5590 outs() << format("0x%" PRIx64, n_value);5591 if (cro.weakIvarLayout != 0)5592 outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);5593 } else5594 outs() << format("0x%" PRIx64, cro.weakIvarLayout);5595 outs() << "\n";5596 print_layout_map64(cro.weakIvarLayout + n_value, info);5597 5598 outs() << " baseProperties ";5599 sym_name =5600 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,5601 info, n_value, cro.baseProperties);5602 if (n_value != 0) {5603 if (info->verbose && sym_name != nullptr)5604 outs() << sym_name;5605 else5606 outs() << format("0x%" PRIx64, n_value);5607 if (cro.baseProperties != 0)5608 outs() << " + " << format("0x%" PRIx64, cro.baseProperties);5609 } else5610 outs() << format("0x%" PRIx64, cro.baseProperties);5611 outs() << "\n";5612 if (cro.baseProperties + n_value != 0)5613 print_objc_property_list64(cro.baseProperties + n_value, info);5614 5615 is_meta_class = (cro.flags & RO_META) != 0;5616 return true;5617}5618 5619static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,5620 bool &is_meta_class) {5621 struct class_ro32_t cro;5622 const char *r;5623 uint32_t offset, xoffset, left;5624 SectionRef S, xS;5625 const char *name;5626 5627 r = get_pointer_32(p, offset, left, S, info);5628 if (r == nullptr)5629 return false;5630 memset(&cro, '\0', sizeof(struct class_ro32_t));5631 if (left < sizeof(struct class_ro32_t)) {5632 memcpy(&cro, r, left);5633 outs() << " (class_ro_t entends past the end of the section)\n";5634 } else5635 memcpy(&cro, r, sizeof(struct class_ro32_t));5636 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5637 swapStruct(cro);5638 outs() << " flags " << format("0x%" PRIx32, cro.flags);5639 if (cro.flags & RO_META)5640 outs() << " RO_META";5641 if (cro.flags & RO_ROOT)5642 outs() << " RO_ROOT";5643 if (cro.flags & RO_HAS_CXX_STRUCTORS)5644 outs() << " RO_HAS_CXX_STRUCTORS";5645 outs() << "\n";5646 outs() << " instanceStart " << cro.instanceStart << "\n";5647 outs() << " instanceSize " << cro.instanceSize << "\n";5648 outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)5649 << "\n";5650 print_layout_map32(cro.ivarLayout, info);5651 5652 outs() << " name " << format("0x%" PRIx32, cro.name);5653 name = get_pointer_32(cro.name, xoffset, left, xS, info);5654 if (name != nullptr)5655 outs() << format(" %.*s", left, name);5656 outs() << "\n";5657 5658 outs() << " baseMethods "5659 << format("0x%" PRIx32, cro.baseMethods)5660 << " (struct method_list_t *)\n";5661 if (cro.baseMethods != 0)5662 print_method_list32_t(cro.baseMethods, info, "");5663 5664 outs() << " baseProtocols "5665 << format("0x%" PRIx32, cro.baseProtocols) << "\n";5666 if (cro.baseProtocols != 0)5667 print_protocol_list32_t(cro.baseProtocols, info);5668 outs() << " ivars " << format("0x%" PRIx32, cro.ivars)5669 << "\n";5670 if (cro.ivars != 0)5671 print_ivar_list32_t(cro.ivars, info);5672 outs() << " weakIvarLayout "5673 << format("0x%" PRIx32, cro.weakIvarLayout) << "\n";5674 print_layout_map32(cro.weakIvarLayout, info);5675 outs() << " baseProperties "5676 << format("0x%" PRIx32, cro.baseProperties) << "\n";5677 if (cro.baseProperties != 0)5678 print_objc_property_list32(cro.baseProperties, info);5679 is_meta_class = (cro.flags & RO_META) != 0;5680 return true;5681}5682 5683static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {5684 struct class64_t c;5685 const char *r;5686 uint32_t offset, left;5687 SectionRef S;5688 const char *name;5689 uint64_t isa_n_value, n_value;5690 5691 r = get_pointer_64(p, offset, left, S, info);5692 if (r == nullptr || left < sizeof(struct class64_t))5693 return;5694 memcpy(&c, r, sizeof(struct class64_t));5695 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5696 swapStruct(c);5697 5698 outs() << " isa " << format("0x%" PRIx64, c.isa);5699 name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,5700 isa_n_value, c.isa);5701 if (name != nullptr)5702 outs() << " " << name;5703 outs() << "\n";5704 5705 outs() << " superclass " << format("0x%" PRIx64, c.superclass);5706 name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,5707 n_value, c.superclass);5708 if (name != nullptr)5709 outs() << " " << name;5710 else {5711 name = get_dyld_bind_info_symbolname(S.getAddress() +5712 offset + offsetof(struct class64_t, superclass), info);5713 if (name != nullptr)5714 outs() << " " << name;5715 }5716 outs() << "\n";5717 5718 outs() << " cache " << format("0x%" PRIx64, c.cache);5719 name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,5720 n_value, c.cache);5721 if (name != nullptr)5722 outs() << " " << name;5723 outs() << "\n";5724 5725 outs() << " vtable " << format("0x%" PRIx64, c.vtable);5726 name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,5727 n_value, c.vtable);5728 if (name != nullptr)5729 outs() << " " << name;5730 outs() << "\n";5731 5732 name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,5733 n_value, c.data);5734 outs() << " data ";5735 if (n_value != 0) {5736 if (info->verbose && name != nullptr)5737 outs() << name;5738 else5739 outs() << format("0x%" PRIx64, n_value);5740 if (c.data != 0)5741 outs() << " + " << format("0x%" PRIx64, c.data);5742 } else5743 outs() << format("0x%" PRIx64, c.data);5744 outs() << " (struct class_ro_t *)";5745 5746 // This is a Swift class if some of the low bits of the pointer are set.5747 if ((c.data + n_value) & 0x7)5748 outs() << " Swift class";5749 outs() << "\n";5750 bool is_meta_class;5751 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))5752 return;5753 5754 if (!is_meta_class &&5755 c.isa + isa_n_value != p &&5756 c.isa + isa_n_value != 0 &&5757 info->depth < 100) {5758 info->depth++;5759 outs() << "Meta Class\n";5760 print_class64_t(c.isa + isa_n_value, info);5761 }5762}5763 5764static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {5765 struct class32_t c;5766 const char *r;5767 uint32_t offset, left;5768 SectionRef S;5769 const char *name;5770 5771 r = get_pointer_32(p, offset, left, S, info);5772 if (r == nullptr)5773 return;5774 memset(&c, '\0', sizeof(struct class32_t));5775 if (left < sizeof(struct class32_t)) {5776 memcpy(&c, r, left);5777 outs() << " (class_t entends past the end of the section)\n";5778 } else5779 memcpy(&c, r, sizeof(struct class32_t));5780 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5781 swapStruct(c);5782 5783 outs() << " isa " << format("0x%" PRIx32, c.isa);5784 name =5785 get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);5786 if (name != nullptr)5787 outs() << " " << name;5788 outs() << "\n";5789 5790 outs() << " superclass " << format("0x%" PRIx32, c.superclass);5791 name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,5792 c.superclass);5793 if (name != nullptr)5794 outs() << " " << name;5795 outs() << "\n";5796 5797 outs() << " cache " << format("0x%" PRIx32, c.cache);5798 name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,5799 c.cache);5800 if (name != nullptr)5801 outs() << " " << name;5802 outs() << "\n";5803 5804 outs() << " vtable " << format("0x%" PRIx32, c.vtable);5805 name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,5806 c.vtable);5807 if (name != nullptr)5808 outs() << " " << name;5809 outs() << "\n";5810 5811 name =5812 get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);5813 outs() << " data " << format("0x%" PRIx32, c.data)5814 << " (struct class_ro_t *)";5815 5816 // This is a Swift class if some of the low bits of the pointer are set.5817 if (c.data & 0x3)5818 outs() << " Swift class";5819 outs() << "\n";5820 bool is_meta_class;5821 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))5822 return;5823 5824 if (!is_meta_class) {5825 outs() << "Meta Class\n";5826 print_class32_t(c.isa, info);5827 }5828}5829 5830static void print_objc_class_t(struct objc_class_t *objc_class,5831 struct DisassembleInfo *info) {5832 uint32_t offset, left, xleft;5833 const char *name, *p, *ivar_list;5834 SectionRef S;5835 int32_t i;5836 struct objc_ivar_list_t objc_ivar_list;5837 struct objc_ivar_t ivar;5838 5839 outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);5840 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {5841 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);5842 if (name != nullptr)5843 outs() << format(" %.*s", left, name);5844 else5845 outs() << " (not in an __OBJC section)";5846 }5847 outs() << "\n";5848 5849 outs() << "\t super_class "5850 << format("0x%08" PRIx32, objc_class->super_class);5851 if (info->verbose) {5852 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);5853 if (name != nullptr)5854 outs() << format(" %.*s", left, name);5855 else5856 outs() << " (not in an __OBJC section)";5857 }5858 outs() << "\n";5859 5860 outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);5861 if (info->verbose) {5862 name = get_pointer_32(objc_class->name, offset, left, S, info, true);5863 if (name != nullptr)5864 outs() << format(" %.*s", left, name);5865 else5866 outs() << " (not in an __OBJC section)";5867 }5868 outs() << "\n";5869 5870 outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)5871 << "\n";5872 5873 outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);5874 if (info->verbose) {5875 if (CLS_GETINFO(objc_class, CLS_CLASS))5876 outs() << " CLS_CLASS";5877 else if (CLS_GETINFO(objc_class, CLS_META))5878 outs() << " CLS_META";5879 }5880 outs() << "\n";5881 5882 outs() << "\t instance_size "5883 << format("0x%08" PRIx32, objc_class->instance_size) << "\n";5884 5885 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);5886 outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);5887 if (p != nullptr) {5888 if (left > sizeof(struct objc_ivar_list_t)) {5889 outs() << "\n";5890 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));5891 } else {5892 outs() << " (entends past the end of the section)\n";5893 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));5894 memcpy(&objc_ivar_list, p, left);5895 }5896 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5897 swapStruct(objc_ivar_list);5898 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";5899 ivar_list = p + sizeof(struct objc_ivar_list_t);5900 for (i = 0; i < objc_ivar_list.ivar_count; i++) {5901 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {5902 outs() << "\t\t remaining ivar's extend past the of the section\n";5903 break;5904 }5905 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),5906 sizeof(struct objc_ivar_t));5907 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)5908 swapStruct(ivar);5909 5910 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);5911 if (info->verbose) {5912 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);5913 if (name != nullptr)5914 outs() << format(" %.*s", xleft, name);5915 else5916 outs() << " (not in an __OBJC section)";5917 }5918 outs() << "\n";5919 5920 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);5921 if (info->verbose) {5922 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);5923 if (name != nullptr)5924 outs() << format(" %.*s", xleft, name);5925 else5926 outs() << " (not in an __OBJC section)";5927 }5928 outs() << "\n";5929 5930 outs() << "\t\t ivar_offset "5931 << format("0x%08" PRIx32, ivar.ivar_offset) << "\n";5932 }5933 } else {5934 outs() << " (not in an __OBJC section)\n";5935 }5936 5937 outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);5938 if (print_method_list(objc_class->methodLists, info))5939 outs() << " (not in an __OBJC section)\n";5940 5941 outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)5942 << "\n";5943 5944 outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);5945 if (print_protocol_list(objc_class->protocols, 16, info))5946 outs() << " (not in an __OBJC section)\n";5947}5948 5949static void print_objc_objc_category_t(struct objc_category_t *objc_category,5950 struct DisassembleInfo *info) {5951 uint32_t offset, left;5952 const char *name;5953 SectionRef S;5954 5955 outs() << "\t category name "5956 << format("0x%08" PRIx32, objc_category->category_name);5957 if (info->verbose) {5958 name = get_pointer_32(objc_category->category_name, offset, left, S, info,5959 true);5960 if (name != nullptr)5961 outs() << format(" %.*s", left, name);5962 else5963 outs() << " (not in an __OBJC section)";5964 }5965 outs() << "\n";5966 5967 outs() << "\t\t class name "5968 << format("0x%08" PRIx32, objc_category->class_name);5969 if (info->verbose) {5970 name =5971 get_pointer_32(objc_category->class_name, offset, left, S, info, true);5972 if (name != nullptr)5973 outs() << format(" %.*s", left, name);5974 else5975 outs() << " (not in an __OBJC section)";5976 }5977 outs() << "\n";5978 5979 outs() << "\t instance methods "5980 << format("0x%08" PRIx32, objc_category->instance_methods);5981 if (print_method_list(objc_category->instance_methods, info))5982 outs() << " (not in an __OBJC section)\n";5983 5984 outs() << "\t class methods "5985 << format("0x%08" PRIx32, objc_category->class_methods);5986 if (print_method_list(objc_category->class_methods, info))5987 outs() << " (not in an __OBJC section)\n";5988}5989 5990static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {5991 struct category64_t c;5992 const char *r;5993 uint32_t offset, xoffset, left;5994 SectionRef S, xS;5995 const char *name, *sym_name;5996 uint64_t n_value;5997 5998 r = get_pointer_64(p, offset, left, S, info);5999 if (r == nullptr)6000 return;6001 memset(&c, '\0', sizeof(struct category64_t));6002 if (left < sizeof(struct category64_t)) {6003 memcpy(&c, r, left);6004 outs() << " (category_t entends past the end of the section)\n";6005 } else6006 memcpy(&c, r, sizeof(struct category64_t));6007 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6008 swapStruct(c);6009 6010 outs() << " name ";6011 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,6012 info, n_value, c.name);6013 if (n_value != 0) {6014 if (info->verbose && sym_name != nullptr)6015 outs() << sym_name;6016 else6017 outs() << format("0x%" PRIx64, n_value);6018 if (c.name != 0)6019 outs() << " + " << format("0x%" PRIx64, c.name);6020 } else6021 outs() << format("0x%" PRIx64, c.name);6022 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);6023 if (name != nullptr)6024 outs() << format(" %.*s", left, name);6025 outs() << "\n";6026 6027 outs() << " cls ";6028 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,6029 n_value, c.cls);6030 if (n_value != 0) {6031 if (info->verbose && sym_name != nullptr)6032 outs() << sym_name;6033 else6034 outs() << format("0x%" PRIx64, n_value);6035 if (c.cls != 0)6036 outs() << " + " << format("0x%" PRIx64, c.cls);6037 } else6038 outs() << format("0x%" PRIx64, c.cls);6039 outs() << "\n";6040 if (c.cls + n_value != 0)6041 print_class64_t(c.cls + n_value, info);6042 6043 outs() << " instanceMethods ";6044 sym_name =6045 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,6046 info, n_value, c.instanceMethods);6047 if (n_value != 0) {6048 if (info->verbose && sym_name != nullptr)6049 outs() << sym_name;6050 else6051 outs() << format("0x%" PRIx64, n_value);6052 if (c.instanceMethods != 0)6053 outs() << " + " << format("0x%" PRIx64, c.instanceMethods);6054 } else6055 outs() << format("0x%" PRIx64, c.instanceMethods);6056 outs() << "\n";6057 if (c.instanceMethods + n_value != 0)6058 print_method_list64_t(c.instanceMethods + n_value, info, "");6059 6060 outs() << " classMethods ";6061 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),6062 S, info, n_value, c.classMethods);6063 if (n_value != 0) {6064 if (info->verbose && sym_name != nullptr)6065 outs() << sym_name;6066 else6067 outs() << format("0x%" PRIx64, n_value);6068 if (c.classMethods != 0)6069 outs() << " + " << format("0x%" PRIx64, c.classMethods);6070 } else6071 outs() << format("0x%" PRIx64, c.classMethods);6072 outs() << "\n";6073 if (c.classMethods + n_value != 0)6074 print_method_list64_t(c.classMethods + n_value, info, "");6075 6076 outs() << " protocols ";6077 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,6078 info, n_value, c.protocols);6079 if (n_value != 0) {6080 if (info->verbose && sym_name != nullptr)6081 outs() << sym_name;6082 else6083 outs() << format("0x%" PRIx64, n_value);6084 if (c.protocols != 0)6085 outs() << " + " << format("0x%" PRIx64, c.protocols);6086 } else6087 outs() << format("0x%" PRIx64, c.protocols);6088 outs() << "\n";6089 if (c.protocols + n_value != 0)6090 print_protocol_list64_t(c.protocols + n_value, info);6091 6092 outs() << "instanceProperties ";6093 sym_name =6094 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),6095 S, info, n_value, c.instanceProperties);6096 if (n_value != 0) {6097 if (info->verbose && sym_name != nullptr)6098 outs() << sym_name;6099 else6100 outs() << format("0x%" PRIx64, n_value);6101 if (c.instanceProperties != 0)6102 outs() << " + " << format("0x%" PRIx64, c.instanceProperties);6103 } else6104 outs() << format("0x%" PRIx64, c.instanceProperties);6105 outs() << "\n";6106 if (c.instanceProperties + n_value != 0)6107 print_objc_property_list64(c.instanceProperties + n_value, info);6108}6109 6110static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {6111 struct category32_t c;6112 const char *r;6113 uint32_t offset, left;6114 SectionRef S, xS;6115 const char *name;6116 6117 r = get_pointer_32(p, offset, left, S, info);6118 if (r == nullptr)6119 return;6120 memset(&c, '\0', sizeof(struct category32_t));6121 if (left < sizeof(struct category32_t)) {6122 memcpy(&c, r, left);6123 outs() << " (category_t entends past the end of the section)\n";6124 } else6125 memcpy(&c, r, sizeof(struct category32_t));6126 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6127 swapStruct(c);6128 6129 outs() << " name " << format("0x%" PRIx32, c.name);6130 name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,6131 c.name);6132 if (name)6133 outs() << " " << name;6134 outs() << "\n";6135 6136 outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";6137 if (c.cls != 0)6138 print_class32_t(c.cls, info);6139 outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)6140 << "\n";6141 if (c.instanceMethods != 0)6142 print_method_list32_t(c.instanceMethods, info, "");6143 outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)6144 << "\n";6145 if (c.classMethods != 0)6146 print_method_list32_t(c.classMethods, info, "");6147 outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";6148 if (c.protocols != 0)6149 print_protocol_list32_t(c.protocols, info);6150 outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)6151 << "\n";6152 if (c.instanceProperties != 0)6153 print_objc_property_list32(c.instanceProperties, info);6154}6155 6156static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {6157 uint32_t i, left, offset, xoffset;6158 uint64_t p, n_value;6159 struct message_ref64 mr;6160 const char *name, *sym_name;6161 const char *r;6162 SectionRef xS;6163 6164 if (S == SectionRef())6165 return;6166 6167 StringRef SectName;6168 Expected<StringRef> SecNameOrErr = S.getName();6169 if (SecNameOrErr)6170 SectName = *SecNameOrErr;6171 else6172 consumeError(SecNameOrErr.takeError());6173 6174 DataRefImpl Ref = S.getRawDataRefImpl();6175 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6176 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6177 offset = 0;6178 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6179 p = S.getAddress() + i;6180 r = get_pointer_64(p, offset, left, S, info);6181 if (r == nullptr)6182 return;6183 memset(&mr, '\0', sizeof(struct message_ref64));6184 if (left < sizeof(struct message_ref64)) {6185 memcpy(&mr, r, left);6186 outs() << " (message_ref entends past the end of the section)\n";6187 } else6188 memcpy(&mr, r, sizeof(struct message_ref64));6189 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6190 swapStruct(mr);6191 6192 outs() << " imp ";6193 name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,6194 n_value, mr.imp);6195 if (n_value != 0) {6196 outs() << format("0x%" PRIx64, n_value) << " ";6197 if (mr.imp != 0)6198 outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";6199 } else6200 outs() << format("0x%" PRIx64, mr.imp) << " ";6201 if (name != nullptr)6202 outs() << " " << name;6203 outs() << "\n";6204 6205 outs() << " sel ";6206 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,6207 info, n_value, mr.sel);6208 if (n_value != 0) {6209 if (info->verbose && sym_name != nullptr)6210 outs() << sym_name;6211 else6212 outs() << format("0x%" PRIx64, n_value);6213 if (mr.sel != 0)6214 outs() << " + " << format("0x%" PRIx64, mr.sel);6215 } else6216 outs() << format("0x%" PRIx64, mr.sel);6217 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);6218 if (name != nullptr)6219 outs() << format(" %.*s", left, name);6220 outs() << "\n";6221 6222 offset += sizeof(struct message_ref64);6223 }6224}6225 6226static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {6227 uint32_t i, left, offset, xoffset, p;6228 struct message_ref32 mr;6229 const char *name, *r;6230 SectionRef xS;6231 6232 if (S == SectionRef())6233 return;6234 6235 StringRef SectName;6236 Expected<StringRef> SecNameOrErr = S.getName();6237 if (SecNameOrErr)6238 SectName = *SecNameOrErr;6239 else6240 consumeError(SecNameOrErr.takeError());6241 6242 DataRefImpl Ref = S.getRawDataRefImpl();6243 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6244 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6245 offset = 0;6246 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {6247 p = S.getAddress() + i;6248 r = get_pointer_32(p, offset, left, S, info);6249 if (r == nullptr)6250 return;6251 memset(&mr, '\0', sizeof(struct message_ref32));6252 if (left < sizeof(struct message_ref32)) {6253 memcpy(&mr, r, left);6254 outs() << " (message_ref entends past the end of the section)\n";6255 } else6256 memcpy(&mr, r, sizeof(struct message_ref32));6257 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6258 swapStruct(mr);6259 6260 outs() << " imp " << format("0x%" PRIx32, mr.imp);6261 name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,6262 mr.imp);6263 if (name != nullptr)6264 outs() << " " << name;6265 outs() << "\n";6266 6267 outs() << " sel " << format("0x%" PRIx32, mr.sel);6268 name = get_pointer_32(mr.sel, xoffset, left, xS, info);6269 if (name != nullptr)6270 outs() << " " << name;6271 outs() << "\n";6272 6273 offset += sizeof(struct message_ref32);6274 }6275}6276 6277static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {6278 uint32_t left, offset, swift_version;6279 uint64_t p;6280 struct objc_image_info64 o;6281 const char *r;6282 6283 if (S == SectionRef())6284 return;6285 6286 StringRef SectName;6287 Expected<StringRef> SecNameOrErr = S.getName();6288 if (SecNameOrErr)6289 SectName = *SecNameOrErr;6290 else6291 consumeError(SecNameOrErr.takeError());6292 6293 DataRefImpl Ref = S.getRawDataRefImpl();6294 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6295 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6296 p = S.getAddress();6297 r = get_pointer_64(p, offset, left, S, info);6298 if (r == nullptr)6299 return;6300 memset(&o, '\0', sizeof(struct objc_image_info64));6301 if (left < sizeof(struct objc_image_info64)) {6302 memcpy(&o, r, left);6303 outs() << " (objc_image_info entends past the end of the section)\n";6304 } else6305 memcpy(&o, r, sizeof(struct objc_image_info64));6306 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6307 swapStruct(o);6308 outs() << " version " << o.version << "\n";6309 outs() << " flags " << format("0x%" PRIx32, o.flags);6310 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6311 outs() << " OBJC_IMAGE_IS_REPLACEMENT";6312 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6313 outs() << " OBJC_IMAGE_SUPPORTS_GC";6314 if (o.flags & OBJC_IMAGE_IS_SIMULATED)6315 outs() << " OBJC_IMAGE_IS_SIMULATED";6316 if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)6317 outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";6318 swift_version = (o.flags >> 8) & 0xff;6319 if (swift_version != 0) {6320 if (swift_version == 1)6321 outs() << " Swift 1.0";6322 else if (swift_version == 2)6323 outs() << " Swift 1.1";6324 else if(swift_version == 3)6325 outs() << " Swift 2.0";6326 else if(swift_version == 4)6327 outs() << " Swift 3.0";6328 else if(swift_version == 5)6329 outs() << " Swift 4.0";6330 else if(swift_version == 6)6331 outs() << " Swift 4.1/Swift 4.2";6332 else if(swift_version == 7)6333 outs() << " Swift 5 or later";6334 else6335 outs() << " unknown future Swift version (" << swift_version << ")";6336 }6337 outs() << "\n";6338}6339 6340static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {6341 uint32_t left, offset, swift_version, p;6342 struct objc_image_info32 o;6343 const char *r;6344 6345 if (S == SectionRef())6346 return;6347 6348 StringRef SectName;6349 Expected<StringRef> SecNameOrErr = S.getName();6350 if (SecNameOrErr)6351 SectName = *SecNameOrErr;6352 else6353 consumeError(SecNameOrErr.takeError());6354 6355 DataRefImpl Ref = S.getRawDataRefImpl();6356 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6357 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6358 p = S.getAddress();6359 r = get_pointer_32(p, offset, left, S, info);6360 if (r == nullptr)6361 return;6362 memset(&o, '\0', sizeof(struct objc_image_info32));6363 if (left < sizeof(struct objc_image_info32)) {6364 memcpy(&o, r, left);6365 outs() << " (objc_image_info entends past the end of the section)\n";6366 } else6367 memcpy(&o, r, sizeof(struct objc_image_info32));6368 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6369 swapStruct(o);6370 outs() << " version " << o.version << "\n";6371 outs() << " flags " << format("0x%" PRIx32, o.flags);6372 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)6373 outs() << " OBJC_IMAGE_IS_REPLACEMENT";6374 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)6375 outs() << " OBJC_IMAGE_SUPPORTS_GC";6376 swift_version = (o.flags >> 8) & 0xff;6377 if (swift_version != 0) {6378 if (swift_version == 1)6379 outs() << " Swift 1.0";6380 else if (swift_version == 2)6381 outs() << " Swift 1.1";6382 else if(swift_version == 3)6383 outs() << " Swift 2.0";6384 else if(swift_version == 4)6385 outs() << " Swift 3.0";6386 else if(swift_version == 5)6387 outs() << " Swift 4.0";6388 else if(swift_version == 6)6389 outs() << " Swift 4.1/Swift 4.2";6390 else if(swift_version == 7)6391 outs() << " Swift 5 or later";6392 else6393 outs() << " unknown future Swift version (" << swift_version << ")";6394 }6395 outs() << "\n";6396}6397 6398static void print_image_info(SectionRef S, struct DisassembleInfo *info) {6399 uint32_t left, offset, p;6400 struct imageInfo_t o;6401 const char *r;6402 6403 StringRef SectName;6404 Expected<StringRef> SecNameOrErr = S.getName();6405 if (SecNameOrErr)6406 SectName = *SecNameOrErr;6407 else6408 consumeError(SecNameOrErr.takeError());6409 6410 DataRefImpl Ref = S.getRawDataRefImpl();6411 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);6412 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";6413 p = S.getAddress();6414 r = get_pointer_32(p, offset, left, S, info);6415 if (r == nullptr)6416 return;6417 memset(&o, '\0', sizeof(struct imageInfo_t));6418 if (left < sizeof(struct imageInfo_t)) {6419 memcpy(&o, r, left);6420 outs() << " (imageInfo entends past the end of the section)\n";6421 } else6422 memcpy(&o, r, sizeof(struct imageInfo_t));6423 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)6424 swapStruct(o);6425 outs() << " version " << o.version << "\n";6426 outs() << " flags " << format("0x%" PRIx32, o.flags);6427 if (o.flags & 0x1)6428 outs() << " F&C";6429 if (o.flags & 0x2)6430 outs() << " GC";6431 if (o.flags & 0x4)6432 outs() << " GC-only";6433 else6434 outs() << " RR";6435 outs() << "\n";6436}6437 6438static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {6439 SymbolAddressMap AddrMap;6440 if (verbose)6441 CreateSymbolAddressMap(O, &AddrMap);6442 6443 std::vector<SectionRef> Sections;6444 append_range(Sections, O->sections());6445 6446 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6447 6448 SectionRef CL = get_section(O, "__OBJC2", "__class_list");6449 if (CL == SectionRef())6450 CL = get_section(O, "__DATA", "__objc_classlist");6451 if (CL == SectionRef())6452 CL = get_section(O, "__DATA_CONST", "__objc_classlist");6453 if (CL == SectionRef())6454 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6455 info.S = CL;6456 walk_pointer_list_64("class", CL, O, &info, print_class64_t);6457 6458 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6459 if (CR == SectionRef())6460 CR = get_section(O, "__DATA", "__objc_classrefs");6461 if (CR == SectionRef())6462 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6463 if (CR == SectionRef())6464 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6465 info.S = CR;6466 walk_pointer_list_64("class refs", CR, O, &info, nullptr);6467 6468 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6469 if (SR == SectionRef())6470 SR = get_section(O, "__DATA", "__objc_superrefs");6471 if (SR == SectionRef())6472 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6473 if (SR == SectionRef())6474 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6475 info.S = SR;6476 walk_pointer_list_64("super refs", SR, O, &info, nullptr);6477 6478 SectionRef CA = get_section(O, "__OBJC2", "__category_list");6479 if (CA == SectionRef())6480 CA = get_section(O, "__DATA", "__objc_catlist");6481 if (CA == SectionRef())6482 CA = get_section(O, "__DATA_CONST", "__objc_catlist");6483 if (CA == SectionRef())6484 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6485 info.S = CA;6486 walk_pointer_list_64("category", CA, O, &info, print_category64_t);6487 6488 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6489 if (PL == SectionRef())6490 PL = get_section(O, "__DATA", "__objc_protolist");6491 if (PL == SectionRef())6492 PL = get_section(O, "__DATA_CONST", "__objc_protolist");6493 if (PL == SectionRef())6494 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6495 info.S = PL;6496 walk_pointer_list_64("protocol", PL, O, &info, nullptr);6497 6498 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6499 if (MR == SectionRef())6500 MR = get_section(O, "__DATA", "__objc_msgrefs");6501 if (MR == SectionRef())6502 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6503 if (MR == SectionRef())6504 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6505 info.S = MR;6506 print_message_refs64(MR, &info);6507 6508 SectionRef II = get_section(O, "__OBJC2", "__image_info");6509 if (II == SectionRef())6510 II = get_section(O, "__DATA", "__objc_imageinfo");6511 if (II == SectionRef())6512 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6513 if (II == SectionRef())6514 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6515 info.S = II;6516 print_image_info64(II, &info);6517}6518 6519static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {6520 SymbolAddressMap AddrMap;6521 if (verbose)6522 CreateSymbolAddressMap(O, &AddrMap);6523 6524 std::vector<SectionRef> Sections;6525 append_range(Sections, O->sections());6526 6527 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6528 6529 SectionRef CL = get_section(O, "__OBJC2", "__class_list");6530 if (CL == SectionRef())6531 CL = get_section(O, "__DATA", "__objc_classlist");6532 if (CL == SectionRef())6533 CL = get_section(O, "__DATA_CONST", "__objc_classlist");6534 if (CL == SectionRef())6535 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");6536 info.S = CL;6537 walk_pointer_list_32("class", CL, O, &info, print_class32_t);6538 6539 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");6540 if (CR == SectionRef())6541 CR = get_section(O, "__DATA", "__objc_classrefs");6542 if (CR == SectionRef())6543 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");6544 if (CR == SectionRef())6545 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");6546 info.S = CR;6547 walk_pointer_list_32("class refs", CR, O, &info, nullptr);6548 6549 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");6550 if (SR == SectionRef())6551 SR = get_section(O, "__DATA", "__objc_superrefs");6552 if (SR == SectionRef())6553 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");6554 if (SR == SectionRef())6555 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");6556 info.S = SR;6557 walk_pointer_list_32("super refs", SR, O, &info, nullptr);6558 6559 SectionRef CA = get_section(O, "__OBJC2", "__category_list");6560 if (CA == SectionRef())6561 CA = get_section(O, "__DATA", "__objc_catlist");6562 if (CA == SectionRef())6563 CA = get_section(O, "__DATA_CONST", "__objc_catlist");6564 if (CA == SectionRef())6565 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");6566 info.S = CA;6567 walk_pointer_list_32("category", CA, O, &info, print_category32_t);6568 6569 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");6570 if (PL == SectionRef())6571 PL = get_section(O, "__DATA", "__objc_protolist");6572 if (PL == SectionRef())6573 PL = get_section(O, "__DATA_CONST", "__objc_protolist");6574 if (PL == SectionRef())6575 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");6576 info.S = PL;6577 walk_pointer_list_32("protocol", PL, O, &info, nullptr);6578 6579 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");6580 if (MR == SectionRef())6581 MR = get_section(O, "__DATA", "__objc_msgrefs");6582 if (MR == SectionRef())6583 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");6584 if (MR == SectionRef())6585 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");6586 info.S = MR;6587 print_message_refs32(MR, &info);6588 6589 SectionRef II = get_section(O, "__OBJC2", "__image_info");6590 if (II == SectionRef())6591 II = get_section(O, "__DATA", "__objc_imageinfo");6592 if (II == SectionRef())6593 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");6594 if (II == SectionRef())6595 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");6596 info.S = II;6597 print_image_info32(II, &info);6598}6599 6600static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {6601 uint32_t i, j, p, offset, xoffset, left, defs_left, def;6602 const char *r, *name, *defs;6603 struct objc_module_t module;6604 SectionRef S, xS;6605 struct objc_symtab_t symtab;6606 struct objc_class_t objc_class;6607 struct objc_category_t objc_category;6608 6609 outs() << "Objective-C segment\n";6610 S = get_section(O, "__OBJC", "__module_info");6611 if (S == SectionRef())6612 return false;6613 6614 SymbolAddressMap AddrMap;6615 if (verbose)6616 CreateSymbolAddressMap(O, &AddrMap);6617 6618 std::vector<SectionRef> Sections;6619 append_range(Sections, O->sections());6620 6621 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);6622 6623 for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {6624 p = S.getAddress() + i;6625 r = get_pointer_32(p, offset, left, S, &info, true);6626 if (r == nullptr)6627 return true;6628 memset(&module, '\0', sizeof(struct objc_module_t));6629 if (left < sizeof(struct objc_module_t)) {6630 memcpy(&module, r, left);6631 outs() << " (module extends past end of __module_info section)\n";6632 } else6633 memcpy(&module, r, sizeof(struct objc_module_t));6634 if (O->isLittleEndian() != sys::IsLittleEndianHost)6635 swapStruct(module);6636 6637 outs() << "Module " << format("0x%" PRIx32, p) << "\n";6638 outs() << " version " << module.version << "\n";6639 outs() << " size " << module.size << "\n";6640 outs() << " name ";6641 name = get_pointer_32(module.name, xoffset, left, xS, &info, true);6642 if (name != nullptr)6643 outs() << format("%.*s", left, name);6644 else6645 outs() << format("0x%08" PRIx32, module.name)6646 << "(not in an __OBJC section)";6647 outs() << "\n";6648 6649 r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);6650 if (module.symtab == 0 || r == nullptr) {6651 outs() << " symtab " << format("0x%08" PRIx32, module.symtab)6652 << " (not in an __OBJC section)\n";6653 continue;6654 }6655 outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";6656 memset(&symtab, '\0', sizeof(struct objc_symtab_t));6657 defs_left = 0;6658 defs = nullptr;6659 if (left < sizeof(struct objc_symtab_t)) {6660 memcpy(&symtab, r, left);6661 outs() << "\tsymtab extends past end of an __OBJC section)\n";6662 } else {6663 memcpy(&symtab, r, sizeof(struct objc_symtab_t));6664 if (left > sizeof(struct objc_symtab_t)) {6665 defs_left = left - sizeof(struct objc_symtab_t);6666 defs = r + sizeof(struct objc_symtab_t);6667 }6668 }6669 if (O->isLittleEndian() != sys::IsLittleEndianHost)6670 swapStruct(symtab);6671 6672 outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";6673 r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);6674 outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);6675 if (r == nullptr)6676 outs() << " (not in an __OBJC section)";6677 outs() << "\n";6678 outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";6679 outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";6680 if (symtab.cls_def_cnt > 0)6681 outs() << "\tClass Definitions\n";6682 for (j = 0; j < symtab.cls_def_cnt; j++) {6683 if ((j + 1) * sizeof(uint32_t) > defs_left) {6684 outs() << "\t(remaining class defs entries entends past the end of the "6685 << "section)\n";6686 break;6687 }6688 memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));6689 if (O->isLittleEndian() != sys::IsLittleEndianHost)6690 sys::swapByteOrder(def);6691 6692 r = get_pointer_32(def, xoffset, left, xS, &info, true);6693 outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);6694 if (r != nullptr) {6695 if (left > sizeof(struct objc_class_t)) {6696 outs() << "\n";6697 memcpy(&objc_class, r, sizeof(struct objc_class_t));6698 } else {6699 outs() << " (entends past the end of the section)\n";6700 memset(&objc_class, '\0', sizeof(struct objc_class_t));6701 memcpy(&objc_class, r, left);6702 }6703 if (O->isLittleEndian() != sys::IsLittleEndianHost)6704 swapStruct(objc_class);6705 print_objc_class_t(&objc_class, &info);6706 } else {6707 outs() << "(not in an __OBJC section)\n";6708 }6709 6710 if (CLS_GETINFO(&objc_class, CLS_CLASS)) {6711 outs() << "\tMeta Class";6712 r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);6713 if (r != nullptr) {6714 if (left > sizeof(struct objc_class_t)) {6715 outs() << "\n";6716 memcpy(&objc_class, r, sizeof(struct objc_class_t));6717 } else {6718 outs() << " (entends past the end of the section)\n";6719 memset(&objc_class, '\0', sizeof(struct objc_class_t));6720 memcpy(&objc_class, r, left);6721 }6722 if (O->isLittleEndian() != sys::IsLittleEndianHost)6723 swapStruct(objc_class);6724 print_objc_class_t(&objc_class, &info);6725 } else {6726 outs() << "(not in an __OBJC section)\n";6727 }6728 }6729 }6730 if (symtab.cat_def_cnt > 0)6731 outs() << "\tCategory Definitions\n";6732 for (j = 0; j < symtab.cat_def_cnt; j++) {6733 if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {6734 outs() << "\t(remaining category defs entries entends past the end of "6735 << "the section)\n";6736 break;6737 }6738 memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),6739 sizeof(uint32_t));6740 if (O->isLittleEndian() != sys::IsLittleEndianHost)6741 sys::swapByteOrder(def);6742 6743 r = get_pointer_32(def, xoffset, left, xS, &info, true);6744 outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "6745 << format("0x%08" PRIx32, def);6746 if (r != nullptr) {6747 if (left > sizeof(struct objc_category_t)) {6748 outs() << "\n";6749 memcpy(&objc_category, r, sizeof(struct objc_category_t));6750 } else {6751 outs() << " (entends past the end of the section)\n";6752 memset(&objc_category, '\0', sizeof(struct objc_category_t));6753 memcpy(&objc_category, r, left);6754 }6755 if (O->isLittleEndian() != sys::IsLittleEndianHost)6756 swapStruct(objc_category);6757 print_objc_objc_category_t(&objc_category, &info);6758 } else {6759 outs() << "(not in an __OBJC section)\n";6760 }6761 }6762 }6763 const SectionRef II = get_section(O, "__OBJC", "__image_info");6764 if (II != SectionRef())6765 print_image_info(II, &info);6766 6767 return true;6768}6769 6770static void DumpProtocolSection(MachOObjectFile *O, const char *sect,6771 uint32_t size, uint32_t addr) {6772 SymbolAddressMap AddrMap;6773 CreateSymbolAddressMap(O, &AddrMap);6774 6775 std::vector<SectionRef> Sections;6776 append_range(Sections, O->sections());6777 6778 struct DisassembleInfo info(O, &AddrMap, &Sections, true);6779 6780 const char *p;6781 struct objc_protocol_t protocol;6782 uint32_t left, paddr;6783 for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {6784 memset(&protocol, '\0', sizeof(struct objc_protocol_t));6785 left = size - (p - sect);6786 if (left < sizeof(struct objc_protocol_t)) {6787 outs() << "Protocol extends past end of __protocol section\n";6788 memcpy(&protocol, p, left);6789 } else6790 memcpy(&protocol, p, sizeof(struct objc_protocol_t));6791 if (O->isLittleEndian() != sys::IsLittleEndianHost)6792 swapStruct(protocol);6793 paddr = addr + (p - sect);6794 outs() << "Protocol " << format("0x%" PRIx32, paddr);6795 if (print_protocol(paddr, 0, &info))6796 outs() << "(not in an __OBJC section)\n";6797 }6798}6799 6800static void printObjcMetaData(MachOObjectFile *O, bool verbose) {6801 if (O->is64Bit())6802 printObjc2_64bit_MetaData(O, verbose);6803 else {6804 MachO::mach_header H;6805 H = O->getHeader();6806 if (H.cputype == MachO::CPU_TYPE_ARM)6807 printObjc2_32bit_MetaData(O, verbose);6808 else {6809 // This is the 32-bit non-arm cputype case. Which is normally6810 // the first Objective-C ABI. But it may be the case of a6811 // binary for the iOS simulator which is the second Objective-C6812 // ABI. In that case printObjc1_32bit_MetaData() will determine that6813 // and return false.6814 if (!printObjc1_32bit_MetaData(O, verbose))6815 printObjc2_32bit_MetaData(O, verbose);6816 }6817 }6818}6819 6820// GuessLiteralPointer returns a string which for the item in the Mach-O file6821// for the address passed in as ReferenceValue for printing as a comment with6822// the instruction and also returns the corresponding type of that item6823// indirectly through ReferenceType.6824//6825// If ReferenceValue is an address of literal cstring then a pointer to the6826// cstring is returned and ReferenceType is set to6827// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .6828//6829// If ReferenceValue is an address of an Objective-C CFString, Selector ref or6830// Class ref that name is returned and the ReferenceType is set accordingly.6831//6832// Lastly, literals which are Symbol address in a literal pool are looked for6833// and if found the symbol name is returned and ReferenceType is set to6834// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .6835//6836// If there is no item in the Mach-O file for the address passed in as6837// ReferenceValue nullptr is returned and ReferenceType is unchanged.6838static const char *GuessLiteralPointer(uint64_t ReferenceValue,6839 uint64_t ReferencePC,6840 uint64_t *ReferenceType,6841 struct DisassembleInfo *info) {6842 // First see if there is an external relocation entry at the ReferencePC.6843 if (info->O->getHeader().filetype == MachO::MH_OBJECT) {6844 uint64_t sect_addr = info->S.getAddress();6845 uint64_t sect_offset = ReferencePC - sect_addr;6846 bool reloc_found = false;6847 DataRefImpl Rel;6848 MachO::any_relocation_info RE;6849 bool isExtern = false;6850 SymbolRef Symbol;6851 for (const RelocationRef &Reloc : info->S.relocations()) {6852 uint64_t RelocOffset = Reloc.getOffset();6853 if (RelocOffset == sect_offset) {6854 Rel = Reloc.getRawDataRefImpl();6855 RE = info->O->getRelocation(Rel);6856 if (info->O->isRelocationScattered(RE))6857 continue;6858 isExtern = info->O->getPlainRelocationExternal(RE);6859 if (isExtern) {6860 symbol_iterator RelocSym = Reloc.getSymbol();6861 Symbol = *RelocSym;6862 }6863 reloc_found = true;6864 break;6865 }6866 }6867 // If there is an external relocation entry for a symbol in a section6868 // then used that symbol's value for the value of the reference.6869 if (reloc_found && isExtern) {6870 if (info->O->getAnyRelocationPCRel(RE)) {6871 unsigned Type = info->O->getAnyRelocationType(RE);6872 if (Type == MachO::X86_64_RELOC_SIGNED) {6873 ReferenceValue = cantFail(Symbol.getValue());6874 }6875 }6876 }6877 }6878 6879 // Look for literals such as Objective-C CFStrings refs, Selector refs,6880 // Message refs and Class refs.6881 bool classref, selref, msgref, cfstring;6882 uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,6883 selref, msgref, cfstring);6884 if (classref && pointer_value == 0) {6885 // Note the ReferenceValue is a pointer into the __objc_classrefs section.6886 // And the pointer_value in that section is typically zero as it will be6887 // set by dyld as part of the "bind information".6888 const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);6889 if (name != nullptr) {6890 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6891 const char *class_name = strrchr(name, '$');6892 if (class_name != nullptr && class_name[1] == '_' &&6893 class_name[2] != '\0') {6894 info->class_name = class_name + 2;6895 return name;6896 }6897 }6898 }6899 6900 if (classref) {6901 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;6902 const char *name =6903 get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);6904 if (name != nullptr)6905 info->class_name = name;6906 else6907 name = "bad class ref";6908 return name;6909 }6910 6911 if (cfstring) {6912 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;6913 const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);6914 return name;6915 }6916 6917 if (selref && pointer_value == 0)6918 pointer_value = get_objc2_64bit_selref(ReferenceValue, info);6919 6920 if (pointer_value != 0)6921 ReferenceValue = pointer_value;6922 6923 const char *name = GuessCstringPointer(ReferenceValue, info);6924 if (name) {6925 if (pointer_value != 0 && selref) {6926 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;6927 info->selector_name = name;6928 } else if (pointer_value != 0 && msgref) {6929 info->class_name = nullptr;6930 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;6931 info->selector_name = name;6932 } else6933 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;6934 return name;6935 }6936 6937 // Lastly look for an indirect symbol with this ReferenceValue which is in6938 // a literal pool. If found return that symbol name.6939 name = GuessIndirectSymbol(ReferenceValue, info);6940 if (name) {6941 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;6942 return name;6943 }6944 6945 return nullptr;6946}6947 6948// SymbolizerSymbolLookUp is the symbol lookup function passed when creating6949// the Symbolizer. It looks up the ReferenceValue using the info passed via the6950// pointer to the struct DisassembleInfo that was passed when MCSymbolizer6951// is created and returns the symbol name that matches the ReferenceValue or6952// nullptr if none. The ReferenceType is passed in for the IN type of6953// reference the instruction is making from the values in defined in the header6954// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific6955// Out type and the ReferenceName will also be set which is added as a comment6956// to the disassembled instruction.6957//6958// If the symbol name is a C++ mangled name then the demangled name is6959// returned through ReferenceName and ReferenceType is set to6960// LLVMDisassembler_ReferenceType_DeMangled_Name .6961//6962// When this is called to get a symbol name for a branch target then the6963// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then6964// SymbolValue will be looked for in the indirect symbol table to determine if6965// it is an address for a symbol stub. If so then the symbol name for that6966// stub is returned indirectly through ReferenceName and then ReferenceType is6967// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.6968//6969// When this is called with an value loaded via a PC relative load then6970// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the6971// SymbolValue is checked to be an address of literal pointer, symbol pointer,6972// or an Objective-C meta data reference. If so the output ReferenceType is6973// set to correspond to that as well as setting the ReferenceName.6974static const char *SymbolizerSymbolLookUp(void *DisInfo,6975 uint64_t ReferenceValue,6976 uint64_t *ReferenceType,6977 uint64_t ReferencePC,6978 const char **ReferenceName) {6979 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;6980 // If no verbose symbolic information is wanted then just return nullptr.6981 if (!info->verbose) {6982 *ReferenceName = nullptr;6983 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;6984 return nullptr;6985 }6986 6987 const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);6988 6989 if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {6990 *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);6991 if (*ReferenceName != nullptr) {6992 method_reference(info, ReferenceType, ReferenceName);6993 if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)6994 *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;6995 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {6996 if (info->demangled_name != nullptr)6997 free(info->demangled_name);6998 info->demangled_name = itaniumDemangle(SymbolName + 1);6999 if (info->demangled_name != nullptr) {7000 *ReferenceName = info->demangled_name;7001 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;7002 } else7003 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7004 } else7005 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7006 } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {7007 *ReferenceName =7008 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7009 if (*ReferenceName)7010 method_reference(info, ReferenceType, ReferenceName);7011 else7012 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7013 // If this is arm64 and the reference is an adrp instruction save the7014 // instruction, passed in ReferenceValue and the address of the instruction7015 // for use later if we see and add immediate instruction.7016 } else if (info->O->getArch() == Triple::aarch64 &&7017 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {7018 info->adrp_inst = ReferenceValue;7019 info->adrp_addr = ReferencePC;7020 SymbolName = nullptr;7021 *ReferenceName = nullptr;7022 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7023 // If this is arm64 and reference is an add immediate instruction and we7024 // have7025 // seen an adrp instruction just before it and the adrp's Xd register7026 // matches7027 // this add's Xn register reconstruct the value being referenced and look to7028 // see if it is a literal pointer. Note the add immediate instruction is7029 // passed in ReferenceValue.7030 } else if (info->O->getArch() == Triple::aarch64 &&7031 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&7032 ReferencePC - 4 == info->adrp_addr &&7033 (info->adrp_inst & 0x9f000000) == 0x90000000 &&7034 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7035 uint32_t addxri_inst;7036 uint64_t adrp_imm, addxri_imm;7037 7038 adrp_imm =7039 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7040 if (info->adrp_inst & 0x0200000)7041 adrp_imm |= 0xfffffffffc000000LL;7042 7043 addxri_inst = ReferenceValue;7044 addxri_imm = (addxri_inst >> 10) & 0xfff;7045 if (((addxri_inst >> 22) & 0x3) == 1)7046 addxri_imm <<= 12;7047 7048 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7049 (adrp_imm << 12) + addxri_imm;7050 7051 *ReferenceName =7052 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7053 if (*ReferenceName == nullptr)7054 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7055 // If this is arm64 and the reference is a load register instruction and we7056 // have seen an adrp instruction just before it and the adrp's Xd register7057 // matches this add's Xn register reconstruct the value being referenced and7058 // look to see if it is a literal pointer. Note the load register7059 // instruction is passed in ReferenceValue.7060 } else if (info->O->getArch() == Triple::aarch64 &&7061 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&7062 ReferencePC - 4 == info->adrp_addr &&7063 (info->adrp_inst & 0x9f000000) == 0x90000000 &&7064 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {7065 uint32_t ldrxui_inst;7066 uint64_t adrp_imm, ldrxui_imm;7067 7068 adrp_imm =7069 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);7070 if (info->adrp_inst & 0x0200000)7071 adrp_imm |= 0xfffffffffc000000LL;7072 7073 ldrxui_inst = ReferenceValue;7074 ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;7075 7076 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +7077 (adrp_imm << 12) + (ldrxui_imm << 3);7078 7079 *ReferenceName =7080 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7081 if (*ReferenceName == nullptr)7082 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7083 }7084 // If this arm64 and is an load register (PC-relative) instruction the7085 // ReferenceValue is the PC plus the immediate value.7086 else if (info->O->getArch() == Triple::aarch64 &&7087 (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||7088 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {7089 *ReferenceName =7090 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);7091 if (*ReferenceName == nullptr)7092 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7093 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {7094 if (info->demangled_name != nullptr)7095 free(info->demangled_name);7096 info->demangled_name = itaniumDemangle(SymbolName + 1);7097 if (info->demangled_name != nullptr) {7098 *ReferenceName = info->demangled_name;7099 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;7100 }7101 }7102 else {7103 *ReferenceName = nullptr;7104 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;7105 }7106 7107 return SymbolName;7108}7109 7110/// Emits the comments that are stored in the CommentStream.7111/// Each comment in the CommentStream must end with a newline.7112static void emitComments(raw_svector_ostream &CommentStream,7113 SmallString<128> &CommentsToEmit,7114 formatted_raw_ostream &FormattedOS,7115 const MCAsmInfo &MAI) {7116 // Flush the stream before taking its content.7117 StringRef Comments = CommentsToEmit.str();7118 // Get the default information for printing a comment.7119 StringRef CommentBegin = MAI.getCommentString();7120 unsigned CommentColumn = MAI.getCommentColumn();7121 ListSeparator LS("\n");7122 while (!Comments.empty()) {7123 FormattedOS << LS;7124 // Emit a line of comments.7125 FormattedOS.PadToColumn(CommentColumn);7126 size_t Position = Comments.find('\n');7127 FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);7128 // Move after the newline character.7129 Comments = Comments.substr(Position + 1);7130 }7131 FormattedOS.flush();7132 7133 // Tell the comment stream that the vector changed underneath it.7134 CommentsToEmit.clear();7135}7136 7137const MachOObjectFile *7138objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,7139 std::unique_ptr<Binary> &DSYMBinary,7140 std::unique_ptr<MemoryBuffer> &DSYMBuf) {7141 const MachOObjectFile *DbgObj = MachOOF;7142 std::string DSYMPath;7143 7144 // Auto-detect w/o --dsym.7145 if (DSYMFile.empty()) {7146 sys::fs::file_status DSYMStatus;7147 Twine FilenameDSYM = Filename + ".dSYM";7148 if (!status(FilenameDSYM, DSYMStatus)) {7149 if (sys::fs::is_directory(DSYMStatus)) {7150 SmallString<1024> Path;7151 FilenameDSYM.toVector(Path);7152 sys::path::append(Path, "Contents", "Resources", "DWARF",7153 sys::path::filename(Filename));7154 DSYMPath = std::string(Path);7155 } else if (sys::fs::is_regular_file(DSYMStatus)) {7156 DSYMPath = FilenameDSYM.str();7157 }7158 }7159 }7160 7161 if (DSYMPath.empty() && !DSYMFile.empty()) {7162 // If DSYMPath is a .dSYM directory, append the Mach-O file.7163 if (sys::fs::is_directory(DSYMFile) &&7164 sys::path::extension(DSYMFile) == ".dSYM") {7165 SmallString<128> ShortName(sys::path::filename(DSYMFile));7166 sys::path::replace_extension(ShortName, "");7167 SmallString<1024> FullPath(DSYMFile);7168 sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);7169 DSYMPath = FullPath.str();7170 } else {7171 DSYMPath = DSYMFile;7172 }7173 }7174 7175 if (!DSYMPath.empty()) {7176 // Load the file.7177 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =7178 MemoryBuffer::getFileOrSTDIN(DSYMPath);7179 if (std::error_code EC = BufOrErr.getError()) {7180 reportError(errorCodeToError(EC), DSYMPath);7181 return nullptr;7182 }7183 7184 // We need to keep the file alive, because we're replacing DbgObj with it.7185 DSYMBuf = std::move(BufOrErr.get());7186 7187 Expected<std::unique_ptr<Binary>> BinaryOrErr =7188 createBinary(DSYMBuf->getMemBufferRef());7189 if (!BinaryOrErr) {7190 reportError(BinaryOrErr.takeError(), DSYMPath);7191 return nullptr;7192 }7193 7194 // We need to keep the Binary alive with the buffer7195 DSYMBinary = std::move(BinaryOrErr.get());7196 if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {7197 // this is a Mach-O object file, use it7198 if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {7199 DbgObj = MachDSYM;7200 } else {7201 WithColor::error(errs(), "llvm-objdump")7202 << DSYMPath << " is not a Mach-O file type.\n";7203 return nullptr;7204 }7205 } else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {7206 // this is a Universal Binary, find a Mach-O for this architecture7207 uint32_t CPUType, CPUSubType;7208 const char *ArchFlag;7209 if (MachOOF->is64Bit()) {7210 const MachO::mach_header_64 H_64 = MachOOF->getHeader64();7211 CPUType = H_64.cputype;7212 CPUSubType = H_64.cpusubtype;7213 } else {7214 const MachO::mach_header H = MachOOF->getHeader();7215 CPUType = H.cputype;7216 CPUSubType = H.cpusubtype;7217 }7218 Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,7219 &ArchFlag);7220 Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =7221 UB->getMachOObjectForArch(ArchFlag);7222 if (!MachDSYM) {7223 reportError(MachDSYM.takeError(), DSYMPath);7224 return nullptr;7225 }7226 7227 // We need to keep the Binary alive with the buffer7228 DbgObj = &*MachDSYM.get();7229 DSYMBinary = std::move(*MachDSYM);7230 } else {7231 WithColor::error(errs(), "llvm-objdump")7232 << DSYMPath << " is not a Mach-O or Universal file type.\n";7233 return nullptr;7234 }7235 }7236 return DbgObj;7237}7238 7239static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,7240 StringRef DisSegName, StringRef DisSectName) {7241 const char *McpuDefault = nullptr;7242 const Target *ThumbTarget = nullptr;7243 Triple ThumbTriple;7244 const Target *TheTarget =7245 GetTarget(MachOOF, &McpuDefault, &ThumbTarget, ThumbTriple);7246 if (!TheTarget) {7247 // GetTarget prints out stuff.7248 return;7249 }7250 std::string MachOMCPU;7251 if (MCPU.empty() && McpuDefault)7252 MachOMCPU = McpuDefault;7253 else7254 MachOMCPU = MCPU;7255 7256#define CHECK_TARGET_INFO_CREATION(NAME) \7257 do { \7258 if (!NAME) { \7259 WithColor::error(errs(), "llvm-objdump") \7260 << "couldn't initialize disassembler for target " << TripleName \7261 << '\n'; \7262 return; \7263 } \7264 } while (false)7265#define CHECK_THUMB_TARGET_INFO_CREATION(NAME) \7266 do { \7267 if (!NAME) { \7268 WithColor::error(errs(), "llvm-objdump") \7269 << "couldn't initialize disassembler for target " << ThumbTripleName \7270 << '\n'; \7271 return; \7272 } \7273 } while (false)7274 7275 std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());7276 CHECK_TARGET_INFO_CREATION(InstrInfo);7277 std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;7278 if (ThumbTarget) {7279 ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());7280 CHECK_THUMB_TARGET_INFO_CREATION(ThumbInstrInfo);7281 }7282 7283 // Package up features to be passed to target/subtarget7284 std::string FeaturesStr;7285 if (!MAttrs.empty()) {7286 SubtargetFeatures Features;7287 for (unsigned i = 0; i != MAttrs.size(); ++i)7288 Features.AddFeature(MAttrs[i]);7289 FeaturesStr = Features.getString();7290 }7291 7292 Triple TheTriple(TripleName);7293 7294 MCTargetOptions MCOptions;7295 // Set up disassembler.7296 std::unique_ptr<const MCRegisterInfo> MRI(7297 TheTarget->createMCRegInfo(TheTriple));7298 CHECK_TARGET_INFO_CREATION(MRI);7299 std::unique_ptr<const MCAsmInfo> AsmInfo(7300 TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));7301 CHECK_TARGET_INFO_CREATION(AsmInfo);7302 std::unique_ptr<const MCSubtargetInfo> STI(7303 TheTarget->createMCSubtargetInfo(TheTriple, MachOMCPU, FeaturesStr));7304 CHECK_TARGET_INFO_CREATION(STI);7305 MCContext Ctx(TheTriple, AsmInfo.get(), MRI.get(), STI.get());7306 std::unique_ptr<MCDisassembler> DisAsm(7307 TheTarget->createMCDisassembler(*STI, Ctx));7308 CHECK_TARGET_INFO_CREATION(DisAsm);7309 std::unique_ptr<MCSymbolizer> Symbolizer;7310 struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);7311 std::unique_ptr<MCRelocationInfo> RelInfo(7312 TheTarget->createMCRelocationInfo(TheTriple, Ctx));7313 if (RelInfo) {7314 Symbolizer.reset(TheTarget->createMCSymbolizer(7315 TheTriple, SymbolizerGetOpInfo, SymbolizerSymbolLookUp, &SymbolizerInfo,7316 &Ctx, std::move(RelInfo)));7317 DisAsm->setSymbolizer(std::move(Symbolizer));7318 }7319 int AsmPrinterVariant = AsmInfo->getAssemblerDialect();7320 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(7321 TheTriple, AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));7322 CHECK_TARGET_INFO_CREATION(IP);7323 // Set the display preference for hex vs. decimal immediates.7324 IP->setPrintImmHex(PrintImmHex);7325 // Comment stream and backing vector.7326 SmallString<128> CommentsToEmit;7327 raw_svector_ostream CommentStream(CommentsToEmit);7328 // FIXME: Setting the CommentStream in the InstPrinter is problematic in that7329 // if it is done then arm64 comments for string literals don't get printed7330 // and some constant get printed instead and not setting it causes intel7331 // (32-bit and 64-bit) comments printed with different spacing before the7332 // comment causing different diffs with the 'C' disassembler library API.7333 // IP->setCommentStream(CommentStream);7334 7335 for (StringRef Opt : DisassemblerOptions)7336 if (!IP->applyTargetSpecificCLOption(Opt))7337 reportError(Filename, "unrecognized disassembler option: " + Opt);7338 7339 // Set up separate thumb disassembler if needed.7340 std::unique_ptr<const MCRegisterInfo> ThumbMRI;7341 std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;7342 std::unique_ptr<const MCSubtargetInfo> ThumbSTI;7343 std::unique_ptr<MCDisassembler> ThumbDisAsm;7344 std::unique_ptr<MCInstPrinter> ThumbIP;7345 std::unique_ptr<MCContext> ThumbCtx;7346 std::unique_ptr<MCSymbolizer> ThumbSymbolizer;7347 struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);7348 std::unique_ptr<MCRelocationInfo> ThumbRelInfo;7349 if (ThumbTarget) {7350 ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTriple));7351 CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);7352 ThumbAsmInfo.reset(7353 ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTriple, MCOptions));7354 CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);7355 ThumbSTI.reset(ThumbTarget->createMCSubtargetInfo(ThumbTriple, MachOMCPU,7356 FeaturesStr));7357 CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);7358 ThumbCtx.reset(new MCContext(ThumbTriple, ThumbAsmInfo.get(),7359 ThumbMRI.get(), ThumbSTI.get()));7360 ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));7361 CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);7362 MCContext *PtrThumbCtx = ThumbCtx.get();7363 ThumbRelInfo.reset(7364 ThumbTarget->createMCRelocationInfo(ThumbTriple, *PtrThumbCtx));7365 if (ThumbRelInfo) {7366 ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(7367 ThumbTriple, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,7368 &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));7369 ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));7370 }7371 int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();7372 ThumbIP.reset(ThumbTarget->createMCInstPrinter(7373 ThumbTriple, ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo,7374 *ThumbMRI));7375 CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);7376 // Set the display preference for hex vs. decimal immediates.7377 ThumbIP->setPrintImmHex(PrintImmHex);7378 }7379 7380#undef CHECK_TARGET_INFO_CREATION7381#undef CHECK_THUMB_TARGET_INFO_CREATION7382 7383 MachO::mach_header Header = MachOOF->getHeader();7384 7385 // FIXME: Using the -cfg command line option, this code used to be able to7386 // annotate relocations with the referenced symbol's name, and if this was7387 // inside a __[cf]string section, the data it points to. This is now replaced7388 // by the upcoming MCSymbolizer, which needs the appropriate setup done above.7389 std::vector<SectionRef> Sections;7390 std::vector<SymbolRef> Symbols;7391 SmallVector<uint64_t, 8> FoundFns;7392 uint64_t BaseSegmentAddress = 0;7393 7394 getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,7395 BaseSegmentAddress);7396 7397 // Sort the symbols by address, just in case they didn't come in that way.7398 llvm::stable_sort(Symbols, SymbolSorter());7399 7400 // Build a data in code table that is sorted on by the address of each entry.7401 uint64_t BaseAddress = 0;7402 if (Header.filetype == MachO::MH_OBJECT)7403 BaseAddress = Sections[0].getAddress();7404 else7405 BaseAddress = BaseSegmentAddress;7406 DiceTable Dices;7407 for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();7408 DI != DE; ++DI) {7409 uint32_t Offset;7410 DI->getOffset(Offset);7411 Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));7412 }7413 array_pod_sort(Dices.begin(), Dices.end());7414 7415 // Try to find debug info and set up the DIContext for it.7416 std::unique_ptr<DIContext> diContext;7417 std::unique_ptr<Binary> DSYMBinary;7418 std::unique_ptr<MemoryBuffer> DSYMBuf;7419 const ObjectFile *DbgObj = MachOOF;7420 if (UseDbg || PrintSource || PrintLines) {7421 // Look for debug info in external dSYM file or embedded in the object.7422 // getMachODSymObject returns MachOOF by default if no external dSYM found.7423 const ObjectFile *DSym =7424 getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf);7425 if (!DSym)7426 return;7427 DbgObj = DSym;7428 if (UseDbg || PrintLines) {7429 // Setup the DIContext7430 diContext = DWARFContext::create(*DbgObj);7431 }7432 }7433 7434 std::optional<SourcePrinter> SP;7435 std::optional<LiveElementPrinter> LEP;7436 if (PrintSource || PrintLines) {7437 SP.emplace(DbgObj, TheTarget->getName());7438 LEP.emplace(*MRI, *STI);7439 }7440 7441 if (FilterSections.empty())7442 outs() << "(" << DisSegName << "," << DisSectName << ") section\n";7443 7444 for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {7445 Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();7446 if (!SecNameOrErr) {7447 consumeError(SecNameOrErr.takeError());7448 continue;7449 }7450 if (*SecNameOrErr != DisSectName)7451 continue;7452 7453 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();7454 7455 StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);7456 if (SegmentName != DisSegName)7457 continue;7458 7459 StringRef BytesStr =7460 unwrapOrError(Sections[SectIdx].getContents(), Filename);7461 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);7462 uint64_t SectAddress = Sections[SectIdx].getAddress();7463 7464 bool symbolTableWorked = false;7465 7466 // Create a map of symbol addresses to symbol names for use by7467 // the SymbolizerSymbolLookUp() routine.7468 SymbolAddressMap AddrMap;7469 bool DisSymNameFound = false;7470 for (const SymbolRef &Symbol : MachOOF->symbols()) {7471 SymbolRef::Type ST =7472 unwrapOrError(Symbol.getType(), MachOOF->getFileName());7473 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||7474 ST == SymbolRef::ST_Other) {7475 uint64_t Address = cantFail(Symbol.getValue());7476 StringRef SymName =7477 unwrapOrError(Symbol.getName(), MachOOF->getFileName());7478 AddrMap[Address] = SymName;7479 if (!DisSymName.empty() && DisSymName == SymName)7480 DisSymNameFound = true;7481 }7482 }7483 if (!DisSymName.empty() && !DisSymNameFound) {7484 outs() << "Can't find -dis-symname: " << DisSymName << "\n";7485 return;7486 }7487 // Set up the block of info used by the Symbolizer call backs.7488 SymbolizerInfo.verbose = SymbolicOperands;7489 SymbolizerInfo.O = MachOOF;7490 SymbolizerInfo.S = Sections[SectIdx];7491 SymbolizerInfo.AddrMap = &AddrMap;7492 SymbolizerInfo.Sections = &Sections;7493 // Same for the ThumbSymbolizer7494 ThumbSymbolizerInfo.verbose = SymbolicOperands;7495 ThumbSymbolizerInfo.O = MachOOF;7496 ThumbSymbolizerInfo.S = Sections[SectIdx];7497 ThumbSymbolizerInfo.AddrMap = &AddrMap;7498 ThumbSymbolizerInfo.Sections = &Sections;7499 7500 unsigned int Arch = MachOOF->getArch();7501 7502 // Skip all symbols if this is a stubs file.7503 if (Bytes.empty())7504 return;7505 7506 // If the section has symbols but no symbol at the start of the section7507 // these are used to make sure the bytes before the first symbol are7508 // disassembled.7509 bool FirstSymbol = true;7510 bool FirstSymbolAtSectionStart = true;7511 7512 // Disassemble symbol by symbol.7513 for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {7514 StringRef SymName =7515 unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());7516 SymbolRef::Type ST =7517 unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());7518 if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)7519 continue;7520 7521 // Make sure the symbol is defined in this section.7522 bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);7523 if (!containsSym) {7524 if (!DisSymName.empty() && DisSymName == SymName) {7525 outs() << "-dis-symname: " << DisSymName << " not in the section\n";7526 return;7527 }7528 continue;7529 }7530 // The __mh_execute_header is special and we need to deal with that fact7531 // this symbol is before the start of the (__TEXT,__text) section and at the7532 // address of the start of the __TEXT segment. This is because this symbol7533 // is an N_SECT symbol in the (__TEXT,__text) but its address is before the7534 // start of the section in a standard MH_EXECUTE filetype.7535 if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {7536 outs() << "-dis-symname: __mh_execute_header not in any section\n";7537 return;7538 }7539 // When this code is trying to disassemble a symbol at a time and in the7540 // case there is only the __mh_execute_header symbol left as in a stripped7541 // executable, we need to deal with this by ignoring this symbol so the7542 // whole section is disassembled and this symbol is then not displayed.7543 if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||7544 SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||7545 SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")7546 continue;7547 7548 // If we are only disassembling one symbol see if this is that symbol.7549 if (!DisSymName.empty() && DisSymName != SymName)7550 continue;7551 7552 // Start at the address of the symbol relative to the section's address.7553 uint64_t SectSize = Sections[SectIdx].getSize();7554 uint64_t Start = cantFail(Symbols[SymIdx].getValue());7555 uint64_t SectionAddress = Sections[SectIdx].getAddress();7556 Start -= SectionAddress;7557 7558 if (Start > SectSize) {7559 outs() << "section data ends, " << SymName7560 << " lies outside valid range\n";7561 return;7562 }7563 7564 // Stop disassembling either at the beginning of the next symbol or at7565 // the end of the section.7566 bool containsNextSym = false;7567 uint64_t NextSym = 0;7568 uint64_t NextSymIdx = SymIdx + 1;7569 while (Symbols.size() > NextSymIdx) {7570 SymbolRef::Type NextSymType = unwrapOrError(7571 Symbols[NextSymIdx].getType(), MachOOF->getFileName());7572 if (NextSymType == SymbolRef::ST_Function) {7573 containsNextSym =7574 Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);7575 NextSym = cantFail(Symbols[NextSymIdx].getValue());7576 NextSym -= SectionAddress;7577 break;7578 }7579 ++NextSymIdx;7580 }7581 7582 uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;7583 uint64_t Size;7584 7585 symbolTableWorked = true;7586 7587 DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();7588 uint32_t SymbolFlags = cantFail(MachOOF->getSymbolFlags(Symb));7589 bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;7590 7591 // We only need the dedicated Thumb target if there's a real choice7592 // (i.e. we're not targeting M-class) and the function is Thumb.7593 bool UseThumbTarget = IsThumb && ThumbTarget;7594 7595 // If we are not specifying a symbol to start disassembly with and this7596 // is the first symbol in the section but not at the start of the section7597 // then move the disassembly index to the start of the section and7598 // don't print the symbol name just yet. This is so the bytes before the7599 // first symbol are disassembled.7600 uint64_t SymbolStart = Start;7601 if (DisSymName.empty() && FirstSymbol && Start != 0) {7602 FirstSymbolAtSectionStart = false;7603 Start = 0;7604 }7605 else7606 outs() << SymName << ":\n";7607 7608 DILineInfo lastLine;7609 for (uint64_t Index = Start; Index < End; Index += Size) {7610 MCInst Inst;7611 7612 // If this is the first symbol in the section and it was not at the7613 // start of the section, see if we are at its Index now and if so print7614 // the symbol name.7615 if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)7616 outs() << SymName << ":\n";7617 7618 uint64_t PC = SectAddress + Index;7619 7620 if (PrintSource || PrintLines) {7621 formatted_raw_ostream FOS(outs());7622 SP->printSourceLine(FOS, {PC, SectIdx}, Filename, *LEP);7623 }7624 7625 if (LeadingAddr) {7626 if (FullLeadingAddr) {7627 if (MachOOF->is64Bit())7628 outs() << format("%016" PRIx64, PC);7629 else7630 outs() << format("%08" PRIx64, PC);7631 } else {7632 outs() << format("%8" PRIx64 ":", PC);7633 }7634 }7635 if (ShowRawInsn || Arch == Triple::arm)7636 outs() << "\t";7637 7638 if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))7639 continue;7640 7641 SmallVector<char, 64> AnnotationsBytes;7642 raw_svector_ostream Annotations(AnnotationsBytes);7643 7644 bool gotInst;7645 if (UseThumbTarget)7646 gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),7647 PC, Annotations);7648 else7649 gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,7650 Annotations);7651 if (gotInst) {7652 if (ShowRawInsn || Arch == Triple::arm) {7653 dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());7654 }7655 formatted_raw_ostream FormattedOS(outs());7656 StringRef AnnotationsStr = Annotations.str();7657 if (UseThumbTarget)7658 ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI,7659 FormattedOS);7660 else7661 IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);7662 emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);7663 7664 // Print debug info.7665 if (diContext) {7666 DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx})7667 .value_or(DILineInfo());7668 // Print valid line info if it changed.7669 if (dli != lastLine && dli.Line != 0)7670 outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'7671 << dli.Column;7672 lastLine = dli;7673 }7674 outs() << "\n";7675 } else {7676 if (MachOOF->getArchTriple().isX86()) {7677 outs() << format("\t.byte 0x%02x #bad opcode\n",7678 *(Bytes.data() + Index) & 0xff);7679 Size = 1; // skip exactly one illegible byte and move on.7680 } else if (Arch == Triple::aarch64 ||7681 (Arch == Triple::arm && !IsThumb)) {7682 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7683 (*(Bytes.data() + Index + 1) & 0xff) << 8 |7684 (*(Bytes.data() + Index + 2) & 0xff) << 16 |7685 (*(Bytes.data() + Index + 3) & 0xff) << 24;7686 outs() << format("\t.long\t0x%08x\n", opcode);7687 Size = 4;7688 } else if (Arch == Triple::arm) {7689 assert(IsThumb && "ARM mode should have been dealt with above");7690 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |7691 (*(Bytes.data() + Index + 1) & 0xff) << 8;7692 outs() << format("\t.short\t0x%04x\n", opcode);7693 Size = 2;7694 } else{7695 WithColor::warning(errs(), "llvm-objdump")7696 << "invalid instruction encoding\n";7697 if (Size == 0)7698 Size = 1; // skip illegible bytes7699 }7700 }7701 }7702 // Now that we are done disassembled the first symbol set the bool that7703 // were doing this to false.7704 FirstSymbol = false;7705 }7706 if (!symbolTableWorked) {7707 // Reading the symbol table didn't work, disassemble the whole section.7708 uint64_t SectAddress = Sections[SectIdx].getAddress();7709 uint64_t SectSize = Sections[SectIdx].getSize();7710 uint64_t InstSize;7711 for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {7712 MCInst Inst;7713 7714 uint64_t PC = SectAddress + Index;7715 7716 if (PrintSource || PrintLines) {7717 formatted_raw_ostream FOS(outs());7718 SP->printSourceLine(FOS, {PC, SectIdx}, Filename, *LEP);7719 }7720 7721 if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize))7722 continue;7723 7724 SmallVector<char, 64> AnnotationsBytes;7725 raw_svector_ostream Annotations(AnnotationsBytes);7726 if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,7727 Annotations)) {7728 if (LeadingAddr) {7729 if (FullLeadingAddr) {7730 if (MachOOF->is64Bit())7731 outs() << format("%016" PRIx64, PC);7732 else7733 outs() << format("%08" PRIx64, PC);7734 } else {7735 outs() << format("%8" PRIx64 ":", PC);7736 }7737 }7738 if (ShowRawInsn || Arch == Triple::arm) {7739 outs() << "\t";7740 dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());7741 }7742 StringRef AnnotationsStr = Annotations.str();7743 IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());7744 outs() << "\n";7745 } else {7746 if (MachOOF->getArchTriple().isX86()) {7747 outs() << format("\t.byte 0x%02x #bad opcode\n",7748 *(Bytes.data() + Index) & 0xff);7749 InstSize = 1; // skip exactly one illegible byte and move on.7750 } else {7751 WithColor::warning(errs(), "llvm-objdump")7752 << "invalid instruction encoding\n";7753 if (InstSize == 0)7754 InstSize = 1; // skip illegible bytes7755 }7756 }7757 }7758 }7759 // The TripleName's need to be reset if we are called again for a different7760 // architecture.7761 TripleName = "";7762 ThumbTripleName = "";7763 7764 if (SymbolizerInfo.demangled_name != nullptr)7765 free(SymbolizerInfo.demangled_name);7766 if (ThumbSymbolizerInfo.demangled_name != nullptr)7767 free(ThumbSymbolizerInfo.demangled_name);7768 }7769}7770 7771//===----------------------------------------------------------------------===//7772// __compact_unwind section dumping7773//===----------------------------------------------------------------------===//7774 7775namespace {7776 7777template <typename T>7778static uint64_t read(StringRef Contents, ptrdiff_t Offset) {7779 if (Offset + sizeof(T) > Contents.size()) {7780 outs() << "warning: attempt to read past end of buffer\n";7781 return T();7782 }7783 7784 uint64_t Val = support::endian::read<T, llvm::endianness::little>(7785 Contents.data() + Offset);7786 return Val;7787}7788 7789template <typename T>7790static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {7791 T Val = read<T>(Contents, Offset);7792 Offset += sizeof(T);7793 return Val;7794}7795 7796struct CompactUnwindEntry {7797 uint32_t OffsetInSection;7798 7799 uint64_t FunctionAddr;7800 uint32_t Length;7801 uint32_t CompactEncoding;7802 uint64_t PersonalityAddr;7803 uint64_t LSDAAddr;7804 7805 RelocationRef FunctionReloc;7806 RelocationRef PersonalityReloc;7807 RelocationRef LSDAReloc;7808 7809 CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)7810 : OffsetInSection(Offset) {7811 if (Is64)7812 read<uint64_t>(Contents, Offset);7813 else7814 read<uint32_t>(Contents, Offset);7815 }7816 7817private:7818 template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {7819 FunctionAddr = readNext<UIntPtr>(Contents, Offset);7820 Length = readNext<uint32_t>(Contents, Offset);7821 CompactEncoding = readNext<uint32_t>(Contents, Offset);7822 PersonalityAddr = readNext<UIntPtr>(Contents, Offset);7823 LSDAAddr = readNext<UIntPtr>(Contents, Offset);7824 }7825};7826}7827 7828/// Given a relocation from __compact_unwind, consisting of the RelocationRef7829/// and data being relocated, determine the best base Name and Addend to use for7830/// display purposes.7831///7832/// 1. An Extern relocation will directly reference a symbol (and the data is7833/// then already an addend), so use that.7834/// 2. Otherwise the data is an offset in the object file's layout; try to find7835// a symbol before it in the same section, and use the offset from there.7836/// 3. Finally, if all that fails, fall back to an offset from the start of the7837/// referenced section.7838static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,7839 std::map<uint64_t, SymbolRef> &Symbols,7840 const RelocationRef &Reloc, uint64_t Addr,7841 StringRef &Name, uint64_t &Addend) {7842 if (Reloc.getSymbol() != Obj->symbol_end()) {7843 Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());7844 Addend = Addr;7845 return;7846 }7847 7848 auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());7849 SectionRef RelocSection = Obj->getAnyRelocationSection(RE);7850 7851 uint64_t SectionAddr = RelocSection.getAddress();7852 7853 auto Sym = Symbols.upper_bound(Addr);7854 if (Sym == Symbols.begin()) {7855 // The first symbol in the object is after this reference, the best we can7856 // do is section-relative notation.7857 if (Expected<StringRef> NameOrErr = RelocSection.getName())7858 Name = *NameOrErr;7859 else7860 consumeError(NameOrErr.takeError());7861 7862 Addend = Addr - SectionAddr;7863 return;7864 }7865 7866 // Go back one so that SymbolAddress <= Addr.7867 --Sym;7868 7869 section_iterator SymSection =7870 unwrapOrError(Sym->second.getSection(), Obj->getFileName());7871 if (RelocSection == *SymSection) {7872 // There's a valid symbol in the same section before this reference.7873 Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());7874 Addend = Addr - Sym->first;7875 return;7876 }7877 7878 // There is a symbol before this reference, but it's in a different7879 // section. Probably not helpful to mention it, so use the section name.7880 if (Expected<StringRef> NameOrErr = RelocSection.getName())7881 Name = *NameOrErr;7882 else7883 consumeError(NameOrErr.takeError());7884 7885 Addend = Addr - SectionAddr;7886}7887 7888static void printUnwindRelocDest(const MachOObjectFile *Obj,7889 std::map<uint64_t, SymbolRef> &Symbols,7890 const RelocationRef &Reloc, uint64_t Addr) {7891 StringRef Name;7892 uint64_t Addend;7893 7894 if (!Reloc.getObject())7895 return;7896 7897 findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);7898 7899 outs() << Name;7900 if (Addend)7901 outs() << " + " << format("0x%" PRIx64, Addend);7902}7903 7904static void7905printMachOCompactUnwindSection(const MachOObjectFile *Obj,7906 std::map<uint64_t, SymbolRef> &Symbols,7907 const SectionRef &CompactUnwind) {7908 7909 if (!Obj->isLittleEndian()) {7910 outs() << "Skipping big-endian __compact_unwind section\n";7911 return;7912 }7913 7914 bool Is64 = Obj->is64Bit();7915 uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);7916 uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);7917 7918 StringRef Contents =7919 unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());7920 SmallVector<CompactUnwindEntry, 4> CompactUnwinds;7921 7922 // First populate the initial raw offsets, encodings and so on from the entry.7923 for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {7924 CompactUnwindEntry Entry(Contents, Offset, Is64);7925 CompactUnwinds.push_back(Entry);7926 }7927 7928 // Next we need to look at the relocations to find out what objects are7929 // actually being referred to.7930 for (const RelocationRef &Reloc : CompactUnwind.relocations()) {7931 uint64_t RelocAddress = Reloc.getOffset();7932 7933 uint32_t EntryIdx = RelocAddress / EntrySize;7934 uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;7935 CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];7936 7937 if (OffsetInEntry == 0)7938 Entry.FunctionReloc = Reloc;7939 else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))7940 Entry.PersonalityReloc = Reloc;7941 else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))7942 Entry.LSDAReloc = Reloc;7943 else {7944 outs() << "Invalid relocation in __compact_unwind section\n";7945 return;7946 }7947 }7948 7949 // Finally, we're ready to print the data we've gathered.7950 outs() << "Contents of __compact_unwind section:\n";7951 for (auto &Entry : CompactUnwinds) {7952 outs() << " Entry at offset "7953 << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";7954 7955 // 1. Start of the region this entry applies to.7956 outs() << " start: " << format("0x%" PRIx64,7957 Entry.FunctionAddr) << ' ';7958 printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);7959 outs() << '\n';7960 7961 // 2. Length of the region this entry applies to.7962 outs() << " length: " << format("0x%" PRIx32, Entry.Length)7963 << '\n';7964 // 3. The 32-bit compact encoding.7965 outs() << " compact encoding: "7966 << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';7967 7968 // 4. The personality function, if present.7969 if (Entry.PersonalityReloc.getObject()) {7970 outs() << " personality function: "7971 << format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';7972 printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,7973 Entry.PersonalityAddr);7974 outs() << '\n';7975 }7976 7977 // 5. This entry's language-specific data area.7978 if (Entry.LSDAReloc.getObject()) {7979 outs() << " LSDA: " << format("0x%" PRIx64,7980 Entry.LSDAAddr) << ' ';7981 printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);7982 outs() << '\n';7983 }7984 }7985}7986 7987//===----------------------------------------------------------------------===//7988// __unwind_info section dumping7989//===----------------------------------------------------------------------===//7990 7991static void printRegularSecondLevelUnwindPage(StringRef PageData) {7992 ptrdiff_t Pos = 0;7993 uint32_t Kind = readNext<uint32_t>(PageData, Pos);7994 (void)Kind;7995 assert(Kind == 2 && "kind for a regular 2nd level index should be 2");7996 7997 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);7998 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);7999 8000 Pos = EntriesStart;8001 for (unsigned i = 0; i < NumEntries; ++i) {8002 uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);8003 uint32_t Encoding = readNext<uint32_t>(PageData, Pos);8004 8005 outs() << " [" << i << "]: "8006 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8007 << ", "8008 << "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';8009 }8010}8011 8012static void printCompressedSecondLevelUnwindPage(8013 StringRef PageData, uint32_t FunctionBase,8014 const SmallVectorImpl<uint32_t> &CommonEncodings) {8015 ptrdiff_t Pos = 0;8016 uint32_t Kind = readNext<uint32_t>(PageData, Pos);8017 (void)Kind;8018 assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");8019 8020 uint32_t NumCommonEncodings = CommonEncodings.size();8021 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);8022 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);8023 8024 uint16_t PageEncodingsStart = readNext<uint16_t>(PageData, Pos);8025 uint16_t NumPageEncodings = readNext<uint16_t>(PageData, Pos);8026 SmallVector<uint32_t, 64> PageEncodings;8027 if (NumPageEncodings) {8028 outs() << " Page encodings: (count = " << NumPageEncodings << ")\n";8029 Pos = PageEncodingsStart;8030 for (unsigned i = 0; i < NumPageEncodings; ++i) {8031 uint32_t Encoding = readNext<uint32_t>(PageData, Pos);8032 PageEncodings.push_back(Encoding);8033 outs() << " encoding[" << (i + NumCommonEncodings)8034 << "]: " << format("0x%08" PRIx32, Encoding) << '\n';8035 }8036 }8037 8038 Pos = EntriesStart;8039 for (unsigned i = 0; i < NumEntries; ++i) {8040 uint32_t Entry = readNext<uint32_t>(PageData, Pos);8041 uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);8042 uint32_t EncodingIdx = Entry >> 24;8043 8044 uint32_t Encoding;8045 if (EncodingIdx < NumCommonEncodings)8046 Encoding = CommonEncodings[EncodingIdx];8047 else8048 Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];8049 8050 outs() << " [" << i << "]: "8051 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8052 << ", "8053 << "encoding[" << EncodingIdx8054 << "]=" << format("0x%08" PRIx32, Encoding) << '\n';8055 }8056}8057 8058static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,8059 std::map<uint64_t, SymbolRef> &Symbols,8060 const SectionRef &UnwindInfo) {8061 8062 if (!Obj->isLittleEndian()) {8063 outs() << "Skipping big-endian __unwind_info section\n";8064 return;8065 }8066 8067 outs() << "Contents of __unwind_info section:\n";8068 8069 StringRef Contents =8070 unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());8071 ptrdiff_t Pos = 0;8072 8073 //===----------------------------------8074 // Section header8075 //===----------------------------------8076 8077 uint32_t Version = readNext<uint32_t>(Contents, Pos);8078 outs() << " Version: "8079 << format("0x%" PRIx32, Version) << '\n';8080 if (Version != 1) {8081 outs() << " Skipping section with unknown version\n";8082 return;8083 }8084 8085 uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);8086 outs() << " Common encodings array section offset: "8087 << format("0x%" PRIx32, CommonEncodingsStart) << '\n';8088 uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);8089 outs() << " Number of common encodings in array: "8090 << format("0x%" PRIx32, NumCommonEncodings) << '\n';8091 8092 uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);8093 outs() << " Personality function array section offset: "8094 << format("0x%" PRIx32, PersonalitiesStart) << '\n';8095 uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);8096 outs() << " Number of personality functions in array: "8097 << format("0x%" PRIx32, NumPersonalities) << '\n';8098 8099 uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);8100 outs() << " Index array section offset: "8101 << format("0x%" PRIx32, IndicesStart) << '\n';8102 uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);8103 outs() << " Number of indices in array: "8104 << format("0x%" PRIx32, NumIndices) << '\n';8105 8106 //===----------------------------------8107 // A shared list of common encodings8108 //===----------------------------------8109 8110 // These occupy indices in the range [0, N] whenever an encoding is referenced8111 // from a compressed 2nd level index table. In practice the linker only8112 // creates ~128 of these, so that indices are available to embed encodings in8113 // the 2nd level index.8114 8115 SmallVector<uint32_t, 64> CommonEncodings;8116 outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";8117 Pos = CommonEncodingsStart;8118 for (unsigned i = 0; i < NumCommonEncodings; ++i) {8119 uint32_t Encoding = readNext<uint32_t>(Contents, Pos);8120 CommonEncodings.push_back(Encoding);8121 8122 outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)8123 << '\n';8124 }8125 8126 //===----------------------------------8127 // Personality functions used in this executable8128 //===----------------------------------8129 8130 // There should be only a handful of these (one per source language,8131 // roughly). Particularly since they only get 2 bits in the compact encoding.8132 8133 outs() << " Personality functions: (count = " << NumPersonalities << ")\n";8134 Pos = PersonalitiesStart;8135 for (unsigned i = 0; i < NumPersonalities; ++i) {8136 uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);8137 outs() << " personality[" << i + 18138 << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';8139 }8140 8141 //===----------------------------------8142 // The level 1 index entries8143 //===----------------------------------8144 8145 // These specify an approximate place to start searching for the more detailed8146 // information, sorted by PC.8147 8148 struct IndexEntry {8149 uint32_t FunctionOffset;8150 uint32_t SecondLevelPageStart;8151 uint32_t LSDAStart;8152 };8153 8154 SmallVector<IndexEntry, 4> IndexEntries;8155 8156 outs() << " Top level indices: (count = " << NumIndices << ")\n";8157 Pos = IndicesStart;8158 for (unsigned i = 0; i < NumIndices; ++i) {8159 IndexEntry Entry;8160 8161 Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);8162 Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);8163 Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);8164 IndexEntries.push_back(Entry);8165 8166 outs() << " [" << i << "]: "8167 << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)8168 << ", "8169 << "2nd level page offset="8170 << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "8171 << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';8172 }8173 8174 //===----------------------------------8175 // Next come the LSDA tables8176 //===----------------------------------8177 8178 // The LSDA layout is rather implicit: it's a contiguous array of entries from8179 // the first top-level index's LSDAOffset to the last (sentinel).8180 8181 outs() << " LSDA descriptors:\n";8182 Pos = IndexEntries[0].LSDAStart;8183 const uint32_t LSDASize = 2 * sizeof(uint32_t);8184 int NumLSDAs =8185 (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;8186 8187 for (int i = 0; i < NumLSDAs; ++i) {8188 uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);8189 uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);8190 outs() << " [" << i << "]: "8191 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)8192 << ", "8193 << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';8194 }8195 8196 //===----------------------------------8197 // Finally, the 2nd level indices8198 //===----------------------------------8199 8200 // Generally these are 4K in size, and have 2 possible forms:8201 // + Regular stores up to 511 entries with disparate encodings8202 // + Compressed stores up to 1021 entries if few enough compact encoding8203 // values are used.8204 outs() << " Second level indices:\n";8205 for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {8206 // The final sentinel top-level index has no associated 2nd level page8207 if (IndexEntries[i].SecondLevelPageStart == 0)8208 break;8209 8210 outs() << " Second level index[" << i << "]: "8211 << "offset in section="8212 << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)8213 << ", "8214 << "base function offset="8215 << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';8216 8217 Pos = IndexEntries[i].SecondLevelPageStart;8218 if (Pos + sizeof(uint32_t) > Contents.size()) {8219 outs() << "warning: invalid offset for second level page: " << Pos << '\n';8220 continue;8221 }8222 8223 uint32_t Kind =8224 *reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);8225 if (Kind == 2)8226 printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));8227 else if (Kind == 3)8228 printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),8229 IndexEntries[i].FunctionOffset,8230 CommonEncodings);8231 else8232 outs() << " Skipping 2nd level page with unknown kind " << Kind8233 << '\n';8234 }8235}8236 8237void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {8238 std::map<uint64_t, SymbolRef> Symbols;8239 for (const SymbolRef &SymRef : Obj->symbols()) {8240 // Discard any undefined or absolute symbols. They're not going to take part8241 // in the convenience lookup for unwind info and just take up resources.8242 auto SectOrErr = SymRef.getSection();8243 if (!SectOrErr) {8244 // TODO: Actually report errors helpfully.8245 consumeError(SectOrErr.takeError());8246 continue;8247 }8248 section_iterator Section = *SectOrErr;8249 if (Section == Obj->section_end())8250 continue;8251 8252 uint64_t Addr = cantFail(SymRef.getValue());8253 Symbols.insert(std::make_pair(Addr, SymRef));8254 }8255 8256 for (const SectionRef &Section : Obj->sections()) {8257 StringRef SectName;8258 if (Expected<StringRef> NameOrErr = Section.getName())8259 SectName = *NameOrErr;8260 else8261 consumeError(NameOrErr.takeError());8262 8263 if (SectName == "__compact_unwind")8264 printMachOCompactUnwindSection(Obj, Symbols, Section);8265 else if (SectName == "__unwind_info")8266 printMachOUnwindInfoSection(Obj, Symbols, Section);8267 }8268}8269 8270static void PrintMachHeader(uint32_t magic, uint32_t cputype,8271 uint32_t cpusubtype, uint32_t filetype,8272 uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,8273 bool verbose) {8274 outs() << "Mach header\n";8275 outs() << " magic cputype cpusubtype caps filetype ncmds "8276 "sizeofcmds flags\n";8277 if (verbose) {8278 if (magic == MachO::MH_MAGIC)8279 outs() << " MH_MAGIC";8280 else if (magic == MachO::MH_MAGIC_64)8281 outs() << "MH_MAGIC_64";8282 else8283 outs() << format(" 0x%08" PRIx32, magic);8284 switch (cputype) {8285 case MachO::CPU_TYPE_I386:8286 outs() << " I386";8287 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8288 case MachO::CPU_SUBTYPE_I386_ALL:8289 outs() << " ALL";8290 break;8291 default:8292 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8293 break;8294 }8295 break;8296 case MachO::CPU_TYPE_X86_64:8297 outs() << " X86_64";8298 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8299 case MachO::CPU_SUBTYPE_X86_64_ALL:8300 outs() << " ALL";8301 break;8302 case MachO::CPU_SUBTYPE_X86_64_H:8303 outs() << " Haswell";8304 break;8305 default:8306 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8307 break;8308 }8309 break;8310 case MachO::CPU_TYPE_ARM:8311 outs() << " ARM";8312 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8313 case MachO::CPU_SUBTYPE_ARM_ALL:8314 outs() << " ALL";8315 break;8316 case MachO::CPU_SUBTYPE_ARM_V4T:8317 outs() << " V4T";8318 break;8319 case MachO::CPU_SUBTYPE_ARM_V5TEJ:8320 outs() << " V5TEJ";8321 break;8322 case MachO::CPU_SUBTYPE_ARM_XSCALE:8323 outs() << " XSCALE";8324 break;8325 case MachO::CPU_SUBTYPE_ARM_V6:8326 outs() << " V6";8327 break;8328 case MachO::CPU_SUBTYPE_ARM_V6M:8329 outs() << " V6M";8330 break;8331 case MachO::CPU_SUBTYPE_ARM_V7:8332 outs() << " V7";8333 break;8334 case MachO::CPU_SUBTYPE_ARM_V7EM:8335 outs() << " V7EM";8336 break;8337 case MachO::CPU_SUBTYPE_ARM_V7K:8338 outs() << " V7K";8339 break;8340 case MachO::CPU_SUBTYPE_ARM_V7M:8341 outs() << " V7M";8342 break;8343 case MachO::CPU_SUBTYPE_ARM_V7S:8344 outs() << " V7S";8345 break;8346 default:8347 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8348 break;8349 }8350 break;8351 case MachO::CPU_TYPE_ARM64:8352 outs() << " ARM64";8353 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8354 case MachO::CPU_SUBTYPE_ARM64_ALL:8355 outs() << " ALL";8356 break;8357 case MachO::CPU_SUBTYPE_ARM64_V8:8358 outs() << " V8";8359 break;8360 case MachO::CPU_SUBTYPE_ARM64E:8361 outs() << " E";8362 break;8363 default:8364 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8365 break;8366 }8367 break;8368 case MachO::CPU_TYPE_ARM64_32:8369 outs() << " ARM64_32";8370 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8371 case MachO::CPU_SUBTYPE_ARM64_32_V8:8372 outs() << " V8";8373 break;8374 default:8375 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8376 break;8377 }8378 break;8379 case MachO::CPU_TYPE_POWERPC:8380 outs() << " PPC";8381 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8382 case MachO::CPU_SUBTYPE_POWERPC_ALL:8383 outs() << " ALL";8384 break;8385 default:8386 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8387 break;8388 }8389 break;8390 case MachO::CPU_TYPE_POWERPC64:8391 outs() << " PPC64";8392 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {8393 case MachO::CPU_SUBTYPE_POWERPC_ALL:8394 outs() << " ALL";8395 break;8396 default:8397 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8398 break;8399 }8400 break;8401 default:8402 outs() << format(" %7d", cputype);8403 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8404 break;8405 }8406 8407 if (cputype == MachO::CPU_TYPE_ARM64 &&8408 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {8409 const char *Format =8410 MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype)8411 ? " PAK%02d"8412 : " PAC%02d";8413 outs() << format(Format,8414 MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype));8415 } else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) ==8416 MachO::CPU_SUBTYPE_LIB64) {8417 outs() << " LIB64";8418 } else {8419 outs() << format(" 0x%02" PRIx32,8420 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8421 }8422 switch (filetype) {8423 case MachO::MH_OBJECT:8424 outs() << " OBJECT";8425 break;8426 case MachO::MH_EXECUTE:8427 outs() << " EXECUTE";8428 break;8429 case MachO::MH_FVMLIB:8430 outs() << " FVMLIB";8431 break;8432 case MachO::MH_CORE:8433 outs() << " CORE";8434 break;8435 case MachO::MH_PRELOAD:8436 outs() << " PRELOAD";8437 break;8438 case MachO::MH_DYLIB:8439 outs() << " DYLIB";8440 break;8441 case MachO::MH_DYLIB_STUB:8442 outs() << " DYLIB_STUB";8443 break;8444 case MachO::MH_DYLINKER:8445 outs() << " DYLINKER";8446 break;8447 case MachO::MH_BUNDLE:8448 outs() << " BUNDLE";8449 break;8450 case MachO::MH_DSYM:8451 outs() << " DSYM";8452 break;8453 case MachO::MH_KEXT_BUNDLE:8454 outs() << " KEXTBUNDLE";8455 break;8456 case MachO::MH_FILESET:8457 outs() << " FILESET";8458 break;8459 default:8460 outs() << format(" %10u", filetype);8461 break;8462 }8463 outs() << format(" %5u", ncmds);8464 outs() << format(" %10u", sizeofcmds);8465 uint32_t f = flags;8466 if (f & MachO::MH_NOUNDEFS) {8467 outs() << " NOUNDEFS";8468 f &= ~MachO::MH_NOUNDEFS;8469 }8470 if (f & MachO::MH_INCRLINK) {8471 outs() << " INCRLINK";8472 f &= ~MachO::MH_INCRLINK;8473 }8474 if (f & MachO::MH_DYLDLINK) {8475 outs() << " DYLDLINK";8476 f &= ~MachO::MH_DYLDLINK;8477 }8478 if (f & MachO::MH_BINDATLOAD) {8479 outs() << " BINDATLOAD";8480 f &= ~MachO::MH_BINDATLOAD;8481 }8482 if (f & MachO::MH_PREBOUND) {8483 outs() << " PREBOUND";8484 f &= ~MachO::MH_PREBOUND;8485 }8486 if (f & MachO::MH_SPLIT_SEGS) {8487 outs() << " SPLIT_SEGS";8488 f &= ~MachO::MH_SPLIT_SEGS;8489 }8490 if (f & MachO::MH_LAZY_INIT) {8491 outs() << " LAZY_INIT";8492 f &= ~MachO::MH_LAZY_INIT;8493 }8494 if (f & MachO::MH_TWOLEVEL) {8495 outs() << " TWOLEVEL";8496 f &= ~MachO::MH_TWOLEVEL;8497 }8498 if (f & MachO::MH_FORCE_FLAT) {8499 outs() << " FORCE_FLAT";8500 f &= ~MachO::MH_FORCE_FLAT;8501 }8502 if (f & MachO::MH_NOMULTIDEFS) {8503 outs() << " NOMULTIDEFS";8504 f &= ~MachO::MH_NOMULTIDEFS;8505 }8506 if (f & MachO::MH_NOFIXPREBINDING) {8507 outs() << " NOFIXPREBINDING";8508 f &= ~MachO::MH_NOFIXPREBINDING;8509 }8510 if (f & MachO::MH_PREBINDABLE) {8511 outs() << " PREBINDABLE";8512 f &= ~MachO::MH_PREBINDABLE;8513 }8514 if (f & MachO::MH_ALLMODSBOUND) {8515 outs() << " ALLMODSBOUND";8516 f &= ~MachO::MH_ALLMODSBOUND;8517 }8518 if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {8519 outs() << " SUBSECTIONS_VIA_SYMBOLS";8520 f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;8521 }8522 if (f & MachO::MH_CANONICAL) {8523 outs() << " CANONICAL";8524 f &= ~MachO::MH_CANONICAL;8525 }8526 if (f & MachO::MH_WEAK_DEFINES) {8527 outs() << " WEAK_DEFINES";8528 f &= ~MachO::MH_WEAK_DEFINES;8529 }8530 if (f & MachO::MH_BINDS_TO_WEAK) {8531 outs() << " BINDS_TO_WEAK";8532 f &= ~MachO::MH_BINDS_TO_WEAK;8533 }8534 if (f & MachO::MH_ALLOW_STACK_EXECUTION) {8535 outs() << " ALLOW_STACK_EXECUTION";8536 f &= ~MachO::MH_ALLOW_STACK_EXECUTION;8537 }8538 if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {8539 outs() << " DEAD_STRIPPABLE_DYLIB";8540 f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;8541 }8542 if (f & MachO::MH_PIE) {8543 outs() << " PIE";8544 f &= ~MachO::MH_PIE;8545 }8546 if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {8547 outs() << " NO_REEXPORTED_DYLIBS";8548 f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;8549 }8550 if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {8551 outs() << " MH_HAS_TLV_DESCRIPTORS";8552 f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;8553 }8554 if (f & MachO::MH_NO_HEAP_EXECUTION) {8555 outs() << " MH_NO_HEAP_EXECUTION";8556 f &= ~MachO::MH_NO_HEAP_EXECUTION;8557 }8558 if (f & MachO::MH_APP_EXTENSION_SAFE) {8559 outs() << " APP_EXTENSION_SAFE";8560 f &= ~MachO::MH_APP_EXTENSION_SAFE;8561 }8562 if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {8563 outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";8564 f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;8565 }8566 if (f != 0 || flags == 0)8567 outs() << format(" 0x%08" PRIx32, f);8568 } else {8569 outs() << format(" 0x%08" PRIx32, magic);8570 outs() << format(" %7d", cputype);8571 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);8572 outs() << format(" 0x%02" PRIx32,8573 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);8574 outs() << format(" %10u", filetype);8575 outs() << format(" %5u", ncmds);8576 outs() << format(" %10u", sizeofcmds);8577 outs() << format(" 0x%08" PRIx32, flags);8578 }8579 outs() << "\n";8580}8581 8582static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,8583 StringRef SegName, uint64_t vmaddr,8584 uint64_t vmsize, uint64_t fileoff,8585 uint64_t filesize, uint32_t maxprot,8586 uint32_t initprot, uint32_t nsects,8587 uint32_t flags, uint32_t object_size,8588 bool verbose) {8589 uint64_t expected_cmdsize;8590 if (cmd == MachO::LC_SEGMENT) {8591 outs() << " cmd LC_SEGMENT\n";8592 expected_cmdsize = nsects;8593 expected_cmdsize *= sizeof(struct MachO::section);8594 expected_cmdsize += sizeof(struct MachO::segment_command);8595 } else {8596 outs() << " cmd LC_SEGMENT_64\n";8597 expected_cmdsize = nsects;8598 expected_cmdsize *= sizeof(struct MachO::section_64);8599 expected_cmdsize += sizeof(struct MachO::segment_command_64);8600 }8601 outs() << " cmdsize " << cmdsize;8602 if (cmdsize != expected_cmdsize)8603 outs() << " Inconsistent size\n";8604 else8605 outs() << "\n";8606 outs() << " segname " << SegName << "\n";8607 if (cmd == MachO::LC_SEGMENT_64) {8608 outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";8609 outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";8610 } else {8611 outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";8612 outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";8613 }8614 outs() << " fileoff " << fileoff;8615 if (fileoff > object_size)8616 outs() << " (past end of file)\n";8617 else8618 outs() << "\n";8619 outs() << " filesize " << filesize;8620 if (fileoff + filesize > object_size)8621 outs() << " (past end of file)\n";8622 else8623 outs() << "\n";8624 if (verbose) {8625 if ((maxprot &8626 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8627 MachO::VM_PROT_EXECUTE)) != 0)8628 outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";8629 else {8630 outs() << " maxprot ";8631 outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");8632 outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");8633 outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8634 }8635 if ((initprot &8636 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |8637 MachO::VM_PROT_EXECUTE)) != 0)8638 outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";8639 else {8640 outs() << " initprot ";8641 outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");8642 outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");8643 outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");8644 }8645 } else {8646 outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";8647 outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";8648 }8649 outs() << " nsects " << nsects << "\n";8650 if (verbose) {8651 outs() << " flags";8652 if (flags == 0)8653 outs() << " (none)\n";8654 else {8655 if (flags & MachO::SG_HIGHVM) {8656 outs() << " HIGHVM";8657 flags &= ~MachO::SG_HIGHVM;8658 }8659 if (flags & MachO::SG_FVMLIB) {8660 outs() << " FVMLIB";8661 flags &= ~MachO::SG_FVMLIB;8662 }8663 if (flags & MachO::SG_NORELOC) {8664 outs() << " NORELOC";8665 flags &= ~MachO::SG_NORELOC;8666 }8667 if (flags & MachO::SG_PROTECTED_VERSION_1) {8668 outs() << " PROTECTED_VERSION_1";8669 flags &= ~MachO::SG_PROTECTED_VERSION_1;8670 }8671 if (flags & MachO::SG_READ_ONLY) {8672 // Apple's otool prints the SG_ prefix for this flag, but not for the8673 // others.8674 outs() << " SG_READ_ONLY";8675 flags &= ~MachO::SG_READ_ONLY;8676 }8677 if (flags)8678 outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";8679 else8680 outs() << "\n";8681 }8682 } else {8683 outs() << " flags " << format("0x%" PRIx32, flags) << "\n";8684 }8685}8686 8687static void PrintSection(const char *sectname, const char *segname,8688 uint64_t addr, uint64_t size, uint32_t offset,8689 uint32_t align, uint32_t reloff, uint32_t nreloc,8690 uint32_t flags, uint32_t reserved1, uint32_t reserved2,8691 uint32_t cmd, const char *sg_segname,8692 uint32_t filetype, uint32_t object_size,8693 bool verbose) {8694 outs() << "Section\n";8695 outs() << " sectname " << format("%.16s\n", sectname);8696 outs() << " segname " << format("%.16s", segname);8697 if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)8698 outs() << " (does not match segment)\n";8699 else8700 outs() << "\n";8701 if (cmd == MachO::LC_SEGMENT_64) {8702 outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";8703 outs() << " size " << format("0x%016" PRIx64, size);8704 } else {8705 outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";8706 outs() << " size " << format("0x%08" PRIx64, size);8707 }8708 if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)8709 outs() << " (past end of file)\n";8710 else8711 outs() << "\n";8712 outs() << " offset " << offset;8713 if (offset > object_size)8714 outs() << " (past end of file)\n";8715 else8716 outs() << "\n";8717 uint32_t align_shifted = 1 << align;8718 outs() << " align 2^" << align << " (" << align_shifted << ")\n";8719 outs() << " reloff " << reloff;8720 if (reloff > object_size)8721 outs() << " (past end of file)\n";8722 else8723 outs() << "\n";8724 outs() << " nreloc " << nreloc;8725 if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)8726 outs() << " (past end of file)\n";8727 else8728 outs() << "\n";8729 uint32_t section_type = flags & MachO::SECTION_TYPE;8730 if (verbose) {8731 outs() << " type";8732 if (section_type == MachO::S_REGULAR)8733 outs() << " S_REGULAR\n";8734 else if (section_type == MachO::S_ZEROFILL)8735 outs() << " S_ZEROFILL\n";8736 else if (section_type == MachO::S_CSTRING_LITERALS)8737 outs() << " S_CSTRING_LITERALS\n";8738 else if (section_type == MachO::S_4BYTE_LITERALS)8739 outs() << " S_4BYTE_LITERALS\n";8740 else if (section_type == MachO::S_8BYTE_LITERALS)8741 outs() << " S_8BYTE_LITERALS\n";8742 else if (section_type == MachO::S_16BYTE_LITERALS)8743 outs() << " S_16BYTE_LITERALS\n";8744 else if (section_type == MachO::S_LITERAL_POINTERS)8745 outs() << " S_LITERAL_POINTERS\n";8746 else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)8747 outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";8748 else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)8749 outs() << " S_LAZY_SYMBOL_POINTERS\n";8750 else if (section_type == MachO::S_SYMBOL_STUBS)8751 outs() << " S_SYMBOL_STUBS\n";8752 else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)8753 outs() << " S_MOD_INIT_FUNC_POINTERS\n";8754 else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)8755 outs() << " S_MOD_TERM_FUNC_POINTERS\n";8756 else if (section_type == MachO::S_COALESCED)8757 outs() << " S_COALESCED\n";8758 else if (section_type == MachO::S_INTERPOSING)8759 outs() << " S_INTERPOSING\n";8760 else if (section_type == MachO::S_DTRACE_DOF)8761 outs() << " S_DTRACE_DOF\n";8762 else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)8763 outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";8764 else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)8765 outs() << " S_THREAD_LOCAL_REGULAR\n";8766 else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)8767 outs() << " S_THREAD_LOCAL_ZEROFILL\n";8768 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)8769 outs() << " S_THREAD_LOCAL_VARIABLES\n";8770 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8771 outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";8772 else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)8773 outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";8774 else if (section_type == MachO::S_INIT_FUNC_OFFSETS)8775 outs() << " S_INIT_FUNC_OFFSETS\n";8776 else8777 outs() << format("0x%08" PRIx32, section_type) << "\n";8778 outs() << "attributes";8779 uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;8780 if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)8781 outs() << " PURE_INSTRUCTIONS";8782 if (section_attributes & MachO::S_ATTR_NO_TOC)8783 outs() << " NO_TOC";8784 if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)8785 outs() << " STRIP_STATIC_SYMS";8786 if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)8787 outs() << " NO_DEAD_STRIP";8788 if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)8789 outs() << " LIVE_SUPPORT";8790 if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)8791 outs() << " SELF_MODIFYING_CODE";8792 if (section_attributes & MachO::S_ATTR_DEBUG)8793 outs() << " DEBUG";8794 if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)8795 outs() << " SOME_INSTRUCTIONS";8796 if (section_attributes & MachO::S_ATTR_EXT_RELOC)8797 outs() << " EXT_RELOC";8798 if (section_attributes & MachO::S_ATTR_LOC_RELOC)8799 outs() << " LOC_RELOC";8800 if (section_attributes == 0)8801 outs() << " (none)";8802 outs() << "\n";8803 } else8804 outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";8805 outs() << " reserved1 " << reserved1;8806 if (section_type == MachO::S_SYMBOL_STUBS ||8807 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||8808 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||8809 section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||8810 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)8811 outs() << " (index into indirect symbol table)\n";8812 else8813 outs() << "\n";8814 outs() << " reserved2 " << reserved2;8815 if (section_type == MachO::S_SYMBOL_STUBS)8816 outs() << " (size of stubs)\n";8817 else8818 outs() << "\n";8819}8820 8821static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,8822 uint32_t object_size) {8823 outs() << " cmd LC_SYMTAB\n";8824 outs() << " cmdsize " << st.cmdsize;8825 if (st.cmdsize != sizeof(struct MachO::symtab_command))8826 outs() << " Incorrect size\n";8827 else8828 outs() << "\n";8829 outs() << " symoff " << st.symoff;8830 if (st.symoff > object_size)8831 outs() << " (past end of file)\n";8832 else8833 outs() << "\n";8834 outs() << " nsyms " << st.nsyms;8835 uint64_t big_size;8836 if (Is64Bit) {8837 big_size = st.nsyms;8838 big_size *= sizeof(struct MachO::nlist_64);8839 big_size += st.symoff;8840 if (big_size > object_size)8841 outs() << " (past end of file)\n";8842 else8843 outs() << "\n";8844 } else {8845 big_size = st.nsyms;8846 big_size *= sizeof(struct MachO::nlist);8847 big_size += st.symoff;8848 if (big_size > object_size)8849 outs() << " (past end of file)\n";8850 else8851 outs() << "\n";8852 }8853 outs() << " stroff " << st.stroff;8854 if (st.stroff > object_size)8855 outs() << " (past end of file)\n";8856 else8857 outs() << "\n";8858 outs() << " strsize " << st.strsize;8859 big_size = st.stroff;8860 big_size += st.strsize;8861 if (big_size > object_size)8862 outs() << " (past end of file)\n";8863 else8864 outs() << "\n";8865}8866 8867static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,8868 uint32_t nsyms, uint32_t object_size,8869 bool Is64Bit) {8870 outs() << " cmd LC_DYSYMTAB\n";8871 outs() << " cmdsize " << dyst.cmdsize;8872 if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))8873 outs() << " Incorrect size\n";8874 else8875 outs() << "\n";8876 outs() << " ilocalsym " << dyst.ilocalsym;8877 if (dyst.ilocalsym > nsyms)8878 outs() << " (greater than the number of symbols)\n";8879 else8880 outs() << "\n";8881 outs() << " nlocalsym " << dyst.nlocalsym;8882 uint64_t big_size;8883 big_size = dyst.ilocalsym;8884 big_size += dyst.nlocalsym;8885 if (big_size > nsyms)8886 outs() << " (past the end of the symbol table)\n";8887 else8888 outs() << "\n";8889 outs() << " iextdefsym " << dyst.iextdefsym;8890 if (dyst.iextdefsym > nsyms)8891 outs() << " (greater than the number of symbols)\n";8892 else8893 outs() << "\n";8894 outs() << " nextdefsym " << dyst.nextdefsym;8895 big_size = dyst.iextdefsym;8896 big_size += dyst.nextdefsym;8897 if (big_size > nsyms)8898 outs() << " (past the end of the symbol table)\n";8899 else8900 outs() << "\n";8901 outs() << " iundefsym " << dyst.iundefsym;8902 if (dyst.iundefsym > nsyms)8903 outs() << " (greater than the number of symbols)\n";8904 else8905 outs() << "\n";8906 outs() << " nundefsym " << dyst.nundefsym;8907 big_size = dyst.iundefsym;8908 big_size += dyst.nundefsym;8909 if (big_size > nsyms)8910 outs() << " (past the end of the symbol table)\n";8911 else8912 outs() << "\n";8913 outs() << " tocoff " << dyst.tocoff;8914 if (dyst.tocoff > object_size)8915 outs() << " (past end of file)\n";8916 else8917 outs() << "\n";8918 outs() << " ntoc " << dyst.ntoc;8919 big_size = dyst.ntoc;8920 big_size *= sizeof(struct MachO::dylib_table_of_contents);8921 big_size += dyst.tocoff;8922 if (big_size > object_size)8923 outs() << " (past end of file)\n";8924 else8925 outs() << "\n";8926 outs() << " modtaboff " << dyst.modtaboff;8927 if (dyst.modtaboff > object_size)8928 outs() << " (past end of file)\n";8929 else8930 outs() << "\n";8931 outs() << " nmodtab " << dyst.nmodtab;8932 uint64_t modtabend;8933 if (Is64Bit) {8934 modtabend = dyst.nmodtab;8935 modtabend *= sizeof(struct MachO::dylib_module_64);8936 modtabend += dyst.modtaboff;8937 } else {8938 modtabend = dyst.nmodtab;8939 modtabend *= sizeof(struct MachO::dylib_module);8940 modtabend += dyst.modtaboff;8941 }8942 if (modtabend > object_size)8943 outs() << " (past end of file)\n";8944 else8945 outs() << "\n";8946 outs() << " extrefsymoff " << dyst.extrefsymoff;8947 if (dyst.extrefsymoff > object_size)8948 outs() << " (past end of file)\n";8949 else8950 outs() << "\n";8951 outs() << " nextrefsyms " << dyst.nextrefsyms;8952 big_size = dyst.nextrefsyms;8953 big_size *= sizeof(struct MachO::dylib_reference);8954 big_size += dyst.extrefsymoff;8955 if (big_size > object_size)8956 outs() << " (past end of file)\n";8957 else8958 outs() << "\n";8959 outs() << " indirectsymoff " << dyst.indirectsymoff;8960 if (dyst.indirectsymoff > object_size)8961 outs() << " (past end of file)\n";8962 else8963 outs() << "\n";8964 outs() << " nindirectsyms " << dyst.nindirectsyms;8965 big_size = dyst.nindirectsyms;8966 big_size *= sizeof(uint32_t);8967 big_size += dyst.indirectsymoff;8968 if (big_size > object_size)8969 outs() << " (past end of file)\n";8970 else8971 outs() << "\n";8972 outs() << " extreloff " << dyst.extreloff;8973 if (dyst.extreloff > object_size)8974 outs() << " (past end of file)\n";8975 else8976 outs() << "\n";8977 outs() << " nextrel " << dyst.nextrel;8978 big_size = dyst.nextrel;8979 big_size *= sizeof(struct MachO::relocation_info);8980 big_size += dyst.extreloff;8981 if (big_size > object_size)8982 outs() << " (past end of file)\n";8983 else8984 outs() << "\n";8985 outs() << " locreloff " << dyst.locreloff;8986 if (dyst.locreloff > object_size)8987 outs() << " (past end of file)\n";8988 else8989 outs() << "\n";8990 outs() << " nlocrel " << dyst.nlocrel;8991 big_size = dyst.nlocrel;8992 big_size *= sizeof(struct MachO::relocation_info);8993 big_size += dyst.locreloff;8994 if (big_size > object_size)8995 outs() << " (past end of file)\n";8996 else8997 outs() << "\n";8998}8999 9000static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,9001 uint32_t object_size) {9002 if (dc.cmd == MachO::LC_DYLD_INFO)9003 outs() << " cmd LC_DYLD_INFO\n";9004 else9005 outs() << " cmd LC_DYLD_INFO_ONLY\n";9006 outs() << " cmdsize " << dc.cmdsize;9007 if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))9008 outs() << " Incorrect size\n";9009 else9010 outs() << "\n";9011 outs() << " rebase_off " << dc.rebase_off;9012 if (dc.rebase_off > object_size)9013 outs() << " (past end of file)\n";9014 else9015 outs() << "\n";9016 outs() << " rebase_size " << dc.rebase_size;9017 uint64_t big_size;9018 big_size = dc.rebase_off;9019 big_size += dc.rebase_size;9020 if (big_size > object_size)9021 outs() << " (past end of file)\n";9022 else9023 outs() << "\n";9024 outs() << " bind_off " << dc.bind_off;9025 if (dc.bind_off > object_size)9026 outs() << " (past end of file)\n";9027 else9028 outs() << "\n";9029 outs() << " bind_size " << dc.bind_size;9030 big_size = dc.bind_off;9031 big_size += dc.bind_size;9032 if (big_size > object_size)9033 outs() << " (past end of file)\n";9034 else9035 outs() << "\n";9036 outs() << " weak_bind_off " << dc.weak_bind_off;9037 if (dc.weak_bind_off > object_size)9038 outs() << " (past end of file)\n";9039 else9040 outs() << "\n";9041 outs() << " weak_bind_size " << dc.weak_bind_size;9042 big_size = dc.weak_bind_off;9043 big_size += dc.weak_bind_size;9044 if (big_size > object_size)9045 outs() << " (past end of file)\n";9046 else9047 outs() << "\n";9048 outs() << " lazy_bind_off " << dc.lazy_bind_off;9049 if (dc.lazy_bind_off > object_size)9050 outs() << " (past end of file)\n";9051 else9052 outs() << "\n";9053 outs() << " lazy_bind_size " << dc.lazy_bind_size;9054 big_size = dc.lazy_bind_off;9055 big_size += dc.lazy_bind_size;9056 if (big_size > object_size)9057 outs() << " (past end of file)\n";9058 else9059 outs() << "\n";9060 outs() << " export_off " << dc.export_off;9061 if (dc.export_off > object_size)9062 outs() << " (past end of file)\n";9063 else9064 outs() << "\n";9065 outs() << " export_size " << dc.export_size;9066 big_size = dc.export_off;9067 big_size += dc.export_size;9068 if (big_size > object_size)9069 outs() << " (past end of file)\n";9070 else9071 outs() << "\n";9072}9073 9074static void PrintDyldLoadCommand(MachO::dylinker_command dyld,9075 const char *Ptr) {9076 if (dyld.cmd == MachO::LC_ID_DYLINKER)9077 outs() << " cmd LC_ID_DYLINKER\n";9078 else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)9079 outs() << " cmd LC_LOAD_DYLINKER\n";9080 else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)9081 outs() << " cmd LC_DYLD_ENVIRONMENT\n";9082 else9083 outs() << " cmd ?(" << dyld.cmd << ")\n";9084 outs() << " cmdsize " << dyld.cmdsize;9085 if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))9086 outs() << " Incorrect size\n";9087 else9088 outs() << "\n";9089 if (dyld.name >= dyld.cmdsize)9090 outs() << " name ?(bad offset " << dyld.name << ")\n";9091 else {9092 const char *P = Ptr + dyld.name;9093 outs() << " name " << P << " (offset " << dyld.name << ")\n";9094 }9095}9096 9097static void PrintUuidLoadCommand(MachO::uuid_command uuid) {9098 outs() << " cmd LC_UUID\n";9099 outs() << " cmdsize " << uuid.cmdsize;9100 if (uuid.cmdsize != sizeof(struct MachO::uuid_command))9101 outs() << " Incorrect size\n";9102 else9103 outs() << "\n";9104 outs() << " uuid ";9105 for (int i = 0; i < 16; ++i) {9106 outs() << format("%02" PRIX32, uuid.uuid[i]);9107 if (i == 3 || i == 5 || i == 7 || i == 9)9108 outs() << "-";9109 }9110 outs() << "\n";9111}9112 9113static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {9114 outs() << " cmd LC_RPATH\n";9115 outs() << " cmdsize " << rpath.cmdsize;9116 if (rpath.cmdsize < sizeof(struct MachO::rpath_command))9117 outs() << " Incorrect size\n";9118 else9119 outs() << "\n";9120 if (rpath.path >= rpath.cmdsize)9121 outs() << " path ?(bad offset " << rpath.path << ")\n";9122 else {9123 const char *P = Ptr + rpath.path;9124 outs() << " path " << P << " (offset " << rpath.path << ")\n";9125 }9126}9127 9128static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {9129 StringRef LoadCmdName;9130 switch (vd.cmd) {9131 case MachO::LC_VERSION_MIN_MACOSX:9132 LoadCmdName = "LC_VERSION_MIN_MACOSX";9133 break;9134 case MachO::LC_VERSION_MIN_IPHONEOS:9135 LoadCmdName = "LC_VERSION_MIN_IPHONEOS";9136 break;9137 case MachO::LC_VERSION_MIN_TVOS:9138 LoadCmdName = "LC_VERSION_MIN_TVOS";9139 break;9140 case MachO::LC_VERSION_MIN_WATCHOS:9141 LoadCmdName = "LC_VERSION_MIN_WATCHOS";9142 break;9143 default:9144 llvm_unreachable("Unknown version min load command");9145 }9146 9147 outs() << " cmd " << LoadCmdName << '\n';9148 outs() << " cmdsize " << vd.cmdsize;9149 if (vd.cmdsize != sizeof(struct MachO::version_min_command))9150 outs() << " Incorrect size\n";9151 else9152 outs() << "\n";9153 outs() << " version "9154 << MachOObjectFile::getVersionMinMajor(vd, false) << "."9155 << MachOObjectFile::getVersionMinMinor(vd, false);9156 uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);9157 if (Update != 0)9158 outs() << "." << Update;9159 outs() << "\n";9160 if (vd.sdk == 0)9161 outs() << " sdk n/a";9162 else {9163 outs() << " sdk "9164 << MachOObjectFile::getVersionMinMajor(vd, true) << "."9165 << MachOObjectFile::getVersionMinMinor(vd, true);9166 }9167 Update = MachOObjectFile::getVersionMinUpdate(vd, true);9168 if (Update != 0)9169 outs() << "." << Update;9170 outs() << "\n";9171}9172 9173static void PrintNoteLoadCommand(MachO::note_command Nt) {9174 outs() << " cmd LC_NOTE\n";9175 outs() << " cmdsize " << Nt.cmdsize;9176 if (Nt.cmdsize != sizeof(struct MachO::note_command))9177 outs() << " Incorrect size\n";9178 else9179 outs() << "\n";9180 const char *d = Nt.data_owner;9181 outs() << "data_owner " << format("%.16s\n", d);9182 outs() << " offset " << Nt.offset << "\n";9183 outs() << " size " << Nt.size << "\n";9184}9185 9186static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {9187 outs() << " tool ";9188 if (verbose)9189 outs() << MachOObjectFile::getBuildTool(bv.tool);9190 else9191 outs() << bv.tool;9192 outs() << "\n";9193 outs() << " version " << MachOObjectFile::getVersionString(bv.version)9194 << "\n";9195}9196 9197static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,9198 MachO::build_version_command bd,9199 bool verbose) {9200 outs() << " cmd LC_BUILD_VERSION\n";9201 outs() << " cmdsize " << bd.cmdsize;9202 if (bd.cmdsize !=9203 sizeof(struct MachO::build_version_command) +9204 bd.ntools * sizeof(struct MachO::build_tool_version))9205 outs() << " Incorrect size\n";9206 else9207 outs() << "\n";9208 outs() << " platform ";9209 if (verbose)9210 outs() << MachOObjectFile::getBuildPlatform(bd.platform);9211 else9212 outs() << bd.platform;9213 outs() << "\n";9214 if (bd.sdk)9215 outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)9216 << "\n";9217 else9218 outs() << " sdk n/a\n";9219 outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)9220 << "\n";9221 outs() << " ntools " << bd.ntools << "\n";9222 for (unsigned i = 0; i < bd.ntools; ++i) {9223 MachO::build_tool_version bv = obj->getBuildToolVersion(i);9224 PrintBuildToolVersion(bv, verbose);9225 }9226}9227 9228static void PrintSourceVersionCommand(MachO::source_version_command sd) {9229 outs() << " cmd LC_SOURCE_VERSION\n";9230 outs() << " cmdsize " << sd.cmdsize;9231 if (sd.cmdsize != sizeof(struct MachO::source_version_command))9232 outs() << " Incorrect size\n";9233 else9234 outs() << "\n";9235 uint64_t a = (sd.version >> 40) & 0xffffff;9236 uint64_t b = (sd.version >> 30) & 0x3ff;9237 uint64_t c = (sd.version >> 20) & 0x3ff;9238 uint64_t d = (sd.version >> 10) & 0x3ff;9239 uint64_t e = sd.version & 0x3ff;9240 outs() << " version " << a << "." << b;9241 if (e != 0)9242 outs() << "." << c << "." << d << "." << e;9243 else if (d != 0)9244 outs() << "." << c << "." << d;9245 else if (c != 0)9246 outs() << "." << c;9247 outs() << "\n";9248}9249 9250static void PrintEntryPointCommand(MachO::entry_point_command ep) {9251 outs() << " cmd LC_MAIN\n";9252 outs() << " cmdsize " << ep.cmdsize;9253 if (ep.cmdsize != sizeof(struct MachO::entry_point_command))9254 outs() << " Incorrect size\n";9255 else9256 outs() << "\n";9257 outs() << " entryoff " << ep.entryoff << "\n";9258 outs() << " stacksize " << ep.stacksize << "\n";9259}9260 9261static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,9262 uint32_t object_size) {9263 outs() << " cmd LC_ENCRYPTION_INFO\n";9264 outs() << " cmdsize " << ec.cmdsize;9265 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))9266 outs() << " Incorrect size\n";9267 else9268 outs() << "\n";9269 outs() << " cryptoff " << ec.cryptoff;9270 if (ec.cryptoff > object_size)9271 outs() << " (past end of file)\n";9272 else9273 outs() << "\n";9274 outs() << " cryptsize " << ec.cryptsize;9275 if (ec.cryptsize > object_size)9276 outs() << " (past end of file)\n";9277 else9278 outs() << "\n";9279 outs() << " cryptid " << ec.cryptid << "\n";9280}9281 9282static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,9283 uint32_t object_size) {9284 outs() << " cmd LC_ENCRYPTION_INFO_64\n";9285 outs() << " cmdsize " << ec.cmdsize;9286 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))9287 outs() << " Incorrect size\n";9288 else9289 outs() << "\n";9290 outs() << " cryptoff " << ec.cryptoff;9291 if (ec.cryptoff > object_size)9292 outs() << " (past end of file)\n";9293 else9294 outs() << "\n";9295 outs() << " cryptsize " << ec.cryptsize;9296 if (ec.cryptsize > object_size)9297 outs() << " (past end of file)\n";9298 else9299 outs() << "\n";9300 outs() << " cryptid " << ec.cryptid << "\n";9301 outs() << " pad " << ec.pad << "\n";9302}9303 9304static void PrintLinkerOptionCommand(MachO::linker_option_command lo,9305 const char *Ptr) {9306 outs() << " cmd LC_LINKER_OPTION\n";9307 outs() << " cmdsize " << lo.cmdsize;9308 if (lo.cmdsize < sizeof(struct MachO::linker_option_command))9309 outs() << " Incorrect size\n";9310 else9311 outs() << "\n";9312 outs() << " count " << lo.count << "\n";9313 const char *string = Ptr + sizeof(struct MachO::linker_option_command);9314 uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);9315 uint32_t i = 0;9316 while (left > 0) {9317 while (*string == '\0' && left > 0) {9318 string++;9319 left--;9320 }9321 if (left > 0) {9322 i++;9323 outs() << " string #" << i << " " << format("%.*s\n", left, string);9324 uint32_t NullPos = StringRef(string, left).find('\0');9325 uint32_t len = std::min(NullPos, left) + 1;9326 string += len;9327 left -= len;9328 }9329 }9330 if (lo.count != i)9331 outs() << " count " << lo.count << " does not match number of strings "9332 << i << "\n";9333}9334 9335static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,9336 const char *Ptr) {9337 outs() << " cmd LC_SUB_FRAMEWORK\n";9338 outs() << " cmdsize " << sub.cmdsize;9339 if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))9340 outs() << " Incorrect size\n";9341 else9342 outs() << "\n";9343 if (sub.umbrella < sub.cmdsize) {9344 const char *P = Ptr + sub.umbrella;9345 outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";9346 } else {9347 outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";9348 }9349}9350 9351static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,9352 const char *Ptr) {9353 outs() << " cmd LC_SUB_UMBRELLA\n";9354 outs() << " cmdsize " << sub.cmdsize;9355 if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))9356 outs() << " Incorrect size\n";9357 else9358 outs() << "\n";9359 if (sub.sub_umbrella < sub.cmdsize) {9360 const char *P = Ptr + sub.sub_umbrella;9361 outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";9362 } else {9363 outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";9364 }9365}9366 9367static void PrintSubLibraryCommand(MachO::sub_library_command sub,9368 const char *Ptr) {9369 outs() << " cmd LC_SUB_LIBRARY\n";9370 outs() << " cmdsize " << sub.cmdsize;9371 if (sub.cmdsize < sizeof(struct MachO::sub_library_command))9372 outs() << " Incorrect size\n";9373 else9374 outs() << "\n";9375 if (sub.sub_library < sub.cmdsize) {9376 const char *P = Ptr + sub.sub_library;9377 outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";9378 } else {9379 outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";9380 }9381}9382 9383static void PrintSubClientCommand(MachO::sub_client_command sub,9384 const char *Ptr) {9385 outs() << " cmd LC_SUB_CLIENT\n";9386 outs() << " cmdsize " << sub.cmdsize;9387 if (sub.cmdsize < sizeof(struct MachO::sub_client_command))9388 outs() << " Incorrect size\n";9389 else9390 outs() << "\n";9391 if (sub.client < sub.cmdsize) {9392 const char *P = Ptr + sub.client;9393 outs() << " client " << P << " (offset " << sub.client << ")\n";9394 } else {9395 outs() << " client ?(bad offset " << sub.client << ")\n";9396 }9397}9398 9399static void PrintRoutinesCommand(MachO::routines_command r) {9400 outs() << " cmd LC_ROUTINES\n";9401 outs() << " cmdsize " << r.cmdsize;9402 if (r.cmdsize != sizeof(struct MachO::routines_command))9403 outs() << " Incorrect size\n";9404 else9405 outs() << "\n";9406 outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";9407 outs() << " init_module " << r.init_module << "\n";9408 outs() << " reserved1 " << r.reserved1 << "\n";9409 outs() << " reserved2 " << r.reserved2 << "\n";9410 outs() << " reserved3 " << r.reserved3 << "\n";9411 outs() << " reserved4 " << r.reserved4 << "\n";9412 outs() << " reserved5 " << r.reserved5 << "\n";9413 outs() << " reserved6 " << r.reserved6 << "\n";9414}9415 9416static void PrintRoutinesCommand64(MachO::routines_command_64 r) {9417 outs() << " cmd LC_ROUTINES_64\n";9418 outs() << " cmdsize " << r.cmdsize;9419 if (r.cmdsize != sizeof(struct MachO::routines_command_64))9420 outs() << " Incorrect size\n";9421 else9422 outs() << "\n";9423 outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";9424 outs() << " init_module " << r.init_module << "\n";9425 outs() << " reserved1 " << r.reserved1 << "\n";9426 outs() << " reserved2 " << r.reserved2 << "\n";9427 outs() << " reserved3 " << r.reserved3 << "\n";9428 outs() << " reserved4 " << r.reserved4 << "\n";9429 outs() << " reserved5 " << r.reserved5 << "\n";9430 outs() << " reserved6 " << r.reserved6 << "\n";9431}9432 9433static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {9434 outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);9435 outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);9436 outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);9437 outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";9438 outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);9439 outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);9440 outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);9441 outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";9442 outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);9443 outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);9444 outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);9445 outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";9446 outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);9447 outs() << " es " << format("0x%08" PRIx32, cpu32.es);9448 outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);9449 outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";9450}9451 9452static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {9453 outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);9454 outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);9455 outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";9456 outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);9457 outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);9458 outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";9459 outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);9460 outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);9461 outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";9462 outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);9463 outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);9464 outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";9465 outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);9466 outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);9467 outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";9468 outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);9469 outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";9470 outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);9471 outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);9472 outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";9473 outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";9474}9475 9476static void Print_mmst_reg(MachO::mmst_reg_t &r) {9477 uint32_t f;9478 outs() << "\t mmst_reg ";9479 for (f = 0; f < 10; f++)9480 outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";9481 outs() << "\n";9482 outs() << "\t mmst_rsrv ";9483 for (f = 0; f < 6; f++)9484 outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";9485 outs() << "\n";9486}9487 9488static void Print_xmm_reg(MachO::xmm_reg_t &r) {9489 uint32_t f;9490 outs() << "\t xmm_reg ";9491 for (f = 0; f < 16; f++)9492 outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";9493 outs() << "\n";9494}9495 9496static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {9497 outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];9498 outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";9499 outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;9500 outs() << " denorm " << fpu.fpu_fcw.denorm;9501 outs() << " zdiv " << fpu.fpu_fcw.zdiv;9502 outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;9503 outs() << " undfl " << fpu.fpu_fcw.undfl;9504 outs() << " precis " << fpu.fpu_fcw.precis << "\n";9505 outs() << "\t\t pc ";9506 if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)9507 outs() << "FP_PREC_24B ";9508 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)9509 outs() << "FP_PREC_53B ";9510 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)9511 outs() << "FP_PREC_64B ";9512 else9513 outs() << fpu.fpu_fcw.pc << " ";9514 outs() << "rc ";9515 if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)9516 outs() << "FP_RND_NEAR ";9517 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)9518 outs() << "FP_RND_DOWN ";9519 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)9520 outs() << "FP_RND_UP ";9521 else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)9522 outs() << "FP_CHOP ";9523 outs() << "\n";9524 outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;9525 outs() << " denorm " << fpu.fpu_fsw.denorm;9526 outs() << " zdiv " << fpu.fpu_fsw.zdiv;9527 outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;9528 outs() << " undfl " << fpu.fpu_fsw.undfl;9529 outs() << " precis " << fpu.fpu_fsw.precis;9530 outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";9531 outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;9532 outs() << " c0 " << fpu.fpu_fsw.c0;9533 outs() << " c1 " << fpu.fpu_fsw.c1;9534 outs() << " c2 " << fpu.fpu_fsw.c2;9535 outs() << " tos " << fpu.fpu_fsw.tos;9536 outs() << " c3 " << fpu.fpu_fsw.c3;9537 outs() << " busy " << fpu.fpu_fsw.busy << "\n";9538 outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);9539 outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);9540 outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);9541 outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";9542 outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);9543 outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);9544 outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);9545 outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";9546 outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);9547 outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);9548 outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);9549 outs() << "\n";9550 outs() << "\t fpu_stmm0:\n";9551 Print_mmst_reg(fpu.fpu_stmm0);9552 outs() << "\t fpu_stmm1:\n";9553 Print_mmst_reg(fpu.fpu_stmm1);9554 outs() << "\t fpu_stmm2:\n";9555 Print_mmst_reg(fpu.fpu_stmm2);9556 outs() << "\t fpu_stmm3:\n";9557 Print_mmst_reg(fpu.fpu_stmm3);9558 outs() << "\t fpu_stmm4:\n";9559 Print_mmst_reg(fpu.fpu_stmm4);9560 outs() << "\t fpu_stmm5:\n";9561 Print_mmst_reg(fpu.fpu_stmm5);9562 outs() << "\t fpu_stmm6:\n";9563 Print_mmst_reg(fpu.fpu_stmm6);9564 outs() << "\t fpu_stmm7:\n";9565 Print_mmst_reg(fpu.fpu_stmm7);9566 outs() << "\t fpu_xmm0:\n";9567 Print_xmm_reg(fpu.fpu_xmm0);9568 outs() << "\t fpu_xmm1:\n";9569 Print_xmm_reg(fpu.fpu_xmm1);9570 outs() << "\t fpu_xmm2:\n";9571 Print_xmm_reg(fpu.fpu_xmm2);9572 outs() << "\t fpu_xmm3:\n";9573 Print_xmm_reg(fpu.fpu_xmm3);9574 outs() << "\t fpu_xmm4:\n";9575 Print_xmm_reg(fpu.fpu_xmm4);9576 outs() << "\t fpu_xmm5:\n";9577 Print_xmm_reg(fpu.fpu_xmm5);9578 outs() << "\t fpu_xmm6:\n";9579 Print_xmm_reg(fpu.fpu_xmm6);9580 outs() << "\t fpu_xmm7:\n";9581 Print_xmm_reg(fpu.fpu_xmm7);9582 outs() << "\t fpu_xmm8:\n";9583 Print_xmm_reg(fpu.fpu_xmm8);9584 outs() << "\t fpu_xmm9:\n";9585 Print_xmm_reg(fpu.fpu_xmm9);9586 outs() << "\t fpu_xmm10:\n";9587 Print_xmm_reg(fpu.fpu_xmm10);9588 outs() << "\t fpu_xmm11:\n";9589 Print_xmm_reg(fpu.fpu_xmm11);9590 outs() << "\t fpu_xmm12:\n";9591 Print_xmm_reg(fpu.fpu_xmm12);9592 outs() << "\t fpu_xmm13:\n";9593 Print_xmm_reg(fpu.fpu_xmm13);9594 outs() << "\t fpu_xmm14:\n";9595 Print_xmm_reg(fpu.fpu_xmm14);9596 outs() << "\t fpu_xmm15:\n";9597 Print_xmm_reg(fpu.fpu_xmm15);9598 outs() << "\t fpu_rsrv4:\n";9599 for (uint32_t f = 0; f < 6; f++) {9600 outs() << "\t ";9601 for (uint32_t g = 0; g < 16; g++)9602 outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";9603 outs() << "\n";9604 }9605 outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);9606 outs() << "\n";9607}9608 9609static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {9610 outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);9611 outs() << " err " << format("0x%08" PRIx32, exc64.err);9612 outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";9613}9614 9615static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {9616 outs() << "\t r0 " << format("0x%08" PRIx32, cpu32.r[0]);9617 outs() << " r1 " << format("0x%08" PRIx32, cpu32.r[1]);9618 outs() << " r2 " << format("0x%08" PRIx32, cpu32.r[2]);9619 outs() << " r3 " << format("0x%08" PRIx32, cpu32.r[3]) << "\n";9620 outs() << "\t r4 " << format("0x%08" PRIx32, cpu32.r[4]);9621 outs() << " r5 " << format("0x%08" PRIx32, cpu32.r[5]);9622 outs() << " r6 " << format("0x%08" PRIx32, cpu32.r[6]);9623 outs() << " r7 " << format("0x%08" PRIx32, cpu32.r[7]) << "\n";9624 outs() << "\t r8 " << format("0x%08" PRIx32, cpu32.r[8]);9625 outs() << " r9 " << format("0x%08" PRIx32, cpu32.r[9]);9626 outs() << " r10 " << format("0x%08" PRIx32, cpu32.r[10]);9627 outs() << " r11 " << format("0x%08" PRIx32, cpu32.r[11]) << "\n";9628 outs() << "\t r12 " << format("0x%08" PRIx32, cpu32.r[12]);9629 outs() << " sp " << format("0x%08" PRIx32, cpu32.sp);9630 outs() << " lr " << format("0x%08" PRIx32, cpu32.lr);9631 outs() << " pc " << format("0x%08" PRIx32, cpu32.pc) << "\n";9632 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";9633}9634 9635static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {9636 outs() << "\t x0 " << format("0x%016" PRIx64, cpu64.x[0]);9637 outs() << " x1 " << format("0x%016" PRIx64, cpu64.x[1]);9638 outs() << " x2 " << format("0x%016" PRIx64, cpu64.x[2]) << "\n";9639 outs() << "\t x3 " << format("0x%016" PRIx64, cpu64.x[3]);9640 outs() << " x4 " << format("0x%016" PRIx64, cpu64.x[4]);9641 outs() << " x5 " << format("0x%016" PRIx64, cpu64.x[5]) << "\n";9642 outs() << "\t x6 " << format("0x%016" PRIx64, cpu64.x[6]);9643 outs() << " x7 " << format("0x%016" PRIx64, cpu64.x[7]);9644 outs() << " x8 " << format("0x%016" PRIx64, cpu64.x[8]) << "\n";9645 outs() << "\t x9 " << format("0x%016" PRIx64, cpu64.x[9]);9646 outs() << " x10 " << format("0x%016" PRIx64, cpu64.x[10]);9647 outs() << " x11 " << format("0x%016" PRIx64, cpu64.x[11]) << "\n";9648 outs() << "\t x12 " << format("0x%016" PRIx64, cpu64.x[12]);9649 outs() << " x13 " << format("0x%016" PRIx64, cpu64.x[13]);9650 outs() << " x14 " << format("0x%016" PRIx64, cpu64.x[14]) << "\n";9651 outs() << "\t x15 " << format("0x%016" PRIx64, cpu64.x[15]);9652 outs() << " x16 " << format("0x%016" PRIx64, cpu64.x[16]);9653 outs() << " x17 " << format("0x%016" PRIx64, cpu64.x[17]) << "\n";9654 outs() << "\t x18 " << format("0x%016" PRIx64, cpu64.x[18]);9655 outs() << " x19 " << format("0x%016" PRIx64, cpu64.x[19]);9656 outs() << " x20 " << format("0x%016" PRIx64, cpu64.x[20]) << "\n";9657 outs() << "\t x21 " << format("0x%016" PRIx64, cpu64.x[21]);9658 outs() << " x22 " << format("0x%016" PRIx64, cpu64.x[22]);9659 outs() << " x23 " << format("0x%016" PRIx64, cpu64.x[23]) << "\n";9660 outs() << "\t x24 " << format("0x%016" PRIx64, cpu64.x[24]);9661 outs() << " x25 " << format("0x%016" PRIx64, cpu64.x[25]);9662 outs() << " x26 " << format("0x%016" PRIx64, cpu64.x[26]) << "\n";9663 outs() << "\t x27 " << format("0x%016" PRIx64, cpu64.x[27]);9664 outs() << " x28 " << format("0x%016" PRIx64, cpu64.x[28]);9665 outs() << " fp " << format("0x%016" PRIx64, cpu64.fp) << "\n";9666 outs() << "\t lr " << format("0x%016" PRIx64, cpu64.lr);9667 outs() << " sp " << format("0x%016" PRIx64, cpu64.sp);9668 outs() << " pc " << format("0x%016" PRIx64, cpu64.pc) << "\n";9669 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu64.cpsr) << "\n";9670}9671 9672static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,9673 bool isLittleEndian, uint32_t cputype) {9674 if (t.cmd == MachO::LC_THREAD)9675 outs() << " cmd LC_THREAD\n";9676 else if (t.cmd == MachO::LC_UNIXTHREAD)9677 outs() << " cmd LC_UNIXTHREAD\n";9678 else9679 outs() << " cmd " << t.cmd << " (unknown)\n";9680 outs() << " cmdsize " << t.cmdsize;9681 if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))9682 outs() << " Incorrect size\n";9683 else9684 outs() << "\n";9685 9686 const char *begin = Ptr + sizeof(struct MachO::thread_command);9687 const char *end = Ptr + t.cmdsize;9688 uint32_t flavor, count, left;9689 if (cputype == MachO::CPU_TYPE_I386) {9690 while (begin < end) {9691 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9692 memcpy((char *)&flavor, begin, sizeof(uint32_t));9693 begin += sizeof(uint32_t);9694 } else {9695 flavor = 0;9696 begin = end;9697 }9698 if (isLittleEndian != sys::IsLittleEndianHost)9699 sys::swapByteOrder(flavor);9700 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9701 memcpy((char *)&count, begin, sizeof(uint32_t));9702 begin += sizeof(uint32_t);9703 } else {9704 count = 0;9705 begin = end;9706 }9707 if (isLittleEndian != sys::IsLittleEndianHost)9708 sys::swapByteOrder(count);9709 if (flavor == MachO::x86_THREAD_STATE32) {9710 outs() << " flavor i386_THREAD_STATE\n";9711 if (count == MachO::x86_THREAD_STATE32_COUNT)9712 outs() << " count i386_THREAD_STATE_COUNT\n";9713 else9714 outs() << " count " << count9715 << " (not x86_THREAD_STATE32_COUNT)\n";9716 MachO::x86_thread_state32_t cpu32;9717 left = end - begin;9718 if (left >= sizeof(MachO::x86_thread_state32_t)) {9719 memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));9720 begin += sizeof(MachO::x86_thread_state32_t);9721 } else {9722 memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));9723 memcpy(&cpu32, begin, left);9724 begin += left;9725 }9726 if (isLittleEndian != sys::IsLittleEndianHost)9727 swapStruct(cpu32);9728 Print_x86_thread_state32_t(cpu32);9729 } else if (flavor == MachO::x86_THREAD_STATE) {9730 outs() << " flavor x86_THREAD_STATE\n";9731 if (count == MachO::x86_THREAD_STATE_COUNT)9732 outs() << " count x86_THREAD_STATE_COUNT\n";9733 else9734 outs() << " count " << count9735 << " (not x86_THREAD_STATE_COUNT)\n";9736 struct MachO::x86_thread_state_t ts;9737 left = end - begin;9738 if (left >= sizeof(MachO::x86_thread_state_t)) {9739 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9740 begin += sizeof(MachO::x86_thread_state_t);9741 } else {9742 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9743 memcpy(&ts, begin, left);9744 begin += left;9745 }9746 if (isLittleEndian != sys::IsLittleEndianHost)9747 swapStruct(ts);9748 if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {9749 outs() << "\t tsh.flavor x86_THREAD_STATE32 ";9750 if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)9751 outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";9752 else9753 outs() << "tsh.count " << ts.tsh.count9754 << " (not x86_THREAD_STATE32_COUNT\n";9755 Print_x86_thread_state32_t(ts.uts.ts32);9756 } else {9757 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "9758 << ts.tsh.count << "\n";9759 }9760 } else {9761 outs() << " flavor " << flavor << " (unknown)\n";9762 outs() << " count " << count << "\n";9763 outs() << " state (unknown)\n";9764 begin += count * sizeof(uint32_t);9765 }9766 }9767 } else if (cputype == MachO::CPU_TYPE_X86_64) {9768 while (begin < end) {9769 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9770 memcpy((char *)&flavor, begin, sizeof(uint32_t));9771 begin += sizeof(uint32_t);9772 } else {9773 flavor = 0;9774 begin = end;9775 }9776 if (isLittleEndian != sys::IsLittleEndianHost)9777 sys::swapByteOrder(flavor);9778 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9779 memcpy((char *)&count, begin, sizeof(uint32_t));9780 begin += sizeof(uint32_t);9781 } else {9782 count = 0;9783 begin = end;9784 }9785 if (isLittleEndian != sys::IsLittleEndianHost)9786 sys::swapByteOrder(count);9787 if (flavor == MachO::x86_THREAD_STATE64) {9788 outs() << " flavor x86_THREAD_STATE64\n";9789 if (count == MachO::x86_THREAD_STATE64_COUNT)9790 outs() << " count x86_THREAD_STATE64_COUNT\n";9791 else9792 outs() << " count " << count9793 << " (not x86_THREAD_STATE64_COUNT)\n";9794 MachO::x86_thread_state64_t cpu64;9795 left = end - begin;9796 if (left >= sizeof(MachO::x86_thread_state64_t)) {9797 memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));9798 begin += sizeof(MachO::x86_thread_state64_t);9799 } else {9800 memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));9801 memcpy(&cpu64, begin, left);9802 begin += left;9803 }9804 if (isLittleEndian != sys::IsLittleEndianHost)9805 swapStruct(cpu64);9806 Print_x86_thread_state64_t(cpu64);9807 } else if (flavor == MachO::x86_THREAD_STATE) {9808 outs() << " flavor x86_THREAD_STATE\n";9809 if (count == MachO::x86_THREAD_STATE_COUNT)9810 outs() << " count x86_THREAD_STATE_COUNT\n";9811 else9812 outs() << " count " << count9813 << " (not x86_THREAD_STATE_COUNT)\n";9814 struct MachO::x86_thread_state_t ts;9815 left = end - begin;9816 if (left >= sizeof(MachO::x86_thread_state_t)) {9817 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));9818 begin += sizeof(MachO::x86_thread_state_t);9819 } else {9820 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));9821 memcpy(&ts, begin, left);9822 begin += left;9823 }9824 if (isLittleEndian != sys::IsLittleEndianHost)9825 swapStruct(ts);9826 if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {9827 outs() << "\t tsh.flavor x86_THREAD_STATE64 ";9828 if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)9829 outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";9830 else9831 outs() << "tsh.count " << ts.tsh.count9832 << " (not x86_THREAD_STATE64_COUNT\n";9833 Print_x86_thread_state64_t(ts.uts.ts64);9834 } else {9835 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "9836 << ts.tsh.count << "\n";9837 }9838 } else if (flavor == MachO::x86_FLOAT_STATE) {9839 outs() << " flavor x86_FLOAT_STATE\n";9840 if (count == MachO::x86_FLOAT_STATE_COUNT)9841 outs() << " count x86_FLOAT_STATE_COUNT\n";9842 else9843 outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";9844 struct MachO::x86_float_state_t fs;9845 left = end - begin;9846 if (left >= sizeof(MachO::x86_float_state_t)) {9847 memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));9848 begin += sizeof(MachO::x86_float_state_t);9849 } else {9850 memset(&fs, '\0', sizeof(MachO::x86_float_state_t));9851 memcpy(&fs, begin, left);9852 begin += left;9853 }9854 if (isLittleEndian != sys::IsLittleEndianHost)9855 swapStruct(fs);9856 if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {9857 outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";9858 if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)9859 outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";9860 else9861 outs() << "fsh.count " << fs.fsh.count9862 << " (not x86_FLOAT_STATE64_COUNT\n";9863 Print_x86_float_state_t(fs.ufs.fs64);9864 } else {9865 outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "9866 << fs.fsh.count << "\n";9867 }9868 } else if (flavor == MachO::x86_EXCEPTION_STATE) {9869 outs() << " flavor x86_EXCEPTION_STATE\n";9870 if (count == MachO::x86_EXCEPTION_STATE_COUNT)9871 outs() << " count x86_EXCEPTION_STATE_COUNT\n";9872 else9873 outs() << " count " << count9874 << " (not x86_EXCEPTION_STATE_COUNT)\n";9875 struct MachO::x86_exception_state_t es;9876 left = end - begin;9877 if (left >= sizeof(MachO::x86_exception_state_t)) {9878 memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));9879 begin += sizeof(MachO::x86_exception_state_t);9880 } else {9881 memset(&es, '\0', sizeof(MachO::x86_exception_state_t));9882 memcpy(&es, begin, left);9883 begin += left;9884 }9885 if (isLittleEndian != sys::IsLittleEndianHost)9886 swapStruct(es);9887 if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {9888 outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";9889 if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)9890 outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";9891 else9892 outs() << "\t esh.count " << es.esh.count9893 << " (not x86_EXCEPTION_STATE64_COUNT\n";9894 Print_x86_exception_state_t(es.ues.es64);9895 } else {9896 outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "9897 << es.esh.count << "\n";9898 }9899 } else if (flavor == MachO::x86_EXCEPTION_STATE64) {9900 outs() << " flavor x86_EXCEPTION_STATE64\n";9901 if (count == MachO::x86_EXCEPTION_STATE64_COUNT)9902 outs() << " count x86_EXCEPTION_STATE64_COUNT\n";9903 else9904 outs() << " count " << count9905 << " (not x86_EXCEPTION_STATE64_COUNT)\n";9906 struct MachO::x86_exception_state64_t es64;9907 left = end - begin;9908 if (left >= sizeof(MachO::x86_exception_state64_t)) {9909 memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));9910 begin += sizeof(MachO::x86_exception_state64_t);9911 } else {9912 memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));9913 memcpy(&es64, begin, left);9914 begin += left;9915 }9916 if (isLittleEndian != sys::IsLittleEndianHost)9917 swapStruct(es64);9918 Print_x86_exception_state_t(es64);9919 } else {9920 outs() << " flavor " << flavor << " (unknown)\n";9921 outs() << " count " << count << "\n";9922 outs() << " state (unknown)\n";9923 begin += count * sizeof(uint32_t);9924 }9925 }9926 } else if (cputype == MachO::CPU_TYPE_ARM) {9927 while (begin < end) {9928 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9929 memcpy((char *)&flavor, begin, sizeof(uint32_t));9930 begin += sizeof(uint32_t);9931 } else {9932 flavor = 0;9933 begin = end;9934 }9935 if (isLittleEndian != sys::IsLittleEndianHost)9936 sys::swapByteOrder(flavor);9937 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9938 memcpy((char *)&count, begin, sizeof(uint32_t));9939 begin += sizeof(uint32_t);9940 } else {9941 count = 0;9942 begin = end;9943 }9944 if (isLittleEndian != sys::IsLittleEndianHost)9945 sys::swapByteOrder(count);9946 if (flavor == MachO::ARM_THREAD_STATE) {9947 outs() << " flavor ARM_THREAD_STATE\n";9948 if (count == MachO::ARM_THREAD_STATE_COUNT)9949 outs() << " count ARM_THREAD_STATE_COUNT\n";9950 else9951 outs() << " count " << count9952 << " (not ARM_THREAD_STATE_COUNT)\n";9953 MachO::arm_thread_state32_t cpu32;9954 left = end - begin;9955 if (left >= sizeof(MachO::arm_thread_state32_t)) {9956 memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));9957 begin += sizeof(MachO::arm_thread_state32_t);9958 } else {9959 memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));9960 memcpy(&cpu32, begin, left);9961 begin += left;9962 }9963 if (isLittleEndian != sys::IsLittleEndianHost)9964 swapStruct(cpu32);9965 Print_arm_thread_state32_t(cpu32);9966 } else {9967 outs() << " flavor " << flavor << " (unknown)\n";9968 outs() << " count " << count << "\n";9969 outs() << " state (unknown)\n";9970 begin += count * sizeof(uint32_t);9971 }9972 }9973 } else if (cputype == MachO::CPU_TYPE_ARM64 ||9974 cputype == MachO::CPU_TYPE_ARM64_32) {9975 while (begin < end) {9976 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9977 memcpy((char *)&flavor, begin, sizeof(uint32_t));9978 begin += sizeof(uint32_t);9979 } else {9980 flavor = 0;9981 begin = end;9982 }9983 if (isLittleEndian != sys::IsLittleEndianHost)9984 sys::swapByteOrder(flavor);9985 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {9986 memcpy((char *)&count, begin, sizeof(uint32_t));9987 begin += sizeof(uint32_t);9988 } else {9989 count = 0;9990 begin = end;9991 }9992 if (isLittleEndian != sys::IsLittleEndianHost)9993 sys::swapByteOrder(count);9994 if (flavor == MachO::ARM_THREAD_STATE64) {9995 outs() << " flavor ARM_THREAD_STATE64\n";9996 if (count == MachO::ARM_THREAD_STATE64_COUNT)9997 outs() << " count ARM_THREAD_STATE64_COUNT\n";9998 else9999 outs() << " count " << count10000 << " (not ARM_THREAD_STATE64_COUNT)\n";10001 MachO::arm_thread_state64_t cpu64;10002 left = end - begin;10003 if (left >= sizeof(MachO::arm_thread_state64_t)) {10004 memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));10005 begin += sizeof(MachO::arm_thread_state64_t);10006 } else {10007 memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));10008 memcpy(&cpu64, begin, left);10009 begin += left;10010 }10011 if (isLittleEndian != sys::IsLittleEndianHost)10012 swapStruct(cpu64);10013 Print_arm_thread_state64_t(cpu64);10014 } else {10015 outs() << " flavor " << flavor << " (unknown)\n";10016 outs() << " count " << count << "\n";10017 outs() << " state (unknown)\n";10018 begin += count * sizeof(uint32_t);10019 }10020 }10021 } else {10022 while (begin < end) {10023 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {10024 memcpy((char *)&flavor, begin, sizeof(uint32_t));10025 begin += sizeof(uint32_t);10026 } else {10027 flavor = 0;10028 begin = end;10029 }10030 if (isLittleEndian != sys::IsLittleEndianHost)10031 sys::swapByteOrder(flavor);10032 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {10033 memcpy((char *)&count, begin, sizeof(uint32_t));10034 begin += sizeof(uint32_t);10035 } else {10036 count = 0;10037 begin = end;10038 }10039 if (isLittleEndian != sys::IsLittleEndianHost)10040 sys::swapByteOrder(count);10041 outs() << " flavor " << flavor << "\n";10042 outs() << " count " << count << "\n";10043 outs() << " state (Unknown cputype/cpusubtype)\n";10044 begin += count * sizeof(uint32_t);10045 }10046 }10047}10048 10049static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {10050 if (dl.cmd == MachO::LC_ID_DYLIB)10051 outs() << " cmd LC_ID_DYLIB\n";10052 else if (dl.cmd == MachO::LC_LOAD_DYLIB)10053 outs() << " cmd LC_LOAD_DYLIB\n";10054 else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)10055 outs() << " cmd LC_LOAD_WEAK_DYLIB\n";10056 else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)10057 outs() << " cmd LC_REEXPORT_DYLIB\n";10058 else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)10059 outs() << " cmd LC_LAZY_LOAD_DYLIB\n";10060 else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)10061 outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";10062 else10063 outs() << " cmd " << dl.cmd << " (unknown)\n";10064 outs() << " cmdsize " << dl.cmdsize;10065 if (dl.cmdsize < sizeof(struct MachO::dylib_command))10066 outs() << " Incorrect size\n";10067 else10068 outs() << "\n";10069 if (dl.dylib.name < dl.cmdsize) {10070 const char *P = Ptr + dl.dylib.name;10071 outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";10072 } else {10073 outs() << " name ?(bad offset " << dl.dylib.name << ")\n";10074 }10075 outs() << " time stamp " << dl.dylib.timestamp << " ";10076 time_t t = dl.dylib.timestamp;10077 outs() << ctime(&t);10078 outs() << " current version ";10079 if (dl.dylib.current_version == 0xffffffff)10080 outs() << "n/a\n";10081 else10082 outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."10083 << ((dl.dylib.current_version >> 8) & 0xff) << "."10084 << (dl.dylib.current_version & 0xff) << "\n";10085 outs() << "compatibility version ";10086 if (dl.dylib.compatibility_version == 0xffffffff)10087 outs() << "n/a\n";10088 else10089 outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."10090 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."10091 << (dl.dylib.compatibility_version & 0xff) << "\n";10092}10093 10094static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,10095 uint32_t object_size) {10096 if (ld.cmd == MachO::LC_CODE_SIGNATURE)10097 outs() << " cmd LC_CODE_SIGNATURE\n";10098 else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)10099 outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";10100 else if (ld.cmd == MachO::LC_FUNCTION_STARTS)10101 outs() << " cmd LC_FUNCTION_STARTS\n";10102 else if (ld.cmd == MachO::LC_DATA_IN_CODE)10103 outs() << " cmd LC_DATA_IN_CODE\n";10104 else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)10105 outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";10106 else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)10107 outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";10108 else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)10109 outs() << " cmd LC_DYLD_EXPORTS_TRIE\n";10110 else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)10111 outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n";10112 else if (ld.cmd == MachO::LC_ATOM_INFO)10113 outs() << " cmd LC_ATOM_INFO\n";10114 else10115 outs() << " cmd " << ld.cmd << " (?)\n";10116 outs() << " cmdsize " << ld.cmdsize;10117 if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))10118 outs() << " Incorrect size\n";10119 else10120 outs() << "\n";10121 outs() << " dataoff " << ld.dataoff;10122 if (ld.dataoff > object_size)10123 outs() << " (past end of file)\n";10124 else10125 outs() << "\n";10126 outs() << " datasize " << ld.datasize;10127 uint64_t big_size = ld.dataoff;10128 big_size += ld.datasize;10129 if (big_size > object_size)10130 outs() << " (past end of file)\n";10131 else10132 outs() << "\n";10133}10134 10135static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,10136 uint32_t cputype, bool verbose) {10137 StringRef Buf = Obj->getData();10138 unsigned Index = 0;10139 for (const auto &Command : Obj->load_commands()) {10140 outs() << "Load command " << Index++ << "\n";10141 if (Command.C.cmd == MachO::LC_SEGMENT) {10142 MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);10143 const char *sg_segname = SLC.segname;10144 PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,10145 SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,10146 SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),10147 verbose);10148 for (unsigned j = 0; j < SLC.nsects; j++) {10149 MachO::section S = Obj->getSection(Command, j);10150 PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,10151 S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,10152 SLC.cmd, sg_segname, filetype, Buf.size(), verbose);10153 }10154 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10155 MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);10156 const char *sg_segname = SLC_64.segname;10157 PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,10158 SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,10159 SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,10160 SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);10161 for (unsigned j = 0; j < SLC_64.nsects; j++) {10162 MachO::section_64 S_64 = Obj->getSection64(Command, j);10163 PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,10164 S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,10165 S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,10166 sg_segname, filetype, Buf.size(), verbose);10167 }10168 } else if (Command.C.cmd == MachO::LC_SYMTAB) {10169 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10170 PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());10171 } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {10172 MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();10173 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();10174 PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),10175 Obj->is64Bit());10176 } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||10177 Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {10178 MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);10179 PrintDyldInfoLoadCommand(DyldInfo, Buf.size());10180 } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||10181 Command.C.cmd == MachO::LC_ID_DYLINKER ||10182 Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {10183 MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);10184 PrintDyldLoadCommand(Dyld, Command.Ptr);10185 } else if (Command.C.cmd == MachO::LC_UUID) {10186 MachO::uuid_command Uuid = Obj->getUuidCommand(Command);10187 PrintUuidLoadCommand(Uuid);10188 } else if (Command.C.cmd == MachO::LC_RPATH) {10189 MachO::rpath_command Rpath = Obj->getRpathCommand(Command);10190 PrintRpathLoadCommand(Rpath, Command.Ptr);10191 } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||10192 Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||10193 Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||10194 Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {10195 MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);10196 PrintVersionMinLoadCommand(Vd);10197 } else if (Command.C.cmd == MachO::LC_NOTE) {10198 MachO::note_command Nt = Obj->getNoteLoadCommand(Command);10199 PrintNoteLoadCommand(Nt);10200 } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {10201 MachO::build_version_command Bv =10202 Obj->getBuildVersionLoadCommand(Command);10203 PrintBuildVersionLoadCommand(Obj, Bv, verbose);10204 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {10205 MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);10206 PrintSourceVersionCommand(Sd);10207 } else if (Command.C.cmd == MachO::LC_MAIN) {10208 MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);10209 PrintEntryPointCommand(Ep);10210 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {10211 MachO::encryption_info_command Ei =10212 Obj->getEncryptionInfoCommand(Command);10213 PrintEncryptionInfoCommand(Ei, Buf.size());10214 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {10215 MachO::encryption_info_command_64 Ei =10216 Obj->getEncryptionInfoCommand64(Command);10217 PrintEncryptionInfoCommand64(Ei, Buf.size());10218 } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {10219 MachO::linker_option_command Lo =10220 Obj->getLinkerOptionLoadCommand(Command);10221 PrintLinkerOptionCommand(Lo, Command.Ptr);10222 } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {10223 MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);10224 PrintSubFrameworkCommand(Sf, Command.Ptr);10225 } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {10226 MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);10227 PrintSubUmbrellaCommand(Sf, Command.Ptr);10228 } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {10229 MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);10230 PrintSubLibraryCommand(Sl, Command.Ptr);10231 } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {10232 MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);10233 PrintSubClientCommand(Sc, Command.Ptr);10234 } else if (Command.C.cmd == MachO::LC_ROUTINES) {10235 MachO::routines_command Rc = Obj->getRoutinesCommand(Command);10236 PrintRoutinesCommand(Rc);10237 } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {10238 MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);10239 PrintRoutinesCommand64(Rc);10240 } else if (Command.C.cmd == MachO::LC_THREAD ||10241 Command.C.cmd == MachO::LC_UNIXTHREAD) {10242 MachO::thread_command Tc = Obj->getThreadCommand(Command);10243 PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);10244 } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||10245 Command.C.cmd == MachO::LC_ID_DYLIB ||10246 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||10247 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||10248 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||10249 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {10250 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);10251 PrintDylibCommand(Dl, Command.Ptr);10252 } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||10253 Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||10254 Command.C.cmd == MachO::LC_FUNCTION_STARTS ||10255 Command.C.cmd == MachO::LC_DATA_IN_CODE ||10256 Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||10257 Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||10258 Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||10259 Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||10260 Command.C.cmd == MachO::LC_ATOM_INFO) {10261 MachO::linkedit_data_command Ld =10262 Obj->getLinkeditDataLoadCommand(Command);10263 PrintLinkEditDataCommand(Ld, Buf.size());10264 } else {10265 outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)10266 << ")\n";10267 outs() << " cmdsize " << Command.C.cmdsize << "\n";10268 // TODO: get and print the raw bytes of the load command.10269 }10270 // TODO: print all the other kinds of load commands.10271 }10272}10273 10274static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {10275 if (Obj->is64Bit()) {10276 MachO::mach_header_64 H_64;10277 H_64 = Obj->getHeader64();10278 PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,10279 H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);10280 } else {10281 MachO::mach_header H;10282 H = Obj->getHeader();10283 PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,10284 H.sizeofcmds, H.flags, verbose);10285 }10286}10287 10288void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {10289 const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10290 PrintMachHeader(file, Verbose);10291}10292 10293void MachODumper::printPrivateHeaders() {10294 printMachOFileHeader(&Obj);10295 if (!FirstPrivateHeader)10296 printMachOLoadCommands(&Obj);10297}10298 10299void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {10300 const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);10301 uint32_t filetype = 0;10302 uint32_t cputype = 0;10303 if (file->is64Bit()) {10304 MachO::mach_header_64 H_64;10305 H_64 = file->getHeader64();10306 filetype = H_64.filetype;10307 cputype = H_64.cputype;10308 } else {10309 MachO::mach_header H;10310 H = file->getHeader();10311 filetype = H.filetype;10312 cputype = H.cputype;10313 }10314 PrintLoadCommands(file, filetype, cputype, Verbose);10315}10316 10317//===----------------------------------------------------------------------===//10318// export trie dumping10319//===----------------------------------------------------------------------===//10320 10321static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {10322 uint64_t BaseSegmentAddress = 0;10323 for (const auto &Command : Obj->load_commands()) {10324 if (Command.C.cmd == MachO::LC_SEGMENT) {10325 MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);10326 if (Seg.fileoff == 0 && Seg.filesize != 0) {10327 BaseSegmentAddress = Seg.vmaddr;10328 break;10329 }10330 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {10331 MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);10332 if (Seg.fileoff == 0 && Seg.filesize != 0) {10333 BaseSegmentAddress = Seg.vmaddr;10334 break;10335 }10336 }10337 }10338 Error Err = Error::success();10339 for (const object::ExportEntry &Entry : Obj->exports(Err)) {10340 uint64_t Flags = Entry.flags();10341 bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);10342 bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);10343 bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10344 MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);10345 bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==10346 MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);10347 bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);10348 if (ReExport)10349 outs() << "[re-export] ";10350 else10351 outs() << format("0x%08llX ",10352 Entry.address() + BaseSegmentAddress);10353 outs() << Entry.name();10354 if (WeakDef || ThreadLocal || Resolver || Abs) {10355 ListSeparator LS;10356 outs() << " [";10357 if (WeakDef)10358 outs() << LS << "weak_def";10359 if (ThreadLocal)10360 outs() << LS << "per-thread";10361 if (Abs)10362 outs() << LS << "absolute";10363 if (Resolver)10364 outs() << LS << format("resolver=0x%08llX", Entry.other());10365 outs() << "]";10366 }10367 if (ReExport) {10368 StringRef DylibName = "unknown";10369 int Ordinal = Entry.other() - 1;10370 Obj->getLibraryShortNameByIndex(Ordinal, DylibName);10371 if (Entry.otherName().empty())10372 outs() << " (from " << DylibName << ")";10373 else10374 outs() << " (" << Entry.otherName() << " from " << DylibName << ")";10375 }10376 outs() << "\n";10377 }10378 if (Err)10379 reportError(std::move(Err), Obj->getFileName());10380}10381 10382//===----------------------------------------------------------------------===//10383// rebase table dumping10384//===----------------------------------------------------------------------===//10385 10386static void printMachORebaseTable(object::MachOObjectFile *Obj) {10387 outs() << "segment section address type\n";10388 Error Err = Error::success();10389 for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {10390 StringRef SegmentName = Entry.segmentName();10391 StringRef SectionName = Entry.sectionName();10392 uint64_t Address = Entry.address();10393 10394 // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer10395 outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",10396 SegmentName.str().c_str(), SectionName.str().c_str(),10397 Address, Entry.typeName().str().c_str());10398 }10399 if (Err)10400 reportError(std::move(Err), Obj->getFileName());10401}10402 10403static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {10404 StringRef DylibName;10405 switch (Ordinal) {10406 case MachO::BIND_SPECIAL_DYLIB_SELF:10407 return "this-image";10408 case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:10409 return "main-executable";10410 case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:10411 return "flat-namespace";10412 case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:10413 return "weak";10414 default:10415 if (Ordinal > 0) {10416 std::error_code EC =10417 Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);10418 if (EC)10419 return "<<bad library ordinal>>";10420 return DylibName;10421 }10422 }10423 return "<<unknown special ordinal>>";10424}10425 10426//===----------------------------------------------------------------------===//10427// bind table dumping10428//===----------------------------------------------------------------------===//10429 10430static void printMachOBindTable(object::MachOObjectFile *Obj) {10431 // Build table of sections so names can used in final output.10432 outs() << "segment section address type "10433 "addend dylib symbol\n";10434 Error Err = Error::success();10435 for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {10436 StringRef SegmentName = Entry.segmentName();10437 StringRef SectionName = Entry.sectionName();10438 uint64_t Address = Entry.address();10439 10440 // Table lines look like:10441 // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard10442 StringRef Attr;10443 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)10444 Attr = " (weak_import)";10445 outs() << left_justify(SegmentName, 8) << " "10446 << left_justify(SectionName, 18) << " "10447 << format_hex(Address, 10, true) << " "10448 << left_justify(Entry.typeName(), 8) << " "10449 << format_decimal(Entry.addend(), 8) << " "10450 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10451 << Entry.symbolName() << Attr << "\n";10452 }10453 if (Err)10454 reportError(std::move(Err), Obj->getFileName());10455}10456 10457//===----------------------------------------------------------------------===//10458// lazy bind table dumping10459//===----------------------------------------------------------------------===//10460 10461static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {10462 outs() << "segment section address "10463 "dylib symbol\n";10464 Error Err = Error::success();10465 for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {10466 StringRef SegmentName = Entry.segmentName();10467 StringRef SectionName = Entry.sectionName();10468 uint64_t Address = Entry.address();10469 10470 // Table lines look like:10471 // __DATA __got 0x00012010 libSystem ___stack_chk_guard10472 outs() << left_justify(SegmentName, 8) << " "10473 << left_justify(SectionName, 18) << " "10474 << format_hex(Address, 10, true) << " "10475 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "10476 << Entry.symbolName() << "\n";10477 }10478 if (Err)10479 reportError(std::move(Err), Obj->getFileName());10480}10481 10482//===----------------------------------------------------------------------===//10483// weak bind table dumping10484//===----------------------------------------------------------------------===//10485 10486static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {10487 outs() << "segment section address "10488 "type addend symbol\n";10489 Error Err = Error::success();10490 for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {10491 // Strong symbols don't have a location to update.10492 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {10493 outs() << " strong "10494 << Entry.symbolName() << "\n";10495 continue;10496 }10497 StringRef SegmentName = Entry.segmentName();10498 StringRef SectionName = Entry.sectionName();10499 uint64_t Address = Entry.address();10500 10501 // Table lines look like:10502 // __DATA __data 0x00001000 pointer 0 _foo10503 outs() << left_justify(SegmentName, 8) << " "10504 << left_justify(SectionName, 18) << " "10505 << format_hex(Address, 10, true) << " "10506 << left_justify(Entry.typeName(), 8) << " "10507 << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()10508 << "\n";10509 }10510 if (Err)10511 reportError(std::move(Err), Obj->getFileName());10512}10513 10514// get_dyld_bind_info_symbolname() is used for disassembly and passed an10515// address, ReferenceValue, in the Mach-O file and looks in the dyld bind10516// information for that address. If the address is found its binding symbol10517// name is returned. If not nullptr is returned.10518static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,10519 struct DisassembleInfo *info) {10520 if (info->bindtable == nullptr) {10521 info->bindtable = std::make_unique<SymbolAddressMap>();10522 Error Err = Error::success();10523 for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {10524 uint64_t Address = Entry.address();10525 StringRef name = Entry.symbolName();10526 if (!name.empty())10527 (*info->bindtable)[Address] = name;10528 }10529 if (Err)10530 reportError(std::move(Err), info->O->getFileName());10531 }10532 auto name = info->bindtable->lookup(ReferenceValue);10533 return !name.empty() ? name.data() : nullptr;10534}10535 10536void objdump::printLazyBindTable(ObjectFile *o) {10537 outs() << "\nLazy bind table:\n";10538 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10539 printMachOLazyBindTable(MachO);10540 else10541 WithColor::error()10542 << "This operation is only currently supported "10543 "for Mach-O executable files.\n";10544}10545 10546void objdump::printWeakBindTable(ObjectFile *o) {10547 outs() << "\nWeak bind table:\n";10548 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10549 printMachOWeakBindTable(MachO);10550 else10551 WithColor::error()10552 << "This operation is only currently supported "10553 "for Mach-O executable files.\n";10554}10555 10556void objdump::printExportsTrie(const ObjectFile *o) {10557 outs() << "\nExports trie:\n";10558 if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10559 printMachOExportsTrie(MachO);10560 else10561 WithColor::error()10562 << "This operation is only currently supported "10563 "for Mach-O executable files.\n";10564}10565 10566void objdump::printRebaseTable(ObjectFile *o) {10567 outs() << "\nRebase table:\n";10568 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10569 printMachORebaseTable(MachO);10570 else10571 WithColor::error()10572 << "This operation is only currently supported "10573 "for Mach-O executable files.\n";10574}10575 10576void objdump::printBindTable(ObjectFile *o) {10577 outs() << "\nBind table:\n";10578 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))10579 printMachOBindTable(MachO);10580 else10581 WithColor::error()10582 << "This operation is only currently supported "10583 "for Mach-O executable files.\n";10584}10585