[libc] Switch to using the generic `<gpuintrin.h>` implementations (#121810)
[llvm-project.git] / llvm / tools / llvm-objdump / MachODump.cpp
blobab6f65cd41a365791fa1ef5edd402a99c9b1e580
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the MachO-specific dumper for llvm-objdump.
11 //===----------------------------------------------------------------------===//
13 #include "MachODump.h"
15 #include "ObjdumpOptID.h"
16 #include "llvm-objdump.h"
17 #include "llvm-c/Disassembler.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/GraphWriter.h"
45 #include "llvm/Support/LEB128.h"
46 #include "llvm/Support/MemoryBuffer.h"
47 #include "llvm/Support/TargetSelect.h"
48 #include "llvm/Support/ToolOutputFile.h"
49 #include "llvm/Support/WithColor.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include "llvm/TargetParser/Triple.h"
52 #include <algorithm>
53 #include <cstring>
54 #include <system_error>
56 using namespace llvm;
57 using namespace llvm::object;
58 using namespace llvm::objdump;
60 bool objdump::FirstPrivateHeader;
61 bool objdump::ExportsTrie;
62 bool objdump::Rebase;
63 bool objdump::Rpaths;
64 bool objdump::Bind;
65 bool objdump::LazyBind;
66 bool objdump::WeakBind;
67 static bool UseDbg;
68 static std::string DSYMFile;
69 bool objdump::FullLeadingAddr;
70 bool objdump::LeadingHeaders;
71 bool objdump::UniversalHeaders;
72 static bool ArchiveMemberOffsets;
73 bool objdump::IndirectSymbols;
74 bool objdump::DataInCode;
75 FunctionStartsMode objdump::FunctionStartsType =
76 objdump::FunctionStartsMode::None;
77 bool objdump::LinkOptHints;
78 bool objdump::InfoPlist;
79 bool objdump::ChainedFixups;
80 bool objdump::DyldInfo;
81 bool objdump::DylibsUsed;
82 bool objdump::DylibId;
83 bool objdump::Verbose;
84 bool objdump::ObjcMetaData;
85 std::string objdump::DisSymName;
86 bool objdump::SymbolicOperands;
87 static std::vector<std::string> ArchFlags;
89 static bool ArchAll = false;
90 static std::string ThumbTripleName;
92 static StringRef ordinalName(const object::MachOObjectFile *, int);
94 void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
95 FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);
96 ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);
97 Rebase = InputArgs.hasArg(OBJDUMP_rebase);
98 Rpaths = InputArgs.hasArg(OBJDUMP_rpaths);
99 Bind = InputArgs.hasArg(OBJDUMP_bind);
100 LazyBind = InputArgs.hasArg(OBJDUMP_lazy_bind);
101 WeakBind = InputArgs.hasArg(OBJDUMP_weak_bind);
102 UseDbg = InputArgs.hasArg(OBJDUMP_g);
103 DSYMFile = InputArgs.getLastArgValue(OBJDUMP_dsym_EQ).str();
104 FullLeadingAddr = InputArgs.hasArg(OBJDUMP_full_leading_addr);
105 LeadingHeaders = !InputArgs.hasArg(OBJDUMP_no_leading_headers);
106 UniversalHeaders = InputArgs.hasArg(OBJDUMP_universal_headers);
107 ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);
108 IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);
109 DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);
110 if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {
111 FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
112 .Case("addrs", FunctionStartsMode::Addrs)
113 .Case("names", FunctionStartsMode::Names)
114 .Case("both", FunctionStartsMode::Both)
115 .Default(FunctionStartsMode::None);
116 if (FunctionStartsType == FunctionStartsMode::None)
117 invalidArgValue(A);
119 LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
120 InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
121 ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
122 DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);
123 DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);
124 DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);
125 Verbose = !InputArgs.hasArg(OBJDUMP_non_verbose);
126 ObjcMetaData = InputArgs.hasArg(OBJDUMP_objc_meta_data);
127 DisSymName = InputArgs.getLastArgValue(OBJDUMP_dis_symname).str();
128 SymbolicOperands = !InputArgs.hasArg(OBJDUMP_no_symbolic_operands);
129 ArchFlags = InputArgs.getAllArgValues(OBJDUMP_arch_EQ);
132 static const Target *GetTarget(const MachOObjectFile *MachOObj,
133 const char **McpuDefault,
134 const Target **ThumbTarget) {
135 // Figure out the target triple.
136 Triple TT(TripleName);
137 if (TripleName.empty()) {
138 TT = MachOObj->getArchTriple(McpuDefault);
139 TripleName = TT.str();
142 if (TT.getArch() == Triple::arm) {
143 // We've inferred a 32-bit ARM target from the object file. All MachO CPUs
144 // that support ARM are also capable of Thumb mode.
145 Triple ThumbTriple = TT;
146 std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();
147 ThumbTriple.setArchName(ThumbName);
148 ThumbTripleName = ThumbTriple.str();
151 // Get the target specific parser.
152 std::string Error;
153 const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
154 if (TheTarget && ThumbTripleName.empty())
155 return TheTarget;
157 *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
158 if (*ThumbTarget)
159 return TheTarget;
161 WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";
162 if (!TheTarget)
163 errs() << TripleName;
164 else
165 errs() << ThumbTripleName;
166 errs() << "', see --version and --triple.\n";
167 return nullptr;
170 namespace {
171 struct SymbolSorter {
172 bool operator()(const SymbolRef &A, const SymbolRef &B) {
173 Expected<SymbolRef::Type> ATypeOrErr = A.getType();
174 if (!ATypeOrErr)
175 reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());
176 SymbolRef::Type AType = *ATypeOrErr;
177 Expected<SymbolRef::Type> BTypeOrErr = B.getType();
178 if (!BTypeOrErr)
179 reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());
180 SymbolRef::Type BType = *BTypeOrErr;
181 uint64_t AAddr =
182 (AType != SymbolRef::ST_Function) ? 0 : cantFail(A.getValue());
183 uint64_t BAddr =
184 (BType != SymbolRef::ST_Function) ? 0 : cantFail(B.getValue());
185 return AAddr < BAddr;
189 class MachODumper : public Dumper {
190 const object::MachOObjectFile &Obj;
192 public:
193 MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}
194 void printPrivateHeaders() override;
196 } // namespace
198 std::unique_ptr<Dumper>
199 objdump::createMachODumper(const object::MachOObjectFile &Obj) {
200 return std::make_unique<MachODumper>(Obj);
203 // Types for the storted data in code table that is built before disassembly
204 // and the predicate function to sort them.
205 typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
206 typedef std::vector<DiceTableEntry> DiceTable;
207 typedef DiceTable::iterator dice_table_iterator;
209 // This is used to search for a data in code table entry for the PC being
210 // disassembled. The j parameter has the PC in j.first. A single data in code
211 // table entry can cover many bytes for each of its Kind's. So if the offset,
212 // aka the i.first value, of the data in code table entry plus its Length
213 // covers the PC being searched for this will return true. If not it will
214 // return false.
215 static bool compareDiceTableEntries(const DiceTableEntry &i,
216 const DiceTableEntry &j) {
217 uint16_t Length;
218 i.second.getLength(Length);
220 return j.first >= i.first && j.first < i.first + Length;
223 static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
224 unsigned short Kind) {
225 uint32_t Value, Size = 1;
227 switch (Kind) {
228 default:
229 case MachO::DICE_KIND_DATA:
230 if (Length >= 4) {
231 if (ShowRawInsn)
232 dumpBytes(ArrayRef(bytes, 4), outs());
233 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
234 outs() << "\t.long " << Value;
235 Size = 4;
236 } else if (Length >= 2) {
237 if (ShowRawInsn)
238 dumpBytes(ArrayRef(bytes, 2), outs());
239 Value = bytes[1] << 8 | bytes[0];
240 outs() << "\t.short " << Value;
241 Size = 2;
242 } else {
243 if (ShowRawInsn)
244 dumpBytes(ArrayRef(bytes, 2), outs());
245 Value = bytes[0];
246 outs() << "\t.byte " << Value;
247 Size = 1;
249 if (Kind == MachO::DICE_KIND_DATA)
250 outs() << "\t@ KIND_DATA\n";
251 else
252 outs() << "\t@ data in code kind = " << Kind << "\n";
253 break;
254 case MachO::DICE_KIND_JUMP_TABLE8:
255 if (ShowRawInsn)
256 dumpBytes(ArrayRef(bytes, 1), outs());
257 Value = bytes[0];
258 outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
259 Size = 1;
260 break;
261 case MachO::DICE_KIND_JUMP_TABLE16:
262 if (ShowRawInsn)
263 dumpBytes(ArrayRef(bytes, 2), outs());
264 Value = bytes[1] << 8 | bytes[0];
265 outs() << "\t.short " << format("%5u", Value & 0xffff)
266 << "\t@ KIND_JUMP_TABLE16\n";
267 Size = 2;
268 break;
269 case MachO::DICE_KIND_JUMP_TABLE32:
270 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
271 if (ShowRawInsn)
272 dumpBytes(ArrayRef(bytes, 4), outs());
273 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
274 outs() << "\t.long " << Value;
275 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
276 outs() << "\t@ KIND_JUMP_TABLE32\n";
277 else
278 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
279 Size = 4;
280 break;
282 return Size;
285 static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
286 std::vector<SectionRef> &Sections,
287 std::vector<SymbolRef> &Symbols,
288 SmallVectorImpl<uint64_t> &FoundFns,
289 uint64_t &BaseSegmentAddress) {
290 const StringRef FileName = MachOObj->getFileName();
291 for (const SymbolRef &Symbol : MachOObj->symbols()) {
292 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
293 if (!SymName.starts_with("ltmp"))
294 Symbols.push_back(Symbol);
297 append_range(Sections, MachOObj->sections());
299 bool BaseSegmentAddressSet = false;
300 for (const auto &Command : MachOObj->load_commands()) {
301 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
302 // We found a function starts segment, parse the addresses for later
303 // consumption.
304 MachO::linkedit_data_command LLC =
305 MachOObj->getLinkeditDataLoadCommand(Command);
307 MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
308 } else if (Command.C.cmd == MachO::LC_SEGMENT) {
309 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
310 StringRef SegName = SLC.segname;
311 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
312 BaseSegmentAddressSet = true;
313 BaseSegmentAddress = SLC.vmaddr;
315 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
316 MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command);
317 StringRef SegName = SLC.segname;
318 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
319 BaseSegmentAddressSet = true;
320 BaseSegmentAddress = SLC.vmaddr;
326 static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,
327 DiceTable &Dices, uint64_t &InstSize) {
328 // Check the data in code table here to see if this is data not an
329 // instruction to be disassembled.
330 DiceTable Dice;
331 Dice.push_back(std::make_pair(PC, DiceRef()));
332 dice_table_iterator DTI =
333 std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),
334 compareDiceTableEntries);
335 if (DTI != Dices.end()) {
336 uint16_t Length;
337 DTI->second.getLength(Length);
338 uint16_t Kind;
339 DTI->second.getKind(Kind);
340 InstSize = DumpDataInCode(bytes, Length, Kind);
341 if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
342 (PC == (DTI->first + Length - 1)) && (Length & 1))
343 InstSize++;
344 return true;
346 return false;
349 static void printRelocationTargetName(const MachOObjectFile *O,
350 const MachO::any_relocation_info &RE,
351 raw_string_ostream &Fmt) {
352 // Target of a scattered relocation is an address. In the interest of
353 // generating pretty output, scan through the symbol table looking for a
354 // symbol that aligns with that address. If we find one, print it.
355 // Otherwise, we just print the hex address of the target.
356 const StringRef FileName = O->getFileName();
357 if (O->isRelocationScattered(RE)) {
358 uint32_t Val = O->getPlainRelocationSymbolNum(RE);
360 for (const SymbolRef &Symbol : O->symbols()) {
361 uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
362 if (Addr != Val)
363 continue;
364 Fmt << unwrapOrError(Symbol.getName(), FileName);
365 return;
368 // If we couldn't find a symbol that this relocation refers to, try
369 // to find a section beginning instead.
370 for (const SectionRef &Section : ToolSectionFilter(*O)) {
371 uint64_t Addr = Section.getAddress();
372 if (Addr != Val)
373 continue;
374 StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName());
375 Fmt << NameOrErr;
376 return;
379 Fmt << format("0x%x", Val);
380 return;
383 StringRef S;
384 bool isExtern = O->getPlainRelocationExternal(RE);
385 uint64_t Val = O->getPlainRelocationSymbolNum(RE);
387 if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&
388 (O->getArch() == Triple::aarch64 || O->getArch() == Triple::aarch64_be)) {
389 Fmt << format("0x%0" PRIx64, Val);
390 return;
393 if (isExtern) {
394 symbol_iterator SI = O->symbol_begin();
395 std::advance(SI, Val);
396 S = unwrapOrError(SI->getName(), FileName);
397 } else {
398 section_iterator SI = O->section_begin();
399 // Adjust for the fact that sections are 1-indexed.
400 if (Val == 0) {
401 Fmt << "0 (?,?)";
402 return;
404 uint32_t I = Val - 1;
405 while (I != 0 && SI != O->section_end()) {
406 --I;
407 std::advance(SI, 1);
409 if (SI == O->section_end()) {
410 Fmt << Val << " (?,?)";
411 } else {
412 if (Expected<StringRef> NameOrErr = SI->getName())
413 S = *NameOrErr;
414 else
415 consumeError(NameOrErr.takeError());
419 Fmt << S;
422 Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,
423 const RelocationRef &RelRef,
424 SmallVectorImpl<char> &Result) {
425 DataRefImpl Rel = RelRef.getRawDataRefImpl();
426 MachO::any_relocation_info RE = Obj->getRelocation(Rel);
428 unsigned Arch = Obj->getArch();
430 std::string FmtBuf;
431 raw_string_ostream Fmt(FmtBuf);
432 unsigned Type = Obj->getAnyRelocationType(RE);
433 bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
435 // Determine any addends that should be displayed with the relocation.
436 // These require decoding the relocation type, which is triple-specific.
438 // X86_64 has entirely custom relocation types.
439 if (Arch == Triple::x86_64) {
440 switch (Type) {
441 case MachO::X86_64_RELOC_GOT_LOAD:
442 case MachO::X86_64_RELOC_GOT: {
443 printRelocationTargetName(Obj, RE, Fmt);
444 Fmt << "@GOT";
445 if (IsPCRel)
446 Fmt << "PCREL";
447 break;
449 case MachO::X86_64_RELOC_SUBTRACTOR: {
450 DataRefImpl RelNext = Rel;
451 Obj->moveRelocationNext(RelNext);
452 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
454 // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
455 // X86_64_RELOC_UNSIGNED.
456 // NOTE: Scattered relocations don't exist on x86_64.
457 unsigned RType = Obj->getAnyRelocationType(RENext);
458 if (RType != MachO::X86_64_RELOC_UNSIGNED)
459 reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
460 "X86_64_RELOC_SUBTRACTOR.");
462 // The X86_64_RELOC_UNSIGNED contains the minuend symbol;
463 // X86_64_RELOC_SUBTRACTOR contains the subtrahend.
464 printRelocationTargetName(Obj, RENext, Fmt);
465 Fmt << "-";
466 printRelocationTargetName(Obj, RE, Fmt);
467 break;
469 case MachO::X86_64_RELOC_TLV:
470 printRelocationTargetName(Obj, RE, Fmt);
471 Fmt << "@TLV";
472 if (IsPCRel)
473 Fmt << "P";
474 break;
475 case MachO::X86_64_RELOC_SIGNED_1:
476 printRelocationTargetName(Obj, RE, Fmt);
477 Fmt << "-1";
478 break;
479 case MachO::X86_64_RELOC_SIGNED_2:
480 printRelocationTargetName(Obj, RE, Fmt);
481 Fmt << "-2";
482 break;
483 case MachO::X86_64_RELOC_SIGNED_4:
484 printRelocationTargetName(Obj, RE, Fmt);
485 Fmt << "-4";
486 break;
487 default:
488 printRelocationTargetName(Obj, RE, Fmt);
489 break;
491 // X86 and ARM share some relocation types in common.
492 } else if (Arch == Triple::x86 || Arch == Triple::arm ||
493 Arch == Triple::ppc) {
494 // Generic relocation types...
495 switch (Type) {
496 case MachO::GENERIC_RELOC_PAIR: // prints no info
497 return Error::success();
498 case MachO::GENERIC_RELOC_SECTDIFF: {
499 DataRefImpl RelNext = Rel;
500 Obj->moveRelocationNext(RelNext);
501 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
503 // X86 sect diff's must be followed by a relocation of type
504 // GENERIC_RELOC_PAIR.
505 unsigned RType = Obj->getAnyRelocationType(RENext);
507 if (RType != MachO::GENERIC_RELOC_PAIR)
508 reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
509 "GENERIC_RELOC_SECTDIFF.");
511 printRelocationTargetName(Obj, RE, Fmt);
512 Fmt << "-";
513 printRelocationTargetName(Obj, RENext, Fmt);
514 break;
518 if (Arch == Triple::x86 || Arch == Triple::ppc) {
519 switch (Type) {
520 case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
521 DataRefImpl RelNext = Rel;
522 Obj->moveRelocationNext(RelNext);
523 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
525 // X86 sect diff's must be followed by a relocation of type
526 // GENERIC_RELOC_PAIR.
527 unsigned RType = Obj->getAnyRelocationType(RENext);
528 if (RType != MachO::GENERIC_RELOC_PAIR)
529 reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
530 "GENERIC_RELOC_LOCAL_SECTDIFF.");
532 printRelocationTargetName(Obj, RE, Fmt);
533 Fmt << "-";
534 printRelocationTargetName(Obj, RENext, Fmt);
535 break;
537 case MachO::GENERIC_RELOC_TLV: {
538 printRelocationTargetName(Obj, RE, Fmt);
539 Fmt << "@TLV";
540 if (IsPCRel)
541 Fmt << "P";
542 break;
544 default:
545 printRelocationTargetName(Obj, RE, Fmt);
547 } else { // ARM-specific relocations
548 switch (Type) {
549 case MachO::ARM_RELOC_HALF:
550 case MachO::ARM_RELOC_HALF_SECTDIFF: {
551 // Half relocations steal a bit from the length field to encode
552 // whether this is an upper16 or a lower16 relocation.
553 bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
555 if (isUpper)
556 Fmt << ":upper16:(";
557 else
558 Fmt << ":lower16:(";
559 printRelocationTargetName(Obj, RE, Fmt);
561 DataRefImpl RelNext = Rel;
562 Obj->moveRelocationNext(RelNext);
563 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
565 // ARM half relocs must be followed by a relocation of type
566 // ARM_RELOC_PAIR.
567 unsigned RType = Obj->getAnyRelocationType(RENext);
568 if (RType != MachO::ARM_RELOC_PAIR)
569 reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
570 "ARM_RELOC_HALF");
572 // NOTE: The half of the target virtual address is stashed in the
573 // address field of the secondary relocation, but we can't reverse
574 // engineer the constant offset from it without decoding the movw/movt
575 // instruction to find the other half in its immediate field.
577 // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
578 // symbol/section pointer of the follow-on relocation.
579 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
580 Fmt << "-";
581 printRelocationTargetName(Obj, RENext, Fmt);
584 Fmt << ")";
585 break;
587 default: {
588 printRelocationTargetName(Obj, RE, Fmt);
592 } else
593 printRelocationTargetName(Obj, RE, Fmt);
595 Fmt.flush();
596 Result.append(FmtBuf.begin(), FmtBuf.end());
597 return Error::success();
600 static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
601 uint32_t n, uint32_t count,
602 uint32_t stride, uint64_t addr) {
603 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
604 uint32_t nindirectsyms = Dysymtab.nindirectsyms;
605 if (n > nindirectsyms)
606 outs() << " (entries start past the end of the indirect symbol "
607 "table) (reserved1 field greater than the table size)";
608 else if (n + count > nindirectsyms)
609 outs() << " (entries extends past the end of the indirect symbol "
610 "table)";
611 outs() << "\n";
612 uint32_t cputype = O->getHeader().cputype;
613 if (cputype & MachO::CPU_ARCH_ABI64)
614 outs() << "address index";
615 else
616 outs() << "address index";
617 if (verbose)
618 outs() << " name\n";
619 else
620 outs() << "\n";
621 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
622 if (cputype & MachO::CPU_ARCH_ABI64)
623 outs() << format("0x%016" PRIx64, addr + j * stride) << " ";
624 else
625 outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";
626 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
627 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
628 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
629 outs() << "LOCAL\n";
630 continue;
632 if (indirect_symbol ==
633 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
634 outs() << "LOCAL ABSOLUTE\n";
635 continue;
637 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
638 outs() << "ABSOLUTE\n";
639 continue;
641 outs() << format("%5u ", indirect_symbol);
642 if (verbose) {
643 MachO::symtab_command Symtab = O->getSymtabLoadCommand();
644 if (indirect_symbol < Symtab.nsyms) {
645 symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
646 SymbolRef Symbol = *Sym;
647 outs() << unwrapOrError(Symbol.getName(), O->getFileName());
648 } else {
649 outs() << "?";
652 outs() << "\n";
656 static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
657 for (const auto &Load : O->load_commands()) {
658 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
659 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
660 for (unsigned J = 0; J < Seg.nsects; ++J) {
661 MachO::section_64 Sec = O->getSection64(Load, J);
662 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
663 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
664 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
665 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
666 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
667 section_type == MachO::S_SYMBOL_STUBS) {
668 uint32_t stride;
669 if (section_type == MachO::S_SYMBOL_STUBS)
670 stride = Sec.reserved2;
671 else
672 stride = 8;
673 if (stride == 0) {
674 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
675 << Sec.sectname << ") "
676 << "(size of stubs in reserved2 field is zero)\n";
677 continue;
679 uint32_t count = Sec.size / stride;
680 outs() << "Indirect symbols for (" << Sec.segname << ","
681 << Sec.sectname << ") " << count << " entries";
682 uint32_t n = Sec.reserved1;
683 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
686 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
687 MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
688 for (unsigned J = 0; J < Seg.nsects; ++J) {
689 MachO::section Sec = O->getSection(Load, J);
690 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
691 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
692 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
693 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
694 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
695 section_type == MachO::S_SYMBOL_STUBS) {
696 uint32_t stride;
697 if (section_type == MachO::S_SYMBOL_STUBS)
698 stride = Sec.reserved2;
699 else
700 stride = 4;
701 if (stride == 0) {
702 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
703 << Sec.sectname << ") "
704 << "(size of stubs in reserved2 field is zero)\n";
705 continue;
707 uint32_t count = Sec.size / stride;
708 outs() << "Indirect symbols for (" << Sec.segname << ","
709 << Sec.sectname << ") " << count << " entries";
710 uint32_t n = Sec.reserved1;
711 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
718 static void PrintRType(const uint64_t cputype, const unsigned r_type) {
719 static char const *generic_r_types[] = {
720 "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
721 " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
722 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
724 static char const *x86_64_r_types[] = {
725 "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
726 "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
727 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
729 static char const *arm_r_types[] = {
730 "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
731 "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
732 " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
734 static char const *arm64_r_types[] = {
735 "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
736 "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
737 "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
740 if (r_type > 0xf){
741 outs() << format("%-7u", r_type) << " ";
742 return;
744 switch (cputype) {
745 case MachO::CPU_TYPE_I386:
746 outs() << generic_r_types[r_type];
747 break;
748 case MachO::CPU_TYPE_X86_64:
749 outs() << x86_64_r_types[r_type];
750 break;
751 case MachO::CPU_TYPE_ARM:
752 outs() << arm_r_types[r_type];
753 break;
754 case MachO::CPU_TYPE_ARM64:
755 case MachO::CPU_TYPE_ARM64_32:
756 outs() << arm64_r_types[r_type];
757 break;
758 default:
759 outs() << format("%-7u ", r_type);
763 static void PrintRLength(const uint64_t cputype, const unsigned r_type,
764 const unsigned r_length, const bool previous_arm_half){
765 if (cputype == MachO::CPU_TYPE_ARM &&
766 (r_type == MachO::ARM_RELOC_HALF ||
767 r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {
768 if ((r_length & 0x1) == 0)
769 outs() << "lo/";
770 else
771 outs() << "hi/";
772 if ((r_length & 0x1) == 0)
773 outs() << "arm ";
774 else
775 outs() << "thm ";
776 } else {
777 switch (r_length) {
778 case 0:
779 outs() << "byte ";
780 break;
781 case 1:
782 outs() << "word ";
783 break;
784 case 2:
785 outs() << "long ";
786 break;
787 case 3:
788 if (cputype == MachO::CPU_TYPE_X86_64)
789 outs() << "quad ";
790 else
791 outs() << format("?(%2d) ", r_length);
792 break;
793 default:
794 outs() << format("?(%2d) ", r_length);
799 static void PrintRelocationEntries(const MachOObjectFile *O,
800 const relocation_iterator Begin,
801 const relocation_iterator End,
802 const uint64_t cputype,
803 const bool verbose) {
804 const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
805 bool previous_arm_half = false;
806 bool previous_sectdiff = false;
807 uint32_t sectdiff_r_type = 0;
809 for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
810 const DataRefImpl Rel = Reloc->getRawDataRefImpl();
811 const MachO::any_relocation_info RE = O->getRelocation(Rel);
812 const unsigned r_type = O->getAnyRelocationType(RE);
813 const bool r_scattered = O->isRelocationScattered(RE);
814 const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
815 const unsigned r_length = O->getAnyRelocationLength(RE);
816 const unsigned r_address = O->getAnyRelocationAddress(RE);
817 const bool r_extern = (r_scattered ? false :
818 O->getPlainRelocationExternal(RE));
819 const uint32_t r_value = (r_scattered ?
820 O->getScatteredRelocationValue(RE) : 0);
821 const unsigned r_symbolnum = (r_scattered ? 0 :
822 O->getPlainRelocationSymbolNum(RE));
824 if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
825 if (verbose) {
826 // scattered: address
827 if ((cputype == MachO::CPU_TYPE_I386 &&
828 r_type == MachO::GENERIC_RELOC_PAIR) ||
829 (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))
830 outs() << " ";
831 else
832 outs() << format("%08x ", (unsigned int)r_address);
834 // scattered: pcrel
835 if (r_pcrel)
836 outs() << "True ";
837 else
838 outs() << "False ";
840 // scattered: length
841 PrintRLength(cputype, r_type, r_length, previous_arm_half);
843 // scattered: extern & type
844 outs() << "n/a ";
845 PrintRType(cputype, r_type);
847 // scattered: scattered & value
848 outs() << format("True 0x%08x", (unsigned int)r_value);
849 if (previous_sectdiff == false) {
850 if ((cputype == MachO::CPU_TYPE_ARM &&
851 r_type == MachO::ARM_RELOC_PAIR))
852 outs() << format(" half = 0x%04x ", (unsigned int)r_address);
853 } else if (cputype == MachO::CPU_TYPE_ARM &&
854 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)
855 outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
856 if ((cputype == MachO::CPU_TYPE_I386 &&
857 (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
858 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
859 (cputype == MachO::CPU_TYPE_ARM &&
860 (sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||
861 sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
862 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {
863 previous_sectdiff = true;
864 sectdiff_r_type = r_type;
865 } else {
866 previous_sectdiff = false;
867 sectdiff_r_type = 0;
869 if (cputype == MachO::CPU_TYPE_ARM &&
870 (r_type == MachO::ARM_RELOC_HALF ||
871 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
872 previous_arm_half = true;
873 else
874 previous_arm_half = false;
875 outs() << "\n";
877 else {
878 // scattered: address pcrel length extern type scattered value
879 outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",
880 (unsigned int)r_address, r_pcrel, r_length, r_type,
881 (unsigned int)r_value);
884 else {
885 if (verbose) {
886 // plain: address
887 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
888 outs() << " ";
889 else
890 outs() << format("%08x ", (unsigned int)r_address);
892 // plain: pcrel
893 if (r_pcrel)
894 outs() << "True ";
895 else
896 outs() << "False ";
898 // plain: length
899 PrintRLength(cputype, r_type, r_length, previous_arm_half);
901 if (r_extern) {
902 // plain: extern & type & scattered
903 outs() << "True ";
904 PrintRType(cputype, r_type);
905 outs() << "False ";
907 // plain: symbolnum/value
908 if (r_symbolnum > Symtab.nsyms)
909 outs() << format("?(%d)\n", r_symbolnum);
910 else {
911 SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);
912 Expected<StringRef> SymNameNext = Symbol.getName();
913 const char *name = nullptr;
914 if (SymNameNext)
915 name = SymNameNext->data();
916 if (name == nullptr)
917 outs() << format("?(%d)\n", r_symbolnum);
918 else
919 outs() << name << "\n";
922 else {
923 // plain: extern & type & scattered
924 outs() << "False ";
925 PrintRType(cputype, r_type);
926 outs() << "False ";
928 // plain: symbolnum/value
929 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
930 outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
931 else if ((cputype == MachO::CPU_TYPE_ARM64 ||
932 cputype == MachO::CPU_TYPE_ARM64_32) &&
933 r_type == MachO::ARM64_RELOC_ADDEND)
934 outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
935 else {
936 outs() << format("%d ", r_symbolnum);
937 if (r_symbolnum == MachO::R_ABS)
938 outs() << "R_ABS\n";
939 else {
940 // in this case, r_symbolnum is actually a 1-based section number
941 uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
942 if (r_symbolnum > 0 && r_symbolnum <= nsects) {
943 object::DataRefImpl DRI;
944 DRI.d.a = r_symbolnum-1;
945 StringRef SegName = O->getSectionFinalSegmentName(DRI);
946 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
947 outs() << "(" << SegName << "," << *NameOrErr << ")\n";
948 else
949 outs() << "(?,?)\n";
951 else {
952 outs() << "(?,?)\n";
957 if (cputype == MachO::CPU_TYPE_ARM &&
958 (r_type == MachO::ARM_RELOC_HALF ||
959 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
960 previous_arm_half = true;
961 else
962 previous_arm_half = false;
964 else {
965 // plain: address pcrel length extern type scattered symbolnum/section
966 outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",
967 (unsigned int)r_address, r_pcrel, r_length, r_extern,
968 r_type, r_symbolnum);
974 static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
975 const uint64_t cputype = O->getHeader().cputype;
976 const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
977 if (Dysymtab.nextrel != 0) {
978 outs() << "External relocation information " << Dysymtab.nextrel
979 << " entries";
980 outs() << "\naddress pcrel length extern type scattered "
981 "symbolnum/value\n";
982 PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,
983 verbose);
985 if (Dysymtab.nlocrel != 0) {
986 outs() << format("Local relocation information %u entries",
987 Dysymtab.nlocrel);
988 outs() << "\naddress pcrel length extern type scattered "
989 "symbolnum/value\n";
990 PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,
991 verbose);
993 for (const auto &Load : O->load_commands()) {
994 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
995 const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
996 for (unsigned J = 0; J < Seg.nsects; ++J) {
997 const MachO::section_64 Sec = O->getSection64(Load, J);
998 if (Sec.nreloc != 0) {
999 DataRefImpl DRI;
1000 DRI.d.a = J;
1001 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
1002 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
1003 outs() << "Relocation information (" << SegName << "," << *NameOrErr
1004 << format(") %u entries", Sec.nreloc);
1005 else
1006 outs() << "Relocation information (" << SegName << ",?) "
1007 << format("%u entries", Sec.nreloc);
1008 outs() << "\naddress pcrel length extern type scattered "
1009 "symbolnum/value\n";
1010 PrintRelocationEntries(O, O->section_rel_begin(DRI),
1011 O->section_rel_end(DRI), cputype, verbose);
1014 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
1015 const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
1016 for (unsigned J = 0; J < Seg.nsects; ++J) {
1017 const MachO::section Sec = O->getSection(Load, J);
1018 if (Sec.nreloc != 0) {
1019 DataRefImpl DRI;
1020 DRI.d.a = J;
1021 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
1022 if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
1023 outs() << "Relocation information (" << SegName << "," << *NameOrErr
1024 << format(") %u entries", Sec.nreloc);
1025 else
1026 outs() << "Relocation information (" << SegName << ",?) "
1027 << format("%u entries", Sec.nreloc);
1028 outs() << "\naddress pcrel length extern type scattered "
1029 "symbolnum/value\n";
1030 PrintRelocationEntries(O, O->section_rel_begin(DRI),
1031 O->section_rel_end(DRI), cputype, verbose);
1038 static void PrintFunctionStarts(MachOObjectFile *O) {
1039 uint64_t BaseSegmentAddress = 0;
1040 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1041 if (Command.C.cmd == MachO::LC_SEGMENT) {
1042 MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
1043 if (StringRef(SLC.segname) == "__TEXT") {
1044 BaseSegmentAddress = SLC.vmaddr;
1045 break;
1047 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1048 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
1049 if (StringRef(SLC.segname) == "__TEXT") {
1050 BaseSegmentAddress = SLC.vmaddr;
1051 break;
1056 SmallVector<uint64_t, 8> FunctionStarts;
1057 for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {
1058 if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {
1059 MachO::linkedit_data_command FunctionStartsLC =
1060 O->getLinkeditDataLoadCommand(LC);
1061 O->ReadULEB128s(FunctionStartsLC.dataoff, FunctionStarts);
1062 break;
1066 DenseMap<uint64_t, StringRef> SymbolNames;
1067 if (FunctionStartsType == FunctionStartsMode::Names ||
1068 FunctionStartsType == FunctionStartsMode::Both) {
1069 for (SymbolRef Sym : O->symbols()) {
1070 if (Expected<uint64_t> Addr = Sym.getAddress()) {
1071 if (Expected<StringRef> Name = Sym.getName()) {
1072 SymbolNames[*Addr] = *Name;
1078 for (uint64_t S : FunctionStarts) {
1079 uint64_t Addr = BaseSegmentAddress + S;
1080 if (FunctionStartsType == FunctionStartsMode::Names) {
1081 auto It = SymbolNames.find(Addr);
1082 if (It != SymbolNames.end())
1083 outs() << It->second << "\n";
1084 } else {
1085 if (O->is64Bit())
1086 outs() << format("%016" PRIx64, Addr);
1087 else
1088 outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));
1090 if (FunctionStartsType == FunctionStartsMode::Both) {
1091 auto It = SymbolNames.find(Addr);
1092 if (It != SymbolNames.end())
1093 outs() << " " << It->second;
1094 else
1095 outs() << " ?";
1097 outs() << "\n";
1102 static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
1103 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
1104 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
1105 outs() << "Data in code table (" << nentries << " entries)\n";
1106 outs() << "offset length kind\n";
1107 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
1108 ++DI) {
1109 uint32_t Offset;
1110 DI->getOffset(Offset);
1111 outs() << format("0x%08" PRIx32, Offset) << " ";
1112 uint16_t Length;
1113 DI->getLength(Length);
1114 outs() << format("%6u", Length) << " ";
1115 uint16_t Kind;
1116 DI->getKind(Kind);
1117 if (verbose) {
1118 switch (Kind) {
1119 case MachO::DICE_KIND_DATA:
1120 outs() << "DATA";
1121 break;
1122 case MachO::DICE_KIND_JUMP_TABLE8:
1123 outs() << "JUMP_TABLE8";
1124 break;
1125 case MachO::DICE_KIND_JUMP_TABLE16:
1126 outs() << "JUMP_TABLE16";
1127 break;
1128 case MachO::DICE_KIND_JUMP_TABLE32:
1129 outs() << "JUMP_TABLE32";
1130 break;
1131 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
1132 outs() << "ABS_JUMP_TABLE32";
1133 break;
1134 default:
1135 outs() << format("0x%04" PRIx32, Kind);
1136 break;
1138 } else
1139 outs() << format("0x%04" PRIx32, Kind);
1140 outs() << "\n";
1144 static void PrintLinkOptHints(MachOObjectFile *O) {
1145 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
1146 const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
1147 uint32_t nloh = LohLC.datasize;
1148 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
1149 for (uint32_t i = 0; i < nloh;) {
1150 unsigned n;
1151 uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
1152 i += n;
1153 outs() << " identifier " << identifier << " ";
1154 if (i >= nloh)
1155 return;
1156 switch (identifier) {
1157 case 1:
1158 outs() << "AdrpAdrp\n";
1159 break;
1160 case 2:
1161 outs() << "AdrpLdr\n";
1162 break;
1163 case 3:
1164 outs() << "AdrpAddLdr\n";
1165 break;
1166 case 4:
1167 outs() << "AdrpLdrGotLdr\n";
1168 break;
1169 case 5:
1170 outs() << "AdrpAddStr\n";
1171 break;
1172 case 6:
1173 outs() << "AdrpLdrGotStr\n";
1174 break;
1175 case 7:
1176 outs() << "AdrpAdd\n";
1177 break;
1178 case 8:
1179 outs() << "AdrpLdrGot\n";
1180 break;
1181 default:
1182 outs() << "Unknown identifier value\n";
1183 break;
1185 uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
1186 i += n;
1187 outs() << " narguments " << narguments << "\n";
1188 if (i >= nloh)
1189 return;
1191 for (uint32_t j = 0; j < narguments; j++) {
1192 uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
1193 i += n;
1194 outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";
1195 if (i >= nloh)
1196 return;
1201 static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
1202 SmallVector<std::string> Ret;
1203 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1204 if (Command.C.cmd == MachO::LC_SEGMENT) {
1205 MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
1206 Ret.push_back(SLC.segname);
1207 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1208 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
1209 Ret.push_back(SLC.segname);
1212 return Ret;
1215 static void
1216 PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
1217 outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
1218 outs() << " fixups_version = " << H.fixups_version << '\n';
1219 outs() << " starts_offset = " << H.starts_offset << '\n';
1220 outs() << " imports_offset = " << H.imports_offset << '\n';
1221 outs() << " symbols_offset = " << H.symbols_offset << '\n';
1222 outs() << " imports_count = " << H.imports_count << '\n';
1224 outs() << " imports_format = " << H.imports_format;
1225 switch (H.imports_format) {
1226 case llvm::MachO::DYLD_CHAINED_IMPORT:
1227 outs() << " (DYLD_CHAINED_IMPORT)";
1228 break;
1229 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
1230 outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
1231 break;
1232 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
1233 outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
1234 break;
1236 outs() << '\n';
1238 outs() << " symbols_format = " << H.symbols_format;
1239 if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
1240 outs() << " (zlib compressed)";
1241 outs() << '\n';
1244 static constexpr std::array<StringRef, 13> PointerFormats{
1245 "DYLD_CHAINED_PTR_ARM64E",
1246 "DYLD_CHAINED_PTR_64",
1247 "DYLD_CHAINED_PTR_32",
1248 "DYLD_CHAINED_PTR_32_CACHE",
1249 "DYLD_CHAINED_PTR_32_FIRMWARE",
1250 "DYLD_CHAINED_PTR_64_OFFSET",
1251 "DYLD_CHAINED_PTR_ARM64E_KERNEL",
1252 "DYLD_CHAINED_PTR_64_KERNEL_CACHE",
1253 "DYLD_CHAINED_PTR_ARM64E_USERLAND",
1254 "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
1255 "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
1256 "DYLD_CHAINED_PTR_ARM64E_USERLAND24",
1259 static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,
1260 StringRef SegName) {
1261 outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
1262 << ")\n";
1263 outs() << " size = " << Segment.Header.size << '\n';
1264 outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)
1265 << '\n';
1267 outs() << " pointer_format = " << Segment.Header.pointer_format;
1268 if ((Segment.Header.pointer_format - 1) <
1269 MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
1270 outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
1271 outs() << '\n';
1273 outs() << " segment_offset = "
1274 << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';
1275 outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
1276 << '\n';
1277 outs() << " page_count = " << Segment.Header.page_count << '\n';
1278 for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {
1279 outs() << " page_start[" << Index << "] = " << PageStart;
1280 // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
1281 if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
1282 outs() << " (DYLD_CHAINED_PTR_START_NONE)";
1283 outs() << '\n';
1287 static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,
1288 int Format, MachOObjectFile *O) {
1289 if (Format == MachO::DYLD_CHAINED_IMPORT)
1290 outs() << "dyld chained import";
1291 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
1292 outs() << "dyld chained import addend";
1293 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
1294 outs() << "dyld chained import addend64";
1295 // FIXME: otool prints the encoded value as well.
1296 outs() << '[' << Idx << "]\n";
1298 outs() << " lib_ordinal = " << Target.libOrdinal() << " ("
1299 << ordinalName(O, Target.libOrdinal()) << ")\n";
1300 outs() << " weak_import = " << Target.weakImport() << '\n';
1301 outs() << " name_offset = " << Target.nameOffset() << " ("
1302 << Target.symbolName() << ")\n";
1303 if (Format != MachO::DYLD_CHAINED_IMPORT)
1304 outs() << " addend = " << (int64_t)Target.addend() << '\n';
1307 static void PrintChainedFixups(MachOObjectFile *O) {
1308 // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
1309 // FIXME: Support chained fixups in __TEXT,__chain_starts section too.
1310 auto ChainedFixupHeader =
1311 unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());
1312 if (!ChainedFixupHeader)
1313 return;
1315 PrintChainedFixupsHeader(*ChainedFixupHeader);
1317 auto [SegCount, Segments] =
1318 unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());
1320 auto SegNames = GetSegmentNames(O);
1322 size_t StartsIdx = 0;
1323 outs() << "chained starts in image\n";
1324 outs() << " seg_count = " << SegCount << '\n';
1325 for (size_t I = 0; I < SegCount; ++I) {
1326 uint64_t SegOffset = 0;
1327 if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
1328 SegOffset = Segments[StartsIdx].Offset;
1329 ++StartsIdx;
1332 outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
1333 << SegNames[I] << ")\n";
1336 for (const ChainedFixupsSegment &S : Segments)
1337 PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);
1339 auto FixupTargets =
1340 unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());
1342 uint32_t ImportsFormat = ChainedFixupHeader->imports_format;
1343 for (auto [Idx, Target] : enumerate(FixupTargets))
1344 PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);
1347 static void PrintDyldInfo(MachOObjectFile *O) {
1348 Error Err = Error::success();
1350 size_t SegmentWidth = strlen("segment");
1351 size_t SectionWidth = strlen("section");
1352 size_t AddressWidth = strlen("address");
1353 size_t AddendWidth = strlen("addend");
1354 size_t DylibWidth = strlen("dylib");
1355 const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;
1357 auto HexLength = [](uint64_t Num) {
1358 return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;
1360 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1361 SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());
1362 SectionWidth = std::max(SectionWidth, Entry.sectionName().size());
1363 AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);
1364 if (Entry.isBind()) {
1365 AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);
1366 DylibWidth = std::max(DylibWidth, Entry.symbolName().size());
1369 // Errors will be handled when printing the table.
1370 if (Err)
1371 consumeError(std::move(Err));
1373 outs() << "dyld information:\n";
1374 outs() << left_justify("segment", SegmentWidth) << ' '
1375 << left_justify("section", SectionWidth) << ' '
1376 << left_justify("address", AddressWidth) << ' '
1377 << left_justify("pointer", PointerWidth) << " type "
1378 << left_justify("addend", AddendWidth) << ' '
1379 << left_justify("dylib", DylibWidth) << " symbol/vm address\n";
1380 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1381 outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '
1382 << left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"
1383 << left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '
1384 << format_hex(Entry.rawValue(), PointerWidth, true) << ' ';
1385 if (Entry.isBind()) {
1386 outs() << "bind "
1387 << "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)
1388 << ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)
1389 << ' ' << Entry.symbolName();
1390 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
1391 outs() << " (weak import)";
1392 outs() << '\n';
1393 } else {
1394 assert(Entry.isRebase());
1395 outs() << "rebase";
1396 outs().indent(AddendWidth + DylibWidth + 2);
1397 outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';
1400 if (Err)
1401 reportError(std::move(Err), O->getFileName());
1403 // TODO: Print opcode-based fixups if the object uses those.
1406 static void PrintDylibs(MachOObjectFile *O, bool JustId) {
1407 unsigned Index = 0;
1408 for (const auto &Load : O->load_commands()) {
1409 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
1410 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
1411 Load.C.cmd == MachO::LC_LOAD_DYLIB ||
1412 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
1413 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
1414 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
1415 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
1416 MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
1417 if (dl.dylib.name < dl.cmdsize) {
1418 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
1419 if (JustId)
1420 outs() << p << "\n";
1421 else {
1422 outs() << "\t" << p;
1423 outs() << " (compatibility version "
1424 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
1425 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
1426 << (dl.dylib.compatibility_version & 0xff) << ",";
1427 outs() << " current version "
1428 << ((dl.dylib.current_version >> 16) & 0xffff) << "."
1429 << ((dl.dylib.current_version >> 8) & 0xff) << "."
1430 << (dl.dylib.current_version & 0xff);
1431 if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1432 outs() << ", weak";
1433 if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1434 outs() << ", reexport";
1435 if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1436 outs() << ", upward";
1437 if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1438 outs() << ", lazy";
1439 outs() << ")\n";
1441 } else {
1442 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
1443 if (Load.C.cmd == MachO::LC_ID_DYLIB)
1444 outs() << "LC_ID_DYLIB ";
1445 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
1446 outs() << "LC_LOAD_DYLIB ";
1447 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1448 outs() << "LC_LOAD_WEAK_DYLIB ";
1449 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1450 outs() << "LC_LAZY_LOAD_DYLIB ";
1451 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1452 outs() << "LC_REEXPORT_DYLIB ";
1453 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1454 outs() << "LC_LOAD_UPWARD_DYLIB ";
1455 else
1456 outs() << "LC_??? ";
1457 outs() << "command " << Index++ << "\n";
1463 static void printRpaths(MachOObjectFile *O) {
1464 for (const auto &Command : O->load_commands()) {
1465 if (Command.C.cmd == MachO::LC_RPATH) {
1466 auto Rpath = O->getRpathCommand(Command);
1467 const char *P = (const char *)(Command.Ptr) + Rpath.path;
1468 outs() << P << "\n";
1473 typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
1475 static void CreateSymbolAddressMap(MachOObjectFile *O,
1476 SymbolAddressMap *AddrMap) {
1477 // Create a map of symbol addresses to symbol names.
1478 const StringRef FileName = O->getFileName();
1479 for (const SymbolRef &Symbol : O->symbols()) {
1480 SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);
1481 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
1482 ST == SymbolRef::ST_Other) {
1483 uint64_t Address = cantFail(Symbol.getValue());
1484 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
1485 if (!SymName.starts_with(".objc"))
1486 (*AddrMap)[Address] = SymName;
1491 // GuessSymbolName is passed the address of what might be a symbol and a
1492 // pointer to the SymbolAddressMap. It returns the name of a symbol
1493 // with that address or nullptr if no symbol is found with that address.
1494 static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
1495 const char *SymbolName = nullptr;
1496 // A DenseMap can't lookup up some values.
1497 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
1498 StringRef name = AddrMap->lookup(value);
1499 if (!name.empty())
1500 SymbolName = name.data();
1502 return SymbolName;
1505 static void DumpCstringChar(const char c) {
1506 char p[2];
1507 p[0] = c;
1508 p[1] = '\0';
1509 outs().write_escaped(p);
1512 static void DumpCstringSection(MachOObjectFile *O, const char *sect,
1513 uint32_t sect_size, uint64_t sect_addr,
1514 bool print_addresses) {
1515 for (uint32_t i = 0; i < sect_size; i++) {
1516 if (print_addresses) {
1517 if (O->is64Bit())
1518 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1519 else
1520 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1522 for (; i < sect_size && sect[i] != '\0'; i++)
1523 DumpCstringChar(sect[i]);
1524 if (i < sect_size && sect[i] == '\0')
1525 outs() << "\n";
1529 static void DumpLiteral4(uint32_t l, float f) {
1530 outs() << format("0x%08" PRIx32, l);
1531 if ((l & 0x7f800000) != 0x7f800000)
1532 outs() << format(" (%.16e)\n", f);
1533 else {
1534 if (l == 0x7f800000)
1535 outs() << " (+Infinity)\n";
1536 else if (l == 0xff800000)
1537 outs() << " (-Infinity)\n";
1538 else if ((l & 0x00400000) == 0x00400000)
1539 outs() << " (non-signaling Not-a-Number)\n";
1540 else
1541 outs() << " (signaling Not-a-Number)\n";
1545 static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
1546 uint32_t sect_size, uint64_t sect_addr,
1547 bool print_addresses) {
1548 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
1549 if (print_addresses) {
1550 if (O->is64Bit())
1551 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1552 else
1553 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1555 float f;
1556 memcpy(&f, sect + i, sizeof(float));
1557 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1558 sys::swapByteOrder(f);
1559 uint32_t l;
1560 memcpy(&l, sect + i, sizeof(uint32_t));
1561 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1562 sys::swapByteOrder(l);
1563 DumpLiteral4(l, f);
1567 static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
1568 double d) {
1569 outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
1570 uint32_t Hi, Lo;
1571 Hi = (O->isLittleEndian()) ? l1 : l0;
1572 Lo = (O->isLittleEndian()) ? l0 : l1;
1574 // Hi is the high word, so this is equivalent to if(isfinite(d))
1575 if ((Hi & 0x7ff00000) != 0x7ff00000)
1576 outs() << format(" (%.16e)\n", d);
1577 else {
1578 if (Hi == 0x7ff00000 && Lo == 0)
1579 outs() << " (+Infinity)\n";
1580 else if (Hi == 0xfff00000 && Lo == 0)
1581 outs() << " (-Infinity)\n";
1582 else if ((Hi & 0x00080000) == 0x00080000)
1583 outs() << " (non-signaling Not-a-Number)\n";
1584 else
1585 outs() << " (signaling Not-a-Number)\n";
1589 static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
1590 uint32_t sect_size, uint64_t sect_addr,
1591 bool print_addresses) {
1592 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
1593 if (print_addresses) {
1594 if (O->is64Bit())
1595 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1596 else
1597 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1599 double d;
1600 memcpy(&d, sect + i, sizeof(double));
1601 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1602 sys::swapByteOrder(d);
1603 uint32_t l0, l1;
1604 memcpy(&l0, sect + i, sizeof(uint32_t));
1605 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1606 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1607 sys::swapByteOrder(l0);
1608 sys::swapByteOrder(l1);
1610 DumpLiteral8(O, l0, l1, d);
1614 static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
1615 outs() << format("0x%08" PRIx32, l0) << " ";
1616 outs() << format("0x%08" PRIx32, l1) << " ";
1617 outs() << format("0x%08" PRIx32, l2) << " ";
1618 outs() << format("0x%08" PRIx32, l3) << "\n";
1621 static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
1622 uint32_t sect_size, uint64_t sect_addr,
1623 bool print_addresses) {
1624 for (uint32_t i = 0; i < sect_size; i += 16) {
1625 if (print_addresses) {
1626 if (O->is64Bit())
1627 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1628 else
1629 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1631 uint32_t l0, l1, l2, l3;
1632 memcpy(&l0, sect + i, sizeof(uint32_t));
1633 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1634 memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
1635 memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
1636 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1637 sys::swapByteOrder(l0);
1638 sys::swapByteOrder(l1);
1639 sys::swapByteOrder(l2);
1640 sys::swapByteOrder(l3);
1642 DumpLiteral16(l0, l1, l2, l3);
1646 static void DumpLiteralPointerSection(MachOObjectFile *O,
1647 const SectionRef &Section,
1648 const char *sect, uint32_t sect_size,
1649 uint64_t sect_addr,
1650 bool print_addresses) {
1651 // Collect the literal sections in this Mach-O file.
1652 std::vector<SectionRef> LiteralSections;
1653 for (const SectionRef &Section : O->sections()) {
1654 DataRefImpl Ref = Section.getRawDataRefImpl();
1655 uint32_t section_type;
1656 if (O->is64Bit()) {
1657 const MachO::section_64 Sec = O->getSection64(Ref);
1658 section_type = Sec.flags & MachO::SECTION_TYPE;
1659 } else {
1660 const MachO::section Sec = O->getSection(Ref);
1661 section_type = Sec.flags & MachO::SECTION_TYPE;
1663 if (section_type == MachO::S_CSTRING_LITERALS ||
1664 section_type == MachO::S_4BYTE_LITERALS ||
1665 section_type == MachO::S_8BYTE_LITERALS ||
1666 section_type == MachO::S_16BYTE_LITERALS)
1667 LiteralSections.push_back(Section);
1670 // Set the size of the literal pointer.
1671 uint32_t lp_size = O->is64Bit() ? 8 : 4;
1673 // Collect the external relocation symbols for the literal pointers.
1674 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1675 for (const RelocationRef &Reloc : Section.relocations()) {
1676 DataRefImpl Rel;
1677 MachO::any_relocation_info RE;
1678 bool isExtern = false;
1679 Rel = Reloc.getRawDataRefImpl();
1680 RE = O->getRelocation(Rel);
1681 isExtern = O->getPlainRelocationExternal(RE);
1682 if (isExtern) {
1683 uint64_t RelocOffset = Reloc.getOffset();
1684 symbol_iterator RelocSym = Reloc.getSymbol();
1685 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1688 array_pod_sort(Relocs.begin(), Relocs.end());
1690 // Dump each literal pointer.
1691 for (uint32_t i = 0; i < sect_size; i += lp_size) {
1692 if (print_addresses) {
1693 if (O->is64Bit())
1694 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1695 else
1696 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1698 uint64_t lp;
1699 if (O->is64Bit()) {
1700 memcpy(&lp, sect + i, sizeof(uint64_t));
1701 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1702 sys::swapByteOrder(lp);
1703 } else {
1704 uint32_t li;
1705 memcpy(&li, sect + i, sizeof(uint32_t));
1706 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1707 sys::swapByteOrder(li);
1708 lp = li;
1711 // First look for an external relocation entry for this literal pointer.
1712 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1713 return P.first == i;
1715 if (Reloc != Relocs.end()) {
1716 symbol_iterator RelocSym = Reloc->second;
1717 StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());
1718 outs() << "external relocation entry for symbol:" << SymName << "\n";
1719 continue;
1722 // For local references see what the section the literal pointer points to.
1723 auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {
1724 return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();
1726 if (Sect == LiteralSections.end()) {
1727 outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
1728 continue;
1731 uint64_t SectAddress = Sect->getAddress();
1732 uint64_t SectSize = Sect->getSize();
1734 StringRef SectName;
1735 Expected<StringRef> SectNameOrErr = Sect->getName();
1736 if (SectNameOrErr)
1737 SectName = *SectNameOrErr;
1738 else
1739 consumeError(SectNameOrErr.takeError());
1741 DataRefImpl Ref = Sect->getRawDataRefImpl();
1742 StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
1743 outs() << SegmentName << ":" << SectName << ":";
1745 uint32_t section_type;
1746 if (O->is64Bit()) {
1747 const MachO::section_64 Sec = O->getSection64(Ref);
1748 section_type = Sec.flags & MachO::SECTION_TYPE;
1749 } else {
1750 const MachO::section Sec = O->getSection(Ref);
1751 section_type = Sec.flags & MachO::SECTION_TYPE;
1754 StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());
1756 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
1758 switch (section_type) {
1759 case MachO::S_CSTRING_LITERALS:
1760 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
1761 i++) {
1762 DumpCstringChar(Contents[i]);
1764 outs() << "\n";
1765 break;
1766 case MachO::S_4BYTE_LITERALS:
1767 float f;
1768 memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
1769 uint32_t l;
1770 memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
1771 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1772 sys::swapByteOrder(f);
1773 sys::swapByteOrder(l);
1775 DumpLiteral4(l, f);
1776 break;
1777 case MachO::S_8BYTE_LITERALS: {
1778 double d;
1779 memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
1780 uint32_t l0, l1;
1781 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1782 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1783 sizeof(uint32_t));
1784 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1785 sys::swapByteOrder(f);
1786 sys::swapByteOrder(l0);
1787 sys::swapByteOrder(l1);
1789 DumpLiteral8(O, l0, l1, d);
1790 break;
1792 case MachO::S_16BYTE_LITERALS: {
1793 uint32_t l0, l1, l2, l3;
1794 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1795 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1796 sizeof(uint32_t));
1797 memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
1798 sizeof(uint32_t));
1799 memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
1800 sizeof(uint32_t));
1801 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1802 sys::swapByteOrder(l0);
1803 sys::swapByteOrder(l1);
1804 sys::swapByteOrder(l2);
1805 sys::swapByteOrder(l3);
1807 DumpLiteral16(l0, l1, l2, l3);
1808 break;
1814 static void DumpInitTermPointerSection(MachOObjectFile *O,
1815 const SectionRef &Section,
1816 const char *sect,
1817 uint32_t sect_size, uint64_t sect_addr,
1818 SymbolAddressMap *AddrMap,
1819 bool verbose) {
1820 uint32_t stride;
1821 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
1823 // Collect the external relocation symbols for the pointers.
1824 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1825 for (const RelocationRef &Reloc : Section.relocations()) {
1826 DataRefImpl Rel;
1827 MachO::any_relocation_info RE;
1828 bool isExtern = false;
1829 Rel = Reloc.getRawDataRefImpl();
1830 RE = O->getRelocation(Rel);
1831 isExtern = O->getPlainRelocationExternal(RE);
1832 if (isExtern) {
1833 uint64_t RelocOffset = Reloc.getOffset();
1834 symbol_iterator RelocSym = Reloc.getSymbol();
1835 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1838 array_pod_sort(Relocs.begin(), Relocs.end());
1840 for (uint32_t i = 0; i < sect_size; i += stride) {
1841 const char *SymbolName = nullptr;
1842 uint64_t p;
1843 if (O->is64Bit()) {
1844 outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
1845 uint64_t pointer_value;
1846 memcpy(&pointer_value, sect + i, stride);
1847 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1848 sys::swapByteOrder(pointer_value);
1849 outs() << format("0x%016" PRIx64, pointer_value);
1850 p = pointer_value;
1851 } else {
1852 outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
1853 uint32_t pointer_value;
1854 memcpy(&pointer_value, sect + i, stride);
1855 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1856 sys::swapByteOrder(pointer_value);
1857 outs() << format("0x%08" PRIx32, pointer_value);
1858 p = pointer_value;
1860 if (verbose) {
1861 // First look for an external relocation entry for this pointer.
1862 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1863 return P.first == i;
1865 if (Reloc != Relocs.end()) {
1866 symbol_iterator RelocSym = Reloc->second;
1867 outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());
1868 } else {
1869 SymbolName = GuessSymbolName(p, AddrMap);
1870 if (SymbolName)
1871 outs() << " " << SymbolName;
1874 outs() << "\n";
1878 static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
1879 uint32_t size, uint64_t addr) {
1880 uint32_t cputype = O->getHeader().cputype;
1881 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
1882 uint32_t j;
1883 for (uint32_t i = 0; i < size; i += j, addr += j) {
1884 if (O->is64Bit())
1885 outs() << format("%016" PRIx64, addr) << "\t";
1886 else
1887 outs() << format("%08" PRIx64, addr) << "\t";
1888 for (j = 0; j < 16 && i + j < size; j++) {
1889 uint8_t byte_word = *(sect + i + j);
1890 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1892 outs() << "\n";
1894 } else {
1895 uint32_t j;
1896 for (uint32_t i = 0; i < size; i += j, addr += j) {
1897 if (O->is64Bit())
1898 outs() << format("%016" PRIx64, addr) << "\t";
1899 else
1900 outs() << format("%08" PRIx64, addr) << "\t";
1901 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
1902 j += sizeof(int32_t)) {
1903 if (i + j + sizeof(int32_t) <= size) {
1904 uint32_t long_word;
1905 memcpy(&long_word, sect + i + j, sizeof(int32_t));
1906 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1907 sys::swapByteOrder(long_word);
1908 outs() << format("%08" PRIx32, long_word) << " ";
1909 } else {
1910 for (uint32_t k = 0; i + j + k < size; k++) {
1911 uint8_t byte_word = *(sect + i + j + k);
1912 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1916 outs() << "\n";
1921 static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
1922 StringRef DisSegName, StringRef DisSectName);
1923 static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1924 uint32_t size, uint32_t addr);
1925 static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1926 bool verbose) {
1927 SymbolAddressMap AddrMap;
1928 if (verbose)
1929 CreateSymbolAddressMap(O, &AddrMap);
1931 for (unsigned i = 0; i < FilterSections.size(); ++i) {
1932 StringRef DumpSection = FilterSections[i];
1933 std::pair<StringRef, StringRef> DumpSegSectName;
1934 DumpSegSectName = DumpSection.split(',');
1935 StringRef DumpSegName, DumpSectName;
1936 if (!DumpSegSectName.second.empty()) {
1937 DumpSegName = DumpSegSectName.first;
1938 DumpSectName = DumpSegSectName.second;
1939 } else {
1940 DumpSegName = "";
1941 DumpSectName = DumpSegSectName.first;
1943 for (const SectionRef &Section : O->sections()) {
1944 StringRef SectName;
1945 Expected<StringRef> SecNameOrErr = Section.getName();
1946 if (SecNameOrErr)
1947 SectName = *SecNameOrErr;
1948 else
1949 consumeError(SecNameOrErr.takeError());
1951 if (!DumpSection.empty())
1952 FoundSectionSet.insert(DumpSection);
1954 DataRefImpl Ref = Section.getRawDataRefImpl();
1955 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1956 if ((DumpSegName.empty() || SegName == DumpSegName) &&
1957 (SectName == DumpSectName)) {
1959 uint32_t section_flags;
1960 if (O->is64Bit()) {
1961 const MachO::section_64 Sec = O->getSection64(Ref);
1962 section_flags = Sec.flags;
1964 } else {
1965 const MachO::section Sec = O->getSection(Ref);
1966 section_flags = Sec.flags;
1968 uint32_t section_type = section_flags & MachO::SECTION_TYPE;
1970 StringRef BytesStr =
1971 unwrapOrError(Section.getContents(), O->getFileName());
1972 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1973 uint32_t sect_size = BytesStr.size();
1974 uint64_t sect_addr = Section.getAddress();
1976 if (LeadingHeaders)
1977 outs() << "Contents of (" << SegName << "," << SectName
1978 << ") section\n";
1980 if (verbose) {
1981 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1982 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1983 DisassembleMachO(Filename, O, SegName, SectName);
1984 continue;
1986 if (SegName == "__TEXT" && SectName == "__info_plist") {
1987 outs() << sect;
1988 continue;
1990 if (SegName == "__OBJC" && SectName == "__protocol") {
1991 DumpProtocolSection(O, sect, sect_size, sect_addr);
1992 continue;
1994 switch (section_type) {
1995 case MachO::S_REGULAR:
1996 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1997 break;
1998 case MachO::S_ZEROFILL:
1999 outs() << "zerofill section and has no contents in the file\n";
2000 break;
2001 case MachO::S_CSTRING_LITERALS:
2002 DumpCstringSection(O, sect, sect_size, sect_addr, LeadingAddr);
2003 break;
2004 case MachO::S_4BYTE_LITERALS:
2005 DumpLiteral4Section(O, sect, sect_size, sect_addr, LeadingAddr);
2006 break;
2007 case MachO::S_8BYTE_LITERALS:
2008 DumpLiteral8Section(O, sect, sect_size, sect_addr, LeadingAddr);
2009 break;
2010 case MachO::S_16BYTE_LITERALS:
2011 DumpLiteral16Section(O, sect, sect_size, sect_addr, LeadingAddr);
2012 break;
2013 case MachO::S_LITERAL_POINTERS:
2014 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
2015 LeadingAddr);
2016 break;
2017 case MachO::S_MOD_INIT_FUNC_POINTERS:
2018 case MachO::S_MOD_TERM_FUNC_POINTERS:
2019 DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,
2020 &AddrMap, verbose);
2021 break;
2022 default:
2023 outs() << "Unknown section type ("
2024 << format("0x%08" PRIx32, section_type) << ")\n";
2025 DumpRawSectionContents(O, sect, sect_size, sect_addr);
2026 break;
2028 } else {
2029 if (section_type == MachO::S_ZEROFILL)
2030 outs() << "zerofill section and has no contents in the file\n";
2031 else
2032 DumpRawSectionContents(O, sect, sect_size, sect_addr);
2039 static void DumpInfoPlistSectionContents(StringRef Filename,
2040 MachOObjectFile *O) {
2041 for (const SectionRef &Section : O->sections()) {
2042 StringRef SectName;
2043 Expected<StringRef> SecNameOrErr = Section.getName();
2044 if (SecNameOrErr)
2045 SectName = *SecNameOrErr;
2046 else
2047 consumeError(SecNameOrErr.takeError());
2049 DataRefImpl Ref = Section.getRawDataRefImpl();
2050 StringRef SegName = O->getSectionFinalSegmentName(Ref);
2051 if (SegName == "__TEXT" && SectName == "__info_plist") {
2052 if (LeadingHeaders)
2053 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
2054 StringRef BytesStr =
2055 unwrapOrError(Section.getContents(), O->getFileName());
2056 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
2057 outs() << format("%.*s", BytesStr.size(), sect) << "\n";
2058 return;
2063 // checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
2064 // and if it is and there is a list of architecture flags is specified then
2065 // check to make sure this Mach-O file is one of those architectures or all
2066 // architectures were specified. If not then an error is generated and this
2067 // routine returns false. Else it returns true.
2068 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
2069 auto *MachO = dyn_cast<MachOObjectFile>(O);
2071 if (!MachO || ArchAll || ArchFlags.empty())
2072 return true;
2074 MachO::mach_header H;
2075 MachO::mach_header_64 H_64;
2076 Triple T;
2077 const char *McpuDefault, *ArchFlag;
2078 if (MachO->is64Bit()) {
2079 H_64 = MachO->MachOObjectFile::getHeader64();
2080 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
2081 &McpuDefault, &ArchFlag);
2082 } else {
2083 H = MachO->MachOObjectFile::getHeader();
2084 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
2085 &McpuDefault, &ArchFlag);
2087 const std::string ArchFlagName(ArchFlag);
2088 if (!llvm::is_contained(ArchFlags, ArchFlagName)) {
2089 WithColor::error(errs(), "llvm-objdump")
2090 << Filename << ": no architecture specified.\n";
2091 return false;
2093 return true;
2096 static void printObjcMetaData(MachOObjectFile *O, bool verbose);
2098 // ProcessMachO() is passed a single opened Mach-O file, which may be an
2099 // archive member and or in a slice of a universal file. It prints the
2100 // the file name and header info and then processes it according to the
2101 // command line options.
2102 static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
2103 StringRef ArchiveMemberName = StringRef(),
2104 StringRef ArchitectureName = StringRef()) {
2105 std::unique_ptr<Dumper> D = createMachODumper(*MachOOF);
2107 // If we are doing some processing here on the Mach-O file print the header
2108 // info. And don't print it otherwise like in the case of printing the
2109 // UniversalHeaders or ArchiveHeaders.
2110 if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
2111 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
2112 DataInCode || FunctionStartsType != FunctionStartsMode::None ||
2113 LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
2114 Rpaths || ObjcMetaData || (!FilterSections.empty())) {
2115 if (LeadingHeaders) {
2116 outs() << Name;
2117 if (!ArchiveMemberName.empty())
2118 outs() << '(' << ArchiveMemberName << ')';
2119 if (!ArchitectureName.empty())
2120 outs() << " (architecture " << ArchitectureName << ")";
2121 outs() << ":\n";
2124 // To use the report_error() form with an ArchiveName and FileName set
2125 // these up based on what is passed for Name and ArchiveMemberName.
2126 StringRef ArchiveName;
2127 StringRef FileName;
2128 if (!ArchiveMemberName.empty()) {
2129 ArchiveName = Name;
2130 FileName = ArchiveMemberName;
2131 } else {
2132 ArchiveName = StringRef();
2133 FileName = Name;
2136 // If we need the symbol table to do the operation then check it here to
2137 // produce a good error message as to where the Mach-O file comes from in
2138 // the error message.
2139 if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)
2140 if (Error Err = MachOOF->checkSymbolTable())
2141 reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);
2143 if (DisassembleAll) {
2144 for (const SectionRef &Section : MachOOF->sections()) {
2145 StringRef SectName;
2146 if (Expected<StringRef> NameOrErr = Section.getName())
2147 SectName = *NameOrErr;
2148 else
2149 consumeError(NameOrErr.takeError());
2151 if (SectName == "__text") {
2152 DataRefImpl Ref = Section.getRawDataRefImpl();
2153 StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);
2154 DisassembleMachO(FileName, MachOOF, SegName, SectName);
2158 else if (Disassemble) {
2159 if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
2160 MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
2161 DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
2162 else
2163 DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
2165 if (IndirectSymbols)
2166 PrintIndirectSymbols(MachOOF, Verbose);
2167 if (DataInCode)
2168 PrintDataInCodeTable(MachOOF, Verbose);
2169 if (FunctionStartsType != FunctionStartsMode::None)
2170 PrintFunctionStarts(MachOOF);
2171 if (LinkOptHints)
2172 PrintLinkOptHints(MachOOF);
2173 if (Relocations)
2174 PrintRelocations(MachOOF, Verbose);
2175 if (SectionHeaders)
2176 printSectionHeaders(*MachOOF);
2177 if (SectionContents)
2178 printSectionContents(MachOOF);
2179 if (!FilterSections.empty())
2180 DumpSectionContents(FileName, MachOOF, Verbose);
2181 if (InfoPlist)
2182 DumpInfoPlistSectionContents(FileName, MachOOF);
2183 if (DyldInfo)
2184 PrintDyldInfo(MachOOF);
2185 if (ChainedFixups)
2186 PrintChainedFixups(MachOOF);
2187 if (DylibsUsed)
2188 PrintDylibs(MachOOF, false);
2189 if (DylibId)
2190 PrintDylibs(MachOOF, true);
2191 if (SymbolTable)
2192 D->printSymbolTable(ArchiveName, ArchitectureName);
2193 if (UnwindInfo)
2194 printMachOUnwindInfo(MachOOF);
2195 if (PrivateHeaders) {
2196 printMachOFileHeader(MachOOF);
2197 printMachOLoadCommands(MachOOF);
2199 if (FirstPrivateHeader)
2200 printMachOFileHeader(MachOOF);
2201 if (ObjcMetaData)
2202 printObjcMetaData(MachOOF, Verbose);
2203 if (ExportsTrie)
2204 printExportsTrie(MachOOF);
2205 if (Rebase)
2206 printRebaseTable(MachOOF);
2207 if (Rpaths)
2208 printRpaths(MachOOF);
2209 if (Bind)
2210 printBindTable(MachOOF);
2211 if (LazyBind)
2212 printLazyBindTable(MachOOF);
2213 if (WeakBind)
2214 printWeakBindTable(MachOOF);
2216 if (DwarfDumpType != DIDT_Null) {
2217 std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);
2218 // Dump the complete DWARF structure.
2219 DIDumpOptions DumpOpts;
2220 DumpOpts.DumpType = DwarfDumpType;
2221 DICtx->dump(outs(), DumpOpts);
2225 // printUnknownCPUType() helps print_fat_headers for unknown CPU's.
2226 static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
2227 outs() << " cputype (" << cputype << ")\n";
2228 outs() << " cpusubtype (" << cpusubtype << ")\n";
2231 // printCPUType() helps print_fat_headers by printing the cputype and
2232 // pusubtype (symbolically for the one's it knows about).
2233 static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
2234 switch (cputype) {
2235 case MachO::CPU_TYPE_I386:
2236 switch (cpusubtype) {
2237 case MachO::CPU_SUBTYPE_I386_ALL:
2238 outs() << " cputype CPU_TYPE_I386\n";
2239 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
2240 break;
2241 default:
2242 printUnknownCPUType(cputype, cpusubtype);
2243 break;
2245 break;
2246 case MachO::CPU_TYPE_X86_64:
2247 switch (cpusubtype) {
2248 case MachO::CPU_SUBTYPE_X86_64_ALL:
2249 outs() << " cputype CPU_TYPE_X86_64\n";
2250 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
2251 break;
2252 case MachO::CPU_SUBTYPE_X86_64_H:
2253 outs() << " cputype CPU_TYPE_X86_64\n";
2254 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
2255 break;
2256 default:
2257 printUnknownCPUType(cputype, cpusubtype);
2258 break;
2260 break;
2261 case MachO::CPU_TYPE_ARM:
2262 switch (cpusubtype) {
2263 case MachO::CPU_SUBTYPE_ARM_ALL:
2264 outs() << " cputype CPU_TYPE_ARM\n";
2265 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
2266 break;
2267 case MachO::CPU_SUBTYPE_ARM_V4T:
2268 outs() << " cputype CPU_TYPE_ARM\n";
2269 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
2270 break;
2271 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
2272 outs() << " cputype CPU_TYPE_ARM\n";
2273 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
2274 break;
2275 case MachO::CPU_SUBTYPE_ARM_XSCALE:
2276 outs() << " cputype CPU_TYPE_ARM\n";
2277 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
2278 break;
2279 case MachO::CPU_SUBTYPE_ARM_V6:
2280 outs() << " cputype CPU_TYPE_ARM\n";
2281 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
2282 break;
2283 case MachO::CPU_SUBTYPE_ARM_V6M:
2284 outs() << " cputype CPU_TYPE_ARM\n";
2285 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
2286 break;
2287 case MachO::CPU_SUBTYPE_ARM_V7:
2288 outs() << " cputype CPU_TYPE_ARM\n";
2289 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
2290 break;
2291 case MachO::CPU_SUBTYPE_ARM_V7EM:
2292 outs() << " cputype CPU_TYPE_ARM\n";
2293 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
2294 break;
2295 case MachO::CPU_SUBTYPE_ARM_V7K:
2296 outs() << " cputype CPU_TYPE_ARM\n";
2297 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
2298 break;
2299 case MachO::CPU_SUBTYPE_ARM_V7M:
2300 outs() << " cputype CPU_TYPE_ARM\n";
2301 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
2302 break;
2303 case MachO::CPU_SUBTYPE_ARM_V7S:
2304 outs() << " cputype CPU_TYPE_ARM\n";
2305 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
2306 break;
2307 default:
2308 printUnknownCPUType(cputype, cpusubtype);
2309 break;
2311 break;
2312 case MachO::CPU_TYPE_ARM64:
2313 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2314 case MachO::CPU_SUBTYPE_ARM64_ALL:
2315 outs() << " cputype CPU_TYPE_ARM64\n";
2316 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
2317 break;
2318 case MachO::CPU_SUBTYPE_ARM64_V8:
2319 outs() << " cputype CPU_TYPE_ARM64\n";
2320 outs() << " cpusubtype CPU_SUBTYPE_ARM64_V8\n";
2321 break;
2322 case MachO::CPU_SUBTYPE_ARM64E:
2323 outs() << " cputype CPU_TYPE_ARM64\n";
2324 outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";
2325 break;
2326 default:
2327 printUnknownCPUType(cputype, cpusubtype);
2328 break;
2330 break;
2331 case MachO::CPU_TYPE_ARM64_32:
2332 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2333 case MachO::CPU_SUBTYPE_ARM64_32_V8:
2334 outs() << " cputype CPU_TYPE_ARM64_32\n";
2335 outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";
2336 break;
2337 default:
2338 printUnknownCPUType(cputype, cpusubtype);
2339 break;
2341 break;
2342 default:
2343 printUnknownCPUType(cputype, cpusubtype);
2344 break;
2348 static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
2349 bool verbose) {
2350 outs() << "Fat headers\n";
2351 if (verbose) {
2352 if (UB->getMagic() == MachO::FAT_MAGIC)
2353 outs() << "fat_magic FAT_MAGIC\n";
2354 else // UB->getMagic() == MachO::FAT_MAGIC_64
2355 outs() << "fat_magic FAT_MAGIC_64\n";
2356 } else
2357 outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";
2359 uint32_t nfat_arch = UB->getNumberOfObjects();
2360 StringRef Buf = UB->getData();
2361 uint64_t size = Buf.size();
2362 uint64_t big_size = sizeof(struct MachO::fat_header) +
2363 nfat_arch * sizeof(struct MachO::fat_arch);
2364 outs() << "nfat_arch " << UB->getNumberOfObjects();
2365 if (nfat_arch == 0)
2366 outs() << " (malformed, contains zero architecture types)\n";
2367 else if (big_size > size)
2368 outs() << " (malformed, architectures past end of file)\n";
2369 else
2370 outs() << "\n";
2372 for (uint32_t i = 0; i < nfat_arch; ++i) {
2373 MachOUniversalBinary::ObjectForArch OFA(UB, i);
2374 uint32_t cputype = OFA.getCPUType();
2375 uint32_t cpusubtype = OFA.getCPUSubType();
2376 outs() << "architecture ";
2377 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
2378 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
2379 uint32_t other_cputype = other_OFA.getCPUType();
2380 uint32_t other_cpusubtype = other_OFA.getCPUSubType();
2381 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
2382 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
2383 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
2384 outs() << "(illegal duplicate architecture) ";
2385 break;
2388 if (verbose) {
2389 outs() << OFA.getArchFlagName() << "\n";
2390 printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
2391 } else {
2392 outs() << i << "\n";
2393 outs() << " cputype " << cputype << "\n";
2394 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
2395 << "\n";
2397 if (verbose && cputype == MachO::CPU_TYPE_ARM64 &&
2398 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {
2399 outs() << " capabilities CPU_SUBTYPE_ARM64E_";
2400 if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype))
2401 outs() << "KERNEL_";
2402 outs() << format("PTRAUTH_VERSION %d",
2403 MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype))
2404 << "\n";
2405 } else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
2406 MachO::CPU_SUBTYPE_LIB64)
2407 outs() << " capabilities CPU_SUBTYPE_LIB64\n";
2408 else
2409 outs() << " capabilities "
2410 << format("0x%" PRIx32,
2411 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
2412 outs() << " offset " << OFA.getOffset();
2413 if (OFA.getOffset() > size)
2414 outs() << " (past end of file)";
2415 if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)
2416 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
2417 outs() << "\n";
2418 outs() << " size " << OFA.getSize();
2419 big_size = OFA.getOffset() + OFA.getSize();
2420 if (big_size > size)
2421 outs() << " (past end of file)";
2422 outs() << "\n";
2423 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
2424 << ")\n";
2428 static void printArchiveChild(StringRef Filename, const Archive::Child &C,
2429 size_t ChildIndex, bool verbose,
2430 bool print_offset,
2431 StringRef ArchitectureName = StringRef()) {
2432 if (print_offset)
2433 outs() << C.getChildOffset() << "\t";
2434 sys::fs::perms Mode =
2435 unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex),
2436 Filename, ArchitectureName);
2437 if (verbose) {
2438 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
2439 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
2440 outs() << "-";
2441 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
2442 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
2443 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
2444 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
2445 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
2446 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
2447 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
2448 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
2449 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
2450 } else {
2451 outs() << format("0%o ", Mode);
2454 outs() << format("%3d/%-3d %5" PRId64 " ",
2455 unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex),
2456 Filename, ArchitectureName),
2457 unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex),
2458 Filename, ArchitectureName),
2459 unwrapOrError(C.getRawSize(),
2460 getFileNameForError(C, ChildIndex), Filename,
2461 ArchitectureName));
2463 StringRef RawLastModified = C.getRawLastModified();
2464 if (verbose) {
2465 unsigned Seconds;
2466 if (RawLastModified.getAsInteger(10, Seconds))
2467 outs() << "(date: \"" << RawLastModified
2468 << "\" contains non-decimal chars) ";
2469 else {
2470 // Since cime(3) returns a 26 character string of the form:
2471 // "Sun Sep 16 01:03:52 1973\n\0"
2472 // just print 24 characters.
2473 time_t t = Seconds;
2474 outs() << format("%.24s ", ctime(&t));
2476 } else {
2477 outs() << RawLastModified << " ";
2480 if (verbose) {
2481 Expected<StringRef> NameOrErr = C.getName();
2482 if (!NameOrErr) {
2483 consumeError(NameOrErr.takeError());
2484 outs() << unwrapOrError(C.getRawName(),
2485 getFileNameForError(C, ChildIndex), Filename,
2486 ArchitectureName)
2487 << "\n";
2488 } else {
2489 StringRef Name = NameOrErr.get();
2490 outs() << Name << "\n";
2492 } else {
2493 outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex),
2494 Filename, ArchitectureName)
2495 << "\n";
2499 static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
2500 bool print_offset,
2501 StringRef ArchitectureName = StringRef()) {
2502 Error Err = Error::success();
2503 size_t I = 0;
2504 for (const auto &C : A->children(Err, false))
2505 printArchiveChild(Filename, C, I++, verbose, print_offset,
2506 ArchitectureName);
2508 if (Err)
2509 reportError(std::move(Err), Filename, "", ArchitectureName);
2512 static bool ValidateArchFlags() {
2513 // Check for -arch all and verifiy the -arch flags are valid.
2514 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2515 if (ArchFlags[i] == "all") {
2516 ArchAll = true;
2517 } else {
2518 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
2519 WithColor::error(errs(), "llvm-objdump")
2520 << "unknown architecture named '" + ArchFlags[i] +
2521 "'for the -arch option\n";
2522 return false;
2526 return true;
2529 // ParseInputMachO() parses the named Mach-O file in Filename and handles the
2530 // -arch flags selecting just those slices as specified by them and also parses
2531 // archive files. Then for each individual Mach-O file ProcessMachO() is
2532 // called to process the file based on the command line options.
2533 void objdump::parseInputMachO(StringRef Filename) {
2534 if (!ValidateArchFlags())
2535 return;
2537 // Attempt to open the binary.
2538 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
2539 if (!BinaryOrErr) {
2540 if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
2541 reportError(std::move(E), Filename);
2542 else
2543 outs() << Filename << ": is not an object file\n";
2544 return;
2546 Binary &Bin = *BinaryOrErr.get().getBinary();
2548 if (Archive *A = dyn_cast<Archive>(&Bin)) {
2549 outs() << "Archive : " << Filename << "\n";
2550 if (ArchiveHeaders)
2551 printArchiveHeaders(Filename, A, Verbose, ArchiveMemberOffsets);
2553 Error Err = Error::success();
2554 unsigned I = -1;
2555 for (auto &C : A->children(Err)) {
2556 ++I;
2557 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2558 if (!ChildOrErr) {
2559 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2560 reportError(std::move(E), getFileNameForError(C, I), Filename);
2561 continue;
2563 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2564 if (!checkMachOAndArchFlags(O, Filename))
2565 return;
2566 ProcessMachO(Filename, O, O->getFileName());
2569 if (Err)
2570 reportError(std::move(Err), Filename);
2571 return;
2573 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
2574 parseInputMachO(UB);
2575 return;
2577 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
2578 if (!checkMachOAndArchFlags(O, Filename))
2579 return;
2580 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))
2581 ProcessMachO(Filename, MachOOF);
2582 else
2583 WithColor::error(errs(), "llvm-objdump")
2584 << Filename << "': "
2585 << "object is not a Mach-O file type.\n";
2586 return;
2588 llvm_unreachable("Input object can't be invalid at this point");
2591 void objdump::parseInputMachO(MachOUniversalBinary *UB) {
2592 if (!ValidateArchFlags())
2593 return;
2595 auto Filename = UB->getFileName();
2597 if (UniversalHeaders)
2598 printMachOUniversalHeaders(UB, Verbose);
2600 // If we have a list of architecture flags specified dump only those.
2601 if (!ArchAll && !ArchFlags.empty()) {
2602 // Look for a slice in the universal binary that matches each ArchFlag.
2603 bool ArchFound;
2604 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2605 ArchFound = false;
2606 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2607 E = UB->end_objects();
2608 I != E; ++I) {
2609 if (ArchFlags[i] == I->getArchFlagName()) {
2610 ArchFound = true;
2611 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2612 I->getAsObjectFile();
2613 std::string ArchitectureName;
2614 if (ArchFlags.size() > 1)
2615 ArchitectureName = I->getArchFlagName();
2616 if (ObjOrErr) {
2617 ObjectFile &O = *ObjOrErr.get();
2618 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2619 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2620 } else if (Error E = isNotObjectErrorInvalidFileType(
2621 ObjOrErr.takeError())) {
2622 reportError(std::move(E), "", Filename, ArchitectureName);
2623 continue;
2624 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2625 I->getAsArchive()) {
2626 std::unique_ptr<Archive> &A = *AOrErr;
2627 outs() << "Archive : " << Filename;
2628 if (!ArchitectureName.empty())
2629 outs() << " (architecture " << ArchitectureName << ")";
2630 outs() << "\n";
2631 if (ArchiveHeaders)
2632 printArchiveHeaders(Filename, A.get(), Verbose,
2633 ArchiveMemberOffsets, ArchitectureName);
2634 Error Err = Error::success();
2635 unsigned I = -1;
2636 for (auto &C : A->children(Err)) {
2637 ++I;
2638 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2639 if (!ChildOrErr) {
2640 if (Error E =
2641 isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2642 reportError(std::move(E), getFileNameForError(C, I), Filename,
2643 ArchitectureName);
2644 continue;
2646 if (MachOObjectFile *O =
2647 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2648 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
2650 if (Err)
2651 reportError(std::move(Err), Filename);
2652 } else {
2653 consumeError(AOrErr.takeError());
2654 reportError(Filename,
2655 "Mach-O universal file for architecture " +
2656 StringRef(I->getArchFlagName()) +
2657 " is not a Mach-O file or an archive file");
2661 if (!ArchFound) {
2662 WithColor::error(errs(), "llvm-objdump")
2663 << "file: " + Filename + " does not contain "
2664 << "architecture: " + ArchFlags[i] + "\n";
2665 return;
2668 return;
2670 // No architecture flags were specified so if this contains a slice that
2671 // matches the host architecture dump only that.
2672 if (!ArchAll) {
2673 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2674 E = UB->end_objects();
2675 I != E; ++I) {
2676 if (MachOObjectFile::getHostArch().getArchName() ==
2677 I->getArchFlagName()) {
2678 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2679 std::string ArchiveName;
2680 ArchiveName.clear();
2681 if (ObjOrErr) {
2682 ObjectFile &O = *ObjOrErr.get();
2683 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2684 ProcessMachO(Filename, MachOOF);
2685 } else if (Error E =
2686 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2687 reportError(std::move(E), Filename);
2688 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2689 I->getAsArchive()) {
2690 std::unique_ptr<Archive> &A = *AOrErr;
2691 outs() << "Archive : " << Filename << "\n";
2692 if (ArchiveHeaders)
2693 printArchiveHeaders(Filename, A.get(), Verbose,
2694 ArchiveMemberOffsets);
2695 Error Err = Error::success();
2696 unsigned I = -1;
2697 for (auto &C : A->children(Err)) {
2698 ++I;
2699 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2700 if (!ChildOrErr) {
2701 if (Error E =
2702 isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2703 reportError(std::move(E), getFileNameForError(C, I), Filename);
2704 continue;
2706 if (MachOObjectFile *O =
2707 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2708 ProcessMachO(Filename, O, O->getFileName());
2710 if (Err)
2711 reportError(std::move(Err), Filename);
2712 } else {
2713 consumeError(AOrErr.takeError());
2714 reportError(Filename, "Mach-O universal file for architecture " +
2715 StringRef(I->getArchFlagName()) +
2716 " is not a Mach-O file or an archive file");
2718 return;
2722 // Either all architectures have been specified or none have been specified
2723 // and this does not contain the host architecture so dump all the slices.
2724 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
2725 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2726 E = UB->end_objects();
2727 I != E; ++I) {
2728 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2729 std::string ArchitectureName;
2730 if (moreThanOneArch)
2731 ArchitectureName = I->getArchFlagName();
2732 if (ObjOrErr) {
2733 ObjectFile &Obj = *ObjOrErr.get();
2734 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
2735 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2736 } else if (Error E =
2737 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2738 reportError(std::move(E), Filename, "", ArchitectureName);
2739 } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
2740 std::unique_ptr<Archive> &A = *AOrErr;
2741 outs() << "Archive : " << Filename;
2742 if (!ArchitectureName.empty())
2743 outs() << " (architecture " << ArchitectureName << ")";
2744 outs() << "\n";
2745 if (ArchiveHeaders)
2746 printArchiveHeaders(Filename, A.get(), Verbose, ArchiveMemberOffsets,
2747 ArchitectureName);
2748 Error Err = Error::success();
2749 unsigned I = -1;
2750 for (auto &C : A->children(Err)) {
2751 ++I;
2752 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2753 if (!ChildOrErr) {
2754 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2755 reportError(std::move(E), getFileNameForError(C, I), Filename,
2756 ArchitectureName);
2757 continue;
2759 if (MachOObjectFile *O =
2760 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2761 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
2762 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
2763 ArchitectureName);
2766 if (Err)
2767 reportError(std::move(Err), Filename);
2768 } else {
2769 consumeError(AOrErr.takeError());
2770 reportError(Filename, "Mach-O universal file for architecture " +
2771 StringRef(I->getArchFlagName()) +
2772 " is not a Mach-O file or an archive file");
2777 namespace {
2778 // The block of info used by the Symbolizer call backs.
2779 struct DisassembleInfo {
2780 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2781 std::vector<SectionRef> *Sections, bool verbose)
2782 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
2783 bool verbose;
2784 MachOObjectFile *O;
2785 SectionRef S;
2786 SymbolAddressMap *AddrMap;
2787 std::vector<SectionRef> *Sections;
2788 const char *class_name = nullptr;
2789 const char *selector_name = nullptr;
2790 std::unique_ptr<char[]> method = nullptr;
2791 char *demangled_name = nullptr;
2792 uint64_t adrp_addr = 0;
2793 uint32_t adrp_inst = 0;
2794 std::unique_ptr<SymbolAddressMap> bindtable;
2795 uint32_t depth = 0;
2797 } // namespace
2799 // SymbolizerGetOpInfo() is the operand information call back function.
2800 // This is called to get the symbolic information for operand(s) of an
2801 // instruction when it is being done. This routine does this from
2802 // the relocation information, symbol table, etc. That block of information
2803 // is a pointer to the struct DisassembleInfo that was passed when the
2804 // disassembler context was created and passed to back to here when
2805 // called back by the disassembler for instruction operands that could have
2806 // relocation information. The address of the instruction containing operand is
2807 // at the Pc parameter. The immediate value the operand has is passed in
2808 // op_info->Value and is at Offset past the start of the instruction and has a
2809 // byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2810 // LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2811 // names and addends of the symbolic expression to add for the operand. The
2812 // value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2813 // information is returned then this function returns 1 else it returns 0.
2814 static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2815 uint64_t OpSize, uint64_t InstSize, int TagType,
2816 void *TagBuf) {
2817 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2818 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
2819 uint64_t value = op_info->Value;
2821 // Make sure all fields returned are zero if we don't set them.
2822 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
2823 op_info->Value = value;
2825 // If the TagType is not the value 1 which it code knows about or if no
2826 // verbose symbolic information is wanted then just return 0, indicating no
2827 // information is being returned.
2828 if (TagType != 1 || !info->verbose)
2829 return 0;
2831 unsigned int Arch = info->O->getArch();
2832 if (Arch == Triple::x86) {
2833 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2834 return 0;
2835 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2836 // TODO:
2837 // Search the external relocation entries of a fully linked image
2838 // (if any) for an entry that matches this segment offset.
2839 // uint32_t seg_offset = (Pc + Offset);
2840 return 0;
2842 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2843 // for an entry for this section offset.
2844 uint32_t sect_addr = info->S.getAddress();
2845 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2846 bool reloc_found = false;
2847 DataRefImpl Rel;
2848 MachO::any_relocation_info RE;
2849 bool isExtern = false;
2850 SymbolRef Symbol;
2851 bool r_scattered = false;
2852 uint32_t r_value, pair_r_value, r_type;
2853 for (const RelocationRef &Reloc : info->S.relocations()) {
2854 uint64_t RelocOffset = Reloc.getOffset();
2855 if (RelocOffset == sect_offset) {
2856 Rel = Reloc.getRawDataRefImpl();
2857 RE = info->O->getRelocation(Rel);
2858 r_type = info->O->getAnyRelocationType(RE);
2859 r_scattered = info->O->isRelocationScattered(RE);
2860 if (r_scattered) {
2861 r_value = info->O->getScatteredRelocationValue(RE);
2862 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2863 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2864 DataRefImpl RelNext = Rel;
2865 info->O->moveRelocationNext(RelNext);
2866 MachO::any_relocation_info RENext;
2867 RENext = info->O->getRelocation(RelNext);
2868 if (info->O->isRelocationScattered(RENext))
2869 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2870 else
2871 return 0;
2873 } else {
2874 isExtern = info->O->getPlainRelocationExternal(RE);
2875 if (isExtern) {
2876 symbol_iterator RelocSym = Reloc.getSymbol();
2877 Symbol = *RelocSym;
2880 reloc_found = true;
2881 break;
2884 if (reloc_found && isExtern) {
2885 op_info->AddSymbol.Present = 1;
2886 op_info->AddSymbol.Name =
2887 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2888 // For i386 extern relocation entries the value in the instruction is
2889 // the offset from the symbol, and value is already set in op_info->Value.
2890 return 1;
2892 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2893 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
2894 const char *add = GuessSymbolName(r_value, info->AddrMap);
2895 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2896 uint32_t offset = value - (r_value - pair_r_value);
2897 op_info->AddSymbol.Present = 1;
2898 if (add != nullptr)
2899 op_info->AddSymbol.Name = add;
2900 else
2901 op_info->AddSymbol.Value = r_value;
2902 op_info->SubtractSymbol.Present = 1;
2903 if (sub != nullptr)
2904 op_info->SubtractSymbol.Name = sub;
2905 else
2906 op_info->SubtractSymbol.Value = pair_r_value;
2907 op_info->Value = offset;
2908 return 1;
2910 return 0;
2912 if (Arch == Triple::x86_64) {
2913 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2914 return 0;
2915 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2916 // relocation entries of a linked image (if any) for an entry that matches
2917 // this segment offset.
2918 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2919 uint64_t seg_offset = Pc + Offset;
2920 bool reloc_found = false;
2921 DataRefImpl Rel;
2922 MachO::any_relocation_info RE;
2923 bool isExtern = false;
2924 SymbolRef Symbol;
2925 for (const RelocationRef &Reloc : info->O->external_relocations()) {
2926 uint64_t RelocOffset = Reloc.getOffset();
2927 if (RelocOffset == seg_offset) {
2928 Rel = Reloc.getRawDataRefImpl();
2929 RE = info->O->getRelocation(Rel);
2930 // external relocation entries should always be external.
2931 isExtern = info->O->getPlainRelocationExternal(RE);
2932 if (isExtern) {
2933 symbol_iterator RelocSym = Reloc.getSymbol();
2934 Symbol = *RelocSym;
2936 reloc_found = true;
2937 break;
2940 if (reloc_found && isExtern) {
2941 // The Value passed in will be adjusted by the Pc if the instruction
2942 // adds the Pc. But for x86_64 external relocation entries the Value
2943 // is the offset from the external symbol.
2944 if (info->O->getAnyRelocationPCRel(RE))
2945 op_info->Value -= Pc + InstSize;
2946 const char *name =
2947 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2948 op_info->AddSymbol.Present = 1;
2949 op_info->AddSymbol.Name = name;
2950 return 1;
2952 return 0;
2954 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2955 // for an entry for this section offset.
2956 uint64_t sect_addr = info->S.getAddress();
2957 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2958 bool reloc_found = false;
2959 DataRefImpl Rel;
2960 MachO::any_relocation_info RE;
2961 bool isExtern = false;
2962 SymbolRef Symbol;
2963 for (const RelocationRef &Reloc : info->S.relocations()) {
2964 uint64_t RelocOffset = Reloc.getOffset();
2965 if (RelocOffset == sect_offset) {
2966 Rel = Reloc.getRawDataRefImpl();
2967 RE = info->O->getRelocation(Rel);
2968 // NOTE: Scattered relocations don't exist on x86_64.
2969 isExtern = info->O->getPlainRelocationExternal(RE);
2970 if (isExtern) {
2971 symbol_iterator RelocSym = Reloc.getSymbol();
2972 Symbol = *RelocSym;
2974 reloc_found = true;
2975 break;
2978 if (reloc_found && isExtern) {
2979 // The Value passed in will be adjusted by the Pc if the instruction
2980 // adds the Pc. But for x86_64 external relocation entries the Value
2981 // is the offset from the external symbol.
2982 if (info->O->getAnyRelocationPCRel(RE))
2983 op_info->Value -= Pc + InstSize;
2984 const char *name =
2985 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2986 unsigned Type = info->O->getAnyRelocationType(RE);
2987 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2988 DataRefImpl RelNext = Rel;
2989 info->O->moveRelocationNext(RelNext);
2990 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2991 unsigned TypeNext = info->O->getAnyRelocationType(RENext);
2992 bool isExternNext = info->O->getPlainRelocationExternal(RENext);
2993 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
2994 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
2995 op_info->SubtractSymbol.Present = 1;
2996 op_info->SubtractSymbol.Name = name;
2997 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
2998 Symbol = *RelocSymNext;
2999 name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
3002 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
3003 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
3004 op_info->AddSymbol.Present = 1;
3005 op_info->AddSymbol.Name = name;
3006 return 1;
3008 return 0;
3010 if (Arch == Triple::arm) {
3011 if (Offset != 0 || (InstSize != 4 && InstSize != 2))
3012 return 0;
3013 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3014 // TODO:
3015 // Search the external relocation entries of a fully linked image
3016 // (if any) for an entry that matches this segment offset.
3017 // uint32_t seg_offset = (Pc + Offset);
3018 return 0;
3020 // In MH_OBJECT filetypes search the section's relocation entries (if any)
3021 // for an entry for this section offset.
3022 uint32_t sect_addr = info->S.getAddress();
3023 uint32_t sect_offset = (Pc + Offset) - sect_addr;
3024 DataRefImpl Rel;
3025 MachO::any_relocation_info RE;
3026 bool isExtern = false;
3027 SymbolRef Symbol;
3028 bool r_scattered = false;
3029 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
3030 auto Reloc =
3031 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
3032 uint64_t RelocOffset = Reloc.getOffset();
3033 return RelocOffset == sect_offset;
3036 if (Reloc == info->S.relocations().end())
3037 return 0;
3039 Rel = Reloc->getRawDataRefImpl();
3040 RE = info->O->getRelocation(Rel);
3041 r_length = info->O->getAnyRelocationLength(RE);
3042 r_scattered = info->O->isRelocationScattered(RE);
3043 if (r_scattered) {
3044 r_value = info->O->getScatteredRelocationValue(RE);
3045 r_type = info->O->getScatteredRelocationType(RE);
3046 } else {
3047 r_type = info->O->getAnyRelocationType(RE);
3048 isExtern = info->O->getPlainRelocationExternal(RE);
3049 if (isExtern) {
3050 symbol_iterator RelocSym = Reloc->getSymbol();
3051 Symbol = *RelocSym;
3054 if (r_type == MachO::ARM_RELOC_HALF ||
3055 r_type == MachO::ARM_RELOC_SECTDIFF ||
3056 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
3057 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3058 DataRefImpl RelNext = Rel;
3059 info->O->moveRelocationNext(RelNext);
3060 MachO::any_relocation_info RENext;
3061 RENext = info->O->getRelocation(RelNext);
3062 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
3063 if (info->O->isRelocationScattered(RENext))
3064 pair_r_value = info->O->getScatteredRelocationValue(RENext);
3067 if (isExtern) {
3068 const char *name =
3069 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
3070 op_info->AddSymbol.Present = 1;
3071 op_info->AddSymbol.Name = name;
3072 switch (r_type) {
3073 case MachO::ARM_RELOC_HALF:
3074 if ((r_length & 0x1) == 1) {
3075 op_info->Value = value << 16 | other_half;
3076 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3077 } else {
3078 op_info->Value = other_half << 16 | value;
3079 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3081 break;
3082 default:
3083 break;
3085 return 1;
3087 // If we have a branch that is not an external relocation entry then
3088 // return 0 so the code in tryAddingSymbolicOperand() can use the
3089 // SymbolLookUp call back with the branch target address to look up the
3090 // symbol and possibility add an annotation for a symbol stub.
3091 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
3092 r_type == MachO::ARM_THUMB_RELOC_BR22))
3093 return 0;
3095 uint32_t offset = 0;
3096 if (r_type == MachO::ARM_RELOC_HALF ||
3097 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3098 if ((r_length & 0x1) == 1)
3099 value = value << 16 | other_half;
3100 else
3101 value = other_half << 16 | value;
3103 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
3104 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
3105 offset = value - r_value;
3106 value = r_value;
3109 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3110 if ((r_length & 0x1) == 1)
3111 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3112 else
3113 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3114 const char *add = GuessSymbolName(r_value, info->AddrMap);
3115 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
3116 int32_t offset = value - (r_value - pair_r_value);
3117 op_info->AddSymbol.Present = 1;
3118 if (add != nullptr)
3119 op_info->AddSymbol.Name = add;
3120 else
3121 op_info->AddSymbol.Value = r_value;
3122 op_info->SubtractSymbol.Present = 1;
3123 if (sub != nullptr)
3124 op_info->SubtractSymbol.Name = sub;
3125 else
3126 op_info->SubtractSymbol.Value = pair_r_value;
3127 op_info->Value = offset;
3128 return 1;
3131 op_info->AddSymbol.Present = 1;
3132 op_info->Value = offset;
3133 if (r_type == MachO::ARM_RELOC_HALF) {
3134 if ((r_length & 0x1) == 1)
3135 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3136 else
3137 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3139 const char *add = GuessSymbolName(value, info->AddrMap);
3140 if (add != nullptr) {
3141 op_info->AddSymbol.Name = add;
3142 return 1;
3144 op_info->AddSymbol.Value = value;
3145 return 1;
3147 if (Arch == Triple::aarch64) {
3148 if (Offset != 0 || InstSize != 4)
3149 return 0;
3150 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3151 // TODO:
3152 // Search the external relocation entries of a fully linked image
3153 // (if any) for an entry that matches this segment offset.
3154 // uint64_t seg_offset = (Pc + Offset);
3155 return 0;
3157 // In MH_OBJECT filetypes search the section's relocation entries (if any)
3158 // for an entry for this section offset.
3159 uint64_t sect_addr = info->S.getAddress();
3160 uint64_t sect_offset = (Pc + Offset) - sect_addr;
3161 auto Reloc =
3162 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
3163 uint64_t RelocOffset = Reloc.getOffset();
3164 return RelocOffset == sect_offset;
3167 if (Reloc == info->S.relocations().end())
3168 return 0;
3170 DataRefImpl Rel = Reloc->getRawDataRefImpl();
3171 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
3172 uint32_t r_type = info->O->getAnyRelocationType(RE);
3173 if (r_type == MachO::ARM64_RELOC_ADDEND) {
3174 DataRefImpl RelNext = Rel;
3175 info->O->moveRelocationNext(RelNext);
3176 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
3177 if (value == 0) {
3178 value = info->O->getPlainRelocationSymbolNum(RENext);
3179 op_info->Value = value;
3182 // NOTE: Scattered relocations don't exist on arm64.
3183 if (!info->O->getPlainRelocationExternal(RE))
3184 return 0;
3185 const char *name =
3186 unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())
3187 .data();
3188 op_info->AddSymbol.Present = 1;
3189 op_info->AddSymbol.Name = name;
3191 switch (r_type) {
3192 case MachO::ARM64_RELOC_PAGE21:
3193 /* @page */
3194 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
3195 break;
3196 case MachO::ARM64_RELOC_PAGEOFF12:
3197 /* @pageoff */
3198 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
3199 break;
3200 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
3201 /* @gotpage */
3202 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
3203 break;
3204 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
3205 /* @gotpageoff */
3206 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
3207 break;
3208 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
3209 /* @tvlppage is not implemented in llvm-mc */
3210 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
3211 break;
3212 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
3213 /* @tvlppageoff is not implemented in llvm-mc */
3214 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
3215 break;
3216 default:
3217 case MachO::ARM64_RELOC_BRANCH26:
3218 op_info->VariantKind = LLVMDisassembler_VariantKind_None;
3219 break;
3221 return 1;
3223 return 0;
3226 // GuessCstringPointer is passed the address of what might be a pointer to a
3227 // literal string in a cstring section. If that address is in a cstring section
3228 // it returns a pointer to that string. Else it returns nullptr.
3229 static const char *GuessCstringPointer(uint64_t ReferenceValue,
3230 struct DisassembleInfo *info) {
3231 for (const auto &Load : info->O->load_commands()) {
3232 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3233 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3234 for (unsigned J = 0; J < Seg.nsects; ++J) {
3235 MachO::section_64 Sec = info->O->getSection64(Load, J);
3236 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3237 if (section_type == MachO::S_CSTRING_LITERALS &&
3238 ReferenceValue >= Sec.addr &&
3239 ReferenceValue < Sec.addr + Sec.size) {
3240 uint64_t sect_offset = ReferenceValue - Sec.addr;
3241 uint64_t object_offset = Sec.offset + sect_offset;
3242 StringRef MachOContents = info->O->getData();
3243 uint64_t object_size = MachOContents.size();
3244 const char *object_addr = (const char *)MachOContents.data();
3245 if (object_offset < object_size) {
3246 const char *name = object_addr + object_offset;
3247 return name;
3248 } else {
3249 return nullptr;
3253 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
3254 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
3255 for (unsigned J = 0; J < Seg.nsects; ++J) {
3256 MachO::section Sec = info->O->getSection(Load, J);
3257 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3258 if (section_type == MachO::S_CSTRING_LITERALS &&
3259 ReferenceValue >= Sec.addr &&
3260 ReferenceValue < Sec.addr + Sec.size) {
3261 uint64_t sect_offset = ReferenceValue - Sec.addr;
3262 uint64_t object_offset = Sec.offset + sect_offset;
3263 StringRef MachOContents = info->O->getData();
3264 uint64_t object_size = MachOContents.size();
3265 const char *object_addr = (const char *)MachOContents.data();
3266 if (object_offset < object_size) {
3267 const char *name = object_addr + object_offset;
3268 return name;
3269 } else {
3270 return nullptr;
3276 return nullptr;
3279 // GuessIndirectSymbol returns the name of the indirect symbol for the
3280 // ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
3281 // an address of a symbol stub or a lazy or non-lazy pointer to associate the
3282 // symbol name being referenced by the stub or pointer.
3283 static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
3284 struct DisassembleInfo *info) {
3285 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
3286 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
3287 for (const auto &Load : info->O->load_commands()) {
3288 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3289 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3290 for (unsigned J = 0; J < Seg.nsects; ++J) {
3291 MachO::section_64 Sec = info->O->getSection64(Load, J);
3292 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3293 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3294 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3295 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3296 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3297 section_type == MachO::S_SYMBOL_STUBS) &&
3298 ReferenceValue >= Sec.addr &&
3299 ReferenceValue < Sec.addr + Sec.size) {
3300 uint32_t stride;
3301 if (section_type == MachO::S_SYMBOL_STUBS)
3302 stride = Sec.reserved2;
3303 else
3304 stride = 8;
3305 if (stride == 0)
3306 return nullptr;
3307 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3308 if (index < Dysymtab.nindirectsyms) {
3309 uint32_t indirect_symbol =
3310 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
3311 if (indirect_symbol < Symtab.nsyms) {
3312 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
3313 return unwrapOrError(Sym->getName(), info->O->getFileName())
3314 .data();
3319 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
3320 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
3321 for (unsigned J = 0; J < Seg.nsects; ++J) {
3322 MachO::section Sec = info->O->getSection(Load, J);
3323 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3324 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3325 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3326 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3327 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3328 section_type == MachO::S_SYMBOL_STUBS) &&
3329 ReferenceValue >= Sec.addr &&
3330 ReferenceValue < Sec.addr + Sec.size) {
3331 uint32_t stride;
3332 if (section_type == MachO::S_SYMBOL_STUBS)
3333 stride = Sec.reserved2;
3334 else
3335 stride = 4;
3336 if (stride == 0)
3337 return nullptr;
3338 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3339 if (index < Dysymtab.nindirectsyms) {
3340 uint32_t indirect_symbol =
3341 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
3342 if (indirect_symbol < Symtab.nsyms) {
3343 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
3344 return unwrapOrError(Sym->getName(), info->O->getFileName())
3345 .data();
3352 return nullptr;
3355 // method_reference() is called passing it the ReferenceName that might be
3356 // a reference it to an Objective-C method call. If so then it allocates and
3357 // assembles a method call string with the values last seen and saved in
3358 // the DisassembleInfo's class_name and selector_name fields. This is saved
3359 // into the method field of the info and any previous string is free'ed.
3360 // Then the class_name field in the info is set to nullptr. The method call
3361 // string is set into ReferenceName and ReferenceType is set to
3362 // LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
3363 // then both ReferenceType and ReferenceName are left unchanged.
3364 static void method_reference(struct DisassembleInfo *info,
3365 uint64_t *ReferenceType,
3366 const char **ReferenceName) {
3367 unsigned int Arch = info->O->getArch();
3368 if (*ReferenceName != nullptr) {
3369 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
3370 if (info->selector_name != nullptr) {
3371 if (info->class_name != nullptr) {
3372 info->method = std::make_unique<char[]>(
3373 5 + strlen(info->class_name) + strlen(info->selector_name));
3374 char *method = info->method.get();
3375 if (method != nullptr) {
3376 strcpy(method, "+[");
3377 strcat(method, info->class_name);
3378 strcat(method, " ");
3379 strcat(method, info->selector_name);
3380 strcat(method, "]");
3381 *ReferenceName = method;
3382 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3384 } else {
3385 info->method =
3386 std::make_unique<char[]>(9 + strlen(info->selector_name));
3387 char *method = info->method.get();
3388 if (method != nullptr) {
3389 if (Arch == Triple::x86_64)
3390 strcpy(method, "-[%rdi ");
3391 else if (Arch == Triple::aarch64)
3392 strcpy(method, "-[x0 ");
3393 else
3394 strcpy(method, "-[r? ");
3395 strcat(method, info->selector_name);
3396 strcat(method, "]");
3397 *ReferenceName = method;
3398 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3401 info->class_name = nullptr;
3403 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
3404 if (info->selector_name != nullptr) {
3405 info->method =
3406 std::make_unique<char[]>(17 + strlen(info->selector_name));
3407 char *method = info->method.get();
3408 if (method != nullptr) {
3409 if (Arch == Triple::x86_64)
3410 strcpy(method, "-[[%rdi super] ");
3411 else if (Arch == Triple::aarch64)
3412 strcpy(method, "-[[x0 super] ");
3413 else
3414 strcpy(method, "-[[r? super] ");
3415 strcat(method, info->selector_name);
3416 strcat(method, "]");
3417 *ReferenceName = method;
3418 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3420 info->class_name = nullptr;
3426 // GuessPointerPointer() is passed the address of what might be a pointer to
3427 // a reference to an Objective-C class, selector, message ref or cfstring.
3428 // If so the value of the pointer is returned and one of the booleans are set
3429 // to true. If not zero is returned and all the booleans are set to false.
3430 static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
3431 struct DisassembleInfo *info,
3432 bool &classref, bool &selref, bool &msgref,
3433 bool &cfstring) {
3434 classref = false;
3435 selref = false;
3436 msgref = false;
3437 cfstring = false;
3438 for (const auto &Load : info->O->load_commands()) {
3439 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3440 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3441 for (unsigned J = 0; J < Seg.nsects; ++J) {
3442 MachO::section_64 Sec = info->O->getSection64(Load, J);
3443 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
3444 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3445 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
3446 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
3447 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
3448 ReferenceValue >= Sec.addr &&
3449 ReferenceValue < Sec.addr + Sec.size) {
3450 uint64_t sect_offset = ReferenceValue - Sec.addr;
3451 uint64_t object_offset = Sec.offset + sect_offset;
3452 StringRef MachOContents = info->O->getData();
3453 uint64_t object_size = MachOContents.size();
3454 const char *object_addr = (const char *)MachOContents.data();
3455 if (object_offset < object_size) {
3456 uint64_t pointer_value;
3457 memcpy(&pointer_value, object_addr + object_offset,
3458 sizeof(uint64_t));
3459 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3460 sys::swapByteOrder(pointer_value);
3461 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
3462 selref = true;
3463 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3464 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
3465 classref = true;
3466 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
3467 ReferenceValue + 8 < Sec.addr + Sec.size) {
3468 msgref = true;
3469 memcpy(&pointer_value, object_addr + object_offset + 8,
3470 sizeof(uint64_t));
3471 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3472 sys::swapByteOrder(pointer_value);
3473 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
3474 cfstring = true;
3475 return pointer_value;
3476 } else {
3477 return 0;
3482 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
3484 return 0;
3487 // get_pointer_64 returns a pointer to the bytes in the object file at the
3488 // Address from a section in the Mach-O file. And indirectly returns the
3489 // offset into the section, number of bytes left in the section past the offset
3490 // and which section is was being referenced. If the Address is not in a
3491 // section nullptr is returned.
3492 static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
3493 uint32_t &left, SectionRef &S,
3494 DisassembleInfo *info,
3495 bool objc_only = false) {
3496 offset = 0;
3497 left = 0;
3498 S = SectionRef();
3499 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
3500 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
3501 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
3502 if (SectSize == 0)
3503 continue;
3504 if (objc_only) {
3505 StringRef SectName;
3506 Expected<StringRef> SecNameOrErr =
3507 ((*(info->Sections))[SectIdx]).getName();
3508 if (SecNameOrErr)
3509 SectName = *SecNameOrErr;
3510 else
3511 consumeError(SecNameOrErr.takeError());
3513 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
3514 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
3515 if (SegName != "__OBJC" && SectName != "__cstring")
3516 continue;
3518 if (Address >= SectAddress && Address < SectAddress + SectSize) {
3519 S = (*(info->Sections))[SectIdx];
3520 offset = Address - SectAddress;
3521 left = SectSize - offset;
3522 StringRef SectContents = unwrapOrError(
3523 ((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());
3524 return SectContents.data() + offset;
3527 return nullptr;
3530 static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
3531 uint32_t &left, SectionRef &S,
3532 DisassembleInfo *info,
3533 bool objc_only = false) {
3534 return get_pointer_64(Address, offset, left, S, info, objc_only);
3537 // get_symbol_64() returns the name of a symbol (or nullptr) and the address of
3538 // the symbol indirectly through n_value. Based on the relocation information
3539 // for the specified section offset in the specified section reference.
3540 // If no relocation information is found and a non-zero ReferenceValue for the
3541 // symbol is passed, look up that address in the info's AddrMap.
3542 static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
3543 DisassembleInfo *info, uint64_t &n_value,
3544 uint64_t ReferenceValue = 0) {
3545 n_value = 0;
3546 if (!info->verbose)
3547 return nullptr;
3549 // See if there is an external relocation entry at the sect_offset.
3550 bool reloc_found = false;
3551 DataRefImpl Rel;
3552 MachO::any_relocation_info RE;
3553 bool isExtern = false;
3554 SymbolRef Symbol;
3555 for (const RelocationRef &Reloc : S.relocations()) {
3556 uint64_t RelocOffset = Reloc.getOffset();
3557 if (RelocOffset == sect_offset) {
3558 Rel = Reloc.getRawDataRefImpl();
3559 RE = info->O->getRelocation(Rel);
3560 if (info->O->isRelocationScattered(RE))
3561 continue;
3562 isExtern = info->O->getPlainRelocationExternal(RE);
3563 if (isExtern) {
3564 symbol_iterator RelocSym = Reloc.getSymbol();
3565 Symbol = *RelocSym;
3567 reloc_found = true;
3568 break;
3571 // If there is an external relocation entry for a symbol in this section
3572 // at this section_offset then use that symbol's value for the n_value
3573 // and return its name.
3574 const char *SymbolName = nullptr;
3575 if (reloc_found && isExtern) {
3576 n_value = cantFail(Symbol.getValue());
3577 StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());
3578 if (!Name.empty()) {
3579 SymbolName = Name.data();
3580 return SymbolName;
3584 // TODO: For fully linked images, look through the external relocation
3585 // entries off the dynamic symtab command. For these the r_offset is from the
3586 // start of the first writeable segment in the Mach-O file. So the offset
3587 // to this section from that segment is passed to this routine by the caller,
3588 // as the database_offset. Which is the difference of the section's starting
3589 // address and the first writable segment.
3591 // NOTE: need add passing the database_offset to this routine.
3593 // We did not find an external relocation entry so look up the ReferenceValue
3594 // as an address of a symbol and if found return that symbol's name.
3595 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
3597 return SymbolName;
3600 static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3601 DisassembleInfo *info,
3602 uint32_t ReferenceValue) {
3603 uint64_t n_value64;
3604 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
3607 namespace {
3609 // These are structs in the Objective-C meta data and read to produce the
3610 // comments for disassembly. While these are part of the ABI they are no
3611 // public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
3612 // .
3614 // The cfstring object in a 64-bit Mach-O file.
3615 struct cfstring64_t {
3616 uint64_t isa; // class64_t * (64-bit pointer)
3617 uint64_t flags; // flag bits
3618 uint64_t characters; // char * (64-bit pointer)
3619 uint64_t length; // number of non-NULL characters in above
3622 // The class object in a 64-bit Mach-O file.
3623 struct class64_t {
3624 uint64_t isa; // class64_t * (64-bit pointer)
3625 uint64_t superclass; // class64_t * (64-bit pointer)
3626 uint64_t cache; // Cache (64-bit pointer)
3627 uint64_t vtable; // IMP * (64-bit pointer)
3628 uint64_t data; // class_ro64_t * (64-bit pointer)
3631 struct class32_t {
3632 uint32_t isa; /* class32_t * (32-bit pointer) */
3633 uint32_t superclass; /* class32_t * (32-bit pointer) */
3634 uint32_t cache; /* Cache (32-bit pointer) */
3635 uint32_t vtable; /* IMP * (32-bit pointer) */
3636 uint32_t data; /* class_ro32_t * (32-bit pointer) */
3639 struct class_ro64_t {
3640 uint32_t flags;
3641 uint32_t instanceStart;
3642 uint32_t instanceSize;
3643 uint32_t reserved;
3644 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3645 uint64_t name; // const char * (64-bit pointer)
3646 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3647 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3648 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3649 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3650 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3653 struct class_ro32_t {
3654 uint32_t flags;
3655 uint32_t instanceStart;
3656 uint32_t instanceSize;
3657 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3658 uint32_t name; /* const char * (32-bit pointer) */
3659 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3660 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3661 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3662 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3663 uint32_t baseProperties; /* const struct objc_property_list *
3664 (32-bit pointer) */
3667 /* Values for class_ro{64,32}_t->flags */
3668 #define RO_META (1 << 0)
3669 #define RO_ROOT (1 << 1)
3670 #define RO_HAS_CXX_STRUCTORS (1 << 2)
3672 /* Values for method_list{64,32}_t->entsize */
3673 #define ML_HAS_RELATIVE_PTRS (1 << 31)
3674 #define ML_ENTSIZE_MASK 0xFFFF
3676 struct method_list64_t {
3677 uint32_t entsize;
3678 uint32_t count;
3679 /* struct method64_t first; These structures follow inline */
3682 struct method_list32_t {
3683 uint32_t entsize;
3684 uint32_t count;
3685 /* struct method32_t first; These structures follow inline */
3688 struct method64_t {
3689 uint64_t name; /* SEL (64-bit pointer) */
3690 uint64_t types; /* const char * (64-bit pointer) */
3691 uint64_t imp; /* IMP (64-bit pointer) */
3694 struct method32_t {
3695 uint32_t name; /* SEL (32-bit pointer) */
3696 uint32_t types; /* const char * (32-bit pointer) */
3697 uint32_t imp; /* IMP (32-bit pointer) */
3700 struct method_relative_t {
3701 int32_t name; /* SEL (32-bit relative) */
3702 int32_t types; /* const char * (32-bit relative) */
3703 int32_t imp; /* IMP (32-bit relative) */
3706 struct protocol_list64_t {
3707 uint64_t count; /* uintptr_t (a 64-bit value) */
3708 /* struct protocol64_t * list[0]; These pointers follow inline */
3711 struct protocol_list32_t {
3712 uint32_t count; /* uintptr_t (a 32-bit value) */
3713 /* struct protocol32_t * list[0]; These pointers follow inline */
3716 struct protocol64_t {
3717 uint64_t isa; /* id * (64-bit pointer) */
3718 uint64_t name; /* const char * (64-bit pointer) */
3719 uint64_t protocols; /* struct protocol_list64_t *
3720 (64-bit pointer) */
3721 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3722 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3723 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3724 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3725 uint64_t instanceProperties; /* struct objc_property_list *
3726 (64-bit pointer) */
3729 struct protocol32_t {
3730 uint32_t isa; /* id * (32-bit pointer) */
3731 uint32_t name; /* const char * (32-bit pointer) */
3732 uint32_t protocols; /* struct protocol_list_t *
3733 (32-bit pointer) */
3734 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3735 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3736 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3737 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3738 uint32_t instanceProperties; /* struct objc_property_list *
3739 (32-bit pointer) */
3742 struct ivar_list64_t {
3743 uint32_t entsize;
3744 uint32_t count;
3745 /* struct ivar64_t first; These structures follow inline */
3748 struct ivar_list32_t {
3749 uint32_t entsize;
3750 uint32_t count;
3751 /* struct ivar32_t first; These structures follow inline */
3754 struct ivar64_t {
3755 uint64_t offset; /* uintptr_t * (64-bit pointer) */
3756 uint64_t name; /* const char * (64-bit pointer) */
3757 uint64_t type; /* const char * (64-bit pointer) */
3758 uint32_t alignment;
3759 uint32_t size;
3762 struct ivar32_t {
3763 uint32_t offset; /* uintptr_t * (32-bit pointer) */
3764 uint32_t name; /* const char * (32-bit pointer) */
3765 uint32_t type; /* const char * (32-bit pointer) */
3766 uint32_t alignment;
3767 uint32_t size;
3770 struct objc_property_list64 {
3771 uint32_t entsize;
3772 uint32_t count;
3773 /* struct objc_property64 first; These structures follow inline */
3776 struct objc_property_list32 {
3777 uint32_t entsize;
3778 uint32_t count;
3779 /* struct objc_property32 first; These structures follow inline */
3782 struct objc_property64 {
3783 uint64_t name; /* const char * (64-bit pointer) */
3784 uint64_t attributes; /* const char * (64-bit pointer) */
3787 struct objc_property32 {
3788 uint32_t name; /* const char * (32-bit pointer) */
3789 uint32_t attributes; /* const char * (32-bit pointer) */
3792 struct category64_t {
3793 uint64_t name; /* const char * (64-bit pointer) */
3794 uint64_t cls; /* struct class_t * (64-bit pointer) */
3795 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3796 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3797 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3798 uint64_t instanceProperties; /* struct objc_property_list *
3799 (64-bit pointer) */
3802 struct category32_t {
3803 uint32_t name; /* const char * (32-bit pointer) */
3804 uint32_t cls; /* struct class_t * (32-bit pointer) */
3805 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3806 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3807 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3808 uint32_t instanceProperties; /* struct objc_property_list *
3809 (32-bit pointer) */
3812 struct objc_image_info64 {
3813 uint32_t version;
3814 uint32_t flags;
3816 struct objc_image_info32 {
3817 uint32_t version;
3818 uint32_t flags;
3820 struct imageInfo_t {
3821 uint32_t version;
3822 uint32_t flags;
3824 /* masks for objc_image_info.flags */
3825 #define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
3826 #define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
3827 #define OBJC_IMAGE_IS_SIMULATED (1 << 5)
3828 #define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)
3830 struct message_ref64 {
3831 uint64_t imp; /* IMP (64-bit pointer) */
3832 uint64_t sel; /* SEL (64-bit pointer) */
3835 struct message_ref32 {
3836 uint32_t imp; /* IMP (32-bit pointer) */
3837 uint32_t sel; /* SEL (32-bit pointer) */
3840 // Objective-C 1 (32-bit only) meta data structs.
3842 struct objc_module_t {
3843 uint32_t version;
3844 uint32_t size;
3845 uint32_t name; /* char * (32-bit pointer) */
3846 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3849 struct objc_symtab_t {
3850 uint32_t sel_ref_cnt;
3851 uint32_t refs; /* SEL * (32-bit pointer) */
3852 uint16_t cls_def_cnt;
3853 uint16_t cat_def_cnt;
3854 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3857 struct objc_class_t {
3858 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3859 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3860 uint32_t name; /* const char * (32-bit pointer) */
3861 int32_t version;
3862 int32_t info;
3863 int32_t instance_size;
3864 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3865 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3866 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3867 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3870 #define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
3871 // class is not a metaclass
3872 #define CLS_CLASS 0x1
3873 // class is a metaclass
3874 #define CLS_META 0x2
3876 struct objc_category_t {
3877 uint32_t category_name; /* char * (32-bit pointer) */
3878 uint32_t class_name; /* char * (32-bit pointer) */
3879 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3880 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3881 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3884 struct objc_ivar_t {
3885 uint32_t ivar_name; /* char * (32-bit pointer) */
3886 uint32_t ivar_type; /* char * (32-bit pointer) */
3887 int32_t ivar_offset;
3890 struct objc_ivar_list_t {
3891 int32_t ivar_count;
3892 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
3895 struct objc_method_list_t {
3896 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3897 int32_t method_count;
3898 // struct objc_method_t method_list[1]; /* variable length structure */
3901 struct objc_method_t {
3902 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3903 uint32_t method_types; /* char * (32-bit pointer) */
3904 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3905 (32-bit pointer) */
3908 struct objc_protocol_list_t {
3909 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3910 int32_t count;
3911 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3912 // (32-bit pointer) */
3915 struct objc_protocol_t {
3916 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3917 uint32_t protocol_name; /* char * (32-bit pointer) */
3918 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3919 uint32_t instance_methods; /* struct objc_method_description_list *
3920 (32-bit pointer) */
3921 uint32_t class_methods; /* struct objc_method_description_list *
3922 (32-bit pointer) */
3925 struct objc_method_description_list_t {
3926 int32_t count;
3927 // struct objc_method_description_t list[1];
3930 struct objc_method_description_t {
3931 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3932 uint32_t types; /* char * (32-bit pointer) */
3935 inline void swapStruct(struct cfstring64_t &cfs) {
3936 sys::swapByteOrder(cfs.isa);
3937 sys::swapByteOrder(cfs.flags);
3938 sys::swapByteOrder(cfs.characters);
3939 sys::swapByteOrder(cfs.length);
3942 inline void swapStruct(struct class64_t &c) {
3943 sys::swapByteOrder(c.isa);
3944 sys::swapByteOrder(c.superclass);
3945 sys::swapByteOrder(c.cache);
3946 sys::swapByteOrder(c.vtable);
3947 sys::swapByteOrder(c.data);
3950 inline void swapStruct(struct class32_t &c) {
3951 sys::swapByteOrder(c.isa);
3952 sys::swapByteOrder(c.superclass);
3953 sys::swapByteOrder(c.cache);
3954 sys::swapByteOrder(c.vtable);
3955 sys::swapByteOrder(c.data);
3958 inline void swapStruct(struct class_ro64_t &cro) {
3959 sys::swapByteOrder(cro.flags);
3960 sys::swapByteOrder(cro.instanceStart);
3961 sys::swapByteOrder(cro.instanceSize);
3962 sys::swapByteOrder(cro.reserved);
3963 sys::swapByteOrder(cro.ivarLayout);
3964 sys::swapByteOrder(cro.name);
3965 sys::swapByteOrder(cro.baseMethods);
3966 sys::swapByteOrder(cro.baseProtocols);
3967 sys::swapByteOrder(cro.ivars);
3968 sys::swapByteOrder(cro.weakIvarLayout);
3969 sys::swapByteOrder(cro.baseProperties);
3972 inline void swapStruct(struct class_ro32_t &cro) {
3973 sys::swapByteOrder(cro.flags);
3974 sys::swapByteOrder(cro.instanceStart);
3975 sys::swapByteOrder(cro.instanceSize);
3976 sys::swapByteOrder(cro.ivarLayout);
3977 sys::swapByteOrder(cro.name);
3978 sys::swapByteOrder(cro.baseMethods);
3979 sys::swapByteOrder(cro.baseProtocols);
3980 sys::swapByteOrder(cro.ivars);
3981 sys::swapByteOrder(cro.weakIvarLayout);
3982 sys::swapByteOrder(cro.baseProperties);
3985 inline void swapStruct(struct method_list64_t &ml) {
3986 sys::swapByteOrder(ml.entsize);
3987 sys::swapByteOrder(ml.count);
3990 inline void swapStruct(struct method_list32_t &ml) {
3991 sys::swapByteOrder(ml.entsize);
3992 sys::swapByteOrder(ml.count);
3995 inline void swapStruct(struct method64_t &m) {
3996 sys::swapByteOrder(m.name);
3997 sys::swapByteOrder(m.types);
3998 sys::swapByteOrder(m.imp);
4001 inline void swapStruct(struct method32_t &m) {
4002 sys::swapByteOrder(m.name);
4003 sys::swapByteOrder(m.types);
4004 sys::swapByteOrder(m.imp);
4007 inline void swapStruct(struct method_relative_t &m) {
4008 sys::swapByteOrder(m.name);
4009 sys::swapByteOrder(m.types);
4010 sys::swapByteOrder(m.imp);
4013 inline void swapStruct(struct protocol_list64_t &pl) {
4014 sys::swapByteOrder(pl.count);
4017 inline void swapStruct(struct protocol_list32_t &pl) {
4018 sys::swapByteOrder(pl.count);
4021 inline void swapStruct(struct protocol64_t &p) {
4022 sys::swapByteOrder(p.isa);
4023 sys::swapByteOrder(p.name);
4024 sys::swapByteOrder(p.protocols);
4025 sys::swapByteOrder(p.instanceMethods);
4026 sys::swapByteOrder(p.classMethods);
4027 sys::swapByteOrder(p.optionalInstanceMethods);
4028 sys::swapByteOrder(p.optionalClassMethods);
4029 sys::swapByteOrder(p.instanceProperties);
4032 inline void swapStruct(struct protocol32_t &p) {
4033 sys::swapByteOrder(p.isa);
4034 sys::swapByteOrder(p.name);
4035 sys::swapByteOrder(p.protocols);
4036 sys::swapByteOrder(p.instanceMethods);
4037 sys::swapByteOrder(p.classMethods);
4038 sys::swapByteOrder(p.optionalInstanceMethods);
4039 sys::swapByteOrder(p.optionalClassMethods);
4040 sys::swapByteOrder(p.instanceProperties);
4043 inline void swapStruct(struct ivar_list64_t &il) {
4044 sys::swapByteOrder(il.entsize);
4045 sys::swapByteOrder(il.count);
4048 inline void swapStruct(struct ivar_list32_t &il) {
4049 sys::swapByteOrder(il.entsize);
4050 sys::swapByteOrder(il.count);
4053 inline void swapStruct(struct ivar64_t &i) {
4054 sys::swapByteOrder(i.offset);
4055 sys::swapByteOrder(i.name);
4056 sys::swapByteOrder(i.type);
4057 sys::swapByteOrder(i.alignment);
4058 sys::swapByteOrder(i.size);
4061 inline void swapStruct(struct ivar32_t &i) {
4062 sys::swapByteOrder(i.offset);
4063 sys::swapByteOrder(i.name);
4064 sys::swapByteOrder(i.type);
4065 sys::swapByteOrder(i.alignment);
4066 sys::swapByteOrder(i.size);
4069 inline void swapStruct(struct objc_property_list64 &pl) {
4070 sys::swapByteOrder(pl.entsize);
4071 sys::swapByteOrder(pl.count);
4074 inline void swapStruct(struct objc_property_list32 &pl) {
4075 sys::swapByteOrder(pl.entsize);
4076 sys::swapByteOrder(pl.count);
4079 inline void swapStruct(struct objc_property64 &op) {
4080 sys::swapByteOrder(op.name);
4081 sys::swapByteOrder(op.attributes);
4084 inline void swapStruct(struct objc_property32 &op) {
4085 sys::swapByteOrder(op.name);
4086 sys::swapByteOrder(op.attributes);
4089 inline void swapStruct(struct category64_t &c) {
4090 sys::swapByteOrder(c.name);
4091 sys::swapByteOrder(c.cls);
4092 sys::swapByteOrder(c.instanceMethods);
4093 sys::swapByteOrder(c.classMethods);
4094 sys::swapByteOrder(c.protocols);
4095 sys::swapByteOrder(c.instanceProperties);
4098 inline void swapStruct(struct category32_t &c) {
4099 sys::swapByteOrder(c.name);
4100 sys::swapByteOrder(c.cls);
4101 sys::swapByteOrder(c.instanceMethods);
4102 sys::swapByteOrder(c.classMethods);
4103 sys::swapByteOrder(c.protocols);
4104 sys::swapByteOrder(c.instanceProperties);
4107 inline void swapStruct(struct objc_image_info64 &o) {
4108 sys::swapByteOrder(o.version);
4109 sys::swapByteOrder(o.flags);
4112 inline void swapStruct(struct objc_image_info32 &o) {
4113 sys::swapByteOrder(o.version);
4114 sys::swapByteOrder(o.flags);
4117 inline void swapStruct(struct imageInfo_t &o) {
4118 sys::swapByteOrder(o.version);
4119 sys::swapByteOrder(o.flags);
4122 inline void swapStruct(struct message_ref64 &mr) {
4123 sys::swapByteOrder(mr.imp);
4124 sys::swapByteOrder(mr.sel);
4127 inline void swapStruct(struct message_ref32 &mr) {
4128 sys::swapByteOrder(mr.imp);
4129 sys::swapByteOrder(mr.sel);
4132 inline void swapStruct(struct objc_module_t &module) {
4133 sys::swapByteOrder(module.version);
4134 sys::swapByteOrder(module.size);
4135 sys::swapByteOrder(module.name);
4136 sys::swapByteOrder(module.symtab);
4139 inline void swapStruct(struct objc_symtab_t &symtab) {
4140 sys::swapByteOrder(symtab.sel_ref_cnt);
4141 sys::swapByteOrder(symtab.refs);
4142 sys::swapByteOrder(symtab.cls_def_cnt);
4143 sys::swapByteOrder(symtab.cat_def_cnt);
4146 inline void swapStruct(struct objc_class_t &objc_class) {
4147 sys::swapByteOrder(objc_class.isa);
4148 sys::swapByteOrder(objc_class.super_class);
4149 sys::swapByteOrder(objc_class.name);
4150 sys::swapByteOrder(objc_class.version);
4151 sys::swapByteOrder(objc_class.info);
4152 sys::swapByteOrder(objc_class.instance_size);
4153 sys::swapByteOrder(objc_class.ivars);
4154 sys::swapByteOrder(objc_class.methodLists);
4155 sys::swapByteOrder(objc_class.cache);
4156 sys::swapByteOrder(objc_class.protocols);
4159 inline void swapStruct(struct objc_category_t &objc_category) {
4160 sys::swapByteOrder(objc_category.category_name);
4161 sys::swapByteOrder(objc_category.class_name);
4162 sys::swapByteOrder(objc_category.instance_methods);
4163 sys::swapByteOrder(objc_category.class_methods);
4164 sys::swapByteOrder(objc_category.protocols);
4167 inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
4168 sys::swapByteOrder(objc_ivar_list.ivar_count);
4171 inline void swapStruct(struct objc_ivar_t &objc_ivar) {
4172 sys::swapByteOrder(objc_ivar.ivar_name);
4173 sys::swapByteOrder(objc_ivar.ivar_type);
4174 sys::swapByteOrder(objc_ivar.ivar_offset);
4177 inline void swapStruct(struct objc_method_list_t &method_list) {
4178 sys::swapByteOrder(method_list.obsolete);
4179 sys::swapByteOrder(method_list.method_count);
4182 inline void swapStruct(struct objc_method_t &method) {
4183 sys::swapByteOrder(method.method_name);
4184 sys::swapByteOrder(method.method_types);
4185 sys::swapByteOrder(method.method_imp);
4188 inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
4189 sys::swapByteOrder(protocol_list.next);
4190 sys::swapByteOrder(protocol_list.count);
4193 inline void swapStruct(struct objc_protocol_t &protocol) {
4194 sys::swapByteOrder(protocol.isa);
4195 sys::swapByteOrder(protocol.protocol_name);
4196 sys::swapByteOrder(protocol.protocol_list);
4197 sys::swapByteOrder(protocol.instance_methods);
4198 sys::swapByteOrder(protocol.class_methods);
4201 inline void swapStruct(struct objc_method_description_list_t &mdl) {
4202 sys::swapByteOrder(mdl.count);
4205 inline void swapStruct(struct objc_method_description_t &md) {
4206 sys::swapByteOrder(md.name);
4207 sys::swapByteOrder(md.types);
4210 } // namespace
4212 static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
4213 struct DisassembleInfo *info);
4215 // get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
4216 // to an Objective-C class and returns the class name. It is also passed the
4217 // address of the pointer, so when the pointer is zero as it can be in an .o
4218 // file, that is used to look for an external relocation entry with a symbol
4219 // name.
4220 static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
4221 uint64_t ReferenceValue,
4222 struct DisassembleInfo *info) {
4223 const char *r;
4224 uint32_t offset, left;
4225 SectionRef S;
4227 // The pointer_value can be 0 in an object file and have a relocation
4228 // entry for the class symbol at the ReferenceValue (the address of the
4229 // pointer).
4230 if (pointer_value == 0) {
4231 r = get_pointer_64(ReferenceValue, offset, left, S, info);
4232 if (r == nullptr || left < sizeof(uint64_t))
4233 return nullptr;
4234 uint64_t n_value;
4235 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
4236 if (symbol_name == nullptr)
4237 return nullptr;
4238 const char *class_name = strrchr(symbol_name, '$');
4239 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
4240 return class_name + 2;
4241 else
4242 return nullptr;
4245 // The case were the pointer_value is non-zero and points to a class defined
4246 // in this Mach-O file.
4247 r = get_pointer_64(pointer_value, offset, left, S, info);
4248 if (r == nullptr || left < sizeof(struct class64_t))
4249 return nullptr;
4250 struct class64_t c;
4251 memcpy(&c, r, sizeof(struct class64_t));
4252 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4253 swapStruct(c);
4254 if (c.data == 0)
4255 return nullptr;
4256 r = get_pointer_64(c.data, offset, left, S, info);
4257 if (r == nullptr || left < sizeof(struct class_ro64_t))
4258 return nullptr;
4259 struct class_ro64_t cro;
4260 memcpy(&cro, r, sizeof(struct class_ro64_t));
4261 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4262 swapStruct(cro);
4263 if (cro.name == 0)
4264 return nullptr;
4265 const char *name = get_pointer_64(cro.name, offset, left, S, info);
4266 return name;
4269 // get_objc2_64bit_cfstring_name is used for disassembly and is passed a
4270 // pointer to a cfstring and returns its name or nullptr.
4271 static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
4272 struct DisassembleInfo *info) {
4273 const char *r, *name;
4274 uint32_t offset, left;
4275 SectionRef S;
4276 struct cfstring64_t cfs;
4277 uint64_t cfs_characters;
4279 r = get_pointer_64(ReferenceValue, offset, left, S, info);
4280 if (r == nullptr || left < sizeof(struct cfstring64_t))
4281 return nullptr;
4282 memcpy(&cfs, r, sizeof(struct cfstring64_t));
4283 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4284 swapStruct(cfs);
4285 if (cfs.characters == 0) {
4286 uint64_t n_value;
4287 const char *symbol_name = get_symbol_64(
4288 offset + offsetof(struct cfstring64_t, characters), S, info, n_value);
4289 if (symbol_name == nullptr)
4290 return nullptr;
4291 cfs_characters = n_value;
4292 } else
4293 cfs_characters = cfs.characters;
4294 name = get_pointer_64(cfs_characters, offset, left, S, info);
4296 return name;
4299 // get_objc2_64bit_selref() is used for disassembly and is passed a the address
4300 // of a pointer to an Objective-C selector reference when the pointer value is
4301 // zero as in a .o file and is likely to have a external relocation entry with
4302 // who's symbol's n_value is the real pointer to the selector name. If that is
4303 // the case the real pointer to the selector name is returned else 0 is
4304 // returned
4305 static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
4306 struct DisassembleInfo *info) {
4307 uint32_t offset, left;
4308 SectionRef S;
4310 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
4311 if (r == nullptr || left < sizeof(uint64_t))
4312 return 0;
4313 uint64_t n_value;
4314 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
4315 if (symbol_name == nullptr)
4316 return 0;
4317 return n_value;
4320 static const SectionRef get_section(MachOObjectFile *O, const char *segname,
4321 const char *sectname) {
4322 for (const SectionRef &Section : O->sections()) {
4323 StringRef SectName;
4324 Expected<StringRef> SecNameOrErr = Section.getName();
4325 if (SecNameOrErr)
4326 SectName = *SecNameOrErr;
4327 else
4328 consumeError(SecNameOrErr.takeError());
4330 DataRefImpl Ref = Section.getRawDataRefImpl();
4331 StringRef SegName = O->getSectionFinalSegmentName(Ref);
4332 if (SegName == segname && SectName == sectname)
4333 return Section;
4335 return SectionRef();
4338 static void
4339 walk_pointer_list_64(const char *listname, const SectionRef S,
4340 MachOObjectFile *O, struct DisassembleInfo *info,
4341 void (*func)(uint64_t, struct DisassembleInfo *info)) {
4342 if (S == SectionRef())
4343 return;
4345 StringRef SectName;
4346 Expected<StringRef> SecNameOrErr = S.getName();
4347 if (SecNameOrErr)
4348 SectName = *SecNameOrErr;
4349 else
4350 consumeError(SecNameOrErr.takeError());
4352 DataRefImpl Ref = S.getRawDataRefImpl();
4353 StringRef SegName = O->getSectionFinalSegmentName(Ref);
4354 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4356 StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
4357 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
4359 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
4360 uint32_t left = S.getSize() - i;
4361 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
4362 uint64_t p = 0;
4363 memcpy(&p, Contents + i, size);
4364 if (i + sizeof(uint64_t) > S.getSize())
4365 outs() << listname << " list pointer extends past end of (" << SegName
4366 << "," << SectName << ") section\n";
4367 outs() << format("%016" PRIx64, S.getAddress() + i) << " ";
4369 if (O->isLittleEndian() != sys::IsLittleEndianHost)
4370 sys::swapByteOrder(p);
4372 uint64_t n_value = 0;
4373 const char *name = get_symbol_64(i, S, info, n_value, p);
4374 if (name == nullptr)
4375 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
4377 if (n_value != 0) {
4378 outs() << format("0x%" PRIx64, n_value);
4379 if (p != 0)
4380 outs() << " + " << format("0x%" PRIx64, p);
4381 } else
4382 outs() << format("0x%" PRIx64, p);
4383 if (name != nullptr)
4384 outs() << " " << name;
4385 outs() << "\n";
4387 p += n_value;
4388 if (func)
4389 func(p, info);
4393 static void
4394 walk_pointer_list_32(const char *listname, const SectionRef S,
4395 MachOObjectFile *O, struct DisassembleInfo *info,
4396 void (*func)(uint32_t, struct DisassembleInfo *info)) {
4397 if (S == SectionRef())
4398 return;
4400 StringRef SectName = unwrapOrError(S.getName(), O->getFileName());
4401 DataRefImpl Ref = S.getRawDataRefImpl();
4402 StringRef SegName = O->getSectionFinalSegmentName(Ref);
4403 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4405 StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
4406 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
4408 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
4409 uint32_t left = S.getSize() - i;
4410 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
4411 uint32_t p = 0;
4412 memcpy(&p, Contents + i, size);
4413 if (i + sizeof(uint32_t) > S.getSize())
4414 outs() << listname << " list pointer extends past end of (" << SegName
4415 << "," << SectName << ") section\n";
4416 uint32_t Address = S.getAddress() + i;
4417 outs() << format("%08" PRIx32, Address) << " ";
4419 if (O->isLittleEndian() != sys::IsLittleEndianHost)
4420 sys::swapByteOrder(p);
4421 outs() << format("0x%" PRIx32, p);
4423 const char *name = get_symbol_32(i, S, info, p);
4424 if (name != nullptr)
4425 outs() << " " << name;
4426 outs() << "\n";
4428 if (func)
4429 func(p, info);
4433 static void print_layout_map(const char *layout_map, uint32_t left) {
4434 if (layout_map == nullptr)
4435 return;
4436 outs() << " layout map: ";
4437 do {
4438 outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";
4439 left--;
4440 layout_map++;
4441 } while (*layout_map != '\0' && left != 0);
4442 outs() << "\n";
4445 static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
4446 uint32_t offset, left;
4447 SectionRef S;
4448 const char *layout_map;
4450 if (p == 0)
4451 return;
4452 layout_map = get_pointer_64(p, offset, left, S, info);
4453 print_layout_map(layout_map, left);
4456 static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
4457 uint32_t offset, left;
4458 SectionRef S;
4459 const char *layout_map;
4461 if (p == 0)
4462 return;
4463 layout_map = get_pointer_32(p, offset, left, S, info);
4464 print_layout_map(layout_map, left);
4467 static void print_relative_method_list(uint32_t structSizeAndFlags,
4468 uint32_t structCount, uint64_t p,
4469 struct DisassembleInfo *info,
4470 const char *indent,
4471 uint32_t pointerBits) {
4472 struct method_relative_t m;
4473 const char *r, *name;
4474 uint32_t offset, xoffset, left, i;
4475 SectionRef S, xS;
4477 assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&
4478 "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");
4480 outs() << indent << "\t\t entsize "
4481 << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";
4482 outs() << indent << "\t\t count " << structCount << "\n";
4484 for (i = 0; i < structCount; i++) {
4485 r = get_pointer_64(p, offset, left, S, info);
4486 memset(&m, '\0', sizeof(struct method_relative_t));
4487 if (left < sizeof(struct method_relative_t)) {
4488 memcpy(&m, r, left);
4489 outs() << indent << " (method_t extends past the end of the section)\n";
4490 } else
4491 memcpy(&m, r, sizeof(struct method_relative_t));
4492 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4493 swapStruct(m);
4495 outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4496 uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);
4497 uint64_t absNameRefVA = relNameRefVA + m.name;
4498 outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
4500 // since this is a relative list, absNameRefVA is the address of the
4501 // __objc_selrefs entry, so a pointer, not the actual name
4502 const char *nameRefPtr =
4503 get_pointer_64(absNameRefVA, xoffset, left, xS, info);
4504 if (nameRefPtr) {
4505 uint32_t pointerSize = pointerBits / CHAR_BIT;
4506 if (left < pointerSize)
4507 outs() << indent << " (nameRefPtr extends past the end of the section)";
4508 else {
4509 if (pointerSize == 64) {
4510 uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);
4511 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4512 sys::swapByteOrder(nameOff_64);
4513 name = get_pointer_64(nameOff_64, xoffset, left, xS, info);
4514 } else {
4515 uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);
4516 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4517 sys::swapByteOrder(nameOff_32);
4518 name = get_pointer_32(nameOff_32, xoffset, left, xS, info);
4520 if (name != nullptr)
4521 outs() << format(" %.*s", left, name);
4524 outs() << "\n";
4526 outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4527 uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);
4528 uint64_t absTypesVA = relTypesVA + m.types;
4529 outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
4530 name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
4531 if (name != nullptr)
4532 outs() << format(" %.*s", left, name);
4533 outs() << "\n";
4535 outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4536 uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);
4537 uint64_t absImpVA = relImpVA + m.imp;
4538 outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
4539 name = GuessSymbolName(absImpVA, info->AddrMap);
4540 if (name != nullptr)
4541 outs() << " " << name;
4542 outs() << "\n";
4544 p += sizeof(struct method_relative_t);
4545 offset += sizeof(struct method_relative_t);
4549 static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
4550 const char *indent) {
4551 struct method_list64_t ml;
4552 struct method64_t m;
4553 const char *r;
4554 uint32_t offset, xoffset, left, i;
4555 SectionRef S, xS;
4556 const char *name, *sym_name;
4557 uint64_t n_value;
4559 r = get_pointer_64(p, offset, left, S, info);
4560 if (r == nullptr)
4561 return;
4562 memset(&ml, '\0', sizeof(struct method_list64_t));
4563 if (left < sizeof(struct method_list64_t)) {
4564 memcpy(&ml, r, left);
4565 outs() << " (method_list_t entends past the end of the section)\n";
4566 } else
4567 memcpy(&ml, r, sizeof(struct method_list64_t));
4568 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4569 swapStruct(ml);
4570 p += sizeof(struct method_list64_t);
4572 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4573 print_relative_method_list(ml.entsize, ml.count, p, info, indent,
4574 /*pointerBits=*/64);
4575 return;
4578 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4579 outs() << indent << "\t\t count " << ml.count << "\n";
4581 offset += sizeof(struct method_list64_t);
4582 for (i = 0; i < ml.count; i++) {
4583 r = get_pointer_64(p, offset, left, S, info);
4584 if (r == nullptr)
4585 return;
4586 memset(&m, '\0', sizeof(struct method64_t));
4587 if (left < sizeof(struct method64_t)) {
4588 memcpy(&m, r, left);
4589 outs() << indent << " (method_t extends past the end of the section)\n";
4590 } else
4591 memcpy(&m, r, sizeof(struct method64_t));
4592 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4593 swapStruct(m);
4595 outs() << indent << "\t\t name ";
4596 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,
4597 info, n_value, m.name);
4598 if (n_value != 0) {
4599 if (info->verbose && sym_name != nullptr)
4600 outs() << sym_name;
4601 else
4602 outs() << format("0x%" PRIx64, n_value);
4603 if (m.name != 0)
4604 outs() << " + " << format("0x%" PRIx64, m.name);
4605 } else
4606 outs() << format("0x%" PRIx64, m.name);
4607 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
4608 if (name != nullptr)
4609 outs() << format(" %.*s", left, name);
4610 outs() << "\n";
4612 outs() << indent << "\t\t types ";
4613 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,
4614 info, n_value, m.types);
4615 if (n_value != 0) {
4616 if (info->verbose && sym_name != nullptr)
4617 outs() << sym_name;
4618 else
4619 outs() << format("0x%" PRIx64, n_value);
4620 if (m.types != 0)
4621 outs() << " + " << format("0x%" PRIx64, m.types);
4622 } else
4623 outs() << format("0x%" PRIx64, m.types);
4624 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
4625 if (name != nullptr)
4626 outs() << format(" %.*s", left, name);
4627 outs() << "\n";
4629 outs() << indent << "\t\t imp ";
4630 name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,
4631 n_value, m.imp);
4632 if (info->verbose && name == nullptr) {
4633 if (n_value != 0) {
4634 outs() << format("0x%" PRIx64, n_value) << " ";
4635 if (m.imp != 0)
4636 outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";
4637 } else
4638 outs() << format("0x%" PRIx64, m.imp) << " ";
4640 if (name != nullptr)
4641 outs() << name;
4642 outs() << "\n";
4644 p += sizeof(struct method64_t);
4645 offset += sizeof(struct method64_t);
4649 static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
4650 const char *indent) {
4651 struct method_list32_t ml;
4652 struct method32_t m;
4653 const char *r, *name;
4654 uint32_t offset, xoffset, left, i;
4655 SectionRef S, xS;
4657 r = get_pointer_32(p, offset, left, S, info);
4658 if (r == nullptr)
4659 return;
4660 memset(&ml, '\0', sizeof(struct method_list32_t));
4661 if (left < sizeof(struct method_list32_t)) {
4662 memcpy(&ml, r, left);
4663 outs() << " (method_list_t entends past the end of the section)\n";
4664 } else
4665 memcpy(&ml, r, sizeof(struct method_list32_t));
4666 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4667 swapStruct(ml);
4668 p += sizeof(struct method_list32_t);
4670 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4671 print_relative_method_list(ml.entsize, ml.count, p, info, indent,
4672 /*pointerBits=*/32);
4673 return;
4676 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4677 outs() << indent << "\t\t count " << ml.count << "\n";
4679 offset += sizeof(struct method_list32_t);
4680 for (i = 0; i < ml.count; i++) {
4681 r = get_pointer_32(p, offset, left, S, info);
4682 if (r == nullptr)
4683 return;
4684 memset(&m, '\0', sizeof(struct method32_t));
4685 if (left < sizeof(struct method32_t)) {
4686 memcpy(&ml, r, left);
4687 outs() << indent << " (method_t entends past the end of the section)\n";
4688 } else
4689 memcpy(&m, r, sizeof(struct method32_t));
4690 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4691 swapStruct(m);
4693 outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4694 name = get_pointer_32(m.name, xoffset, left, xS, info);
4695 if (name != nullptr)
4696 outs() << format(" %.*s", left, name);
4697 outs() << "\n";
4699 outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4700 name = get_pointer_32(m.types, xoffset, left, xS, info);
4701 if (name != nullptr)
4702 outs() << format(" %.*s", left, name);
4703 outs() << "\n";
4705 outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4706 name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,
4707 m.imp);
4708 if (name != nullptr)
4709 outs() << " " << name;
4710 outs() << "\n";
4712 p += sizeof(struct method32_t);
4713 offset += sizeof(struct method32_t);
4717 static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4718 uint32_t offset, left, xleft;
4719 SectionRef S;
4720 struct objc_method_list_t method_list;
4721 struct objc_method_t method;
4722 const char *r, *methods, *name, *SymbolName;
4723 int32_t i;
4725 r = get_pointer_32(p, offset, left, S, info, true);
4726 if (r == nullptr)
4727 return true;
4729 outs() << "\n";
4730 if (left > sizeof(struct objc_method_list_t)) {
4731 memcpy(&method_list, r, sizeof(struct objc_method_list_t));
4732 } else {
4733 outs() << "\t\t objc_method_list extends past end of the section\n";
4734 memset(&method_list, '\0', sizeof(struct objc_method_list_t));
4735 memcpy(&method_list, r, left);
4737 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4738 swapStruct(method_list);
4740 outs() << "\t\t obsolete "
4741 << format("0x%08" PRIx32, method_list.obsolete) << "\n";
4742 outs() << "\t\t method_count " << method_list.method_count << "\n";
4744 methods = r + sizeof(struct objc_method_list_t);
4745 for (i = 0; i < method_list.method_count; i++) {
4746 if ((i + 1) * sizeof(struct objc_method_t) > left) {
4747 outs() << "\t\t remaining method's extend past the of the section\n";
4748 break;
4750 memcpy(&method, methods + i * sizeof(struct objc_method_t),
4751 sizeof(struct objc_method_t));
4752 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4753 swapStruct(method);
4755 outs() << "\t\t method_name "
4756 << format("0x%08" PRIx32, method.method_name);
4757 if (info->verbose) {
4758 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
4759 if (name != nullptr)
4760 outs() << format(" %.*s", xleft, name);
4761 else
4762 outs() << " (not in an __OBJC section)";
4764 outs() << "\n";
4766 outs() << "\t\t method_types "
4767 << format("0x%08" PRIx32, method.method_types);
4768 if (info->verbose) {
4769 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
4770 if (name != nullptr)
4771 outs() << format(" %.*s", xleft, name);
4772 else
4773 outs() << " (not in an __OBJC section)";
4775 outs() << "\n";
4777 outs() << "\t\t method_imp "
4778 << format("0x%08" PRIx32, method.method_imp) << " ";
4779 if (info->verbose) {
4780 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
4781 if (SymbolName != nullptr)
4782 outs() << SymbolName;
4784 outs() << "\n";
4786 return false;
4789 static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4790 struct protocol_list64_t pl;
4791 uint64_t q, n_value;
4792 struct protocol64_t pc;
4793 const char *r;
4794 uint32_t offset, xoffset, left, i;
4795 SectionRef S, xS;
4796 const char *name, *sym_name;
4798 r = get_pointer_64(p, offset, left, S, info);
4799 if (r == nullptr)
4800 return;
4801 memset(&pl, '\0', sizeof(struct protocol_list64_t));
4802 if (left < sizeof(struct protocol_list64_t)) {
4803 memcpy(&pl, r, left);
4804 outs() << " (protocol_list_t entends past the end of the section)\n";
4805 } else
4806 memcpy(&pl, r, sizeof(struct protocol_list64_t));
4807 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4808 swapStruct(pl);
4809 outs() << " count " << pl.count << "\n";
4811 p += sizeof(struct protocol_list64_t);
4812 offset += sizeof(struct protocol_list64_t);
4813 for (i = 0; i < pl.count; i++) {
4814 r = get_pointer_64(p, offset, left, S, info);
4815 if (r == nullptr)
4816 return;
4817 q = 0;
4818 if (left < sizeof(uint64_t)) {
4819 memcpy(&q, r, left);
4820 outs() << " (protocol_t * entends past the end of the section)\n";
4821 } else
4822 memcpy(&q, r, sizeof(uint64_t));
4823 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4824 sys::swapByteOrder(q);
4826 outs() << "\t\t list[" << i << "] ";
4827 sym_name = get_symbol_64(offset, S, info, n_value, q);
4828 if (n_value != 0) {
4829 if (info->verbose && sym_name != nullptr)
4830 outs() << sym_name;
4831 else
4832 outs() << format("0x%" PRIx64, n_value);
4833 if (q != 0)
4834 outs() << " + " << format("0x%" PRIx64, q);
4835 } else
4836 outs() << format("0x%" PRIx64, q);
4837 outs() << " (struct protocol_t *)\n";
4839 r = get_pointer_64(q + n_value, offset, left, S, info);
4840 if (r == nullptr)
4841 return;
4842 memset(&pc, '\0', sizeof(struct protocol64_t));
4843 if (left < sizeof(struct protocol64_t)) {
4844 memcpy(&pc, r, left);
4845 outs() << " (protocol_t entends past the end of the section)\n";
4846 } else
4847 memcpy(&pc, r, sizeof(struct protocol64_t));
4848 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4849 swapStruct(pc);
4851 outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";
4853 outs() << "\t\t\t name ";
4854 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,
4855 info, n_value, pc.name);
4856 if (n_value != 0) {
4857 if (info->verbose && sym_name != nullptr)
4858 outs() << sym_name;
4859 else
4860 outs() << format("0x%" PRIx64, n_value);
4861 if (pc.name != 0)
4862 outs() << " + " << format("0x%" PRIx64, pc.name);
4863 } else
4864 outs() << format("0x%" PRIx64, pc.name);
4865 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
4866 if (name != nullptr)
4867 outs() << format(" %.*s", left, name);
4868 outs() << "\n";
4870 outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";
4872 outs() << "\t\t instanceMethods ";
4873 sym_name =
4874 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),
4875 S, info, n_value, pc.instanceMethods);
4876 if (n_value != 0) {
4877 if (info->verbose && sym_name != nullptr)
4878 outs() << sym_name;
4879 else
4880 outs() << format("0x%" PRIx64, n_value);
4881 if (pc.instanceMethods != 0)
4882 outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);
4883 } else
4884 outs() << format("0x%" PRIx64, pc.instanceMethods);
4885 outs() << " (struct method_list_t *)\n";
4886 if (pc.instanceMethods + n_value != 0)
4887 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
4889 outs() << "\t\t classMethods ";
4890 sym_name =
4891 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,
4892 info, n_value, pc.classMethods);
4893 if (n_value != 0) {
4894 if (info->verbose && sym_name != nullptr)
4895 outs() << sym_name;
4896 else
4897 outs() << format("0x%" PRIx64, n_value);
4898 if (pc.classMethods != 0)
4899 outs() << " + " << format("0x%" PRIx64, pc.classMethods);
4900 } else
4901 outs() << format("0x%" PRIx64, pc.classMethods);
4902 outs() << " (struct method_list_t *)\n";
4903 if (pc.classMethods + n_value != 0)
4904 print_method_list64_t(pc.classMethods + n_value, info, "\t");
4906 outs() << "\t optionalInstanceMethods "
4907 << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";
4908 outs() << "\t optionalClassMethods "
4909 << format("0x%" PRIx64, pc.optionalClassMethods) << "\n";
4910 outs() << "\t instanceProperties "
4911 << format("0x%" PRIx64, pc.instanceProperties) << "\n";
4913 p += sizeof(uint64_t);
4914 offset += sizeof(uint64_t);
4918 static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4919 struct protocol_list32_t pl;
4920 uint32_t q;
4921 struct protocol32_t pc;
4922 const char *r;
4923 uint32_t offset, xoffset, left, i;
4924 SectionRef S, xS;
4925 const char *name;
4927 r = get_pointer_32(p, offset, left, S, info);
4928 if (r == nullptr)
4929 return;
4930 memset(&pl, '\0', sizeof(struct protocol_list32_t));
4931 if (left < sizeof(struct protocol_list32_t)) {
4932 memcpy(&pl, r, left);
4933 outs() << " (protocol_list_t entends past the end of the section)\n";
4934 } else
4935 memcpy(&pl, r, sizeof(struct protocol_list32_t));
4936 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4937 swapStruct(pl);
4938 outs() << " count " << pl.count << "\n";
4940 p += sizeof(struct protocol_list32_t);
4941 offset += sizeof(struct protocol_list32_t);
4942 for (i = 0; i < pl.count; i++) {
4943 r = get_pointer_32(p, offset, left, S, info);
4944 if (r == nullptr)
4945 return;
4946 q = 0;
4947 if (left < sizeof(uint32_t)) {
4948 memcpy(&q, r, left);
4949 outs() << " (protocol_t * entends past the end of the section)\n";
4950 } else
4951 memcpy(&q, r, sizeof(uint32_t));
4952 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4953 sys::swapByteOrder(q);
4954 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)
4955 << " (struct protocol_t *)\n";
4956 r = get_pointer_32(q, offset, left, S, info);
4957 if (r == nullptr)
4958 return;
4959 memset(&pc, '\0', sizeof(struct protocol32_t));
4960 if (left < sizeof(struct protocol32_t)) {
4961 memcpy(&pc, r, left);
4962 outs() << " (protocol_t entends past the end of the section)\n";
4963 } else
4964 memcpy(&pc, r, sizeof(struct protocol32_t));
4965 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4966 swapStruct(pc);
4967 outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";
4968 outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);
4969 name = get_pointer_32(pc.name, xoffset, left, xS, info);
4970 if (name != nullptr)
4971 outs() << format(" %.*s", left, name);
4972 outs() << "\n";
4973 outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";
4974 outs() << "\t\t instanceMethods "
4975 << format("0x%" PRIx32, pc.instanceMethods)
4976 << " (struct method_list_t *)\n";
4977 if (pc.instanceMethods != 0)
4978 print_method_list32_t(pc.instanceMethods, info, "\t");
4979 outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)
4980 << " (struct method_list_t *)\n";
4981 if (pc.classMethods != 0)
4982 print_method_list32_t(pc.classMethods, info, "\t");
4983 outs() << "\t optionalInstanceMethods "
4984 << format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";
4985 outs() << "\t optionalClassMethods "
4986 << format("0x%" PRIx32, pc.optionalClassMethods) << "\n";
4987 outs() << "\t instanceProperties "
4988 << format("0x%" PRIx32, pc.instanceProperties) << "\n";
4989 p += sizeof(uint32_t);
4990 offset += sizeof(uint32_t);
4994 static void print_indent(uint32_t indent) {
4995 for (uint32_t i = 0; i < indent;) {
4996 if (indent - i >= 8) {
4997 outs() << "\t";
4998 i += 8;
4999 } else {
5000 for (uint32_t j = i; j < indent; j++)
5001 outs() << " ";
5002 return;
5007 static bool print_method_description_list(uint32_t p, uint32_t indent,
5008 struct DisassembleInfo *info) {
5009 uint32_t offset, left, xleft;
5010 SectionRef S;
5011 struct objc_method_description_list_t mdl;
5012 struct objc_method_description_t md;
5013 const char *r, *list, *name;
5014 int32_t i;
5016 r = get_pointer_32(p, offset, left, S, info, true);
5017 if (r == nullptr)
5018 return true;
5020 outs() << "\n";
5021 if (left > sizeof(struct objc_method_description_list_t)) {
5022 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
5023 } else {
5024 print_indent(indent);
5025 outs() << " objc_method_description_list extends past end of the section\n";
5026 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
5027 memcpy(&mdl, r, left);
5029 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5030 swapStruct(mdl);
5032 print_indent(indent);
5033 outs() << " count " << mdl.count << "\n";
5035 list = r + sizeof(struct objc_method_description_list_t);
5036 for (i = 0; i < mdl.count; i++) {
5037 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
5038 print_indent(indent);
5039 outs() << " remaining list entries extend past the of the section\n";
5040 break;
5042 print_indent(indent);
5043 outs() << " list[" << i << "]\n";
5044 memcpy(&md, list + i * sizeof(struct objc_method_description_t),
5045 sizeof(struct objc_method_description_t));
5046 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5047 swapStruct(md);
5049 print_indent(indent);
5050 outs() << " name " << format("0x%08" PRIx32, md.name);
5051 if (info->verbose) {
5052 name = get_pointer_32(md.name, offset, xleft, S, info, true);
5053 if (name != nullptr)
5054 outs() << format(" %.*s", xleft, name);
5055 else
5056 outs() << " (not in an __OBJC section)";
5058 outs() << "\n";
5060 print_indent(indent);
5061 outs() << " types " << format("0x%08" PRIx32, md.types);
5062 if (info->verbose) {
5063 name = get_pointer_32(md.types, offset, xleft, S, info, true);
5064 if (name != nullptr)
5065 outs() << format(" %.*s", xleft, name);
5066 else
5067 outs() << " (not in an __OBJC section)";
5069 outs() << "\n";
5071 return false;
5074 static bool print_protocol_list(uint32_t p, uint32_t indent,
5075 struct DisassembleInfo *info);
5077 static bool print_protocol(uint32_t p, uint32_t indent,
5078 struct DisassembleInfo *info) {
5079 uint32_t offset, left;
5080 SectionRef S;
5081 struct objc_protocol_t protocol;
5082 const char *r, *name;
5084 r = get_pointer_32(p, offset, left, S, info, true);
5085 if (r == nullptr)
5086 return true;
5088 outs() << "\n";
5089 if (left >= sizeof(struct objc_protocol_t)) {
5090 memcpy(&protocol, r, sizeof(struct objc_protocol_t));
5091 } else {
5092 print_indent(indent);
5093 outs() << " Protocol extends past end of the section\n";
5094 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
5095 memcpy(&protocol, r, left);
5097 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5098 swapStruct(protocol);
5100 print_indent(indent);
5101 outs() << " isa " << format("0x%08" PRIx32, protocol.isa)
5102 << "\n";
5104 print_indent(indent);
5105 outs() << " protocol_name "
5106 << format("0x%08" PRIx32, protocol.protocol_name);
5107 if (info->verbose) {
5108 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
5109 if (name != nullptr)
5110 outs() << format(" %.*s", left, name);
5111 else
5112 outs() << " (not in an __OBJC section)";
5114 outs() << "\n";
5116 print_indent(indent);
5117 outs() << " protocol_list "
5118 << format("0x%08" PRIx32, protocol.protocol_list);
5119 if (print_protocol_list(protocol.protocol_list, indent + 4, info))
5120 outs() << " (not in an __OBJC section)\n";
5122 print_indent(indent);
5123 outs() << " instance_methods "
5124 << format("0x%08" PRIx32, protocol.instance_methods);
5125 if (print_method_description_list(protocol.instance_methods, indent, info))
5126 outs() << " (not in an __OBJC section)\n";
5128 print_indent(indent);
5129 outs() << " class_methods "
5130 << format("0x%08" PRIx32, protocol.class_methods);
5131 if (print_method_description_list(protocol.class_methods, indent, info))
5132 outs() << " (not in an __OBJC section)\n";
5134 return false;
5137 static bool print_protocol_list(uint32_t p, uint32_t indent,
5138 struct DisassembleInfo *info) {
5139 uint32_t offset, left, l;
5140 SectionRef S;
5141 struct objc_protocol_list_t protocol_list;
5142 const char *r, *list;
5143 int32_t i;
5145 r = get_pointer_32(p, offset, left, S, info, true);
5146 if (r == nullptr)
5147 return true;
5149 outs() << "\n";
5150 if (left > sizeof(struct objc_protocol_list_t)) {
5151 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
5152 } else {
5153 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
5154 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
5155 memcpy(&protocol_list, r, left);
5157 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5158 swapStruct(protocol_list);
5160 print_indent(indent);
5161 outs() << " next " << format("0x%08" PRIx32, protocol_list.next)
5162 << "\n";
5163 print_indent(indent);
5164 outs() << " count " << protocol_list.count << "\n";
5166 list = r + sizeof(struct objc_protocol_list_t);
5167 for (i = 0; i < protocol_list.count; i++) {
5168 if ((i + 1) * sizeof(uint32_t) > left) {
5169 outs() << "\t\t remaining list entries extend past the of the section\n";
5170 break;
5172 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
5173 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5174 sys::swapByteOrder(l);
5176 print_indent(indent);
5177 outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);
5178 if (print_protocol(l, indent, info))
5179 outs() << "(not in an __OBJC section)\n";
5181 return false;
5184 static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
5185 struct ivar_list64_t il;
5186 struct ivar64_t i;
5187 const char *r;
5188 uint32_t offset, xoffset, left, j;
5189 SectionRef S, xS;
5190 const char *name, *sym_name, *ivar_offset_p;
5191 uint64_t ivar_offset, n_value;
5193 r = get_pointer_64(p, offset, left, S, info);
5194 if (r == nullptr)
5195 return;
5196 memset(&il, '\0', sizeof(struct ivar_list64_t));
5197 if (left < sizeof(struct ivar_list64_t)) {
5198 memcpy(&il, r, left);
5199 outs() << " (ivar_list_t entends past the end of the section)\n";
5200 } else
5201 memcpy(&il, r, sizeof(struct ivar_list64_t));
5202 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5203 swapStruct(il);
5204 outs() << " entsize " << il.entsize << "\n";
5205 outs() << " count " << il.count << "\n";
5207 p += sizeof(struct ivar_list64_t);
5208 offset += sizeof(struct ivar_list64_t);
5209 for (j = 0; j < il.count; j++) {
5210 r = get_pointer_64(p, offset, left, S, info);
5211 if (r == nullptr)
5212 return;
5213 memset(&i, '\0', sizeof(struct ivar64_t));
5214 if (left < sizeof(struct ivar64_t)) {
5215 memcpy(&i, r, left);
5216 outs() << " (ivar_t entends past the end of the section)\n";
5217 } else
5218 memcpy(&i, r, sizeof(struct ivar64_t));
5219 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5220 swapStruct(i);
5222 outs() << "\t\t\t offset ";
5223 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,
5224 info, n_value, i.offset);
5225 if (n_value != 0) {
5226 if (info->verbose && sym_name != nullptr)
5227 outs() << sym_name;
5228 else
5229 outs() << format("0x%" PRIx64, n_value);
5230 if (i.offset != 0)
5231 outs() << " + " << format("0x%" PRIx64, i.offset);
5232 } else
5233 outs() << format("0x%" PRIx64, i.offset);
5234 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
5235 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5236 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
5237 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5238 sys::swapByteOrder(ivar_offset);
5239 outs() << " " << ivar_offset << "\n";
5240 } else
5241 outs() << "\n";
5243 outs() << "\t\t\t name ";
5244 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,
5245 n_value, i.name);
5246 if (n_value != 0) {
5247 if (info->verbose && sym_name != nullptr)
5248 outs() << sym_name;
5249 else
5250 outs() << format("0x%" PRIx64, n_value);
5251 if (i.name != 0)
5252 outs() << " + " << format("0x%" PRIx64, i.name);
5253 } else
5254 outs() << format("0x%" PRIx64, i.name);
5255 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
5256 if (name != nullptr)
5257 outs() << format(" %.*s", left, name);
5258 outs() << "\n";
5260 outs() << "\t\t\t type ";
5261 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,
5262 n_value, i.name);
5263 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
5264 if (n_value != 0) {
5265 if (info->verbose && sym_name != nullptr)
5266 outs() << sym_name;
5267 else
5268 outs() << format("0x%" PRIx64, n_value);
5269 if (i.type != 0)
5270 outs() << " + " << format("0x%" PRIx64, i.type);
5271 } else
5272 outs() << format("0x%" PRIx64, i.type);
5273 if (name != nullptr)
5274 outs() << format(" %.*s", left, name);
5275 outs() << "\n";
5277 outs() << "\t\t\talignment " << i.alignment << "\n";
5278 outs() << "\t\t\t size " << i.size << "\n";
5280 p += sizeof(struct ivar64_t);
5281 offset += sizeof(struct ivar64_t);
5285 static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
5286 struct ivar_list32_t il;
5287 struct ivar32_t i;
5288 const char *r;
5289 uint32_t offset, xoffset, left, j;
5290 SectionRef S, xS;
5291 const char *name, *ivar_offset_p;
5292 uint32_t ivar_offset;
5294 r = get_pointer_32(p, offset, left, S, info);
5295 if (r == nullptr)
5296 return;
5297 memset(&il, '\0', sizeof(struct ivar_list32_t));
5298 if (left < sizeof(struct ivar_list32_t)) {
5299 memcpy(&il, r, left);
5300 outs() << " (ivar_list_t entends past the end of the section)\n";
5301 } else
5302 memcpy(&il, r, sizeof(struct ivar_list32_t));
5303 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5304 swapStruct(il);
5305 outs() << " entsize " << il.entsize << "\n";
5306 outs() << " count " << il.count << "\n";
5308 p += sizeof(struct ivar_list32_t);
5309 offset += sizeof(struct ivar_list32_t);
5310 for (j = 0; j < il.count; j++) {
5311 r = get_pointer_32(p, offset, left, S, info);
5312 if (r == nullptr)
5313 return;
5314 memset(&i, '\0', sizeof(struct ivar32_t));
5315 if (left < sizeof(struct ivar32_t)) {
5316 memcpy(&i, r, left);
5317 outs() << " (ivar_t entends past the end of the section)\n";
5318 } else
5319 memcpy(&i, r, sizeof(struct ivar32_t));
5320 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5321 swapStruct(i);
5323 outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);
5324 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
5325 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5326 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
5327 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5328 sys::swapByteOrder(ivar_offset);
5329 outs() << " " << ivar_offset << "\n";
5330 } else
5331 outs() << "\n";
5333 outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);
5334 name = get_pointer_32(i.name, xoffset, left, xS, info);
5335 if (name != nullptr)
5336 outs() << format(" %.*s", left, name);
5337 outs() << "\n";
5339 outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);
5340 name = get_pointer_32(i.type, xoffset, left, xS, info);
5341 if (name != nullptr)
5342 outs() << format(" %.*s", left, name);
5343 outs() << "\n";
5345 outs() << "\t\t\talignment " << i.alignment << "\n";
5346 outs() << "\t\t\t size " << i.size << "\n";
5348 p += sizeof(struct ivar32_t);
5349 offset += sizeof(struct ivar32_t);
5353 static void print_objc_property_list64(uint64_t p,
5354 struct DisassembleInfo *info) {
5355 struct objc_property_list64 opl;
5356 struct objc_property64 op;
5357 const char *r;
5358 uint32_t offset, xoffset, left, j;
5359 SectionRef S, xS;
5360 const char *name, *sym_name;
5361 uint64_t n_value;
5363 r = get_pointer_64(p, offset, left, S, info);
5364 if (r == nullptr)
5365 return;
5366 memset(&opl, '\0', sizeof(struct objc_property_list64));
5367 if (left < sizeof(struct objc_property_list64)) {
5368 memcpy(&opl, r, left);
5369 outs() << " (objc_property_list entends past the end of the section)\n";
5370 } else
5371 memcpy(&opl, r, sizeof(struct objc_property_list64));
5372 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5373 swapStruct(opl);
5374 outs() << " entsize " << opl.entsize << "\n";
5375 outs() << " count " << opl.count << "\n";
5377 p += sizeof(struct objc_property_list64);
5378 offset += sizeof(struct objc_property_list64);
5379 for (j = 0; j < opl.count; j++) {
5380 r = get_pointer_64(p, offset, left, S, info);
5381 if (r == nullptr)
5382 return;
5383 memset(&op, '\0', sizeof(struct objc_property64));
5384 if (left < sizeof(struct objc_property64)) {
5385 memcpy(&op, r, left);
5386 outs() << " (objc_property entends past the end of the section)\n";
5387 } else
5388 memcpy(&op, r, sizeof(struct objc_property64));
5389 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5390 swapStruct(op);
5392 outs() << "\t\t\t name ";
5393 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,
5394 info, n_value, op.name);
5395 if (n_value != 0) {
5396 if (info->verbose && sym_name != nullptr)
5397 outs() << sym_name;
5398 else
5399 outs() << format("0x%" PRIx64, n_value);
5400 if (op.name != 0)
5401 outs() << " + " << format("0x%" PRIx64, op.name);
5402 } else
5403 outs() << format("0x%" PRIx64, op.name);
5404 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
5405 if (name != nullptr)
5406 outs() << format(" %.*s", left, name);
5407 outs() << "\n";
5409 outs() << "\t\t\tattributes ";
5410 sym_name =
5411 get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,
5412 info, n_value, op.attributes);
5413 if (n_value != 0) {
5414 if (info->verbose && sym_name != nullptr)
5415 outs() << sym_name;
5416 else
5417 outs() << format("0x%" PRIx64, n_value);
5418 if (op.attributes != 0)
5419 outs() << " + " << format("0x%" PRIx64, op.attributes);
5420 } else
5421 outs() << format("0x%" PRIx64, op.attributes);
5422 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
5423 if (name != nullptr)
5424 outs() << format(" %.*s", left, name);
5425 outs() << "\n";
5427 p += sizeof(struct objc_property64);
5428 offset += sizeof(struct objc_property64);
5432 static void print_objc_property_list32(uint32_t p,
5433 struct DisassembleInfo *info) {
5434 struct objc_property_list32 opl;
5435 struct objc_property32 op;
5436 const char *r;
5437 uint32_t offset, xoffset, left, j;
5438 SectionRef S, xS;
5439 const char *name;
5441 r = get_pointer_32(p, offset, left, S, info);
5442 if (r == nullptr)
5443 return;
5444 memset(&opl, '\0', sizeof(struct objc_property_list32));
5445 if (left < sizeof(struct objc_property_list32)) {
5446 memcpy(&opl, r, left);
5447 outs() << " (objc_property_list entends past the end of the section)\n";
5448 } else
5449 memcpy(&opl, r, sizeof(struct objc_property_list32));
5450 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5451 swapStruct(opl);
5452 outs() << " entsize " << opl.entsize << "\n";
5453 outs() << " count " << opl.count << "\n";
5455 p += sizeof(struct objc_property_list32);
5456 offset += sizeof(struct objc_property_list32);
5457 for (j = 0; j < opl.count; j++) {
5458 r = get_pointer_32(p, offset, left, S, info);
5459 if (r == nullptr)
5460 return;
5461 memset(&op, '\0', sizeof(struct objc_property32));
5462 if (left < sizeof(struct objc_property32)) {
5463 memcpy(&op, r, left);
5464 outs() << " (objc_property entends past the end of the section)\n";
5465 } else
5466 memcpy(&op, r, sizeof(struct objc_property32));
5467 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5468 swapStruct(op);
5470 outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);
5471 name = get_pointer_32(op.name, xoffset, left, xS, info);
5472 if (name != nullptr)
5473 outs() << format(" %.*s", left, name);
5474 outs() << "\n";
5476 outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);
5477 name = get_pointer_32(op.attributes, xoffset, left, xS, info);
5478 if (name != nullptr)
5479 outs() << format(" %.*s", left, name);
5480 outs() << "\n";
5482 p += sizeof(struct objc_property32);
5483 offset += sizeof(struct objc_property32);
5487 static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
5488 bool &is_meta_class) {
5489 struct class_ro64_t cro;
5490 const char *r;
5491 uint32_t offset, xoffset, left;
5492 SectionRef S, xS;
5493 const char *name, *sym_name;
5494 uint64_t n_value;
5496 r = get_pointer_64(p, offset, left, S, info);
5497 if (r == nullptr || left < sizeof(struct class_ro64_t))
5498 return false;
5499 memcpy(&cro, r, sizeof(struct class_ro64_t));
5500 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5501 swapStruct(cro);
5502 outs() << " flags " << format("0x%" PRIx32, cro.flags);
5503 if (cro.flags & RO_META)
5504 outs() << " RO_META";
5505 if (cro.flags & RO_ROOT)
5506 outs() << " RO_ROOT";
5507 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5508 outs() << " RO_HAS_CXX_STRUCTORS";
5509 outs() << "\n";
5510 outs() << " instanceStart " << cro.instanceStart << "\n";
5511 outs() << " instanceSize " << cro.instanceSize << "\n";
5512 outs() << " reserved " << format("0x%" PRIx32, cro.reserved)
5513 << "\n";
5514 outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)
5515 << "\n";
5516 print_layout_map64(cro.ivarLayout, info);
5518 outs() << " name ";
5519 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,
5520 info, n_value, cro.name);
5521 if (n_value != 0) {
5522 if (info->verbose && sym_name != nullptr)
5523 outs() << sym_name;
5524 else
5525 outs() << format("0x%" PRIx64, n_value);
5526 if (cro.name != 0)
5527 outs() << " + " << format("0x%" PRIx64, cro.name);
5528 } else
5529 outs() << format("0x%" PRIx64, cro.name);
5530 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
5531 if (name != nullptr)
5532 outs() << format(" %.*s", left, name);
5533 outs() << "\n";
5535 outs() << " baseMethods ";
5536 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),
5537 S, info, n_value, cro.baseMethods);
5538 if (n_value != 0) {
5539 if (info->verbose && sym_name != nullptr)
5540 outs() << sym_name;
5541 else
5542 outs() << format("0x%" PRIx64, n_value);
5543 if (cro.baseMethods != 0)
5544 outs() << " + " << format("0x%" PRIx64, cro.baseMethods);
5545 } else
5546 outs() << format("0x%" PRIx64, cro.baseMethods);
5547 outs() << " (struct method_list_t *)\n";
5548 if (cro.baseMethods + n_value != 0)
5549 print_method_list64_t(cro.baseMethods + n_value, info, "");
5551 outs() << " baseProtocols ";
5552 sym_name =
5553 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,
5554 info, n_value, cro.baseProtocols);
5555 if (n_value != 0) {
5556 if (info->verbose && sym_name != nullptr)
5557 outs() << sym_name;
5558 else
5559 outs() << format("0x%" PRIx64, n_value);
5560 if (cro.baseProtocols != 0)
5561 outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);
5562 } else
5563 outs() << format("0x%" PRIx64, cro.baseProtocols);
5564 outs() << "\n";
5565 if (cro.baseProtocols + n_value != 0)
5566 print_protocol_list64_t(cro.baseProtocols + n_value, info);
5568 outs() << " ivars ";
5569 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,
5570 info, n_value, cro.ivars);
5571 if (n_value != 0) {
5572 if (info->verbose && sym_name != nullptr)
5573 outs() << sym_name;
5574 else
5575 outs() << format("0x%" PRIx64, n_value);
5576 if (cro.ivars != 0)
5577 outs() << " + " << format("0x%" PRIx64, cro.ivars);
5578 } else
5579 outs() << format("0x%" PRIx64, cro.ivars);
5580 outs() << "\n";
5581 if (cro.ivars + n_value != 0)
5582 print_ivar_list64_t(cro.ivars + n_value, info);
5584 outs() << " weakIvarLayout ";
5585 sym_name =
5586 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,
5587 info, n_value, cro.weakIvarLayout);
5588 if (n_value != 0) {
5589 if (info->verbose && sym_name != nullptr)
5590 outs() << sym_name;
5591 else
5592 outs() << format("0x%" PRIx64, n_value);
5593 if (cro.weakIvarLayout != 0)
5594 outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);
5595 } else
5596 outs() << format("0x%" PRIx64, cro.weakIvarLayout);
5597 outs() << "\n";
5598 print_layout_map64(cro.weakIvarLayout + n_value, info);
5600 outs() << " baseProperties ";
5601 sym_name =
5602 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,
5603 info, n_value, cro.baseProperties);
5604 if (n_value != 0) {
5605 if (info->verbose && sym_name != nullptr)
5606 outs() << sym_name;
5607 else
5608 outs() << format("0x%" PRIx64, n_value);
5609 if (cro.baseProperties != 0)
5610 outs() << " + " << format("0x%" PRIx64, cro.baseProperties);
5611 } else
5612 outs() << format("0x%" PRIx64, cro.baseProperties);
5613 outs() << "\n";
5614 if (cro.baseProperties + n_value != 0)
5615 print_objc_property_list64(cro.baseProperties + n_value, info);
5617 is_meta_class = (cro.flags & RO_META) != 0;
5618 return true;
5621 static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
5622 bool &is_meta_class) {
5623 struct class_ro32_t cro;
5624 const char *r;
5625 uint32_t offset, xoffset, left;
5626 SectionRef S, xS;
5627 const char *name;
5629 r = get_pointer_32(p, offset, left, S, info);
5630 if (r == nullptr)
5631 return false;
5632 memset(&cro, '\0', sizeof(struct class_ro32_t));
5633 if (left < sizeof(struct class_ro32_t)) {
5634 memcpy(&cro, r, left);
5635 outs() << " (class_ro_t entends past the end of the section)\n";
5636 } else
5637 memcpy(&cro, r, sizeof(struct class_ro32_t));
5638 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5639 swapStruct(cro);
5640 outs() << " flags " << format("0x%" PRIx32, cro.flags);
5641 if (cro.flags & RO_META)
5642 outs() << " RO_META";
5643 if (cro.flags & RO_ROOT)
5644 outs() << " RO_ROOT";
5645 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5646 outs() << " RO_HAS_CXX_STRUCTORS";
5647 outs() << "\n";
5648 outs() << " instanceStart " << cro.instanceStart << "\n";
5649 outs() << " instanceSize " << cro.instanceSize << "\n";
5650 outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)
5651 << "\n";
5652 print_layout_map32(cro.ivarLayout, info);
5654 outs() << " name " << format("0x%" PRIx32, cro.name);
5655 name = get_pointer_32(cro.name, xoffset, left, xS, info);
5656 if (name != nullptr)
5657 outs() << format(" %.*s", left, name);
5658 outs() << "\n";
5660 outs() << " baseMethods "
5661 << format("0x%" PRIx32, cro.baseMethods)
5662 << " (struct method_list_t *)\n";
5663 if (cro.baseMethods != 0)
5664 print_method_list32_t(cro.baseMethods, info, "");
5666 outs() << " baseProtocols "
5667 << format("0x%" PRIx32, cro.baseProtocols) << "\n";
5668 if (cro.baseProtocols != 0)
5669 print_protocol_list32_t(cro.baseProtocols, info);
5670 outs() << " ivars " << format("0x%" PRIx32, cro.ivars)
5671 << "\n";
5672 if (cro.ivars != 0)
5673 print_ivar_list32_t(cro.ivars, info);
5674 outs() << " weakIvarLayout "
5675 << format("0x%" PRIx32, cro.weakIvarLayout) << "\n";
5676 print_layout_map32(cro.weakIvarLayout, info);
5677 outs() << " baseProperties "
5678 << format("0x%" PRIx32, cro.baseProperties) << "\n";
5679 if (cro.baseProperties != 0)
5680 print_objc_property_list32(cro.baseProperties, info);
5681 is_meta_class = (cro.flags & RO_META) != 0;
5682 return true;
5685 static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
5686 struct class64_t c;
5687 const char *r;
5688 uint32_t offset, left;
5689 SectionRef S;
5690 const char *name;
5691 uint64_t isa_n_value, n_value;
5693 r = get_pointer_64(p, offset, left, S, info);
5694 if (r == nullptr || left < sizeof(struct class64_t))
5695 return;
5696 memcpy(&c, r, sizeof(struct class64_t));
5697 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5698 swapStruct(c);
5700 outs() << " isa " << format("0x%" PRIx64, c.isa);
5701 name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,
5702 isa_n_value, c.isa);
5703 if (name != nullptr)
5704 outs() << " " << name;
5705 outs() << "\n";
5707 outs() << " superclass " << format("0x%" PRIx64, c.superclass);
5708 name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,
5709 n_value, c.superclass);
5710 if (name != nullptr)
5711 outs() << " " << name;
5712 else {
5713 name = get_dyld_bind_info_symbolname(S.getAddress() +
5714 offset + offsetof(struct class64_t, superclass), info);
5715 if (name != nullptr)
5716 outs() << " " << name;
5718 outs() << "\n";
5720 outs() << " cache " << format("0x%" PRIx64, c.cache);
5721 name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,
5722 n_value, c.cache);
5723 if (name != nullptr)
5724 outs() << " " << name;
5725 outs() << "\n";
5727 outs() << " vtable " << format("0x%" PRIx64, c.vtable);
5728 name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,
5729 n_value, c.vtable);
5730 if (name != nullptr)
5731 outs() << " " << name;
5732 outs() << "\n";
5734 name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,
5735 n_value, c.data);
5736 outs() << " data ";
5737 if (n_value != 0) {
5738 if (info->verbose && name != nullptr)
5739 outs() << name;
5740 else
5741 outs() << format("0x%" PRIx64, n_value);
5742 if (c.data != 0)
5743 outs() << " + " << format("0x%" PRIx64, c.data);
5744 } else
5745 outs() << format("0x%" PRIx64, c.data);
5746 outs() << " (struct class_ro_t *)";
5748 // This is a Swift class if some of the low bits of the pointer are set.
5749 if ((c.data + n_value) & 0x7)
5750 outs() << " Swift class";
5751 outs() << "\n";
5752 bool is_meta_class;
5753 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
5754 return;
5756 if (!is_meta_class &&
5757 c.isa + isa_n_value != p &&
5758 c.isa + isa_n_value != 0 &&
5759 info->depth < 100) {
5760 info->depth++;
5761 outs() << "Meta Class\n";
5762 print_class64_t(c.isa + isa_n_value, info);
5766 static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5767 struct class32_t c;
5768 const char *r;
5769 uint32_t offset, left;
5770 SectionRef S;
5771 const char *name;
5773 r = get_pointer_32(p, offset, left, S, info);
5774 if (r == nullptr)
5775 return;
5776 memset(&c, '\0', sizeof(struct class32_t));
5777 if (left < sizeof(struct class32_t)) {
5778 memcpy(&c, r, left);
5779 outs() << " (class_t entends past the end of the section)\n";
5780 } else
5781 memcpy(&c, r, sizeof(struct class32_t));
5782 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5783 swapStruct(c);
5785 outs() << " isa " << format("0x%" PRIx32, c.isa);
5786 name =
5787 get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);
5788 if (name != nullptr)
5789 outs() << " " << name;
5790 outs() << "\n";
5792 outs() << " superclass " << format("0x%" PRIx32, c.superclass);
5793 name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,
5794 c.superclass);
5795 if (name != nullptr)
5796 outs() << " " << name;
5797 outs() << "\n";
5799 outs() << " cache " << format("0x%" PRIx32, c.cache);
5800 name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,
5801 c.cache);
5802 if (name != nullptr)
5803 outs() << " " << name;
5804 outs() << "\n";
5806 outs() << " vtable " << format("0x%" PRIx32, c.vtable);
5807 name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,
5808 c.vtable);
5809 if (name != nullptr)
5810 outs() << " " << name;
5811 outs() << "\n";
5813 name =
5814 get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);
5815 outs() << " data " << format("0x%" PRIx32, c.data)
5816 << " (struct class_ro_t *)";
5818 // This is a Swift class if some of the low bits of the pointer are set.
5819 if (c.data & 0x3)
5820 outs() << " Swift class";
5821 outs() << "\n";
5822 bool is_meta_class;
5823 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
5824 return;
5826 if (!is_meta_class) {
5827 outs() << "Meta Class\n";
5828 print_class32_t(c.isa, info);
5832 static void print_objc_class_t(struct objc_class_t *objc_class,
5833 struct DisassembleInfo *info) {
5834 uint32_t offset, left, xleft;
5835 const char *name, *p, *ivar_list;
5836 SectionRef S;
5837 int32_t i;
5838 struct objc_ivar_list_t objc_ivar_list;
5839 struct objc_ivar_t ivar;
5841 outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);
5842 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {
5843 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
5844 if (name != nullptr)
5845 outs() << format(" %.*s", left, name);
5846 else
5847 outs() << " (not in an __OBJC section)";
5849 outs() << "\n";
5851 outs() << "\t super_class "
5852 << format("0x%08" PRIx32, objc_class->super_class);
5853 if (info->verbose) {
5854 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
5855 if (name != nullptr)
5856 outs() << format(" %.*s", left, name);
5857 else
5858 outs() << " (not in an __OBJC section)";
5860 outs() << "\n";
5862 outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);
5863 if (info->verbose) {
5864 name = get_pointer_32(objc_class->name, offset, left, S, info, true);
5865 if (name != nullptr)
5866 outs() << format(" %.*s", left, name);
5867 else
5868 outs() << " (not in an __OBJC section)";
5870 outs() << "\n";
5872 outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)
5873 << "\n";
5875 outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);
5876 if (info->verbose) {
5877 if (CLS_GETINFO(objc_class, CLS_CLASS))
5878 outs() << " CLS_CLASS";
5879 else if (CLS_GETINFO(objc_class, CLS_META))
5880 outs() << " CLS_META";
5882 outs() << "\n";
5884 outs() << "\t instance_size "
5885 << format("0x%08" PRIx32, objc_class->instance_size) << "\n";
5887 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
5888 outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);
5889 if (p != nullptr) {
5890 if (left > sizeof(struct objc_ivar_list_t)) {
5891 outs() << "\n";
5892 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
5893 } else {
5894 outs() << " (entends past the end of the section)\n";
5895 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
5896 memcpy(&objc_ivar_list, p, left);
5898 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5899 swapStruct(objc_ivar_list);
5900 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5901 ivar_list = p + sizeof(struct objc_ivar_list_t);
5902 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5903 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5904 outs() << "\t\t remaining ivar's extend past the of the section\n";
5905 break;
5907 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
5908 sizeof(struct objc_ivar_t));
5909 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5910 swapStruct(ivar);
5912 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);
5913 if (info->verbose) {
5914 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
5915 if (name != nullptr)
5916 outs() << format(" %.*s", xleft, name);
5917 else
5918 outs() << " (not in an __OBJC section)";
5920 outs() << "\n";
5922 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);
5923 if (info->verbose) {
5924 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
5925 if (name != nullptr)
5926 outs() << format(" %.*s", xleft, name);
5927 else
5928 outs() << " (not in an __OBJC section)";
5930 outs() << "\n";
5932 outs() << "\t\t ivar_offset "
5933 << format("0x%08" PRIx32, ivar.ivar_offset) << "\n";
5935 } else {
5936 outs() << " (not in an __OBJC section)\n";
5939 outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);
5940 if (print_method_list(objc_class->methodLists, info))
5941 outs() << " (not in an __OBJC section)\n";
5943 outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)
5944 << "\n";
5946 outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);
5947 if (print_protocol_list(objc_class->protocols, 16, info))
5948 outs() << " (not in an __OBJC section)\n";
5951 static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5952 struct DisassembleInfo *info) {
5953 uint32_t offset, left;
5954 const char *name;
5955 SectionRef S;
5957 outs() << "\t category name "
5958 << format("0x%08" PRIx32, objc_category->category_name);
5959 if (info->verbose) {
5960 name = get_pointer_32(objc_category->category_name, offset, left, S, info,
5961 true);
5962 if (name != nullptr)
5963 outs() << format(" %.*s", left, name);
5964 else
5965 outs() << " (not in an __OBJC section)";
5967 outs() << "\n";
5969 outs() << "\t\t class name "
5970 << format("0x%08" PRIx32, objc_category->class_name);
5971 if (info->verbose) {
5972 name =
5973 get_pointer_32(objc_category->class_name, offset, left, S, info, true);
5974 if (name != nullptr)
5975 outs() << format(" %.*s", left, name);
5976 else
5977 outs() << " (not in an __OBJC section)";
5979 outs() << "\n";
5981 outs() << "\t instance methods "
5982 << format("0x%08" PRIx32, objc_category->instance_methods);
5983 if (print_method_list(objc_category->instance_methods, info))
5984 outs() << " (not in an __OBJC section)\n";
5986 outs() << "\t class methods "
5987 << format("0x%08" PRIx32, objc_category->class_methods);
5988 if (print_method_list(objc_category->class_methods, info))
5989 outs() << " (not in an __OBJC section)\n";
5992 static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
5993 struct category64_t c;
5994 const char *r;
5995 uint32_t offset, xoffset, left;
5996 SectionRef S, xS;
5997 const char *name, *sym_name;
5998 uint64_t n_value;
6000 r = get_pointer_64(p, offset, left, S, info);
6001 if (r == nullptr)
6002 return;
6003 memset(&c, '\0', sizeof(struct category64_t));
6004 if (left < sizeof(struct category64_t)) {
6005 memcpy(&c, r, left);
6006 outs() << " (category_t entends past the end of the section)\n";
6007 } else
6008 memcpy(&c, r, sizeof(struct category64_t));
6009 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6010 swapStruct(c);
6012 outs() << " name ";
6013 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,
6014 info, n_value, c.name);
6015 if (n_value != 0) {
6016 if (info->verbose && sym_name != nullptr)
6017 outs() << sym_name;
6018 else
6019 outs() << format("0x%" PRIx64, n_value);
6020 if (c.name != 0)
6021 outs() << " + " << format("0x%" PRIx64, c.name);
6022 } else
6023 outs() << format("0x%" PRIx64, c.name);
6024 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
6025 if (name != nullptr)
6026 outs() << format(" %.*s", left, name);
6027 outs() << "\n";
6029 outs() << " cls ";
6030 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,
6031 n_value, c.cls);
6032 if (n_value != 0) {
6033 if (info->verbose && sym_name != nullptr)
6034 outs() << sym_name;
6035 else
6036 outs() << format("0x%" PRIx64, n_value);
6037 if (c.cls != 0)
6038 outs() << " + " << format("0x%" PRIx64, c.cls);
6039 } else
6040 outs() << format("0x%" PRIx64, c.cls);
6041 outs() << "\n";
6042 if (c.cls + n_value != 0)
6043 print_class64_t(c.cls + n_value, info);
6045 outs() << " instanceMethods ";
6046 sym_name =
6047 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,
6048 info, n_value, c.instanceMethods);
6049 if (n_value != 0) {
6050 if (info->verbose && sym_name != nullptr)
6051 outs() << sym_name;
6052 else
6053 outs() << format("0x%" PRIx64, n_value);
6054 if (c.instanceMethods != 0)
6055 outs() << " + " << format("0x%" PRIx64, c.instanceMethods);
6056 } else
6057 outs() << format("0x%" PRIx64, c.instanceMethods);
6058 outs() << "\n";
6059 if (c.instanceMethods + n_value != 0)
6060 print_method_list64_t(c.instanceMethods + n_value, info, "");
6062 outs() << " classMethods ";
6063 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),
6064 S, info, n_value, c.classMethods);
6065 if (n_value != 0) {
6066 if (info->verbose && sym_name != nullptr)
6067 outs() << sym_name;
6068 else
6069 outs() << format("0x%" PRIx64, n_value);
6070 if (c.classMethods != 0)
6071 outs() << " + " << format("0x%" PRIx64, c.classMethods);
6072 } else
6073 outs() << format("0x%" PRIx64, c.classMethods);
6074 outs() << "\n";
6075 if (c.classMethods + n_value != 0)
6076 print_method_list64_t(c.classMethods + n_value, info, "");
6078 outs() << " protocols ";
6079 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,
6080 info, n_value, c.protocols);
6081 if (n_value != 0) {
6082 if (info->verbose && sym_name != nullptr)
6083 outs() << sym_name;
6084 else
6085 outs() << format("0x%" PRIx64, n_value);
6086 if (c.protocols != 0)
6087 outs() << " + " << format("0x%" PRIx64, c.protocols);
6088 } else
6089 outs() << format("0x%" PRIx64, c.protocols);
6090 outs() << "\n";
6091 if (c.protocols + n_value != 0)
6092 print_protocol_list64_t(c.protocols + n_value, info);
6094 outs() << "instanceProperties ";
6095 sym_name =
6096 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),
6097 S, info, n_value, c.instanceProperties);
6098 if (n_value != 0) {
6099 if (info->verbose && sym_name != nullptr)
6100 outs() << sym_name;
6101 else
6102 outs() << format("0x%" PRIx64, n_value);
6103 if (c.instanceProperties != 0)
6104 outs() << " + " << format("0x%" PRIx64, c.instanceProperties);
6105 } else
6106 outs() << format("0x%" PRIx64, c.instanceProperties);
6107 outs() << "\n";
6108 if (c.instanceProperties + n_value != 0)
6109 print_objc_property_list64(c.instanceProperties + n_value, info);
6112 static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
6113 struct category32_t c;
6114 const char *r;
6115 uint32_t offset, left;
6116 SectionRef S, xS;
6117 const char *name;
6119 r = get_pointer_32(p, offset, left, S, info);
6120 if (r == nullptr)
6121 return;
6122 memset(&c, '\0', sizeof(struct category32_t));
6123 if (left < sizeof(struct category32_t)) {
6124 memcpy(&c, r, left);
6125 outs() << " (category_t entends past the end of the section)\n";
6126 } else
6127 memcpy(&c, r, sizeof(struct category32_t));
6128 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6129 swapStruct(c);
6131 outs() << " name " << format("0x%" PRIx32, c.name);
6132 name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,
6133 c.name);
6134 if (name)
6135 outs() << " " << name;
6136 outs() << "\n";
6138 outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";
6139 if (c.cls != 0)
6140 print_class32_t(c.cls, info);
6141 outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)
6142 << "\n";
6143 if (c.instanceMethods != 0)
6144 print_method_list32_t(c.instanceMethods, info, "");
6145 outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)
6146 << "\n";
6147 if (c.classMethods != 0)
6148 print_method_list32_t(c.classMethods, info, "");
6149 outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";
6150 if (c.protocols != 0)
6151 print_protocol_list32_t(c.protocols, info);
6152 outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)
6153 << "\n";
6154 if (c.instanceProperties != 0)
6155 print_objc_property_list32(c.instanceProperties, info);
6158 static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
6159 uint32_t i, left, offset, xoffset;
6160 uint64_t p, n_value;
6161 struct message_ref64 mr;
6162 const char *name, *sym_name;
6163 const char *r;
6164 SectionRef xS;
6166 if (S == SectionRef())
6167 return;
6169 StringRef SectName;
6170 Expected<StringRef> SecNameOrErr = S.getName();
6171 if (SecNameOrErr)
6172 SectName = *SecNameOrErr;
6173 else
6174 consumeError(SecNameOrErr.takeError());
6176 DataRefImpl Ref = S.getRawDataRefImpl();
6177 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6178 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6179 offset = 0;
6180 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6181 p = S.getAddress() + i;
6182 r = get_pointer_64(p, offset, left, S, info);
6183 if (r == nullptr)
6184 return;
6185 memset(&mr, '\0', sizeof(struct message_ref64));
6186 if (left < sizeof(struct message_ref64)) {
6187 memcpy(&mr, r, left);
6188 outs() << " (message_ref entends past the end of the section)\n";
6189 } else
6190 memcpy(&mr, r, sizeof(struct message_ref64));
6191 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6192 swapStruct(mr);
6194 outs() << " imp ";
6195 name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,
6196 n_value, mr.imp);
6197 if (n_value != 0) {
6198 outs() << format("0x%" PRIx64, n_value) << " ";
6199 if (mr.imp != 0)
6200 outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";
6201 } else
6202 outs() << format("0x%" PRIx64, mr.imp) << " ";
6203 if (name != nullptr)
6204 outs() << " " << name;
6205 outs() << "\n";
6207 outs() << " sel ";
6208 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,
6209 info, n_value, mr.sel);
6210 if (n_value != 0) {
6211 if (info->verbose && sym_name != nullptr)
6212 outs() << sym_name;
6213 else
6214 outs() << format("0x%" PRIx64, n_value);
6215 if (mr.sel != 0)
6216 outs() << " + " << format("0x%" PRIx64, mr.sel);
6217 } else
6218 outs() << format("0x%" PRIx64, mr.sel);
6219 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
6220 if (name != nullptr)
6221 outs() << format(" %.*s", left, name);
6222 outs() << "\n";
6224 offset += sizeof(struct message_ref64);
6228 static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
6229 uint32_t i, left, offset, xoffset, p;
6230 struct message_ref32 mr;
6231 const char *name, *r;
6232 SectionRef xS;
6234 if (S == SectionRef())
6235 return;
6237 StringRef SectName;
6238 Expected<StringRef> SecNameOrErr = S.getName();
6239 if (SecNameOrErr)
6240 SectName = *SecNameOrErr;
6241 else
6242 consumeError(SecNameOrErr.takeError());
6244 DataRefImpl Ref = S.getRawDataRefImpl();
6245 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6246 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6247 offset = 0;
6248 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6249 p = S.getAddress() + i;
6250 r = get_pointer_32(p, offset, left, S, info);
6251 if (r == nullptr)
6252 return;
6253 memset(&mr, '\0', sizeof(struct message_ref32));
6254 if (left < sizeof(struct message_ref32)) {
6255 memcpy(&mr, r, left);
6256 outs() << " (message_ref entends past the end of the section)\n";
6257 } else
6258 memcpy(&mr, r, sizeof(struct message_ref32));
6259 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6260 swapStruct(mr);
6262 outs() << " imp " << format("0x%" PRIx32, mr.imp);
6263 name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,
6264 mr.imp);
6265 if (name != nullptr)
6266 outs() << " " << name;
6267 outs() << "\n";
6269 outs() << " sel " << format("0x%" PRIx32, mr.sel);
6270 name = get_pointer_32(mr.sel, xoffset, left, xS, info);
6271 if (name != nullptr)
6272 outs() << " " << name;
6273 outs() << "\n";
6275 offset += sizeof(struct message_ref32);
6279 static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
6280 uint32_t left, offset, swift_version;
6281 uint64_t p;
6282 struct objc_image_info64 o;
6283 const char *r;
6285 if (S == SectionRef())
6286 return;
6288 StringRef SectName;
6289 Expected<StringRef> SecNameOrErr = S.getName();
6290 if (SecNameOrErr)
6291 SectName = *SecNameOrErr;
6292 else
6293 consumeError(SecNameOrErr.takeError());
6295 DataRefImpl Ref = S.getRawDataRefImpl();
6296 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6297 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6298 p = S.getAddress();
6299 r = get_pointer_64(p, offset, left, S, info);
6300 if (r == nullptr)
6301 return;
6302 memset(&o, '\0', sizeof(struct objc_image_info64));
6303 if (left < sizeof(struct objc_image_info64)) {
6304 memcpy(&o, r, left);
6305 outs() << " (objc_image_info entends past the end of the section)\n";
6306 } else
6307 memcpy(&o, r, sizeof(struct objc_image_info64));
6308 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6309 swapStruct(o);
6310 outs() << " version " << o.version << "\n";
6311 outs() << " flags " << format("0x%" PRIx32, o.flags);
6312 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6313 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6314 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6315 outs() << " OBJC_IMAGE_SUPPORTS_GC";
6316 if (o.flags & OBJC_IMAGE_IS_SIMULATED)
6317 outs() << " OBJC_IMAGE_IS_SIMULATED";
6318 if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)
6319 outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";
6320 swift_version = (o.flags >> 8) & 0xff;
6321 if (swift_version != 0) {
6322 if (swift_version == 1)
6323 outs() << " Swift 1.0";
6324 else if (swift_version == 2)
6325 outs() << " Swift 1.1";
6326 else if(swift_version == 3)
6327 outs() << " Swift 2.0";
6328 else if(swift_version == 4)
6329 outs() << " Swift 3.0";
6330 else if(swift_version == 5)
6331 outs() << " Swift 4.0";
6332 else if(swift_version == 6)
6333 outs() << " Swift 4.1/Swift 4.2";
6334 else if(swift_version == 7)
6335 outs() << " Swift 5 or later";
6336 else
6337 outs() << " unknown future Swift version (" << swift_version << ")";
6339 outs() << "\n";
6342 static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
6343 uint32_t left, offset, swift_version, p;
6344 struct objc_image_info32 o;
6345 const char *r;
6347 if (S == SectionRef())
6348 return;
6350 StringRef SectName;
6351 Expected<StringRef> SecNameOrErr = S.getName();
6352 if (SecNameOrErr)
6353 SectName = *SecNameOrErr;
6354 else
6355 consumeError(SecNameOrErr.takeError());
6357 DataRefImpl Ref = S.getRawDataRefImpl();
6358 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6359 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6360 p = S.getAddress();
6361 r = get_pointer_32(p, offset, left, S, info);
6362 if (r == nullptr)
6363 return;
6364 memset(&o, '\0', sizeof(struct objc_image_info32));
6365 if (left < sizeof(struct objc_image_info32)) {
6366 memcpy(&o, r, left);
6367 outs() << " (objc_image_info entends past the end of the section)\n";
6368 } else
6369 memcpy(&o, r, sizeof(struct objc_image_info32));
6370 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6371 swapStruct(o);
6372 outs() << " version " << o.version << "\n";
6373 outs() << " flags " << format("0x%" PRIx32, o.flags);
6374 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6375 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6376 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6377 outs() << " OBJC_IMAGE_SUPPORTS_GC";
6378 swift_version = (o.flags >> 8) & 0xff;
6379 if (swift_version != 0) {
6380 if (swift_version == 1)
6381 outs() << " Swift 1.0";
6382 else if (swift_version == 2)
6383 outs() << " Swift 1.1";
6384 else if(swift_version == 3)
6385 outs() << " Swift 2.0";
6386 else if(swift_version == 4)
6387 outs() << " Swift 3.0";
6388 else if(swift_version == 5)
6389 outs() << " Swift 4.0";
6390 else if(swift_version == 6)
6391 outs() << " Swift 4.1/Swift 4.2";
6392 else if(swift_version == 7)
6393 outs() << " Swift 5 or later";
6394 else
6395 outs() << " unknown future Swift version (" << swift_version << ")";
6397 outs() << "\n";
6400 static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
6401 uint32_t left, offset, p;
6402 struct imageInfo_t o;
6403 const char *r;
6405 StringRef SectName;
6406 Expected<StringRef> SecNameOrErr = S.getName();
6407 if (SecNameOrErr)
6408 SectName = *SecNameOrErr;
6409 else
6410 consumeError(SecNameOrErr.takeError());
6412 DataRefImpl Ref = S.getRawDataRefImpl();
6413 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6414 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6415 p = S.getAddress();
6416 r = get_pointer_32(p, offset, left, S, info);
6417 if (r == nullptr)
6418 return;
6419 memset(&o, '\0', sizeof(struct imageInfo_t));
6420 if (left < sizeof(struct imageInfo_t)) {
6421 memcpy(&o, r, left);
6422 outs() << " (imageInfo entends past the end of the section)\n";
6423 } else
6424 memcpy(&o, r, sizeof(struct imageInfo_t));
6425 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6426 swapStruct(o);
6427 outs() << " version " << o.version << "\n";
6428 outs() << " flags " << format("0x%" PRIx32, o.flags);
6429 if (o.flags & 0x1)
6430 outs() << " F&C";
6431 if (o.flags & 0x2)
6432 outs() << " GC";
6433 if (o.flags & 0x4)
6434 outs() << " GC-only";
6435 else
6436 outs() << " RR";
6437 outs() << "\n";
6440 static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
6441 SymbolAddressMap AddrMap;
6442 if (verbose)
6443 CreateSymbolAddressMap(O, &AddrMap);
6445 std::vector<SectionRef> Sections;
6446 append_range(Sections, O->sections());
6448 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6450 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
6451 if (CL == SectionRef())
6452 CL = get_section(O, "__DATA", "__objc_classlist");
6453 if (CL == SectionRef())
6454 CL = get_section(O, "__DATA_CONST", "__objc_classlist");
6455 if (CL == SectionRef())
6456 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
6457 info.S = CL;
6458 walk_pointer_list_64("class", CL, O, &info, print_class64_t);
6460 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
6461 if (CR == SectionRef())
6462 CR = get_section(O, "__DATA", "__objc_classrefs");
6463 if (CR == SectionRef())
6464 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
6465 if (CR == SectionRef())
6466 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
6467 info.S = CR;
6468 walk_pointer_list_64("class refs", CR, O, &info, nullptr);
6470 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
6471 if (SR == SectionRef())
6472 SR = get_section(O, "__DATA", "__objc_superrefs");
6473 if (SR == SectionRef())
6474 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
6475 if (SR == SectionRef())
6476 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
6477 info.S = SR;
6478 walk_pointer_list_64("super refs", SR, O, &info, nullptr);
6480 SectionRef CA = get_section(O, "__OBJC2", "__category_list");
6481 if (CA == SectionRef())
6482 CA = get_section(O, "__DATA", "__objc_catlist");
6483 if (CA == SectionRef())
6484 CA = get_section(O, "__DATA_CONST", "__objc_catlist");
6485 if (CA == SectionRef())
6486 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
6487 info.S = CA;
6488 walk_pointer_list_64("category", CA, O, &info, print_category64_t);
6490 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
6491 if (PL == SectionRef())
6492 PL = get_section(O, "__DATA", "__objc_protolist");
6493 if (PL == SectionRef())
6494 PL = get_section(O, "__DATA_CONST", "__objc_protolist");
6495 if (PL == SectionRef())
6496 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
6497 info.S = PL;
6498 walk_pointer_list_64("protocol", PL, O, &info, nullptr);
6500 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
6501 if (MR == SectionRef())
6502 MR = get_section(O, "__DATA", "__objc_msgrefs");
6503 if (MR == SectionRef())
6504 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
6505 if (MR == SectionRef())
6506 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
6507 info.S = MR;
6508 print_message_refs64(MR, &info);
6510 SectionRef II = get_section(O, "__OBJC2", "__image_info");
6511 if (II == SectionRef())
6512 II = get_section(O, "__DATA", "__objc_imageinfo");
6513 if (II == SectionRef())
6514 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6515 if (II == SectionRef())
6516 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
6517 info.S = II;
6518 print_image_info64(II, &info);
6521 static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6522 SymbolAddressMap AddrMap;
6523 if (verbose)
6524 CreateSymbolAddressMap(O, &AddrMap);
6526 std::vector<SectionRef> Sections;
6527 append_range(Sections, O->sections());
6529 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6531 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
6532 if (CL == SectionRef())
6533 CL = get_section(O, "__DATA", "__objc_classlist");
6534 if (CL == SectionRef())
6535 CL = get_section(O, "__DATA_CONST", "__objc_classlist");
6536 if (CL == SectionRef())
6537 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
6538 info.S = CL;
6539 walk_pointer_list_32("class", CL, O, &info, print_class32_t);
6541 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
6542 if (CR == SectionRef())
6543 CR = get_section(O, "__DATA", "__objc_classrefs");
6544 if (CR == SectionRef())
6545 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
6546 if (CR == SectionRef())
6547 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
6548 info.S = CR;
6549 walk_pointer_list_32("class refs", CR, O, &info, nullptr);
6551 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
6552 if (SR == SectionRef())
6553 SR = get_section(O, "__DATA", "__objc_superrefs");
6554 if (SR == SectionRef())
6555 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
6556 if (SR == SectionRef())
6557 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
6558 info.S = SR;
6559 walk_pointer_list_32("super refs", SR, O, &info, nullptr);
6561 SectionRef CA = get_section(O, "__OBJC2", "__category_list");
6562 if (CA == SectionRef())
6563 CA = get_section(O, "__DATA", "__objc_catlist");
6564 if (CA == SectionRef())
6565 CA = get_section(O, "__DATA_CONST", "__objc_catlist");
6566 if (CA == SectionRef())
6567 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
6568 info.S = CA;
6569 walk_pointer_list_32("category", CA, O, &info, print_category32_t);
6571 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
6572 if (PL == SectionRef())
6573 PL = get_section(O, "__DATA", "__objc_protolist");
6574 if (PL == SectionRef())
6575 PL = get_section(O, "__DATA_CONST", "__objc_protolist");
6576 if (PL == SectionRef())
6577 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
6578 info.S = PL;
6579 walk_pointer_list_32("protocol", PL, O, &info, nullptr);
6581 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
6582 if (MR == SectionRef())
6583 MR = get_section(O, "__DATA", "__objc_msgrefs");
6584 if (MR == SectionRef())
6585 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
6586 if (MR == SectionRef())
6587 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
6588 info.S = MR;
6589 print_message_refs32(MR, &info);
6591 SectionRef II = get_section(O, "__OBJC2", "__image_info");
6592 if (II == SectionRef())
6593 II = get_section(O, "__DATA", "__objc_imageinfo");
6594 if (II == SectionRef())
6595 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6596 if (II == SectionRef())
6597 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
6598 info.S = II;
6599 print_image_info32(II, &info);
6602 static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6603 uint32_t i, j, p, offset, xoffset, left, defs_left, def;
6604 const char *r, *name, *defs;
6605 struct objc_module_t module;
6606 SectionRef S, xS;
6607 struct objc_symtab_t symtab;
6608 struct objc_class_t objc_class;
6609 struct objc_category_t objc_category;
6611 outs() << "Objective-C segment\n";
6612 S = get_section(O, "__OBJC", "__module_info");
6613 if (S == SectionRef())
6614 return false;
6616 SymbolAddressMap AddrMap;
6617 if (verbose)
6618 CreateSymbolAddressMap(O, &AddrMap);
6620 std::vector<SectionRef> Sections;
6621 append_range(Sections, O->sections());
6623 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6625 for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
6626 p = S.getAddress() + i;
6627 r = get_pointer_32(p, offset, left, S, &info, true);
6628 if (r == nullptr)
6629 return true;
6630 memset(&module, '\0', sizeof(struct objc_module_t));
6631 if (left < sizeof(struct objc_module_t)) {
6632 memcpy(&module, r, left);
6633 outs() << " (module extends past end of __module_info section)\n";
6634 } else
6635 memcpy(&module, r, sizeof(struct objc_module_t));
6636 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6637 swapStruct(module);
6639 outs() << "Module " << format("0x%" PRIx32, p) << "\n";
6640 outs() << " version " << module.version << "\n";
6641 outs() << " size " << module.size << "\n";
6642 outs() << " name ";
6643 name = get_pointer_32(module.name, xoffset, left, xS, &info, true);
6644 if (name != nullptr)
6645 outs() << format("%.*s", left, name);
6646 else
6647 outs() << format("0x%08" PRIx32, module.name)
6648 << "(not in an __OBJC section)";
6649 outs() << "\n";
6651 r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);
6652 if (module.symtab == 0 || r == nullptr) {
6653 outs() << " symtab " << format("0x%08" PRIx32, module.symtab)
6654 << " (not in an __OBJC section)\n";
6655 continue;
6657 outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";
6658 memset(&symtab, '\0', sizeof(struct objc_symtab_t));
6659 defs_left = 0;
6660 defs = nullptr;
6661 if (left < sizeof(struct objc_symtab_t)) {
6662 memcpy(&symtab, r, left);
6663 outs() << "\tsymtab extends past end of an __OBJC section)\n";
6664 } else {
6665 memcpy(&symtab, r, sizeof(struct objc_symtab_t));
6666 if (left > sizeof(struct objc_symtab_t)) {
6667 defs_left = left - sizeof(struct objc_symtab_t);
6668 defs = r + sizeof(struct objc_symtab_t);
6671 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6672 swapStruct(symtab);
6674 outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
6675 r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);
6676 outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);
6677 if (r == nullptr)
6678 outs() << " (not in an __OBJC section)";
6679 outs() << "\n";
6680 outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
6681 outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
6682 if (symtab.cls_def_cnt > 0)
6683 outs() << "\tClass Definitions\n";
6684 for (j = 0; j < symtab.cls_def_cnt; j++) {
6685 if ((j + 1) * sizeof(uint32_t) > defs_left) {
6686 outs() << "\t(remaining class defs entries entends past the end of the "
6687 << "section)\n";
6688 break;
6690 memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));
6691 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6692 sys::swapByteOrder(def);
6694 r = get_pointer_32(def, xoffset, left, xS, &info, true);
6695 outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);
6696 if (r != nullptr) {
6697 if (left > sizeof(struct objc_class_t)) {
6698 outs() << "\n";
6699 memcpy(&objc_class, r, sizeof(struct objc_class_t));
6700 } else {
6701 outs() << " (entends past the end of the section)\n";
6702 memset(&objc_class, '\0', sizeof(struct objc_class_t));
6703 memcpy(&objc_class, r, left);
6705 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6706 swapStruct(objc_class);
6707 print_objc_class_t(&objc_class, &info);
6708 } else {
6709 outs() << "(not in an __OBJC section)\n";
6712 if (CLS_GETINFO(&objc_class, CLS_CLASS)) {
6713 outs() << "\tMeta Class";
6714 r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);
6715 if (r != nullptr) {
6716 if (left > sizeof(struct objc_class_t)) {
6717 outs() << "\n";
6718 memcpy(&objc_class, r, sizeof(struct objc_class_t));
6719 } else {
6720 outs() << " (entends past the end of the section)\n";
6721 memset(&objc_class, '\0', sizeof(struct objc_class_t));
6722 memcpy(&objc_class, r, left);
6724 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6725 swapStruct(objc_class);
6726 print_objc_class_t(&objc_class, &info);
6727 } else {
6728 outs() << "(not in an __OBJC section)\n";
6732 if (symtab.cat_def_cnt > 0)
6733 outs() << "\tCategory Definitions\n";
6734 for (j = 0; j < symtab.cat_def_cnt; j++) {
6735 if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
6736 outs() << "\t(remaining category defs entries entends past the end of "
6737 << "the section)\n";
6738 break;
6740 memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
6741 sizeof(uint32_t));
6742 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6743 sys::swapByteOrder(def);
6745 r = get_pointer_32(def, xoffset, left, xS, &info, true);
6746 outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
6747 << format("0x%08" PRIx32, def);
6748 if (r != nullptr) {
6749 if (left > sizeof(struct objc_category_t)) {
6750 outs() << "\n";
6751 memcpy(&objc_category, r, sizeof(struct objc_category_t));
6752 } else {
6753 outs() << " (entends past the end of the section)\n";
6754 memset(&objc_category, '\0', sizeof(struct objc_category_t));
6755 memcpy(&objc_category, r, left);
6757 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6758 swapStruct(objc_category);
6759 print_objc_objc_category_t(&objc_category, &info);
6760 } else {
6761 outs() << "(not in an __OBJC section)\n";
6765 const SectionRef II = get_section(O, "__OBJC", "__image_info");
6766 if (II != SectionRef())
6767 print_image_info(II, &info);
6769 return true;
6772 static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
6773 uint32_t size, uint32_t addr) {
6774 SymbolAddressMap AddrMap;
6775 CreateSymbolAddressMap(O, &AddrMap);
6777 std::vector<SectionRef> Sections;
6778 append_range(Sections, O->sections());
6780 struct DisassembleInfo info(O, &AddrMap, &Sections, true);
6782 const char *p;
6783 struct objc_protocol_t protocol;
6784 uint32_t left, paddr;
6785 for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
6786 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
6787 left = size - (p - sect);
6788 if (left < sizeof(struct objc_protocol_t)) {
6789 outs() << "Protocol extends past end of __protocol section\n";
6790 memcpy(&protocol, p, left);
6791 } else
6792 memcpy(&protocol, p, sizeof(struct objc_protocol_t));
6793 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6794 swapStruct(protocol);
6795 paddr = addr + (p - sect);
6796 outs() << "Protocol " << format("0x%" PRIx32, paddr);
6797 if (print_protocol(paddr, 0, &info))
6798 outs() << "(not in an __OBJC section)\n";
6802 static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
6803 if (O->is64Bit())
6804 printObjc2_64bit_MetaData(O, verbose);
6805 else {
6806 MachO::mach_header H;
6807 H = O->getHeader();
6808 if (H.cputype == MachO::CPU_TYPE_ARM)
6809 printObjc2_32bit_MetaData(O, verbose);
6810 else {
6811 // This is the 32-bit non-arm cputype case. Which is normally
6812 // the first Objective-C ABI. But it may be the case of a
6813 // binary for the iOS simulator which is the second Objective-C
6814 // ABI. In that case printObjc1_32bit_MetaData() will determine that
6815 // and return false.
6816 if (!printObjc1_32bit_MetaData(O, verbose))
6817 printObjc2_32bit_MetaData(O, verbose);
6822 // GuessLiteralPointer returns a string which for the item in the Mach-O file
6823 // for the address passed in as ReferenceValue for printing as a comment with
6824 // the instruction and also returns the corresponding type of that item
6825 // indirectly through ReferenceType.
6827 // If ReferenceValue is an address of literal cstring then a pointer to the
6828 // cstring is returned and ReferenceType is set to
6829 // LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
6831 // If ReferenceValue is an address of an Objective-C CFString, Selector ref or
6832 // Class ref that name is returned and the ReferenceType is set accordingly.
6834 // Lastly, literals which are Symbol address in a literal pool are looked for
6835 // and if found the symbol name is returned and ReferenceType is set to
6836 // LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
6838 // If there is no item in the Mach-O file for the address passed in as
6839 // ReferenceValue nullptr is returned and ReferenceType is unchanged.
6840 static const char *GuessLiteralPointer(uint64_t ReferenceValue,
6841 uint64_t ReferencePC,
6842 uint64_t *ReferenceType,
6843 struct DisassembleInfo *info) {
6844 // First see if there is an external relocation entry at the ReferencePC.
6845 if (info->O->getHeader().filetype == MachO::MH_OBJECT) {
6846 uint64_t sect_addr = info->S.getAddress();
6847 uint64_t sect_offset = ReferencePC - sect_addr;
6848 bool reloc_found = false;
6849 DataRefImpl Rel;
6850 MachO::any_relocation_info RE;
6851 bool isExtern = false;
6852 SymbolRef Symbol;
6853 for (const RelocationRef &Reloc : info->S.relocations()) {
6854 uint64_t RelocOffset = Reloc.getOffset();
6855 if (RelocOffset == sect_offset) {
6856 Rel = Reloc.getRawDataRefImpl();
6857 RE = info->O->getRelocation(Rel);
6858 if (info->O->isRelocationScattered(RE))
6859 continue;
6860 isExtern = info->O->getPlainRelocationExternal(RE);
6861 if (isExtern) {
6862 symbol_iterator RelocSym = Reloc.getSymbol();
6863 Symbol = *RelocSym;
6865 reloc_found = true;
6866 break;
6869 // If there is an external relocation entry for a symbol in a section
6870 // then used that symbol's value for the value of the reference.
6871 if (reloc_found && isExtern) {
6872 if (info->O->getAnyRelocationPCRel(RE)) {
6873 unsigned Type = info->O->getAnyRelocationType(RE);
6874 if (Type == MachO::X86_64_RELOC_SIGNED) {
6875 ReferenceValue = cantFail(Symbol.getValue());
6881 // Look for literals such as Objective-C CFStrings refs, Selector refs,
6882 // Message refs and Class refs.
6883 bool classref, selref, msgref, cfstring;
6884 uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
6885 selref, msgref, cfstring);
6886 if (classref && pointer_value == 0) {
6887 // Note the ReferenceValue is a pointer into the __objc_classrefs section.
6888 // And the pointer_value in that section is typically zero as it will be
6889 // set by dyld as part of the "bind information".
6890 const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
6891 if (name != nullptr) {
6892 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6893 const char *class_name = strrchr(name, '$');
6894 if (class_name != nullptr && class_name[1] == '_' &&
6895 class_name[2] != '\0') {
6896 info->class_name = class_name + 2;
6897 return name;
6902 if (classref) {
6903 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6904 const char *name =
6905 get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
6906 if (name != nullptr)
6907 info->class_name = name;
6908 else
6909 name = "bad class ref";
6910 return name;
6913 if (cfstring) {
6914 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
6915 const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
6916 return name;
6919 if (selref && pointer_value == 0)
6920 pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
6922 if (pointer_value != 0)
6923 ReferenceValue = pointer_value;
6925 const char *name = GuessCstringPointer(ReferenceValue, info);
6926 if (name) {
6927 if (pointer_value != 0 && selref) {
6928 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
6929 info->selector_name = name;
6930 } else if (pointer_value != 0 && msgref) {
6931 info->class_name = nullptr;
6932 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
6933 info->selector_name = name;
6934 } else
6935 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;
6936 return name;
6939 // Lastly look for an indirect symbol with this ReferenceValue which is in
6940 // a literal pool. If found return that symbol name.
6941 name = GuessIndirectSymbol(ReferenceValue, info);
6942 if (name) {
6943 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
6944 return name;
6947 return nullptr;
6950 // SymbolizerSymbolLookUp is the symbol lookup function passed when creating
6951 // the Symbolizer. It looks up the ReferenceValue using the info passed via the
6952 // pointer to the struct DisassembleInfo that was passed when MCSymbolizer
6953 // is created and returns the symbol name that matches the ReferenceValue or
6954 // nullptr if none. The ReferenceType is passed in for the IN type of
6955 // reference the instruction is making from the values in defined in the header
6956 // "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
6957 // Out type and the ReferenceName will also be set which is added as a comment
6958 // to the disassembled instruction.
6960 // If the symbol name is a C++ mangled name then the demangled name is
6961 // returned through ReferenceName and ReferenceType is set to
6962 // LLVMDisassembler_ReferenceType_DeMangled_Name .
6964 // When this is called to get a symbol name for a branch target then the
6965 // ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
6966 // SymbolValue will be looked for in the indirect symbol table to determine if
6967 // it is an address for a symbol stub. If so then the symbol name for that
6968 // stub is returned indirectly through ReferenceName and then ReferenceType is
6969 // set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
6971 // When this is called with an value loaded via a PC relative load then
6972 // ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
6973 // SymbolValue is checked to be an address of literal pointer, symbol pointer,
6974 // or an Objective-C meta data reference. If so the output ReferenceType is
6975 // set to correspond to that as well as setting the ReferenceName.
6976 static const char *SymbolizerSymbolLookUp(void *DisInfo,
6977 uint64_t ReferenceValue,
6978 uint64_t *ReferenceType,
6979 uint64_t ReferencePC,
6980 const char **ReferenceName) {
6981 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
6982 // If no verbose symbolic information is wanted then just return nullptr.
6983 if (!info->verbose) {
6984 *ReferenceName = nullptr;
6985 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6986 return nullptr;
6989 const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
6991 if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
6992 *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
6993 if (*ReferenceName != nullptr) {
6994 method_reference(info, ReferenceType, ReferenceName);
6995 if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
6996 *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
6997 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
6998 if (info->demangled_name != nullptr)
6999 free(info->demangled_name);
7000 info->demangled_name = itaniumDemangle(SymbolName + 1);
7001 if (info->demangled_name != nullptr) {
7002 *ReferenceName = info->demangled_name;
7003 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
7004 } else
7005 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7006 } else
7007 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7008 } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
7009 *ReferenceName =
7010 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7011 if (*ReferenceName)
7012 method_reference(info, ReferenceType, ReferenceName);
7013 else
7014 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7015 // If this is arm64 and the reference is an adrp instruction save the
7016 // instruction, passed in ReferenceValue and the address of the instruction
7017 // for use later if we see and add immediate instruction.
7018 } else if (info->O->getArch() == Triple::aarch64 &&
7019 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
7020 info->adrp_inst = ReferenceValue;
7021 info->adrp_addr = ReferencePC;
7022 SymbolName = nullptr;
7023 *ReferenceName = nullptr;
7024 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7025 // If this is arm64 and reference is an add immediate instruction and we
7026 // have
7027 // seen an adrp instruction just before it and the adrp's Xd register
7028 // matches
7029 // this add's Xn register reconstruct the value being referenced and look to
7030 // see if it is a literal pointer. Note the add immediate instruction is
7031 // passed in ReferenceValue.
7032 } else if (info->O->getArch() == Triple::aarch64 &&
7033 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
7034 ReferencePC - 4 == info->adrp_addr &&
7035 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
7036 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7037 uint32_t addxri_inst;
7038 uint64_t adrp_imm, addxri_imm;
7040 adrp_imm =
7041 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7042 if (info->adrp_inst & 0x0200000)
7043 adrp_imm |= 0xfffffffffc000000LL;
7045 addxri_inst = ReferenceValue;
7046 addxri_imm = (addxri_inst >> 10) & 0xfff;
7047 if (((addxri_inst >> 22) & 0x3) == 1)
7048 addxri_imm <<= 12;
7050 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7051 (adrp_imm << 12) + addxri_imm;
7053 *ReferenceName =
7054 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7055 if (*ReferenceName == nullptr)
7056 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7057 // If this is arm64 and the reference is a load register instruction and we
7058 // have seen an adrp instruction just before it and the adrp's Xd register
7059 // matches this add's Xn register reconstruct the value being referenced and
7060 // look to see if it is a literal pointer. Note the load register
7061 // instruction is passed in ReferenceValue.
7062 } else if (info->O->getArch() == Triple::aarch64 &&
7063 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&
7064 ReferencePC - 4 == info->adrp_addr &&
7065 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
7066 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7067 uint32_t ldrxui_inst;
7068 uint64_t adrp_imm, ldrxui_imm;
7070 adrp_imm =
7071 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7072 if (info->adrp_inst & 0x0200000)
7073 adrp_imm |= 0xfffffffffc000000LL;
7075 ldrxui_inst = ReferenceValue;
7076 ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
7078 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7079 (adrp_imm << 12) + (ldrxui_imm << 3);
7081 *ReferenceName =
7082 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7083 if (*ReferenceName == nullptr)
7084 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7086 // If this arm64 and is an load register (PC-relative) instruction the
7087 // ReferenceValue is the PC plus the immediate value.
7088 else if (info->O->getArch() == Triple::aarch64 &&
7089 (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||
7090 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {
7091 *ReferenceName =
7092 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7093 if (*ReferenceName == nullptr)
7094 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7095 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
7096 if (info->demangled_name != nullptr)
7097 free(info->demangled_name);
7098 info->demangled_name = itaniumDemangle(SymbolName + 1);
7099 if (info->demangled_name != nullptr) {
7100 *ReferenceName = info->demangled_name;
7101 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
7104 else {
7105 *ReferenceName = nullptr;
7106 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7109 return SymbolName;
7112 /// Emits the comments that are stored in the CommentStream.
7113 /// Each comment in the CommentStream must end with a newline.
7114 static void emitComments(raw_svector_ostream &CommentStream,
7115 SmallString<128> &CommentsToEmit,
7116 formatted_raw_ostream &FormattedOS,
7117 const MCAsmInfo &MAI) {
7118 // Flush the stream before taking its content.
7119 StringRef Comments = CommentsToEmit.str();
7120 // Get the default information for printing a comment.
7121 StringRef CommentBegin = MAI.getCommentString();
7122 unsigned CommentColumn = MAI.getCommentColumn();
7123 ListSeparator LS("\n");
7124 while (!Comments.empty()) {
7125 FormattedOS << LS;
7126 // Emit a line of comments.
7127 FormattedOS.PadToColumn(CommentColumn);
7128 size_t Position = Comments.find('\n');
7129 FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
7130 // Move after the newline character.
7131 Comments = Comments.substr(Position + 1);
7133 FormattedOS.flush();
7135 // Tell the comment stream that the vector changed underneath it.
7136 CommentsToEmit.clear();
7139 const MachOObjectFile *
7140 objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,
7141 std::unique_ptr<Binary> &DSYMBinary,
7142 std::unique_ptr<MemoryBuffer> &DSYMBuf) {
7143 const MachOObjectFile *DbgObj = MachOOF;
7144 std::string DSYMPath;
7146 // Auto-detect w/o --dsym.
7147 if (DSYMFile.empty()) {
7148 sys::fs::file_status DSYMStatus;
7149 Twine FilenameDSYM = Filename + ".dSYM";
7150 if (!status(FilenameDSYM, DSYMStatus)) {
7151 if (sys::fs::is_directory(DSYMStatus)) {
7152 SmallString<1024> Path;
7153 FilenameDSYM.toVector(Path);
7154 sys::path::append(Path, "Contents", "Resources", "DWARF",
7155 sys::path::filename(Filename));
7156 DSYMPath = std::string(Path);
7157 } else if (sys::fs::is_regular_file(DSYMStatus)) {
7158 DSYMPath = FilenameDSYM.str();
7163 if (DSYMPath.empty() && !DSYMFile.empty()) {
7164 // If DSYMPath is a .dSYM directory, append the Mach-O file.
7165 if (sys::fs::is_directory(DSYMFile) &&
7166 sys::path::extension(DSYMFile) == ".dSYM") {
7167 SmallString<128> ShortName(sys::path::filename(DSYMFile));
7168 sys::path::replace_extension(ShortName, "");
7169 SmallString<1024> FullPath(DSYMFile);
7170 sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);
7171 DSYMPath = FullPath.str();
7172 } else {
7173 DSYMPath = DSYMFile;
7177 if (!DSYMPath.empty()) {
7178 // Load the file.
7179 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
7180 MemoryBuffer::getFileOrSTDIN(DSYMPath);
7181 if (std::error_code EC = BufOrErr.getError()) {
7182 reportError(errorCodeToError(EC), DSYMPath);
7183 return nullptr;
7186 // We need to keep the file alive, because we're replacing DbgObj with it.
7187 DSYMBuf = std::move(BufOrErr.get());
7189 Expected<std::unique_ptr<Binary>> BinaryOrErr =
7190 createBinary(DSYMBuf->getMemBufferRef());
7191 if (!BinaryOrErr) {
7192 reportError(BinaryOrErr.takeError(), DSYMPath);
7193 return nullptr;
7196 // We need to keep the Binary alive with the buffer
7197 DSYMBinary = std::move(BinaryOrErr.get());
7198 if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
7199 // this is a Mach-O object file, use it
7200 if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
7201 DbgObj = MachDSYM;
7202 } else {
7203 WithColor::error(errs(), "llvm-objdump")
7204 << DSYMPath << " is not a Mach-O file type.\n";
7205 return nullptr;
7207 } else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {
7208 // this is a Universal Binary, find a Mach-O for this architecture
7209 uint32_t CPUType, CPUSubType;
7210 const char *ArchFlag;
7211 if (MachOOF->is64Bit()) {
7212 const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
7213 CPUType = H_64.cputype;
7214 CPUSubType = H_64.cpusubtype;
7215 } else {
7216 const MachO::mach_header H = MachOOF->getHeader();
7217 CPUType = H.cputype;
7218 CPUSubType = H.cpusubtype;
7220 Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
7221 &ArchFlag);
7222 Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
7223 UB->getMachOObjectForArch(ArchFlag);
7224 if (!MachDSYM) {
7225 reportError(MachDSYM.takeError(), DSYMPath);
7226 return nullptr;
7229 // We need to keep the Binary alive with the buffer
7230 DbgObj = &*MachDSYM.get();
7231 DSYMBinary = std::move(*MachDSYM);
7232 } else {
7233 WithColor::error(errs(), "llvm-objdump")
7234 << DSYMPath << " is not a Mach-O or Universal file type.\n";
7235 return nullptr;
7238 return DbgObj;
7241 static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
7242 StringRef DisSegName, StringRef DisSectName) {
7243 const char *McpuDefault = nullptr;
7244 const Target *ThumbTarget = nullptr;
7245 const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
7246 if (!TheTarget) {
7247 // GetTarget prints out stuff.
7248 return;
7250 std::string MachOMCPU;
7251 if (MCPU.empty() && McpuDefault)
7252 MachOMCPU = McpuDefault;
7253 else
7254 MachOMCPU = MCPU;
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; \
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; \
7273 } while (false)
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);
7283 // Package up features to be passed to target/subtarget
7284 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();
7292 MCTargetOptions MCOptions;
7293 // Set up disassembler.
7294 std::unique_ptr<const MCRegisterInfo> MRI(
7295 TheTarget->createMCRegInfo(TripleName));
7296 CHECK_TARGET_INFO_CREATION(MRI);
7297 std::unique_ptr<const MCAsmInfo> AsmInfo(
7298 TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
7299 CHECK_TARGET_INFO_CREATION(AsmInfo);
7300 std::unique_ptr<const MCSubtargetInfo> STI(
7301 TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr));
7302 CHECK_TARGET_INFO_CREATION(STI);
7303 MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
7304 std::unique_ptr<MCDisassembler> DisAsm(
7305 TheTarget->createMCDisassembler(*STI, Ctx));
7306 CHECK_TARGET_INFO_CREATION(DisAsm);
7307 std::unique_ptr<MCSymbolizer> Symbolizer;
7308 struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);
7309 std::unique_ptr<MCRelocationInfo> RelInfo(
7310 TheTarget->createMCRelocationInfo(TripleName, Ctx));
7311 if (RelInfo) {
7312 Symbolizer.reset(TheTarget->createMCSymbolizer(
7313 TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
7314 &SymbolizerInfo, &Ctx, std::move(RelInfo)));
7315 DisAsm->setSymbolizer(std::move(Symbolizer));
7317 int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
7318 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
7319 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));
7320 CHECK_TARGET_INFO_CREATION(IP);
7321 // Set the display preference for hex vs. decimal immediates.
7322 IP->setPrintImmHex(PrintImmHex);
7323 // Comment stream and backing vector.
7324 SmallString<128> CommentsToEmit;
7325 raw_svector_ostream CommentStream(CommentsToEmit);
7326 // FIXME: Setting the CommentStream in the InstPrinter is problematic in that
7327 // if it is done then arm64 comments for string literals don't get printed
7328 // and some constant get printed instead and not setting it causes intel
7329 // (32-bit and 64-bit) comments printed with different spacing before the
7330 // comment causing different diffs with the 'C' disassembler library API.
7331 // IP->setCommentStream(CommentStream);
7333 for (StringRef Opt : DisassemblerOptions)
7334 if (!IP->applyTargetSpecificCLOption(Opt))
7335 reportError(Filename, "unrecognized disassembler option: " + Opt);
7337 // Set up separate thumb disassembler if needed.
7338 std::unique_ptr<const MCRegisterInfo> ThumbMRI;
7339 std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
7340 std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
7341 std::unique_ptr<MCDisassembler> ThumbDisAsm;
7342 std::unique_ptr<MCInstPrinter> ThumbIP;
7343 std::unique_ptr<MCContext> ThumbCtx;
7344 std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
7345 struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);
7346 std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
7347 if (ThumbTarget) {
7348 ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
7349 CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);
7350 ThumbAsmInfo.reset(
7351 ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName, MCOptions));
7352 CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);
7353 ThumbSTI.reset(
7354 ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU,
7355 FeaturesStr));
7356 CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);
7357 ThumbCtx.reset(new MCContext(Triple(ThumbTripleName), ThumbAsmInfo.get(),
7358 ThumbMRI.get(), ThumbSTI.get()));
7359 ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
7360 CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);
7361 MCContext *PtrThumbCtx = ThumbCtx.get();
7362 ThumbRelInfo.reset(
7363 ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));
7364 if (ThumbRelInfo) {
7365 ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
7366 ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
7367 &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
7368 ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
7370 int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
7371 ThumbIP.reset(ThumbTarget->createMCInstPrinter(
7372 Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,
7373 *ThumbInstrInfo, *ThumbMRI));
7374 CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);
7375 // Set the display preference for hex vs. decimal immediates.
7376 ThumbIP->setPrintImmHex(PrintImmHex);
7379 #undef CHECK_TARGET_INFO_CREATION
7380 #undef CHECK_THUMB_TARGET_INFO_CREATION
7382 MachO::mach_header Header = MachOOF->getHeader();
7384 // FIXME: Using the -cfg command line option, this code used to be able to
7385 // annotate relocations with the referenced symbol's name, and if this was
7386 // inside a __[cf]string section, the data it points to. This is now replaced
7387 // by the upcoming MCSymbolizer, which needs the appropriate setup done above.
7388 std::vector<SectionRef> Sections;
7389 std::vector<SymbolRef> Symbols;
7390 SmallVector<uint64_t, 8> FoundFns;
7391 uint64_t BaseSegmentAddress = 0;
7393 getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,
7394 BaseSegmentAddress);
7396 // Sort the symbols by address, just in case they didn't come in that way.
7397 llvm::stable_sort(Symbols, SymbolSorter());
7399 // Build a data in code table that is sorted on by the address of each entry.
7400 uint64_t BaseAddress = 0;
7401 if (Header.filetype == MachO::MH_OBJECT)
7402 BaseAddress = Sections[0].getAddress();
7403 else
7404 BaseAddress = BaseSegmentAddress;
7405 DiceTable Dices;
7406 for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
7407 DI != DE; ++DI) {
7408 uint32_t Offset;
7409 DI->getOffset(Offset);
7410 Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
7412 array_pod_sort(Dices.begin(), Dices.end());
7414 // Try to find debug info and set up the DIContext for it.
7415 std::unique_ptr<DIContext> diContext;
7416 std::unique_ptr<Binary> DSYMBinary;
7417 std::unique_ptr<MemoryBuffer> DSYMBuf;
7418 if (UseDbg) {
7419 // If separate DSym file path was specified, parse it as a macho file,
7420 // get the sections and supply it to the section name parsing machinery.
7421 if (const ObjectFile *DbgObj =
7422 getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf)) {
7423 // Setup the DIContext
7424 diContext = DWARFContext::create(*DbgObj);
7425 } else {
7426 return;
7430 if (FilterSections.empty())
7431 outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
7433 for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
7434 Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();
7435 if (!SecNameOrErr) {
7436 consumeError(SecNameOrErr.takeError());
7437 continue;
7439 if (*SecNameOrErr != DisSectName)
7440 continue;
7442 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
7444 StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
7445 if (SegmentName != DisSegName)
7446 continue;
7448 StringRef BytesStr =
7449 unwrapOrError(Sections[SectIdx].getContents(), Filename);
7450 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);
7451 uint64_t SectAddress = Sections[SectIdx].getAddress();
7453 bool symbolTableWorked = false;
7455 // Create a map of symbol addresses to symbol names for use by
7456 // the SymbolizerSymbolLookUp() routine.
7457 SymbolAddressMap AddrMap;
7458 bool DisSymNameFound = false;
7459 for (const SymbolRef &Symbol : MachOOF->symbols()) {
7460 SymbolRef::Type ST =
7461 unwrapOrError(Symbol.getType(), MachOOF->getFileName());
7462 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
7463 ST == SymbolRef::ST_Other) {
7464 uint64_t Address = cantFail(Symbol.getValue());
7465 StringRef SymName =
7466 unwrapOrError(Symbol.getName(), MachOOF->getFileName());
7467 AddrMap[Address] = SymName;
7468 if (!DisSymName.empty() && DisSymName == SymName)
7469 DisSymNameFound = true;
7472 if (!DisSymName.empty() && !DisSymNameFound) {
7473 outs() << "Can't find -dis-symname: " << DisSymName << "\n";
7474 return;
7476 // Set up the block of info used by the Symbolizer call backs.
7477 SymbolizerInfo.verbose = SymbolicOperands;
7478 SymbolizerInfo.O = MachOOF;
7479 SymbolizerInfo.S = Sections[SectIdx];
7480 SymbolizerInfo.AddrMap = &AddrMap;
7481 SymbolizerInfo.Sections = &Sections;
7482 // Same for the ThumbSymbolizer
7483 ThumbSymbolizerInfo.verbose = SymbolicOperands;
7484 ThumbSymbolizerInfo.O = MachOOF;
7485 ThumbSymbolizerInfo.S = Sections[SectIdx];
7486 ThumbSymbolizerInfo.AddrMap = &AddrMap;
7487 ThumbSymbolizerInfo.Sections = &Sections;
7489 unsigned int Arch = MachOOF->getArch();
7491 // Skip all symbols if this is a stubs file.
7492 if (Bytes.empty())
7493 return;
7495 // If the section has symbols but no symbol at the start of the section
7496 // these are used to make sure the bytes before the first symbol are
7497 // disassembled.
7498 bool FirstSymbol = true;
7499 bool FirstSymbolAtSectionStart = true;
7501 // Disassemble symbol by symbol.
7502 for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
7503 StringRef SymName =
7504 unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());
7505 SymbolRef::Type ST =
7506 unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());
7507 if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
7508 continue;
7510 // Make sure the symbol is defined in this section.
7511 bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);
7512 if (!containsSym) {
7513 if (!DisSymName.empty() && DisSymName == SymName) {
7514 outs() << "-dis-symname: " << DisSymName << " not in the section\n";
7515 return;
7517 continue;
7519 // The __mh_execute_header is special and we need to deal with that fact
7520 // this symbol is before the start of the (__TEXT,__text) section and at the
7521 // address of the start of the __TEXT segment. This is because this symbol
7522 // is an N_SECT symbol in the (__TEXT,__text) but its address is before the
7523 // start of the section in a standard MH_EXECUTE filetype.
7524 if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {
7525 outs() << "-dis-symname: __mh_execute_header not in any section\n";
7526 return;
7528 // When this code is trying to disassemble a symbol at a time and in the
7529 // case there is only the __mh_execute_header symbol left as in a stripped
7530 // executable, we need to deal with this by ignoring this symbol so the
7531 // whole section is disassembled and this symbol is then not displayed.
7532 if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||
7533 SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||
7534 SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")
7535 continue;
7537 // If we are only disassembling one symbol see if this is that symbol.
7538 if (!DisSymName.empty() && DisSymName != SymName)
7539 continue;
7541 // Start at the address of the symbol relative to the section's address.
7542 uint64_t SectSize = Sections[SectIdx].getSize();
7543 uint64_t Start = cantFail(Symbols[SymIdx].getValue());
7544 uint64_t SectionAddress = Sections[SectIdx].getAddress();
7545 Start -= SectionAddress;
7547 if (Start > SectSize) {
7548 outs() << "section data ends, " << SymName
7549 << " lies outside valid range\n";
7550 return;
7553 // Stop disassembling either at the beginning of the next symbol or at
7554 // the end of the section.
7555 bool containsNextSym = false;
7556 uint64_t NextSym = 0;
7557 uint64_t NextSymIdx = SymIdx + 1;
7558 while (Symbols.size() > NextSymIdx) {
7559 SymbolRef::Type NextSymType = unwrapOrError(
7560 Symbols[NextSymIdx].getType(), MachOOF->getFileName());
7561 if (NextSymType == SymbolRef::ST_Function) {
7562 containsNextSym =
7563 Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
7564 NextSym = cantFail(Symbols[NextSymIdx].getValue());
7565 NextSym -= SectionAddress;
7566 break;
7568 ++NextSymIdx;
7571 uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;
7572 uint64_t Size;
7574 symbolTableWorked = true;
7576 DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
7577 uint32_t SymbolFlags = cantFail(MachOOF->getSymbolFlags(Symb));
7578 bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;
7580 // We only need the dedicated Thumb target if there's a real choice
7581 // (i.e. we're not targeting M-class) and the function is Thumb.
7582 bool UseThumbTarget = IsThumb && ThumbTarget;
7584 // If we are not specifying a symbol to start disassembly with and this
7585 // is the first symbol in the section but not at the start of the section
7586 // then move the disassembly index to the start of the section and
7587 // don't print the symbol name just yet. This is so the bytes before the
7588 // first symbol are disassembled.
7589 uint64_t SymbolStart = Start;
7590 if (DisSymName.empty() && FirstSymbol && Start != 0) {
7591 FirstSymbolAtSectionStart = false;
7592 Start = 0;
7594 else
7595 outs() << SymName << ":\n";
7597 DILineInfo lastLine;
7598 for (uint64_t Index = Start; Index < End; Index += Size) {
7599 MCInst Inst;
7601 // If this is the first symbol in the section and it was not at the
7602 // start of the section, see if we are at its Index now and if so print
7603 // the symbol name.
7604 if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
7605 outs() << SymName << ":\n";
7607 uint64_t PC = SectAddress + Index;
7608 if (LeadingAddr) {
7609 if (FullLeadingAddr) {
7610 if (MachOOF->is64Bit())
7611 outs() << format("%016" PRIx64, PC);
7612 else
7613 outs() << format("%08" PRIx64, PC);
7614 } else {
7615 outs() << format("%8" PRIx64 ":", PC);
7618 if (ShowRawInsn || Arch == Triple::arm)
7619 outs() << "\t";
7621 if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))
7622 continue;
7624 SmallVector<char, 64> AnnotationsBytes;
7625 raw_svector_ostream Annotations(AnnotationsBytes);
7627 bool gotInst;
7628 if (UseThumbTarget)
7629 gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
7630 PC, Annotations);
7631 else
7632 gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,
7633 Annotations);
7634 if (gotInst) {
7635 if (ShowRawInsn || Arch == Triple::arm) {
7636 dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());
7638 formatted_raw_ostream FormattedOS(outs());
7639 StringRef AnnotationsStr = Annotations.str();
7640 if (UseThumbTarget)
7641 ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI,
7642 FormattedOS);
7643 else
7644 IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);
7645 emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
7647 // Print debug info.
7648 if (diContext) {
7649 DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
7650 // Print valid line info if it changed.
7651 if (dli != lastLine && dli.Line != 0)
7652 outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
7653 << dli.Column;
7654 lastLine = dli;
7656 outs() << "\n";
7657 } else {
7658 if (MachOOF->getArchTriple().isX86()) {
7659 outs() << format("\t.byte 0x%02x #bad opcode\n",
7660 *(Bytes.data() + Index) & 0xff);
7661 Size = 1; // skip exactly one illegible byte and move on.
7662 } else if (Arch == Triple::aarch64 ||
7663 (Arch == Triple::arm && !IsThumb)) {
7664 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7665 (*(Bytes.data() + Index + 1) & 0xff) << 8 |
7666 (*(Bytes.data() + Index + 2) & 0xff) << 16 |
7667 (*(Bytes.data() + Index + 3) & 0xff) << 24;
7668 outs() << format("\t.long\t0x%08x\n", opcode);
7669 Size = 4;
7670 } else if (Arch == Triple::arm) {
7671 assert(IsThumb && "ARM mode should have been dealt with above");
7672 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7673 (*(Bytes.data() + Index + 1) & 0xff) << 8;
7674 outs() << format("\t.short\t0x%04x\n", opcode);
7675 Size = 2;
7676 } else{
7677 WithColor::warning(errs(), "llvm-objdump")
7678 << "invalid instruction encoding\n";
7679 if (Size == 0)
7680 Size = 1; // skip illegible bytes
7684 // Now that we are done disassembled the first symbol set the bool that
7685 // were doing this to false.
7686 FirstSymbol = false;
7688 if (!symbolTableWorked) {
7689 // Reading the symbol table didn't work, disassemble the whole section.
7690 uint64_t SectAddress = Sections[SectIdx].getAddress();
7691 uint64_t SectSize = Sections[SectIdx].getSize();
7692 uint64_t InstSize;
7693 for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
7694 MCInst Inst;
7696 uint64_t PC = SectAddress + Index;
7698 if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize))
7699 continue;
7701 SmallVector<char, 64> AnnotationsBytes;
7702 raw_svector_ostream Annotations(AnnotationsBytes);
7703 if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
7704 Annotations)) {
7705 if (LeadingAddr) {
7706 if (FullLeadingAddr) {
7707 if (MachOOF->is64Bit())
7708 outs() << format("%016" PRIx64, PC);
7709 else
7710 outs() << format("%08" PRIx64, PC);
7711 } else {
7712 outs() << format("%8" PRIx64 ":", PC);
7715 if (ShowRawInsn || Arch == Triple::arm) {
7716 outs() << "\t";
7717 dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());
7719 StringRef AnnotationsStr = Annotations.str();
7720 IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());
7721 outs() << "\n";
7722 } else {
7723 if (MachOOF->getArchTriple().isX86()) {
7724 outs() << format("\t.byte 0x%02x #bad opcode\n",
7725 *(Bytes.data() + Index) & 0xff);
7726 InstSize = 1; // skip exactly one illegible byte and move on.
7727 } else {
7728 WithColor::warning(errs(), "llvm-objdump")
7729 << "invalid instruction encoding\n";
7730 if (InstSize == 0)
7731 InstSize = 1; // skip illegible bytes
7736 // The TripleName's need to be reset if we are called again for a different
7737 // architecture.
7738 TripleName = "";
7739 ThumbTripleName = "";
7741 if (SymbolizerInfo.demangled_name != nullptr)
7742 free(SymbolizerInfo.demangled_name);
7743 if (ThumbSymbolizerInfo.demangled_name != nullptr)
7744 free(ThumbSymbolizerInfo.demangled_name);
7748 //===----------------------------------------------------------------------===//
7749 // __compact_unwind section dumping
7750 //===----------------------------------------------------------------------===//
7752 namespace {
7754 template <typename T>
7755 static uint64_t read(StringRef Contents, ptrdiff_t Offset) {
7756 if (Offset + sizeof(T) > Contents.size()) {
7757 outs() << "warning: attempt to read past end of buffer\n";
7758 return T();
7761 uint64_t Val = support::endian::read<T, llvm::endianness::little>(
7762 Contents.data() + Offset);
7763 return Val;
7766 template <typename T>
7767 static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {
7768 T Val = read<T>(Contents, Offset);
7769 Offset += sizeof(T);
7770 return Val;
7773 struct CompactUnwindEntry {
7774 uint32_t OffsetInSection;
7776 uint64_t FunctionAddr;
7777 uint32_t Length;
7778 uint32_t CompactEncoding;
7779 uint64_t PersonalityAddr;
7780 uint64_t LSDAAddr;
7782 RelocationRef FunctionReloc;
7783 RelocationRef PersonalityReloc;
7784 RelocationRef LSDAReloc;
7786 CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
7787 : OffsetInSection(Offset) {
7788 if (Is64)
7789 read<uint64_t>(Contents, Offset);
7790 else
7791 read<uint32_t>(Contents, Offset);
7794 private:
7795 template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {
7796 FunctionAddr = readNext<UIntPtr>(Contents, Offset);
7797 Length = readNext<uint32_t>(Contents, Offset);
7798 CompactEncoding = readNext<uint32_t>(Contents, Offset);
7799 PersonalityAddr = readNext<UIntPtr>(Contents, Offset);
7800 LSDAAddr = readNext<UIntPtr>(Contents, Offset);
7805 /// Given a relocation from __compact_unwind, consisting of the RelocationRef
7806 /// and data being relocated, determine the best base Name and Addend to use for
7807 /// display purposes.
7809 /// 1. An Extern relocation will directly reference a symbol (and the data is
7810 /// then already an addend), so use that.
7811 /// 2. Otherwise the data is an offset in the object file's layout; try to find
7812 // a symbol before it in the same section, and use the offset from there.
7813 /// 3. Finally, if all that fails, fall back to an offset from the start of the
7814 /// referenced section.
7815 static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
7816 std::map<uint64_t, SymbolRef> &Symbols,
7817 const RelocationRef &Reloc, uint64_t Addr,
7818 StringRef &Name, uint64_t &Addend) {
7819 if (Reloc.getSymbol() != Obj->symbol_end()) {
7820 Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());
7821 Addend = Addr;
7822 return;
7825 auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
7826 SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
7828 uint64_t SectionAddr = RelocSection.getAddress();
7830 auto Sym = Symbols.upper_bound(Addr);
7831 if (Sym == Symbols.begin()) {
7832 // The first symbol in the object is after this reference, the best we can
7833 // do is section-relative notation.
7834 if (Expected<StringRef> NameOrErr = RelocSection.getName())
7835 Name = *NameOrErr;
7836 else
7837 consumeError(NameOrErr.takeError());
7839 Addend = Addr - SectionAddr;
7840 return;
7843 // Go back one so that SymbolAddress <= Addr.
7844 --Sym;
7846 section_iterator SymSection =
7847 unwrapOrError(Sym->second.getSection(), Obj->getFileName());
7848 if (RelocSection == *SymSection) {
7849 // There's a valid symbol in the same section before this reference.
7850 Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());
7851 Addend = Addr - Sym->first;
7852 return;
7855 // There is a symbol before this reference, but it's in a different
7856 // section. Probably not helpful to mention it, so use the section name.
7857 if (Expected<StringRef> NameOrErr = RelocSection.getName())
7858 Name = *NameOrErr;
7859 else
7860 consumeError(NameOrErr.takeError());
7862 Addend = Addr - SectionAddr;
7865 static void printUnwindRelocDest(const MachOObjectFile *Obj,
7866 std::map<uint64_t, SymbolRef> &Symbols,
7867 const RelocationRef &Reloc, uint64_t Addr) {
7868 StringRef Name;
7869 uint64_t Addend;
7871 if (!Reloc.getObject())
7872 return;
7874 findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
7876 outs() << Name;
7877 if (Addend)
7878 outs() << " + " << format("0x%" PRIx64, Addend);
7881 static void
7882 printMachOCompactUnwindSection(const MachOObjectFile *Obj,
7883 std::map<uint64_t, SymbolRef> &Symbols,
7884 const SectionRef &CompactUnwind) {
7886 if (!Obj->isLittleEndian()) {
7887 outs() << "Skipping big-endian __compact_unwind section\n";
7888 return;
7891 bool Is64 = Obj->is64Bit();
7892 uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
7893 uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
7895 StringRef Contents =
7896 unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());
7897 SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
7899 // First populate the initial raw offsets, encodings and so on from the entry.
7900 for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
7901 CompactUnwindEntry Entry(Contents, Offset, Is64);
7902 CompactUnwinds.push_back(Entry);
7905 // Next we need to look at the relocations to find out what objects are
7906 // actually being referred to.
7907 for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
7908 uint64_t RelocAddress = Reloc.getOffset();
7910 uint32_t EntryIdx = RelocAddress / EntrySize;
7911 uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
7912 CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
7914 if (OffsetInEntry == 0)
7915 Entry.FunctionReloc = Reloc;
7916 else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
7917 Entry.PersonalityReloc = Reloc;
7918 else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
7919 Entry.LSDAReloc = Reloc;
7920 else {
7921 outs() << "Invalid relocation in __compact_unwind section\n";
7922 return;
7926 // Finally, we're ready to print the data we've gathered.
7927 outs() << "Contents of __compact_unwind section:\n";
7928 for (auto &Entry : CompactUnwinds) {
7929 outs() << " Entry at offset "
7930 << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";
7932 // 1. Start of the region this entry applies to.
7933 outs() << " start: " << format("0x%" PRIx64,
7934 Entry.FunctionAddr) << ' ';
7935 printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);
7936 outs() << '\n';
7938 // 2. Length of the region this entry applies to.
7939 outs() << " length: " << format("0x%" PRIx32, Entry.Length)
7940 << '\n';
7941 // 3. The 32-bit compact encoding.
7942 outs() << " compact encoding: "
7943 << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';
7945 // 4. The personality function, if present.
7946 if (Entry.PersonalityReloc.getObject()) {
7947 outs() << " personality function: "
7948 << format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';
7949 printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
7950 Entry.PersonalityAddr);
7951 outs() << '\n';
7954 // 5. This entry's language-specific data area.
7955 if (Entry.LSDAReloc.getObject()) {
7956 outs() << " LSDA: " << format("0x%" PRIx64,
7957 Entry.LSDAAddr) << ' ';
7958 printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
7959 outs() << '\n';
7964 //===----------------------------------------------------------------------===//
7965 // __unwind_info section dumping
7966 //===----------------------------------------------------------------------===//
7968 static void printRegularSecondLevelUnwindPage(StringRef PageData) {
7969 ptrdiff_t Pos = 0;
7970 uint32_t Kind = readNext<uint32_t>(PageData, Pos);
7971 (void)Kind;
7972 assert(Kind == 2 && "kind for a regular 2nd level index should be 2");
7974 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7975 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
7977 Pos = EntriesStart;
7978 for (unsigned i = 0; i < NumEntries; ++i) {
7979 uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);
7980 uint32_t Encoding = readNext<uint32_t>(PageData, Pos);
7982 outs() << " [" << i << "]: "
7983 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
7984 << ", "
7985 << "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';
7989 static void printCompressedSecondLevelUnwindPage(
7990 StringRef PageData, uint32_t FunctionBase,
7991 const SmallVectorImpl<uint32_t> &CommonEncodings) {
7992 ptrdiff_t Pos = 0;
7993 uint32_t Kind = readNext<uint32_t>(PageData, Pos);
7994 (void)Kind;
7995 assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");
7997 uint32_t NumCommonEncodings = CommonEncodings.size();
7998 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7999 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
8001 uint16_t PageEncodingsStart = readNext<uint16_t>(PageData, Pos);
8002 uint16_t NumPageEncodings = readNext<uint16_t>(PageData, Pos);
8003 SmallVector<uint32_t, 64> PageEncodings;
8004 if (NumPageEncodings) {
8005 outs() << " Page encodings: (count = " << NumPageEncodings << ")\n";
8006 Pos = PageEncodingsStart;
8007 for (unsigned i = 0; i < NumPageEncodings; ++i) {
8008 uint32_t Encoding = readNext<uint32_t>(PageData, Pos);
8009 PageEncodings.push_back(Encoding);
8010 outs() << " encoding[" << (i + NumCommonEncodings)
8011 << "]: " << format("0x%08" PRIx32, Encoding) << '\n';
8015 Pos = EntriesStart;
8016 for (unsigned i = 0; i < NumEntries; ++i) {
8017 uint32_t Entry = readNext<uint32_t>(PageData, Pos);
8018 uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
8019 uint32_t EncodingIdx = Entry >> 24;
8021 uint32_t Encoding;
8022 if (EncodingIdx < NumCommonEncodings)
8023 Encoding = CommonEncodings[EncodingIdx];
8024 else
8025 Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];
8027 outs() << " [" << i << "]: "
8028 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
8029 << ", "
8030 << "encoding[" << EncodingIdx
8031 << "]=" << format("0x%08" PRIx32, Encoding) << '\n';
8035 static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
8036 std::map<uint64_t, SymbolRef> &Symbols,
8037 const SectionRef &UnwindInfo) {
8039 if (!Obj->isLittleEndian()) {
8040 outs() << "Skipping big-endian __unwind_info section\n";
8041 return;
8044 outs() << "Contents of __unwind_info section:\n";
8046 StringRef Contents =
8047 unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());
8048 ptrdiff_t Pos = 0;
8050 //===----------------------------------
8051 // Section header
8052 //===----------------------------------
8054 uint32_t Version = readNext<uint32_t>(Contents, Pos);
8055 outs() << " Version: "
8056 << format("0x%" PRIx32, Version) << '\n';
8057 if (Version != 1) {
8058 outs() << " Skipping section with unknown version\n";
8059 return;
8062 uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);
8063 outs() << " Common encodings array section offset: "
8064 << format("0x%" PRIx32, CommonEncodingsStart) << '\n';
8065 uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);
8066 outs() << " Number of common encodings in array: "
8067 << format("0x%" PRIx32, NumCommonEncodings) << '\n';
8069 uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);
8070 outs() << " Personality function array section offset: "
8071 << format("0x%" PRIx32, PersonalitiesStart) << '\n';
8072 uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);
8073 outs() << " Number of personality functions in array: "
8074 << format("0x%" PRIx32, NumPersonalities) << '\n';
8076 uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);
8077 outs() << " Index array section offset: "
8078 << format("0x%" PRIx32, IndicesStart) << '\n';
8079 uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);
8080 outs() << " Number of indices in array: "
8081 << format("0x%" PRIx32, NumIndices) << '\n';
8083 //===----------------------------------
8084 // A shared list of common encodings
8085 //===----------------------------------
8087 // These occupy indices in the range [0, N] whenever an encoding is referenced
8088 // from a compressed 2nd level index table. In practice the linker only
8089 // creates ~128 of these, so that indices are available to embed encodings in
8090 // the 2nd level index.
8092 SmallVector<uint32_t, 64> CommonEncodings;
8093 outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
8094 Pos = CommonEncodingsStart;
8095 for (unsigned i = 0; i < NumCommonEncodings; ++i) {
8096 uint32_t Encoding = readNext<uint32_t>(Contents, Pos);
8097 CommonEncodings.push_back(Encoding);
8099 outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)
8100 << '\n';
8103 //===----------------------------------
8104 // Personality functions used in this executable
8105 //===----------------------------------
8107 // There should be only a handful of these (one per source language,
8108 // roughly). Particularly since they only get 2 bits in the compact encoding.
8110 outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
8111 Pos = PersonalitiesStart;
8112 for (unsigned i = 0; i < NumPersonalities; ++i) {
8113 uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);
8114 outs() << " personality[" << i + 1
8115 << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';
8118 //===----------------------------------
8119 // The level 1 index entries
8120 //===----------------------------------
8122 // These specify an approximate place to start searching for the more detailed
8123 // information, sorted by PC.
8125 struct IndexEntry {
8126 uint32_t FunctionOffset;
8127 uint32_t SecondLevelPageStart;
8128 uint32_t LSDAStart;
8131 SmallVector<IndexEntry, 4> IndexEntries;
8133 outs() << " Top level indices: (count = " << NumIndices << ")\n";
8134 Pos = IndicesStart;
8135 for (unsigned i = 0; i < NumIndices; ++i) {
8136 IndexEntry Entry;
8138 Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);
8139 Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);
8140 Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);
8141 IndexEntries.push_back(Entry);
8143 outs() << " [" << i << "]: "
8144 << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)
8145 << ", "
8146 << "2nd level page offset="
8147 << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "
8148 << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';
8151 //===----------------------------------
8152 // Next come the LSDA tables
8153 //===----------------------------------
8155 // The LSDA layout is rather implicit: it's a contiguous array of entries from
8156 // the first top-level index's LSDAOffset to the last (sentinel).
8158 outs() << " LSDA descriptors:\n";
8159 Pos = IndexEntries[0].LSDAStart;
8160 const uint32_t LSDASize = 2 * sizeof(uint32_t);
8161 int NumLSDAs =
8162 (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;
8164 for (int i = 0; i < NumLSDAs; ++i) {
8165 uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);
8166 uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);
8167 outs() << " [" << i << "]: "
8168 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
8169 << ", "
8170 << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';
8173 //===----------------------------------
8174 // Finally, the 2nd level indices
8175 //===----------------------------------
8177 // Generally these are 4K in size, and have 2 possible forms:
8178 // + Regular stores up to 511 entries with disparate encodings
8179 // + Compressed stores up to 1021 entries if few enough compact encoding
8180 // values are used.
8181 outs() << " Second level indices:\n";
8182 for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
8183 // The final sentinel top-level index has no associated 2nd level page
8184 if (IndexEntries[i].SecondLevelPageStart == 0)
8185 break;
8187 outs() << " Second level index[" << i << "]: "
8188 << "offset in section="
8189 << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)
8190 << ", "
8191 << "base function offset="
8192 << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';
8194 Pos = IndexEntries[i].SecondLevelPageStart;
8195 if (Pos + sizeof(uint32_t) > Contents.size()) {
8196 outs() << "warning: invalid offset for second level page: " << Pos << '\n';
8197 continue;
8200 uint32_t Kind =
8201 *reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);
8202 if (Kind == 2)
8203 printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));
8204 else if (Kind == 3)
8205 printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),
8206 IndexEntries[i].FunctionOffset,
8207 CommonEncodings);
8208 else
8209 outs() << " Skipping 2nd level page with unknown kind " << Kind
8210 << '\n';
8214 void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {
8215 std::map<uint64_t, SymbolRef> Symbols;
8216 for (const SymbolRef &SymRef : Obj->symbols()) {
8217 // Discard any undefined or absolute symbols. They're not going to take part
8218 // in the convenience lookup for unwind info and just take up resources.
8219 auto SectOrErr = SymRef.getSection();
8220 if (!SectOrErr) {
8221 // TODO: Actually report errors helpfully.
8222 consumeError(SectOrErr.takeError());
8223 continue;
8225 section_iterator Section = *SectOrErr;
8226 if (Section == Obj->section_end())
8227 continue;
8229 uint64_t Addr = cantFail(SymRef.getValue());
8230 Symbols.insert(std::make_pair(Addr, SymRef));
8233 for (const SectionRef &Section : Obj->sections()) {
8234 StringRef SectName;
8235 if (Expected<StringRef> NameOrErr = Section.getName())
8236 SectName = *NameOrErr;
8237 else
8238 consumeError(NameOrErr.takeError());
8240 if (SectName == "__compact_unwind")
8241 printMachOCompactUnwindSection(Obj, Symbols, Section);
8242 else if (SectName == "__unwind_info")
8243 printMachOUnwindInfoSection(Obj, Symbols, Section);
8247 static void PrintMachHeader(uint32_t magic, uint32_t cputype,
8248 uint32_t cpusubtype, uint32_t filetype,
8249 uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
8250 bool verbose) {
8251 outs() << "Mach header\n";
8252 outs() << " magic cputype cpusubtype caps filetype ncmds "
8253 "sizeofcmds flags\n";
8254 if (verbose) {
8255 if (magic == MachO::MH_MAGIC)
8256 outs() << " MH_MAGIC";
8257 else if (magic == MachO::MH_MAGIC_64)
8258 outs() << "MH_MAGIC_64";
8259 else
8260 outs() << format(" 0x%08" PRIx32, magic);
8261 switch (cputype) {
8262 case MachO::CPU_TYPE_I386:
8263 outs() << " I386";
8264 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8265 case MachO::CPU_SUBTYPE_I386_ALL:
8266 outs() << " ALL";
8267 break;
8268 default:
8269 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8270 break;
8272 break;
8273 case MachO::CPU_TYPE_X86_64:
8274 outs() << " X86_64";
8275 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8276 case MachO::CPU_SUBTYPE_X86_64_ALL:
8277 outs() << " ALL";
8278 break;
8279 case MachO::CPU_SUBTYPE_X86_64_H:
8280 outs() << " Haswell";
8281 break;
8282 default:
8283 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8284 break;
8286 break;
8287 case MachO::CPU_TYPE_ARM:
8288 outs() << " ARM";
8289 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8290 case MachO::CPU_SUBTYPE_ARM_ALL:
8291 outs() << " ALL";
8292 break;
8293 case MachO::CPU_SUBTYPE_ARM_V4T:
8294 outs() << " V4T";
8295 break;
8296 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
8297 outs() << " V5TEJ";
8298 break;
8299 case MachO::CPU_SUBTYPE_ARM_XSCALE:
8300 outs() << " XSCALE";
8301 break;
8302 case MachO::CPU_SUBTYPE_ARM_V6:
8303 outs() << " V6";
8304 break;
8305 case MachO::CPU_SUBTYPE_ARM_V6M:
8306 outs() << " V6M";
8307 break;
8308 case MachO::CPU_SUBTYPE_ARM_V7:
8309 outs() << " V7";
8310 break;
8311 case MachO::CPU_SUBTYPE_ARM_V7EM:
8312 outs() << " V7EM";
8313 break;
8314 case MachO::CPU_SUBTYPE_ARM_V7K:
8315 outs() << " V7K";
8316 break;
8317 case MachO::CPU_SUBTYPE_ARM_V7M:
8318 outs() << " V7M";
8319 break;
8320 case MachO::CPU_SUBTYPE_ARM_V7S:
8321 outs() << " V7S";
8322 break;
8323 default:
8324 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8325 break;
8327 break;
8328 case MachO::CPU_TYPE_ARM64:
8329 outs() << " ARM64";
8330 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8331 case MachO::CPU_SUBTYPE_ARM64_ALL:
8332 outs() << " ALL";
8333 break;
8334 case MachO::CPU_SUBTYPE_ARM64_V8:
8335 outs() << " V8";
8336 break;
8337 case MachO::CPU_SUBTYPE_ARM64E:
8338 outs() << " E";
8339 break;
8340 default:
8341 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8342 break;
8344 break;
8345 case MachO::CPU_TYPE_ARM64_32:
8346 outs() << " ARM64_32";
8347 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8348 case MachO::CPU_SUBTYPE_ARM64_32_V8:
8349 outs() << " V8";
8350 break;
8351 default:
8352 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8353 break;
8355 break;
8356 case MachO::CPU_TYPE_POWERPC:
8357 outs() << " PPC";
8358 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8359 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8360 outs() << " ALL";
8361 break;
8362 default:
8363 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8364 break;
8366 break;
8367 case MachO::CPU_TYPE_POWERPC64:
8368 outs() << " PPC64";
8369 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8370 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8371 outs() << " ALL";
8372 break;
8373 default:
8374 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8375 break;
8377 break;
8378 default:
8379 outs() << format(" %7d", cputype);
8380 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8381 break;
8384 if (cputype == MachO::CPU_TYPE_ARM64 &&
8385 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {
8386 const char *Format =
8387 MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype)
8388 ? " PAK%02d"
8389 : " PAC%02d";
8390 outs() << format(Format,
8391 MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype));
8392 } else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
8393 MachO::CPU_SUBTYPE_LIB64) {
8394 outs() << " LIB64";
8395 } else {
8396 outs() << format(" 0x%02" PRIx32,
8397 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8399 switch (filetype) {
8400 case MachO::MH_OBJECT:
8401 outs() << " OBJECT";
8402 break;
8403 case MachO::MH_EXECUTE:
8404 outs() << " EXECUTE";
8405 break;
8406 case MachO::MH_FVMLIB:
8407 outs() << " FVMLIB";
8408 break;
8409 case MachO::MH_CORE:
8410 outs() << " CORE";
8411 break;
8412 case MachO::MH_PRELOAD:
8413 outs() << " PRELOAD";
8414 break;
8415 case MachO::MH_DYLIB:
8416 outs() << " DYLIB";
8417 break;
8418 case MachO::MH_DYLIB_STUB:
8419 outs() << " DYLIB_STUB";
8420 break;
8421 case MachO::MH_DYLINKER:
8422 outs() << " DYLINKER";
8423 break;
8424 case MachO::MH_BUNDLE:
8425 outs() << " BUNDLE";
8426 break;
8427 case MachO::MH_DSYM:
8428 outs() << " DSYM";
8429 break;
8430 case MachO::MH_KEXT_BUNDLE:
8431 outs() << " KEXTBUNDLE";
8432 break;
8433 case MachO::MH_FILESET:
8434 outs() << " FILESET";
8435 break;
8436 default:
8437 outs() << format(" %10u", filetype);
8438 break;
8440 outs() << format(" %5u", ncmds);
8441 outs() << format(" %10u", sizeofcmds);
8442 uint32_t f = flags;
8443 if (f & MachO::MH_NOUNDEFS) {
8444 outs() << " NOUNDEFS";
8445 f &= ~MachO::MH_NOUNDEFS;
8447 if (f & MachO::MH_INCRLINK) {
8448 outs() << " INCRLINK";
8449 f &= ~MachO::MH_INCRLINK;
8451 if (f & MachO::MH_DYLDLINK) {
8452 outs() << " DYLDLINK";
8453 f &= ~MachO::MH_DYLDLINK;
8455 if (f & MachO::MH_BINDATLOAD) {
8456 outs() << " BINDATLOAD";
8457 f &= ~MachO::MH_BINDATLOAD;
8459 if (f & MachO::MH_PREBOUND) {
8460 outs() << " PREBOUND";
8461 f &= ~MachO::MH_PREBOUND;
8463 if (f & MachO::MH_SPLIT_SEGS) {
8464 outs() << " SPLIT_SEGS";
8465 f &= ~MachO::MH_SPLIT_SEGS;
8467 if (f & MachO::MH_LAZY_INIT) {
8468 outs() << " LAZY_INIT";
8469 f &= ~MachO::MH_LAZY_INIT;
8471 if (f & MachO::MH_TWOLEVEL) {
8472 outs() << " TWOLEVEL";
8473 f &= ~MachO::MH_TWOLEVEL;
8475 if (f & MachO::MH_FORCE_FLAT) {
8476 outs() << " FORCE_FLAT";
8477 f &= ~MachO::MH_FORCE_FLAT;
8479 if (f & MachO::MH_NOMULTIDEFS) {
8480 outs() << " NOMULTIDEFS";
8481 f &= ~MachO::MH_NOMULTIDEFS;
8483 if (f & MachO::MH_NOFIXPREBINDING) {
8484 outs() << " NOFIXPREBINDING";
8485 f &= ~MachO::MH_NOFIXPREBINDING;
8487 if (f & MachO::MH_PREBINDABLE) {
8488 outs() << " PREBINDABLE";
8489 f &= ~MachO::MH_PREBINDABLE;
8491 if (f & MachO::MH_ALLMODSBOUND) {
8492 outs() << " ALLMODSBOUND";
8493 f &= ~MachO::MH_ALLMODSBOUND;
8495 if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
8496 outs() << " SUBSECTIONS_VIA_SYMBOLS";
8497 f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
8499 if (f & MachO::MH_CANONICAL) {
8500 outs() << " CANONICAL";
8501 f &= ~MachO::MH_CANONICAL;
8503 if (f & MachO::MH_WEAK_DEFINES) {
8504 outs() << " WEAK_DEFINES";
8505 f &= ~MachO::MH_WEAK_DEFINES;
8507 if (f & MachO::MH_BINDS_TO_WEAK) {
8508 outs() << " BINDS_TO_WEAK";
8509 f &= ~MachO::MH_BINDS_TO_WEAK;
8511 if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
8512 outs() << " ALLOW_STACK_EXECUTION";
8513 f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
8515 if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
8516 outs() << " DEAD_STRIPPABLE_DYLIB";
8517 f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
8519 if (f & MachO::MH_PIE) {
8520 outs() << " PIE";
8521 f &= ~MachO::MH_PIE;
8523 if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
8524 outs() << " NO_REEXPORTED_DYLIBS";
8525 f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
8527 if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
8528 outs() << " MH_HAS_TLV_DESCRIPTORS";
8529 f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
8531 if (f & MachO::MH_NO_HEAP_EXECUTION) {
8532 outs() << " MH_NO_HEAP_EXECUTION";
8533 f &= ~MachO::MH_NO_HEAP_EXECUTION;
8535 if (f & MachO::MH_APP_EXTENSION_SAFE) {
8536 outs() << " APP_EXTENSION_SAFE";
8537 f &= ~MachO::MH_APP_EXTENSION_SAFE;
8539 if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
8540 outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
8541 f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
8543 if (f != 0 || flags == 0)
8544 outs() << format(" 0x%08" PRIx32, f);
8545 } else {
8546 outs() << format(" 0x%08" PRIx32, magic);
8547 outs() << format(" %7d", cputype);
8548 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8549 outs() << format(" 0x%02" PRIx32,
8550 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8551 outs() << format(" %10u", filetype);
8552 outs() << format(" %5u", ncmds);
8553 outs() << format(" %10u", sizeofcmds);
8554 outs() << format(" 0x%08" PRIx32, flags);
8556 outs() << "\n";
8559 static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
8560 StringRef SegName, uint64_t vmaddr,
8561 uint64_t vmsize, uint64_t fileoff,
8562 uint64_t filesize, uint32_t maxprot,
8563 uint32_t initprot, uint32_t nsects,
8564 uint32_t flags, uint32_t object_size,
8565 bool verbose) {
8566 uint64_t expected_cmdsize;
8567 if (cmd == MachO::LC_SEGMENT) {
8568 outs() << " cmd LC_SEGMENT\n";
8569 expected_cmdsize = nsects;
8570 expected_cmdsize *= sizeof(struct MachO::section);
8571 expected_cmdsize += sizeof(struct MachO::segment_command);
8572 } else {
8573 outs() << " cmd LC_SEGMENT_64\n";
8574 expected_cmdsize = nsects;
8575 expected_cmdsize *= sizeof(struct MachO::section_64);
8576 expected_cmdsize += sizeof(struct MachO::segment_command_64);
8578 outs() << " cmdsize " << cmdsize;
8579 if (cmdsize != expected_cmdsize)
8580 outs() << " Inconsistent size\n";
8581 else
8582 outs() << "\n";
8583 outs() << " segname " << SegName << "\n";
8584 if (cmd == MachO::LC_SEGMENT_64) {
8585 outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";
8586 outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";
8587 } else {
8588 outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";
8589 outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";
8591 outs() << " fileoff " << fileoff;
8592 if (fileoff > object_size)
8593 outs() << " (past end of file)\n";
8594 else
8595 outs() << "\n";
8596 outs() << " filesize " << filesize;
8597 if (fileoff + filesize > object_size)
8598 outs() << " (past end of file)\n";
8599 else
8600 outs() << "\n";
8601 if (verbose) {
8602 if ((maxprot &
8603 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8604 MachO::VM_PROT_EXECUTE)) != 0)
8605 outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";
8606 else {
8607 outs() << " maxprot ";
8608 outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");
8609 outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8610 outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8612 if ((initprot &
8613 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8614 MachO::VM_PROT_EXECUTE)) != 0)
8615 outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";
8616 else {
8617 outs() << " initprot ";
8618 outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");
8619 outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8620 outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8622 } else {
8623 outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";
8624 outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";
8626 outs() << " nsects " << nsects << "\n";
8627 if (verbose) {
8628 outs() << " flags";
8629 if (flags == 0)
8630 outs() << " (none)\n";
8631 else {
8632 if (flags & MachO::SG_HIGHVM) {
8633 outs() << " HIGHVM";
8634 flags &= ~MachO::SG_HIGHVM;
8636 if (flags & MachO::SG_FVMLIB) {
8637 outs() << " FVMLIB";
8638 flags &= ~MachO::SG_FVMLIB;
8640 if (flags & MachO::SG_NORELOC) {
8641 outs() << " NORELOC";
8642 flags &= ~MachO::SG_NORELOC;
8644 if (flags & MachO::SG_PROTECTED_VERSION_1) {
8645 outs() << " PROTECTED_VERSION_1";
8646 flags &= ~MachO::SG_PROTECTED_VERSION_1;
8648 if (flags & MachO::SG_READ_ONLY) {
8649 // Apple's otool prints the SG_ prefix for this flag, but not for the
8650 // others.
8651 outs() << " SG_READ_ONLY";
8652 flags &= ~MachO::SG_READ_ONLY;
8654 if (flags)
8655 outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
8656 else
8657 outs() << "\n";
8659 } else {
8660 outs() << " flags " << format("0x%" PRIx32, flags) << "\n";
8664 static void PrintSection(const char *sectname, const char *segname,
8665 uint64_t addr, uint64_t size, uint32_t offset,
8666 uint32_t align, uint32_t reloff, uint32_t nreloc,
8667 uint32_t flags, uint32_t reserved1, uint32_t reserved2,
8668 uint32_t cmd, const char *sg_segname,
8669 uint32_t filetype, uint32_t object_size,
8670 bool verbose) {
8671 outs() << "Section\n";
8672 outs() << " sectname " << format("%.16s\n", sectname);
8673 outs() << " segname " << format("%.16s", segname);
8674 if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)
8675 outs() << " (does not match segment)\n";
8676 else
8677 outs() << "\n";
8678 if (cmd == MachO::LC_SEGMENT_64) {
8679 outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";
8680 outs() << " size " << format("0x%016" PRIx64, size);
8681 } else {
8682 outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";
8683 outs() << " size " << format("0x%08" PRIx64, size);
8685 if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
8686 outs() << " (past end of file)\n";
8687 else
8688 outs() << "\n";
8689 outs() << " offset " << offset;
8690 if (offset > object_size)
8691 outs() << " (past end of file)\n";
8692 else
8693 outs() << "\n";
8694 uint32_t align_shifted = 1 << align;
8695 outs() << " align 2^" << align << " (" << align_shifted << ")\n";
8696 outs() << " reloff " << reloff;
8697 if (reloff > object_size)
8698 outs() << " (past end of file)\n";
8699 else
8700 outs() << "\n";
8701 outs() << " nreloc " << nreloc;
8702 if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
8703 outs() << " (past end of file)\n";
8704 else
8705 outs() << "\n";
8706 uint32_t section_type = flags & MachO::SECTION_TYPE;
8707 if (verbose) {
8708 outs() << " type";
8709 if (section_type == MachO::S_REGULAR)
8710 outs() << " S_REGULAR\n";
8711 else if (section_type == MachO::S_ZEROFILL)
8712 outs() << " S_ZEROFILL\n";
8713 else if (section_type == MachO::S_CSTRING_LITERALS)
8714 outs() << " S_CSTRING_LITERALS\n";
8715 else if (section_type == MachO::S_4BYTE_LITERALS)
8716 outs() << " S_4BYTE_LITERALS\n";
8717 else if (section_type == MachO::S_8BYTE_LITERALS)
8718 outs() << " S_8BYTE_LITERALS\n";
8719 else if (section_type == MachO::S_16BYTE_LITERALS)
8720 outs() << " S_16BYTE_LITERALS\n";
8721 else if (section_type == MachO::S_LITERAL_POINTERS)
8722 outs() << " S_LITERAL_POINTERS\n";
8723 else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
8724 outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
8725 else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
8726 outs() << " S_LAZY_SYMBOL_POINTERS\n";
8727 else if (section_type == MachO::S_SYMBOL_STUBS)
8728 outs() << " S_SYMBOL_STUBS\n";
8729 else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
8730 outs() << " S_MOD_INIT_FUNC_POINTERS\n";
8731 else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
8732 outs() << " S_MOD_TERM_FUNC_POINTERS\n";
8733 else if (section_type == MachO::S_COALESCED)
8734 outs() << " S_COALESCED\n";
8735 else if (section_type == MachO::S_INTERPOSING)
8736 outs() << " S_INTERPOSING\n";
8737 else if (section_type == MachO::S_DTRACE_DOF)
8738 outs() << " S_DTRACE_DOF\n";
8739 else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
8740 outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
8741 else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
8742 outs() << " S_THREAD_LOCAL_REGULAR\n";
8743 else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
8744 outs() << " S_THREAD_LOCAL_ZEROFILL\n";
8745 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
8746 outs() << " S_THREAD_LOCAL_VARIABLES\n";
8747 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8748 outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
8749 else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
8750 outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
8751 else if (section_type == MachO::S_INIT_FUNC_OFFSETS)
8752 outs() << " S_INIT_FUNC_OFFSETS\n";
8753 else
8754 outs() << format("0x%08" PRIx32, section_type) << "\n";
8755 outs() << "attributes";
8756 uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
8757 if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
8758 outs() << " PURE_INSTRUCTIONS";
8759 if (section_attributes & MachO::S_ATTR_NO_TOC)
8760 outs() << " NO_TOC";
8761 if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
8762 outs() << " STRIP_STATIC_SYMS";
8763 if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
8764 outs() << " NO_DEAD_STRIP";
8765 if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
8766 outs() << " LIVE_SUPPORT";
8767 if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
8768 outs() << " SELF_MODIFYING_CODE";
8769 if (section_attributes & MachO::S_ATTR_DEBUG)
8770 outs() << " DEBUG";
8771 if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
8772 outs() << " SOME_INSTRUCTIONS";
8773 if (section_attributes & MachO::S_ATTR_EXT_RELOC)
8774 outs() << " EXT_RELOC";
8775 if (section_attributes & MachO::S_ATTR_LOC_RELOC)
8776 outs() << " LOC_RELOC";
8777 if (section_attributes == 0)
8778 outs() << " (none)";
8779 outs() << "\n";
8780 } else
8781 outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";
8782 outs() << " reserved1 " << reserved1;
8783 if (section_type == MachO::S_SYMBOL_STUBS ||
8784 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
8785 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
8786 section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
8787 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8788 outs() << " (index into indirect symbol table)\n";
8789 else
8790 outs() << "\n";
8791 outs() << " reserved2 " << reserved2;
8792 if (section_type == MachO::S_SYMBOL_STUBS)
8793 outs() << " (size of stubs)\n";
8794 else
8795 outs() << "\n";
8798 static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
8799 uint32_t object_size) {
8800 outs() << " cmd LC_SYMTAB\n";
8801 outs() << " cmdsize " << st.cmdsize;
8802 if (st.cmdsize != sizeof(struct MachO::symtab_command))
8803 outs() << " Incorrect size\n";
8804 else
8805 outs() << "\n";
8806 outs() << " symoff " << st.symoff;
8807 if (st.symoff > object_size)
8808 outs() << " (past end of file)\n";
8809 else
8810 outs() << "\n";
8811 outs() << " nsyms " << st.nsyms;
8812 uint64_t big_size;
8813 if (Is64Bit) {
8814 big_size = st.nsyms;
8815 big_size *= sizeof(struct MachO::nlist_64);
8816 big_size += st.symoff;
8817 if (big_size > object_size)
8818 outs() << " (past end of file)\n";
8819 else
8820 outs() << "\n";
8821 } else {
8822 big_size = st.nsyms;
8823 big_size *= sizeof(struct MachO::nlist);
8824 big_size += st.symoff;
8825 if (big_size > object_size)
8826 outs() << " (past end of file)\n";
8827 else
8828 outs() << "\n";
8830 outs() << " stroff " << st.stroff;
8831 if (st.stroff > object_size)
8832 outs() << " (past end of file)\n";
8833 else
8834 outs() << "\n";
8835 outs() << " strsize " << st.strsize;
8836 big_size = st.stroff;
8837 big_size += st.strsize;
8838 if (big_size > object_size)
8839 outs() << " (past end of file)\n";
8840 else
8841 outs() << "\n";
8844 static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
8845 uint32_t nsyms, uint32_t object_size,
8846 bool Is64Bit) {
8847 outs() << " cmd LC_DYSYMTAB\n";
8848 outs() << " cmdsize " << dyst.cmdsize;
8849 if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
8850 outs() << " Incorrect size\n";
8851 else
8852 outs() << "\n";
8853 outs() << " ilocalsym " << dyst.ilocalsym;
8854 if (dyst.ilocalsym > nsyms)
8855 outs() << " (greater than the number of symbols)\n";
8856 else
8857 outs() << "\n";
8858 outs() << " nlocalsym " << dyst.nlocalsym;
8859 uint64_t big_size;
8860 big_size = dyst.ilocalsym;
8861 big_size += dyst.nlocalsym;
8862 if (big_size > nsyms)
8863 outs() << " (past the end of the symbol table)\n";
8864 else
8865 outs() << "\n";
8866 outs() << " iextdefsym " << dyst.iextdefsym;
8867 if (dyst.iextdefsym > nsyms)
8868 outs() << " (greater than the number of symbols)\n";
8869 else
8870 outs() << "\n";
8871 outs() << " nextdefsym " << dyst.nextdefsym;
8872 big_size = dyst.iextdefsym;
8873 big_size += dyst.nextdefsym;
8874 if (big_size > nsyms)
8875 outs() << " (past the end of the symbol table)\n";
8876 else
8877 outs() << "\n";
8878 outs() << " iundefsym " << dyst.iundefsym;
8879 if (dyst.iundefsym > nsyms)
8880 outs() << " (greater than the number of symbols)\n";
8881 else
8882 outs() << "\n";
8883 outs() << " nundefsym " << dyst.nundefsym;
8884 big_size = dyst.iundefsym;
8885 big_size += dyst.nundefsym;
8886 if (big_size > nsyms)
8887 outs() << " (past the end of the symbol table)\n";
8888 else
8889 outs() << "\n";
8890 outs() << " tocoff " << dyst.tocoff;
8891 if (dyst.tocoff > object_size)
8892 outs() << " (past end of file)\n";
8893 else
8894 outs() << "\n";
8895 outs() << " ntoc " << dyst.ntoc;
8896 big_size = dyst.ntoc;
8897 big_size *= sizeof(struct MachO::dylib_table_of_contents);
8898 big_size += dyst.tocoff;
8899 if (big_size > object_size)
8900 outs() << " (past end of file)\n";
8901 else
8902 outs() << "\n";
8903 outs() << " modtaboff " << dyst.modtaboff;
8904 if (dyst.modtaboff > object_size)
8905 outs() << " (past end of file)\n";
8906 else
8907 outs() << "\n";
8908 outs() << " nmodtab " << dyst.nmodtab;
8909 uint64_t modtabend;
8910 if (Is64Bit) {
8911 modtabend = dyst.nmodtab;
8912 modtabend *= sizeof(struct MachO::dylib_module_64);
8913 modtabend += dyst.modtaboff;
8914 } else {
8915 modtabend = dyst.nmodtab;
8916 modtabend *= sizeof(struct MachO::dylib_module);
8917 modtabend += dyst.modtaboff;
8919 if (modtabend > object_size)
8920 outs() << " (past end of file)\n";
8921 else
8922 outs() << "\n";
8923 outs() << " extrefsymoff " << dyst.extrefsymoff;
8924 if (dyst.extrefsymoff > object_size)
8925 outs() << " (past end of file)\n";
8926 else
8927 outs() << "\n";
8928 outs() << " nextrefsyms " << dyst.nextrefsyms;
8929 big_size = dyst.nextrefsyms;
8930 big_size *= sizeof(struct MachO::dylib_reference);
8931 big_size += dyst.extrefsymoff;
8932 if (big_size > object_size)
8933 outs() << " (past end of file)\n";
8934 else
8935 outs() << "\n";
8936 outs() << " indirectsymoff " << dyst.indirectsymoff;
8937 if (dyst.indirectsymoff > object_size)
8938 outs() << " (past end of file)\n";
8939 else
8940 outs() << "\n";
8941 outs() << " nindirectsyms " << dyst.nindirectsyms;
8942 big_size = dyst.nindirectsyms;
8943 big_size *= sizeof(uint32_t);
8944 big_size += dyst.indirectsymoff;
8945 if (big_size > object_size)
8946 outs() << " (past end of file)\n";
8947 else
8948 outs() << "\n";
8949 outs() << " extreloff " << dyst.extreloff;
8950 if (dyst.extreloff > object_size)
8951 outs() << " (past end of file)\n";
8952 else
8953 outs() << "\n";
8954 outs() << " nextrel " << dyst.nextrel;
8955 big_size = dyst.nextrel;
8956 big_size *= sizeof(struct MachO::relocation_info);
8957 big_size += dyst.extreloff;
8958 if (big_size > object_size)
8959 outs() << " (past end of file)\n";
8960 else
8961 outs() << "\n";
8962 outs() << " locreloff " << dyst.locreloff;
8963 if (dyst.locreloff > object_size)
8964 outs() << " (past end of file)\n";
8965 else
8966 outs() << "\n";
8967 outs() << " nlocrel " << dyst.nlocrel;
8968 big_size = dyst.nlocrel;
8969 big_size *= sizeof(struct MachO::relocation_info);
8970 big_size += dyst.locreloff;
8971 if (big_size > object_size)
8972 outs() << " (past end of file)\n";
8973 else
8974 outs() << "\n";
8977 static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
8978 uint32_t object_size) {
8979 if (dc.cmd == MachO::LC_DYLD_INFO)
8980 outs() << " cmd LC_DYLD_INFO\n";
8981 else
8982 outs() << " cmd LC_DYLD_INFO_ONLY\n";
8983 outs() << " cmdsize " << dc.cmdsize;
8984 if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
8985 outs() << " Incorrect size\n";
8986 else
8987 outs() << "\n";
8988 outs() << " rebase_off " << dc.rebase_off;
8989 if (dc.rebase_off > object_size)
8990 outs() << " (past end of file)\n";
8991 else
8992 outs() << "\n";
8993 outs() << " rebase_size " << dc.rebase_size;
8994 uint64_t big_size;
8995 big_size = dc.rebase_off;
8996 big_size += dc.rebase_size;
8997 if (big_size > object_size)
8998 outs() << " (past end of file)\n";
8999 else
9000 outs() << "\n";
9001 outs() << " bind_off " << dc.bind_off;
9002 if (dc.bind_off > object_size)
9003 outs() << " (past end of file)\n";
9004 else
9005 outs() << "\n";
9006 outs() << " bind_size " << dc.bind_size;
9007 big_size = dc.bind_off;
9008 big_size += dc.bind_size;
9009 if (big_size > object_size)
9010 outs() << " (past end of file)\n";
9011 else
9012 outs() << "\n";
9013 outs() << " weak_bind_off " << dc.weak_bind_off;
9014 if (dc.weak_bind_off > object_size)
9015 outs() << " (past end of file)\n";
9016 else
9017 outs() << "\n";
9018 outs() << " weak_bind_size " << dc.weak_bind_size;
9019 big_size = dc.weak_bind_off;
9020 big_size += dc.weak_bind_size;
9021 if (big_size > object_size)
9022 outs() << " (past end of file)\n";
9023 else
9024 outs() << "\n";
9025 outs() << " lazy_bind_off " << dc.lazy_bind_off;
9026 if (dc.lazy_bind_off > object_size)
9027 outs() << " (past end of file)\n";
9028 else
9029 outs() << "\n";
9030 outs() << " lazy_bind_size " << dc.lazy_bind_size;
9031 big_size = dc.lazy_bind_off;
9032 big_size += dc.lazy_bind_size;
9033 if (big_size > object_size)
9034 outs() << " (past end of file)\n";
9035 else
9036 outs() << "\n";
9037 outs() << " export_off " << dc.export_off;
9038 if (dc.export_off > object_size)
9039 outs() << " (past end of file)\n";
9040 else
9041 outs() << "\n";
9042 outs() << " export_size " << dc.export_size;
9043 big_size = dc.export_off;
9044 big_size += dc.export_size;
9045 if (big_size > object_size)
9046 outs() << " (past end of file)\n";
9047 else
9048 outs() << "\n";
9051 static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
9052 const char *Ptr) {
9053 if (dyld.cmd == MachO::LC_ID_DYLINKER)
9054 outs() << " cmd LC_ID_DYLINKER\n";
9055 else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
9056 outs() << " cmd LC_LOAD_DYLINKER\n";
9057 else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
9058 outs() << " cmd LC_DYLD_ENVIRONMENT\n";
9059 else
9060 outs() << " cmd ?(" << dyld.cmd << ")\n";
9061 outs() << " cmdsize " << dyld.cmdsize;
9062 if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
9063 outs() << " Incorrect size\n";
9064 else
9065 outs() << "\n";
9066 if (dyld.name >= dyld.cmdsize)
9067 outs() << " name ?(bad offset " << dyld.name << ")\n";
9068 else {
9069 const char *P = (const char *)(Ptr) + dyld.name;
9070 outs() << " name " << P << " (offset " << dyld.name << ")\n";
9074 static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
9075 outs() << " cmd LC_UUID\n";
9076 outs() << " cmdsize " << uuid.cmdsize;
9077 if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
9078 outs() << " Incorrect size\n";
9079 else
9080 outs() << "\n";
9081 outs() << " uuid ";
9082 for (int i = 0; i < 16; ++i) {
9083 outs() << format("%02" PRIX32, uuid.uuid[i]);
9084 if (i == 3 || i == 5 || i == 7 || i == 9)
9085 outs() << "-";
9087 outs() << "\n";
9090 static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
9091 outs() << " cmd LC_RPATH\n";
9092 outs() << " cmdsize " << rpath.cmdsize;
9093 if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
9094 outs() << " Incorrect size\n";
9095 else
9096 outs() << "\n";
9097 if (rpath.path >= rpath.cmdsize)
9098 outs() << " path ?(bad offset " << rpath.path << ")\n";
9099 else {
9100 const char *P = (const char *)(Ptr) + rpath.path;
9101 outs() << " path " << P << " (offset " << rpath.path << ")\n";
9105 static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
9106 StringRef LoadCmdName;
9107 switch (vd.cmd) {
9108 case MachO::LC_VERSION_MIN_MACOSX:
9109 LoadCmdName = "LC_VERSION_MIN_MACOSX";
9110 break;
9111 case MachO::LC_VERSION_MIN_IPHONEOS:
9112 LoadCmdName = "LC_VERSION_MIN_IPHONEOS";
9113 break;
9114 case MachO::LC_VERSION_MIN_TVOS:
9115 LoadCmdName = "LC_VERSION_MIN_TVOS";
9116 break;
9117 case MachO::LC_VERSION_MIN_WATCHOS:
9118 LoadCmdName = "LC_VERSION_MIN_WATCHOS";
9119 break;
9120 default:
9121 llvm_unreachable("Unknown version min load command");
9124 outs() << " cmd " << LoadCmdName << '\n';
9125 outs() << " cmdsize " << vd.cmdsize;
9126 if (vd.cmdsize != sizeof(struct MachO::version_min_command))
9127 outs() << " Incorrect size\n";
9128 else
9129 outs() << "\n";
9130 outs() << " version "
9131 << MachOObjectFile::getVersionMinMajor(vd, false) << "."
9132 << MachOObjectFile::getVersionMinMinor(vd, false);
9133 uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);
9134 if (Update != 0)
9135 outs() << "." << Update;
9136 outs() << "\n";
9137 if (vd.sdk == 0)
9138 outs() << " sdk n/a";
9139 else {
9140 outs() << " sdk "
9141 << MachOObjectFile::getVersionMinMajor(vd, true) << "."
9142 << MachOObjectFile::getVersionMinMinor(vd, true);
9144 Update = MachOObjectFile::getVersionMinUpdate(vd, true);
9145 if (Update != 0)
9146 outs() << "." << Update;
9147 outs() << "\n";
9150 static void PrintNoteLoadCommand(MachO::note_command Nt) {
9151 outs() << " cmd LC_NOTE\n";
9152 outs() << " cmdsize " << Nt.cmdsize;
9153 if (Nt.cmdsize != sizeof(struct MachO::note_command))
9154 outs() << " Incorrect size\n";
9155 else
9156 outs() << "\n";
9157 const char *d = Nt.data_owner;
9158 outs() << "data_owner " << format("%.16s\n", d);
9159 outs() << " offset " << Nt.offset << "\n";
9160 outs() << " size " << Nt.size << "\n";
9163 static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {
9164 outs() << " tool ";
9165 if (verbose)
9166 outs() << MachOObjectFile::getBuildTool(bv.tool);
9167 else
9168 outs() << bv.tool;
9169 outs() << "\n";
9170 outs() << " version " << MachOObjectFile::getVersionString(bv.version)
9171 << "\n";
9174 static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
9175 MachO::build_version_command bd,
9176 bool verbose) {
9177 outs() << " cmd LC_BUILD_VERSION\n";
9178 outs() << " cmdsize " << bd.cmdsize;
9179 if (bd.cmdsize !=
9180 sizeof(struct MachO::build_version_command) +
9181 bd.ntools * sizeof(struct MachO::build_tool_version))
9182 outs() << " Incorrect size\n";
9183 else
9184 outs() << "\n";
9185 outs() << " platform ";
9186 if (verbose)
9187 outs() << MachOObjectFile::getBuildPlatform(bd.platform);
9188 else
9189 outs() << bd.platform;
9190 outs() << "\n";
9191 if (bd.sdk)
9192 outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
9193 << "\n";
9194 else
9195 outs() << " sdk n/a\n";
9196 outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
9197 << "\n";
9198 outs() << " ntools " << bd.ntools << "\n";
9199 for (unsigned i = 0; i < bd.ntools; ++i) {
9200 MachO::build_tool_version bv = obj->getBuildToolVersion(i);
9201 PrintBuildToolVersion(bv, verbose);
9205 static void PrintSourceVersionCommand(MachO::source_version_command sd) {
9206 outs() << " cmd LC_SOURCE_VERSION\n";
9207 outs() << " cmdsize " << sd.cmdsize;
9208 if (sd.cmdsize != sizeof(struct MachO::source_version_command))
9209 outs() << " Incorrect size\n";
9210 else
9211 outs() << "\n";
9212 uint64_t a = (sd.version >> 40) & 0xffffff;
9213 uint64_t b = (sd.version >> 30) & 0x3ff;
9214 uint64_t c = (sd.version >> 20) & 0x3ff;
9215 uint64_t d = (sd.version >> 10) & 0x3ff;
9216 uint64_t e = sd.version & 0x3ff;
9217 outs() << " version " << a << "." << b;
9218 if (e != 0)
9219 outs() << "." << c << "." << d << "." << e;
9220 else if (d != 0)
9221 outs() << "." << c << "." << d;
9222 else if (c != 0)
9223 outs() << "." << c;
9224 outs() << "\n";
9227 static void PrintEntryPointCommand(MachO::entry_point_command ep) {
9228 outs() << " cmd LC_MAIN\n";
9229 outs() << " cmdsize " << ep.cmdsize;
9230 if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
9231 outs() << " Incorrect size\n";
9232 else
9233 outs() << "\n";
9234 outs() << " entryoff " << ep.entryoff << "\n";
9235 outs() << " stacksize " << ep.stacksize << "\n";
9238 static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
9239 uint32_t object_size) {
9240 outs() << " cmd LC_ENCRYPTION_INFO\n";
9241 outs() << " cmdsize " << ec.cmdsize;
9242 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
9243 outs() << " Incorrect size\n";
9244 else
9245 outs() << "\n";
9246 outs() << " cryptoff " << ec.cryptoff;
9247 if (ec.cryptoff > object_size)
9248 outs() << " (past end of file)\n";
9249 else
9250 outs() << "\n";
9251 outs() << " cryptsize " << ec.cryptsize;
9252 if (ec.cryptsize > object_size)
9253 outs() << " (past end of file)\n";
9254 else
9255 outs() << "\n";
9256 outs() << " cryptid " << ec.cryptid << "\n";
9259 static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
9260 uint32_t object_size) {
9261 outs() << " cmd LC_ENCRYPTION_INFO_64\n";
9262 outs() << " cmdsize " << ec.cmdsize;
9263 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
9264 outs() << " Incorrect size\n";
9265 else
9266 outs() << "\n";
9267 outs() << " cryptoff " << ec.cryptoff;
9268 if (ec.cryptoff > object_size)
9269 outs() << " (past end of file)\n";
9270 else
9271 outs() << "\n";
9272 outs() << " cryptsize " << ec.cryptsize;
9273 if (ec.cryptsize > object_size)
9274 outs() << " (past end of file)\n";
9275 else
9276 outs() << "\n";
9277 outs() << " cryptid " << ec.cryptid << "\n";
9278 outs() << " pad " << ec.pad << "\n";
9281 static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
9282 const char *Ptr) {
9283 outs() << " cmd LC_LINKER_OPTION\n";
9284 outs() << " cmdsize " << lo.cmdsize;
9285 if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
9286 outs() << " Incorrect size\n";
9287 else
9288 outs() << "\n";
9289 outs() << " count " << lo.count << "\n";
9290 const char *string = Ptr + sizeof(struct MachO::linker_option_command);
9291 uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
9292 uint32_t i = 0;
9293 while (left > 0) {
9294 while (*string == '\0' && left > 0) {
9295 string++;
9296 left--;
9298 if (left > 0) {
9299 i++;
9300 outs() << " string #" << i << " " << format("%.*s\n", left, string);
9301 uint32_t NullPos = StringRef(string, left).find('\0');
9302 uint32_t len = std::min(NullPos, left) + 1;
9303 string += len;
9304 left -= len;
9307 if (lo.count != i)
9308 outs() << " count " << lo.count << " does not match number of strings "
9309 << i << "\n";
9312 static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
9313 const char *Ptr) {
9314 outs() << " cmd LC_SUB_FRAMEWORK\n";
9315 outs() << " cmdsize " << sub.cmdsize;
9316 if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
9317 outs() << " Incorrect size\n";
9318 else
9319 outs() << "\n";
9320 if (sub.umbrella < sub.cmdsize) {
9321 const char *P = Ptr + sub.umbrella;
9322 outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
9323 } else {
9324 outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
9328 static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
9329 const char *Ptr) {
9330 outs() << " cmd LC_SUB_UMBRELLA\n";
9331 outs() << " cmdsize " << sub.cmdsize;
9332 if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
9333 outs() << " Incorrect size\n";
9334 else
9335 outs() << "\n";
9336 if (sub.sub_umbrella < sub.cmdsize) {
9337 const char *P = Ptr + sub.sub_umbrella;
9338 outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
9339 } else {
9340 outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
9344 static void PrintSubLibraryCommand(MachO::sub_library_command sub,
9345 const char *Ptr) {
9346 outs() << " cmd LC_SUB_LIBRARY\n";
9347 outs() << " cmdsize " << sub.cmdsize;
9348 if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
9349 outs() << " Incorrect size\n";
9350 else
9351 outs() << "\n";
9352 if (sub.sub_library < sub.cmdsize) {
9353 const char *P = Ptr + sub.sub_library;
9354 outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
9355 } else {
9356 outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
9360 static void PrintSubClientCommand(MachO::sub_client_command sub,
9361 const char *Ptr) {
9362 outs() << " cmd LC_SUB_CLIENT\n";
9363 outs() << " cmdsize " << sub.cmdsize;
9364 if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
9365 outs() << " Incorrect size\n";
9366 else
9367 outs() << "\n";
9368 if (sub.client < sub.cmdsize) {
9369 const char *P = Ptr + sub.client;
9370 outs() << " client " << P << " (offset " << sub.client << ")\n";
9371 } else {
9372 outs() << " client ?(bad offset " << sub.client << ")\n";
9376 static void PrintRoutinesCommand(MachO::routines_command r) {
9377 outs() << " cmd LC_ROUTINES\n";
9378 outs() << " cmdsize " << r.cmdsize;
9379 if (r.cmdsize != sizeof(struct MachO::routines_command))
9380 outs() << " Incorrect size\n";
9381 else
9382 outs() << "\n";
9383 outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";
9384 outs() << " init_module " << r.init_module << "\n";
9385 outs() << " reserved1 " << r.reserved1 << "\n";
9386 outs() << " reserved2 " << r.reserved2 << "\n";
9387 outs() << " reserved3 " << r.reserved3 << "\n";
9388 outs() << " reserved4 " << r.reserved4 << "\n";
9389 outs() << " reserved5 " << r.reserved5 << "\n";
9390 outs() << " reserved6 " << r.reserved6 << "\n";
9393 static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
9394 outs() << " cmd LC_ROUTINES_64\n";
9395 outs() << " cmdsize " << r.cmdsize;
9396 if (r.cmdsize != sizeof(struct MachO::routines_command_64))
9397 outs() << " Incorrect size\n";
9398 else
9399 outs() << "\n";
9400 outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";
9401 outs() << " init_module " << r.init_module << "\n";
9402 outs() << " reserved1 " << r.reserved1 << "\n";
9403 outs() << " reserved2 " << r.reserved2 << "\n";
9404 outs() << " reserved3 " << r.reserved3 << "\n";
9405 outs() << " reserved4 " << r.reserved4 << "\n";
9406 outs() << " reserved5 " << r.reserved5 << "\n";
9407 outs() << " reserved6 " << r.reserved6 << "\n";
9410 static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
9411 outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);
9412 outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);
9413 outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);
9414 outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";
9415 outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);
9416 outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);
9417 outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);
9418 outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";
9419 outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);
9420 outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);
9421 outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);
9422 outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";
9423 outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);
9424 outs() << " es " << format("0x%08" PRIx32, cpu32.es);
9425 outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);
9426 outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";
9429 static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
9430 outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
9431 outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
9432 outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";
9433 outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);
9434 outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);
9435 outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";
9436 outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);
9437 outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);
9438 outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";
9439 outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);
9440 outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);
9441 outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";
9442 outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);
9443 outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);
9444 outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";
9445 outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);
9446 outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";
9447 outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);
9448 outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);
9449 outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";
9450 outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";
9453 static void Print_mmst_reg(MachO::mmst_reg_t &r) {
9454 uint32_t f;
9455 outs() << "\t mmst_reg ";
9456 for (f = 0; f < 10; f++)
9457 outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";
9458 outs() << "\n";
9459 outs() << "\t mmst_rsrv ";
9460 for (f = 0; f < 6; f++)
9461 outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";
9462 outs() << "\n";
9465 static void Print_xmm_reg(MachO::xmm_reg_t &r) {
9466 uint32_t f;
9467 outs() << "\t xmm_reg ";
9468 for (f = 0; f < 16; f++)
9469 outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";
9470 outs() << "\n";
9473 static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
9474 outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
9475 outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
9476 outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
9477 outs() << " denorm " << fpu.fpu_fcw.denorm;
9478 outs() << " zdiv " << fpu.fpu_fcw.zdiv;
9479 outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
9480 outs() << " undfl " << fpu.fpu_fcw.undfl;
9481 outs() << " precis " << fpu.fpu_fcw.precis << "\n";
9482 outs() << "\t\t pc ";
9483 if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
9484 outs() << "FP_PREC_24B ";
9485 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
9486 outs() << "FP_PREC_53B ";
9487 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
9488 outs() << "FP_PREC_64B ";
9489 else
9490 outs() << fpu.fpu_fcw.pc << " ";
9491 outs() << "rc ";
9492 if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
9493 outs() << "FP_RND_NEAR ";
9494 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
9495 outs() << "FP_RND_DOWN ";
9496 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
9497 outs() << "FP_RND_UP ";
9498 else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
9499 outs() << "FP_CHOP ";
9500 outs() << "\n";
9501 outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
9502 outs() << " denorm " << fpu.fpu_fsw.denorm;
9503 outs() << " zdiv " << fpu.fpu_fsw.zdiv;
9504 outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
9505 outs() << " undfl " << fpu.fpu_fsw.undfl;
9506 outs() << " precis " << fpu.fpu_fsw.precis;
9507 outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
9508 outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
9509 outs() << " c0 " << fpu.fpu_fsw.c0;
9510 outs() << " c1 " << fpu.fpu_fsw.c1;
9511 outs() << " c2 " << fpu.fpu_fsw.c2;
9512 outs() << " tos " << fpu.fpu_fsw.tos;
9513 outs() << " c3 " << fpu.fpu_fsw.c3;
9514 outs() << " busy " << fpu.fpu_fsw.busy << "\n";
9515 outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);
9516 outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);
9517 outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);
9518 outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";
9519 outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);
9520 outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);
9521 outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);
9522 outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";
9523 outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);
9524 outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);
9525 outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);
9526 outs() << "\n";
9527 outs() << "\t fpu_stmm0:\n";
9528 Print_mmst_reg(fpu.fpu_stmm0);
9529 outs() << "\t fpu_stmm1:\n";
9530 Print_mmst_reg(fpu.fpu_stmm1);
9531 outs() << "\t fpu_stmm2:\n";
9532 Print_mmst_reg(fpu.fpu_stmm2);
9533 outs() << "\t fpu_stmm3:\n";
9534 Print_mmst_reg(fpu.fpu_stmm3);
9535 outs() << "\t fpu_stmm4:\n";
9536 Print_mmst_reg(fpu.fpu_stmm4);
9537 outs() << "\t fpu_stmm5:\n";
9538 Print_mmst_reg(fpu.fpu_stmm5);
9539 outs() << "\t fpu_stmm6:\n";
9540 Print_mmst_reg(fpu.fpu_stmm6);
9541 outs() << "\t fpu_stmm7:\n";
9542 Print_mmst_reg(fpu.fpu_stmm7);
9543 outs() << "\t fpu_xmm0:\n";
9544 Print_xmm_reg(fpu.fpu_xmm0);
9545 outs() << "\t fpu_xmm1:\n";
9546 Print_xmm_reg(fpu.fpu_xmm1);
9547 outs() << "\t fpu_xmm2:\n";
9548 Print_xmm_reg(fpu.fpu_xmm2);
9549 outs() << "\t fpu_xmm3:\n";
9550 Print_xmm_reg(fpu.fpu_xmm3);
9551 outs() << "\t fpu_xmm4:\n";
9552 Print_xmm_reg(fpu.fpu_xmm4);
9553 outs() << "\t fpu_xmm5:\n";
9554 Print_xmm_reg(fpu.fpu_xmm5);
9555 outs() << "\t fpu_xmm6:\n";
9556 Print_xmm_reg(fpu.fpu_xmm6);
9557 outs() << "\t fpu_xmm7:\n";
9558 Print_xmm_reg(fpu.fpu_xmm7);
9559 outs() << "\t fpu_xmm8:\n";
9560 Print_xmm_reg(fpu.fpu_xmm8);
9561 outs() << "\t fpu_xmm9:\n";
9562 Print_xmm_reg(fpu.fpu_xmm9);
9563 outs() << "\t fpu_xmm10:\n";
9564 Print_xmm_reg(fpu.fpu_xmm10);
9565 outs() << "\t fpu_xmm11:\n";
9566 Print_xmm_reg(fpu.fpu_xmm11);
9567 outs() << "\t fpu_xmm12:\n";
9568 Print_xmm_reg(fpu.fpu_xmm12);
9569 outs() << "\t fpu_xmm13:\n";
9570 Print_xmm_reg(fpu.fpu_xmm13);
9571 outs() << "\t fpu_xmm14:\n";
9572 Print_xmm_reg(fpu.fpu_xmm14);
9573 outs() << "\t fpu_xmm15:\n";
9574 Print_xmm_reg(fpu.fpu_xmm15);
9575 outs() << "\t fpu_rsrv4:\n";
9576 for (uint32_t f = 0; f < 6; f++) {
9577 outs() << "\t ";
9578 for (uint32_t g = 0; g < 16; g++)
9579 outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";
9580 outs() << "\n";
9582 outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);
9583 outs() << "\n";
9586 static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
9587 outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);
9588 outs() << " err " << format("0x%08" PRIx32, exc64.err);
9589 outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";
9592 static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {
9593 outs() << "\t r0 " << format("0x%08" PRIx32, cpu32.r[0]);
9594 outs() << " r1 " << format("0x%08" PRIx32, cpu32.r[1]);
9595 outs() << " r2 " << format("0x%08" PRIx32, cpu32.r[2]);
9596 outs() << " r3 " << format("0x%08" PRIx32, cpu32.r[3]) << "\n";
9597 outs() << "\t r4 " << format("0x%08" PRIx32, cpu32.r[4]);
9598 outs() << " r5 " << format("0x%08" PRIx32, cpu32.r[5]);
9599 outs() << " r6 " << format("0x%08" PRIx32, cpu32.r[6]);
9600 outs() << " r7 " << format("0x%08" PRIx32, cpu32.r[7]) << "\n";
9601 outs() << "\t r8 " << format("0x%08" PRIx32, cpu32.r[8]);
9602 outs() << " r9 " << format("0x%08" PRIx32, cpu32.r[9]);
9603 outs() << " r10 " << format("0x%08" PRIx32, cpu32.r[10]);
9604 outs() << " r11 " << format("0x%08" PRIx32, cpu32.r[11]) << "\n";
9605 outs() << "\t r12 " << format("0x%08" PRIx32, cpu32.r[12]);
9606 outs() << " sp " << format("0x%08" PRIx32, cpu32.sp);
9607 outs() << " lr " << format("0x%08" PRIx32, cpu32.lr);
9608 outs() << " pc " << format("0x%08" PRIx32, cpu32.pc) << "\n";
9609 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";
9612 static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {
9613 outs() << "\t x0 " << format("0x%016" PRIx64, cpu64.x[0]);
9614 outs() << " x1 " << format("0x%016" PRIx64, cpu64.x[1]);
9615 outs() << " x2 " << format("0x%016" PRIx64, cpu64.x[2]) << "\n";
9616 outs() << "\t x3 " << format("0x%016" PRIx64, cpu64.x[3]);
9617 outs() << " x4 " << format("0x%016" PRIx64, cpu64.x[4]);
9618 outs() << " x5 " << format("0x%016" PRIx64, cpu64.x[5]) << "\n";
9619 outs() << "\t x6 " << format("0x%016" PRIx64, cpu64.x[6]);
9620 outs() << " x7 " << format("0x%016" PRIx64, cpu64.x[7]);
9621 outs() << " x8 " << format("0x%016" PRIx64, cpu64.x[8]) << "\n";
9622 outs() << "\t x9 " << format("0x%016" PRIx64, cpu64.x[9]);
9623 outs() << " x10 " << format("0x%016" PRIx64, cpu64.x[10]);
9624 outs() << " x11 " << format("0x%016" PRIx64, cpu64.x[11]) << "\n";
9625 outs() << "\t x12 " << format("0x%016" PRIx64, cpu64.x[12]);
9626 outs() << " x13 " << format("0x%016" PRIx64, cpu64.x[13]);
9627 outs() << " x14 " << format("0x%016" PRIx64, cpu64.x[14]) << "\n";
9628 outs() << "\t x15 " << format("0x%016" PRIx64, cpu64.x[15]);
9629 outs() << " x16 " << format("0x%016" PRIx64, cpu64.x[16]);
9630 outs() << " x17 " << format("0x%016" PRIx64, cpu64.x[17]) << "\n";
9631 outs() << "\t x18 " << format("0x%016" PRIx64, cpu64.x[18]);
9632 outs() << " x19 " << format("0x%016" PRIx64, cpu64.x[19]);
9633 outs() << " x20 " << format("0x%016" PRIx64, cpu64.x[20]) << "\n";
9634 outs() << "\t x21 " << format("0x%016" PRIx64, cpu64.x[21]);
9635 outs() << " x22 " << format("0x%016" PRIx64, cpu64.x[22]);
9636 outs() << " x23 " << format("0x%016" PRIx64, cpu64.x[23]) << "\n";
9637 outs() << "\t x24 " << format("0x%016" PRIx64, cpu64.x[24]);
9638 outs() << " x25 " << format("0x%016" PRIx64, cpu64.x[25]);
9639 outs() << " x26 " << format("0x%016" PRIx64, cpu64.x[26]) << "\n";
9640 outs() << "\t x27 " << format("0x%016" PRIx64, cpu64.x[27]);
9641 outs() << " x28 " << format("0x%016" PRIx64, cpu64.x[28]);
9642 outs() << " fp " << format("0x%016" PRIx64, cpu64.fp) << "\n";
9643 outs() << "\t lr " << format("0x%016" PRIx64, cpu64.lr);
9644 outs() << " sp " << format("0x%016" PRIx64, cpu64.sp);
9645 outs() << " pc " << format("0x%016" PRIx64, cpu64.pc) << "\n";
9646 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu64.cpsr) << "\n";
9649 static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
9650 bool isLittleEndian, uint32_t cputype) {
9651 if (t.cmd == MachO::LC_THREAD)
9652 outs() << " cmd LC_THREAD\n";
9653 else if (t.cmd == MachO::LC_UNIXTHREAD)
9654 outs() << " cmd LC_UNIXTHREAD\n";
9655 else
9656 outs() << " cmd " << t.cmd << " (unknown)\n";
9657 outs() << " cmdsize " << t.cmdsize;
9658 if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
9659 outs() << " Incorrect size\n";
9660 else
9661 outs() << "\n";
9663 const char *begin = Ptr + sizeof(struct MachO::thread_command);
9664 const char *end = Ptr + t.cmdsize;
9665 uint32_t flavor, count, left;
9666 if (cputype == MachO::CPU_TYPE_I386) {
9667 while (begin < end) {
9668 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9669 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9670 begin += sizeof(uint32_t);
9671 } else {
9672 flavor = 0;
9673 begin = end;
9675 if (isLittleEndian != sys::IsLittleEndianHost)
9676 sys::swapByteOrder(flavor);
9677 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9678 memcpy((char *)&count, begin, sizeof(uint32_t));
9679 begin += sizeof(uint32_t);
9680 } else {
9681 count = 0;
9682 begin = end;
9684 if (isLittleEndian != sys::IsLittleEndianHost)
9685 sys::swapByteOrder(count);
9686 if (flavor == MachO::x86_THREAD_STATE32) {
9687 outs() << " flavor i386_THREAD_STATE\n";
9688 if (count == MachO::x86_THREAD_STATE32_COUNT)
9689 outs() << " count i386_THREAD_STATE_COUNT\n";
9690 else
9691 outs() << " count " << count
9692 << " (not x86_THREAD_STATE32_COUNT)\n";
9693 MachO::x86_thread_state32_t cpu32;
9694 left = end - begin;
9695 if (left >= sizeof(MachO::x86_thread_state32_t)) {
9696 memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));
9697 begin += sizeof(MachO::x86_thread_state32_t);
9698 } else {
9699 memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));
9700 memcpy(&cpu32, begin, left);
9701 begin += left;
9703 if (isLittleEndian != sys::IsLittleEndianHost)
9704 swapStruct(cpu32);
9705 Print_x86_thread_state32_t(cpu32);
9706 } else if (flavor == MachO::x86_THREAD_STATE) {
9707 outs() << " flavor x86_THREAD_STATE\n";
9708 if (count == MachO::x86_THREAD_STATE_COUNT)
9709 outs() << " count x86_THREAD_STATE_COUNT\n";
9710 else
9711 outs() << " count " << count
9712 << " (not x86_THREAD_STATE_COUNT)\n";
9713 struct MachO::x86_thread_state_t ts;
9714 left = end - begin;
9715 if (left >= sizeof(MachO::x86_thread_state_t)) {
9716 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9717 begin += sizeof(MachO::x86_thread_state_t);
9718 } else {
9719 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9720 memcpy(&ts, begin, left);
9721 begin += left;
9723 if (isLittleEndian != sys::IsLittleEndianHost)
9724 swapStruct(ts);
9725 if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
9726 outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
9727 if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
9728 outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
9729 else
9730 outs() << "tsh.count " << ts.tsh.count
9731 << " (not x86_THREAD_STATE32_COUNT\n";
9732 Print_x86_thread_state32_t(ts.uts.ts32);
9733 } else {
9734 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9735 << ts.tsh.count << "\n";
9737 } else {
9738 outs() << " flavor " << flavor << " (unknown)\n";
9739 outs() << " count " << count << "\n";
9740 outs() << " state (unknown)\n";
9741 begin += count * sizeof(uint32_t);
9744 } else if (cputype == MachO::CPU_TYPE_X86_64) {
9745 while (begin < end) {
9746 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9747 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9748 begin += sizeof(uint32_t);
9749 } else {
9750 flavor = 0;
9751 begin = end;
9753 if (isLittleEndian != sys::IsLittleEndianHost)
9754 sys::swapByteOrder(flavor);
9755 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9756 memcpy((char *)&count, begin, sizeof(uint32_t));
9757 begin += sizeof(uint32_t);
9758 } else {
9759 count = 0;
9760 begin = end;
9762 if (isLittleEndian != sys::IsLittleEndianHost)
9763 sys::swapByteOrder(count);
9764 if (flavor == MachO::x86_THREAD_STATE64) {
9765 outs() << " flavor x86_THREAD_STATE64\n";
9766 if (count == MachO::x86_THREAD_STATE64_COUNT)
9767 outs() << " count x86_THREAD_STATE64_COUNT\n";
9768 else
9769 outs() << " count " << count
9770 << " (not x86_THREAD_STATE64_COUNT)\n";
9771 MachO::x86_thread_state64_t cpu64;
9772 left = end - begin;
9773 if (left >= sizeof(MachO::x86_thread_state64_t)) {
9774 memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));
9775 begin += sizeof(MachO::x86_thread_state64_t);
9776 } else {
9777 memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));
9778 memcpy(&cpu64, begin, left);
9779 begin += left;
9781 if (isLittleEndian != sys::IsLittleEndianHost)
9782 swapStruct(cpu64);
9783 Print_x86_thread_state64_t(cpu64);
9784 } else if (flavor == MachO::x86_THREAD_STATE) {
9785 outs() << " flavor x86_THREAD_STATE\n";
9786 if (count == MachO::x86_THREAD_STATE_COUNT)
9787 outs() << " count x86_THREAD_STATE_COUNT\n";
9788 else
9789 outs() << " count " << count
9790 << " (not x86_THREAD_STATE_COUNT)\n";
9791 struct MachO::x86_thread_state_t ts;
9792 left = end - begin;
9793 if (left >= sizeof(MachO::x86_thread_state_t)) {
9794 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9795 begin += sizeof(MachO::x86_thread_state_t);
9796 } else {
9797 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9798 memcpy(&ts, begin, left);
9799 begin += left;
9801 if (isLittleEndian != sys::IsLittleEndianHost)
9802 swapStruct(ts);
9803 if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
9804 outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
9805 if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
9806 outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
9807 else
9808 outs() << "tsh.count " << ts.tsh.count
9809 << " (not x86_THREAD_STATE64_COUNT\n";
9810 Print_x86_thread_state64_t(ts.uts.ts64);
9811 } else {
9812 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9813 << ts.tsh.count << "\n";
9815 } else if (flavor == MachO::x86_FLOAT_STATE) {
9816 outs() << " flavor x86_FLOAT_STATE\n";
9817 if (count == MachO::x86_FLOAT_STATE_COUNT)
9818 outs() << " count x86_FLOAT_STATE_COUNT\n";
9819 else
9820 outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
9821 struct MachO::x86_float_state_t fs;
9822 left = end - begin;
9823 if (left >= sizeof(MachO::x86_float_state_t)) {
9824 memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));
9825 begin += sizeof(MachO::x86_float_state_t);
9826 } else {
9827 memset(&fs, '\0', sizeof(MachO::x86_float_state_t));
9828 memcpy(&fs, begin, left);
9829 begin += left;
9831 if (isLittleEndian != sys::IsLittleEndianHost)
9832 swapStruct(fs);
9833 if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
9834 outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
9835 if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
9836 outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
9837 else
9838 outs() << "fsh.count " << fs.fsh.count
9839 << " (not x86_FLOAT_STATE64_COUNT\n";
9840 Print_x86_float_state_t(fs.ufs.fs64);
9841 } else {
9842 outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
9843 << fs.fsh.count << "\n";
9845 } else if (flavor == MachO::x86_EXCEPTION_STATE) {
9846 outs() << " flavor x86_EXCEPTION_STATE\n";
9847 if (count == MachO::x86_EXCEPTION_STATE_COUNT)
9848 outs() << " count x86_EXCEPTION_STATE_COUNT\n";
9849 else
9850 outs() << " count " << count
9851 << " (not x86_EXCEPTION_STATE_COUNT)\n";
9852 struct MachO::x86_exception_state_t es;
9853 left = end - begin;
9854 if (left >= sizeof(MachO::x86_exception_state_t)) {
9855 memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));
9856 begin += sizeof(MachO::x86_exception_state_t);
9857 } else {
9858 memset(&es, '\0', sizeof(MachO::x86_exception_state_t));
9859 memcpy(&es, begin, left);
9860 begin += left;
9862 if (isLittleEndian != sys::IsLittleEndianHost)
9863 swapStruct(es);
9864 if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
9865 outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
9866 if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
9867 outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
9868 else
9869 outs() << "\t esh.count " << es.esh.count
9870 << " (not x86_EXCEPTION_STATE64_COUNT\n";
9871 Print_x86_exception_state_t(es.ues.es64);
9872 } else {
9873 outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
9874 << es.esh.count << "\n";
9876 } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
9877 outs() << " flavor x86_EXCEPTION_STATE64\n";
9878 if (count == MachO::x86_EXCEPTION_STATE64_COUNT)
9879 outs() << " count x86_EXCEPTION_STATE64_COUNT\n";
9880 else
9881 outs() << " count " << count
9882 << " (not x86_EXCEPTION_STATE64_COUNT)\n";
9883 struct MachO::x86_exception_state64_t es64;
9884 left = end - begin;
9885 if (left >= sizeof(MachO::x86_exception_state64_t)) {
9886 memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));
9887 begin += sizeof(MachO::x86_exception_state64_t);
9888 } else {
9889 memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));
9890 memcpy(&es64, begin, left);
9891 begin += left;
9893 if (isLittleEndian != sys::IsLittleEndianHost)
9894 swapStruct(es64);
9895 Print_x86_exception_state_t(es64);
9896 } else {
9897 outs() << " flavor " << flavor << " (unknown)\n";
9898 outs() << " count " << count << "\n";
9899 outs() << " state (unknown)\n";
9900 begin += count * sizeof(uint32_t);
9903 } else if (cputype == MachO::CPU_TYPE_ARM) {
9904 while (begin < end) {
9905 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9906 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9907 begin += sizeof(uint32_t);
9908 } else {
9909 flavor = 0;
9910 begin = end;
9912 if (isLittleEndian != sys::IsLittleEndianHost)
9913 sys::swapByteOrder(flavor);
9914 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9915 memcpy((char *)&count, begin, sizeof(uint32_t));
9916 begin += sizeof(uint32_t);
9917 } else {
9918 count = 0;
9919 begin = end;
9921 if (isLittleEndian != sys::IsLittleEndianHost)
9922 sys::swapByteOrder(count);
9923 if (flavor == MachO::ARM_THREAD_STATE) {
9924 outs() << " flavor ARM_THREAD_STATE\n";
9925 if (count == MachO::ARM_THREAD_STATE_COUNT)
9926 outs() << " count ARM_THREAD_STATE_COUNT\n";
9927 else
9928 outs() << " count " << count
9929 << " (not ARM_THREAD_STATE_COUNT)\n";
9930 MachO::arm_thread_state32_t cpu32;
9931 left = end - begin;
9932 if (left >= sizeof(MachO::arm_thread_state32_t)) {
9933 memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));
9934 begin += sizeof(MachO::arm_thread_state32_t);
9935 } else {
9936 memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));
9937 memcpy(&cpu32, begin, left);
9938 begin += left;
9940 if (isLittleEndian != sys::IsLittleEndianHost)
9941 swapStruct(cpu32);
9942 Print_arm_thread_state32_t(cpu32);
9943 } else {
9944 outs() << " flavor " << flavor << " (unknown)\n";
9945 outs() << " count " << count << "\n";
9946 outs() << " state (unknown)\n";
9947 begin += count * sizeof(uint32_t);
9950 } else if (cputype == MachO::CPU_TYPE_ARM64 ||
9951 cputype == MachO::CPU_TYPE_ARM64_32) {
9952 while (begin < end) {
9953 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9954 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9955 begin += sizeof(uint32_t);
9956 } else {
9957 flavor = 0;
9958 begin = end;
9960 if (isLittleEndian != sys::IsLittleEndianHost)
9961 sys::swapByteOrder(flavor);
9962 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9963 memcpy((char *)&count, begin, sizeof(uint32_t));
9964 begin += sizeof(uint32_t);
9965 } else {
9966 count = 0;
9967 begin = end;
9969 if (isLittleEndian != sys::IsLittleEndianHost)
9970 sys::swapByteOrder(count);
9971 if (flavor == MachO::ARM_THREAD_STATE64) {
9972 outs() << " flavor ARM_THREAD_STATE64\n";
9973 if (count == MachO::ARM_THREAD_STATE64_COUNT)
9974 outs() << " count ARM_THREAD_STATE64_COUNT\n";
9975 else
9976 outs() << " count " << count
9977 << " (not ARM_THREAD_STATE64_COUNT)\n";
9978 MachO::arm_thread_state64_t cpu64;
9979 left = end - begin;
9980 if (left >= sizeof(MachO::arm_thread_state64_t)) {
9981 memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));
9982 begin += sizeof(MachO::arm_thread_state64_t);
9983 } else {
9984 memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));
9985 memcpy(&cpu64, begin, left);
9986 begin += left;
9988 if (isLittleEndian != sys::IsLittleEndianHost)
9989 swapStruct(cpu64);
9990 Print_arm_thread_state64_t(cpu64);
9991 } else {
9992 outs() << " flavor " << flavor << " (unknown)\n";
9993 outs() << " count " << count << "\n";
9994 outs() << " state (unknown)\n";
9995 begin += count * sizeof(uint32_t);
9998 } else {
9999 while (begin < end) {
10000 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10001 memcpy((char *)&flavor, begin, sizeof(uint32_t));
10002 begin += sizeof(uint32_t);
10003 } else {
10004 flavor = 0;
10005 begin = end;
10007 if (isLittleEndian != sys::IsLittleEndianHost)
10008 sys::swapByteOrder(flavor);
10009 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10010 memcpy((char *)&count, begin, sizeof(uint32_t));
10011 begin += sizeof(uint32_t);
10012 } else {
10013 count = 0;
10014 begin = end;
10016 if (isLittleEndian != sys::IsLittleEndianHost)
10017 sys::swapByteOrder(count);
10018 outs() << " flavor " << flavor << "\n";
10019 outs() << " count " << count << "\n";
10020 outs() << " state (Unknown cputype/cpusubtype)\n";
10021 begin += count * sizeof(uint32_t);
10026 static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
10027 if (dl.cmd == MachO::LC_ID_DYLIB)
10028 outs() << " cmd LC_ID_DYLIB\n";
10029 else if (dl.cmd == MachO::LC_LOAD_DYLIB)
10030 outs() << " cmd LC_LOAD_DYLIB\n";
10031 else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
10032 outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
10033 else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
10034 outs() << " cmd LC_REEXPORT_DYLIB\n";
10035 else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
10036 outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
10037 else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
10038 outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
10039 else
10040 outs() << " cmd " << dl.cmd << " (unknown)\n";
10041 outs() << " cmdsize " << dl.cmdsize;
10042 if (dl.cmdsize < sizeof(struct MachO::dylib_command))
10043 outs() << " Incorrect size\n";
10044 else
10045 outs() << "\n";
10046 if (dl.dylib.name < dl.cmdsize) {
10047 const char *P = (const char *)(Ptr) + dl.dylib.name;
10048 outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
10049 } else {
10050 outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
10052 outs() << " time stamp " << dl.dylib.timestamp << " ";
10053 time_t t = dl.dylib.timestamp;
10054 outs() << ctime(&t);
10055 outs() << " current version ";
10056 if (dl.dylib.current_version == 0xffffffff)
10057 outs() << "n/a\n";
10058 else
10059 outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
10060 << ((dl.dylib.current_version >> 8) & 0xff) << "."
10061 << (dl.dylib.current_version & 0xff) << "\n";
10062 outs() << "compatibility version ";
10063 if (dl.dylib.compatibility_version == 0xffffffff)
10064 outs() << "n/a\n";
10065 else
10066 outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
10067 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
10068 << (dl.dylib.compatibility_version & 0xff) << "\n";
10071 static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
10072 uint32_t object_size) {
10073 if (ld.cmd == MachO::LC_CODE_SIGNATURE)
10074 outs() << " cmd LC_CODE_SIGNATURE\n";
10075 else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
10076 outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
10077 else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
10078 outs() << " cmd LC_FUNCTION_STARTS\n";
10079 else if (ld.cmd == MachO::LC_DATA_IN_CODE)
10080 outs() << " cmd LC_DATA_IN_CODE\n";
10081 else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
10082 outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
10083 else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
10084 outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
10085 else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)
10086 outs() << " cmd LC_DYLD_EXPORTS_TRIE\n";
10087 else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)
10088 outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n";
10089 else if (ld.cmd == MachO::LC_ATOM_INFO)
10090 outs() << " cmd LC_ATOM_INFO\n";
10091 else
10092 outs() << " cmd " << ld.cmd << " (?)\n";
10093 outs() << " cmdsize " << ld.cmdsize;
10094 if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
10095 outs() << " Incorrect size\n";
10096 else
10097 outs() << "\n";
10098 outs() << " dataoff " << ld.dataoff;
10099 if (ld.dataoff > object_size)
10100 outs() << " (past end of file)\n";
10101 else
10102 outs() << "\n";
10103 outs() << " datasize " << ld.datasize;
10104 uint64_t big_size = ld.dataoff;
10105 big_size += ld.datasize;
10106 if (big_size > object_size)
10107 outs() << " (past end of file)\n";
10108 else
10109 outs() << "\n";
10112 static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
10113 uint32_t cputype, bool verbose) {
10114 StringRef Buf = Obj->getData();
10115 unsigned Index = 0;
10116 for (const auto &Command : Obj->load_commands()) {
10117 outs() << "Load command " << Index++ << "\n";
10118 if (Command.C.cmd == MachO::LC_SEGMENT) {
10119 MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
10120 const char *sg_segname = SLC.segname;
10121 PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,
10122 SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,
10123 SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
10124 verbose);
10125 for (unsigned j = 0; j < SLC.nsects; j++) {
10126 MachO::section S = Obj->getSection(Command, j);
10127 PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,
10128 S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,
10129 SLC.cmd, sg_segname, filetype, Buf.size(), verbose);
10131 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10132 MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);
10133 const char *sg_segname = SLC_64.segname;
10134 PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,
10135 SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,
10136 SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,
10137 SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);
10138 for (unsigned j = 0; j < SLC_64.nsects; j++) {
10139 MachO::section_64 S_64 = Obj->getSection64(Command, j);
10140 PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,
10141 S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,
10142 S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,
10143 sg_segname, filetype, Buf.size(), verbose);
10145 } else if (Command.C.cmd == MachO::LC_SYMTAB) {
10146 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10147 PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());
10148 } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
10149 MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
10150 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10151 PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),
10152 Obj->is64Bit());
10153 } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
10154 Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
10155 MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);
10156 PrintDyldInfoLoadCommand(DyldInfo, Buf.size());
10157 } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
10158 Command.C.cmd == MachO::LC_ID_DYLINKER ||
10159 Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
10160 MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);
10161 PrintDyldLoadCommand(Dyld, Command.Ptr);
10162 } else if (Command.C.cmd == MachO::LC_UUID) {
10163 MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
10164 PrintUuidLoadCommand(Uuid);
10165 } else if (Command.C.cmd == MachO::LC_RPATH) {
10166 MachO::rpath_command Rpath = Obj->getRpathCommand(Command);
10167 PrintRpathLoadCommand(Rpath, Command.Ptr);
10168 } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
10169 Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||
10170 Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||
10171 Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
10172 MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
10173 PrintVersionMinLoadCommand(Vd);
10174 } else if (Command.C.cmd == MachO::LC_NOTE) {
10175 MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
10176 PrintNoteLoadCommand(Nt);
10177 } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
10178 MachO::build_version_command Bv =
10179 Obj->getBuildVersionLoadCommand(Command);
10180 PrintBuildVersionLoadCommand(Obj, Bv, verbose);
10181 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
10182 MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
10183 PrintSourceVersionCommand(Sd);
10184 } else if (Command.C.cmd == MachO::LC_MAIN) {
10185 MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);
10186 PrintEntryPointCommand(Ep);
10187 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
10188 MachO::encryption_info_command Ei =
10189 Obj->getEncryptionInfoCommand(Command);
10190 PrintEncryptionInfoCommand(Ei, Buf.size());
10191 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
10192 MachO::encryption_info_command_64 Ei =
10193 Obj->getEncryptionInfoCommand64(Command);
10194 PrintEncryptionInfoCommand64(Ei, Buf.size());
10195 } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
10196 MachO::linker_option_command Lo =
10197 Obj->getLinkerOptionLoadCommand(Command);
10198 PrintLinkerOptionCommand(Lo, Command.Ptr);
10199 } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
10200 MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);
10201 PrintSubFrameworkCommand(Sf, Command.Ptr);
10202 } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
10203 MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);
10204 PrintSubUmbrellaCommand(Sf, Command.Ptr);
10205 } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
10206 MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);
10207 PrintSubLibraryCommand(Sl, Command.Ptr);
10208 } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
10209 MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);
10210 PrintSubClientCommand(Sc, Command.Ptr);
10211 } else if (Command.C.cmd == MachO::LC_ROUTINES) {
10212 MachO::routines_command Rc = Obj->getRoutinesCommand(Command);
10213 PrintRoutinesCommand(Rc);
10214 } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
10215 MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);
10216 PrintRoutinesCommand64(Rc);
10217 } else if (Command.C.cmd == MachO::LC_THREAD ||
10218 Command.C.cmd == MachO::LC_UNIXTHREAD) {
10219 MachO::thread_command Tc = Obj->getThreadCommand(Command);
10220 PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);
10221 } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
10222 Command.C.cmd == MachO::LC_ID_DYLIB ||
10223 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
10224 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
10225 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
10226 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
10227 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);
10228 PrintDylibCommand(Dl, Command.Ptr);
10229 } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
10230 Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
10231 Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
10232 Command.C.cmd == MachO::LC_DATA_IN_CODE ||
10233 Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
10234 Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||
10235 Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||
10236 Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||
10237 Command.C.cmd == MachO::LC_ATOM_INFO) {
10238 MachO::linkedit_data_command Ld =
10239 Obj->getLinkeditDataLoadCommand(Command);
10240 PrintLinkEditDataCommand(Ld, Buf.size());
10241 } else {
10242 outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)
10243 << ")\n";
10244 outs() << " cmdsize " << Command.C.cmdsize << "\n";
10245 // TODO: get and print the raw bytes of the load command.
10247 // TODO: print all the other kinds of load commands.
10251 static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
10252 if (Obj->is64Bit()) {
10253 MachO::mach_header_64 H_64;
10254 H_64 = Obj->getHeader64();
10255 PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
10256 H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
10257 } else {
10258 MachO::mach_header H;
10259 H = Obj->getHeader();
10260 PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
10261 H.sizeofcmds, H.flags, verbose);
10265 void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {
10266 const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);
10267 PrintMachHeader(file, Verbose);
10270 void MachODumper::printPrivateHeaders() {
10271 printMachOFileHeader(&Obj);
10272 if (!FirstPrivateHeader)
10273 printMachOLoadCommands(&Obj);
10276 void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {
10277 const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);
10278 uint32_t filetype = 0;
10279 uint32_t cputype = 0;
10280 if (file->is64Bit()) {
10281 MachO::mach_header_64 H_64;
10282 H_64 = file->getHeader64();
10283 filetype = H_64.filetype;
10284 cputype = H_64.cputype;
10285 } else {
10286 MachO::mach_header H;
10287 H = file->getHeader();
10288 filetype = H.filetype;
10289 cputype = H.cputype;
10291 PrintLoadCommands(file, filetype, cputype, Verbose);
10294 //===----------------------------------------------------------------------===//
10295 // export trie dumping
10296 //===----------------------------------------------------------------------===//
10298 static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {
10299 uint64_t BaseSegmentAddress = 0;
10300 for (const auto &Command : Obj->load_commands()) {
10301 if (Command.C.cmd == MachO::LC_SEGMENT) {
10302 MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);
10303 if (Seg.fileoff == 0 && Seg.filesize != 0) {
10304 BaseSegmentAddress = Seg.vmaddr;
10305 break;
10307 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10308 MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);
10309 if (Seg.fileoff == 0 && Seg.filesize != 0) {
10310 BaseSegmentAddress = Seg.vmaddr;
10311 break;
10315 Error Err = Error::success();
10316 for (const object::ExportEntry &Entry : Obj->exports(Err)) {
10317 uint64_t Flags = Entry.flags();
10318 bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
10319 bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
10320 bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10321 MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
10322 bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10323 MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
10324 bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
10325 if (ReExport)
10326 outs() << "[re-export] ";
10327 else
10328 outs() << format("0x%08llX ",
10329 Entry.address() + BaseSegmentAddress);
10330 outs() << Entry.name();
10331 if (WeakDef || ThreadLocal || Resolver || Abs) {
10332 ListSeparator LS;
10333 outs() << " [";
10334 if (WeakDef)
10335 outs() << LS << "weak_def";
10336 if (ThreadLocal)
10337 outs() << LS << "per-thread";
10338 if (Abs)
10339 outs() << LS << "absolute";
10340 if (Resolver)
10341 outs() << LS << format("resolver=0x%08llX", Entry.other());
10342 outs() << "]";
10344 if (ReExport) {
10345 StringRef DylibName = "unknown";
10346 int Ordinal = Entry.other() - 1;
10347 Obj->getLibraryShortNameByIndex(Ordinal, DylibName);
10348 if (Entry.otherName().empty())
10349 outs() << " (from " << DylibName << ")";
10350 else
10351 outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
10353 outs() << "\n";
10355 if (Err)
10356 reportError(std::move(Err), Obj->getFileName());
10359 //===----------------------------------------------------------------------===//
10360 // rebase table dumping
10361 //===----------------------------------------------------------------------===//
10363 static void printMachORebaseTable(object::MachOObjectFile *Obj) {
10364 outs() << "segment section address type\n";
10365 Error Err = Error::success();
10366 for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
10367 StringRef SegmentName = Entry.segmentName();
10368 StringRef SectionName = Entry.sectionName();
10369 uint64_t Address = Entry.address();
10371 // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
10372 outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
10373 SegmentName.str().c_str(), SectionName.str().c_str(),
10374 Address, Entry.typeName().str().c_str());
10376 if (Err)
10377 reportError(std::move(Err), Obj->getFileName());
10380 static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
10381 StringRef DylibName;
10382 switch (Ordinal) {
10383 case MachO::BIND_SPECIAL_DYLIB_SELF:
10384 return "this-image";
10385 case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
10386 return "main-executable";
10387 case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
10388 return "flat-namespace";
10389 case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
10390 return "weak";
10391 default:
10392 if (Ordinal > 0) {
10393 std::error_code EC =
10394 Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);
10395 if (EC)
10396 return "<<bad library ordinal>>";
10397 return DylibName;
10400 return "<<unknown special ordinal>>";
10403 //===----------------------------------------------------------------------===//
10404 // bind table dumping
10405 //===----------------------------------------------------------------------===//
10407 static void printMachOBindTable(object::MachOObjectFile *Obj) {
10408 // Build table of sections so names can used in final output.
10409 outs() << "segment section address type "
10410 "addend dylib symbol\n";
10411 Error Err = Error::success();
10412 for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
10413 StringRef SegmentName = Entry.segmentName();
10414 StringRef SectionName = Entry.sectionName();
10415 uint64_t Address = Entry.address();
10417 // Table lines look like:
10418 // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
10419 StringRef Attr;
10420 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
10421 Attr = " (weak_import)";
10422 outs() << left_justify(SegmentName, 8) << " "
10423 << left_justify(SectionName, 18) << " "
10424 << format_hex(Address, 10, true) << " "
10425 << left_justify(Entry.typeName(), 8) << " "
10426 << format_decimal(Entry.addend(), 8) << " "
10427 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
10428 << Entry.symbolName() << Attr << "\n";
10430 if (Err)
10431 reportError(std::move(Err), Obj->getFileName());
10434 //===----------------------------------------------------------------------===//
10435 // lazy bind table dumping
10436 //===----------------------------------------------------------------------===//
10438 static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {
10439 outs() << "segment section address "
10440 "dylib symbol\n";
10441 Error Err = Error::success();
10442 for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
10443 StringRef SegmentName = Entry.segmentName();
10444 StringRef SectionName = Entry.sectionName();
10445 uint64_t Address = Entry.address();
10447 // Table lines look like:
10448 // __DATA __got 0x00012010 libSystem ___stack_chk_guard
10449 outs() << left_justify(SegmentName, 8) << " "
10450 << left_justify(SectionName, 18) << " "
10451 << format_hex(Address, 10, true) << " "
10452 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
10453 << Entry.symbolName() << "\n";
10455 if (Err)
10456 reportError(std::move(Err), Obj->getFileName());
10459 //===----------------------------------------------------------------------===//
10460 // weak bind table dumping
10461 //===----------------------------------------------------------------------===//
10463 static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {
10464 outs() << "segment section address "
10465 "type addend symbol\n";
10466 Error Err = Error::success();
10467 for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
10468 // Strong symbols don't have a location to update.
10469 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
10470 outs() << " strong "
10471 << Entry.symbolName() << "\n";
10472 continue;
10474 StringRef SegmentName = Entry.segmentName();
10475 StringRef SectionName = Entry.sectionName();
10476 uint64_t Address = Entry.address();
10478 // Table lines look like:
10479 // __DATA __data 0x00001000 pointer 0 _foo
10480 outs() << left_justify(SegmentName, 8) << " "
10481 << left_justify(SectionName, 18) << " "
10482 << format_hex(Address, 10, true) << " "
10483 << left_justify(Entry.typeName(), 8) << " "
10484 << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
10485 << "\n";
10487 if (Err)
10488 reportError(std::move(Err), Obj->getFileName());
10491 // get_dyld_bind_info_symbolname() is used for disassembly and passed an
10492 // address, ReferenceValue, in the Mach-O file and looks in the dyld bind
10493 // information for that address. If the address is found its binding symbol
10494 // name is returned. If not nullptr is returned.
10495 static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
10496 struct DisassembleInfo *info) {
10497 if (info->bindtable == nullptr) {
10498 info->bindtable = std::make_unique<SymbolAddressMap>();
10499 Error Err = Error::success();
10500 for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
10501 uint64_t Address = Entry.address();
10502 StringRef name = Entry.symbolName();
10503 if (!name.empty())
10504 (*info->bindtable)[Address] = name;
10506 if (Err)
10507 reportError(std::move(Err), info->O->getFileName());
10509 auto name = info->bindtable->lookup(ReferenceValue);
10510 return !name.empty() ? name.data() : nullptr;
10513 void objdump::printLazyBindTable(ObjectFile *o) {
10514 outs() << "\nLazy bind table:\n";
10515 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10516 printMachOLazyBindTable(MachO);
10517 else
10518 WithColor::error()
10519 << "This operation is only currently supported "
10520 "for Mach-O executable files.\n";
10523 void objdump::printWeakBindTable(ObjectFile *o) {
10524 outs() << "\nWeak bind table:\n";
10525 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10526 printMachOWeakBindTable(MachO);
10527 else
10528 WithColor::error()
10529 << "This operation is only currently supported "
10530 "for Mach-O executable files.\n";
10533 void objdump::printExportsTrie(const ObjectFile *o) {
10534 outs() << "\nExports trie:\n";
10535 if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10536 printMachOExportsTrie(MachO);
10537 else
10538 WithColor::error()
10539 << "This operation is only currently supported "
10540 "for Mach-O executable files.\n";
10543 void objdump::printRebaseTable(ObjectFile *o) {
10544 outs() << "\nRebase table:\n";
10545 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10546 printMachORebaseTable(MachO);
10547 else
10548 WithColor::error()
10549 << "This operation is only currently supported "
10550 "for Mach-O executable files.\n";
10553 void objdump::printBindTable(ObjectFile *o) {
10554 outs() << "\nBind table:\n";
10555 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10556 printMachOBindTable(MachO);
10557 else
10558 WithColor::error()
10559 << "This operation is only currently supported "
10560 "for Mach-O executable files.\n";