Bug Summary

File:tools/llvm-objdump/MachODump.cpp
Warning:line 406, column 10
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name MachODump.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn329677/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/llvm-objdump -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-04-11-031539-24776-1 -x c++ /build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-objdump/MachODump.cpp

/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-objdump/MachODump.cpp

1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the MachO-specific dumper for llvm-objdump.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm-objdump.h"
15#include "llvm-c/Disassembler.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/ADT/Triple.h"
19#include "llvm/BinaryFormat/MachO.h"
20#include "llvm/Config/config.h"
21#include "llvm/DebugInfo/DIContext.h"
22#include "llvm/DebugInfo/DWARF/DWARFContext.h"
23#include "llvm/Demangle/Demangle.h"
24#include "llvm/MC/MCAsmInfo.h"
25#include "llvm/MC/MCContext.h"
26#include "llvm/MC/MCDisassembler/MCDisassembler.h"
27#include "llvm/MC/MCInst.h"
28#include "llvm/MC/MCInstPrinter.h"
29#include "llvm/MC/MCInstrDesc.h"
30#include "llvm/MC/MCInstrInfo.h"
31#include "llvm/MC/MCRegisterInfo.h"
32#include "llvm/MC/MCSubtargetInfo.h"
33#include "llvm/Object/MachO.h"
34#include "llvm/Object/MachOUniversal.h"
35#include "llvm/Support/Casting.h"
36#include "llvm/Support/CommandLine.h"
37#include "llvm/Support/Debug.h"
38#include "llvm/Support/Endian.h"
39#include "llvm/Support/Format.h"
40#include "llvm/Support/FormattedStream.h"
41#include "llvm/Support/GraphWriter.h"
42#include "llvm/Support/LEB128.h"
43#include "llvm/Support/MemoryBuffer.h"
44#include "llvm/Support/TargetRegistry.h"
45#include "llvm/Support/TargetSelect.h"
46#include "llvm/Support/ToolOutputFile.h"
47#include "llvm/Support/raw_ostream.h"
48#include <algorithm>
49#include <cstring>
50#include <system_error>
51
52#ifdef HAVE_LIBXAR
53extern "C" {
54#include <xar/xar.h>
55}
56#endif
57
58using namespace llvm;
59using namespace object;
60
61static cl::opt<bool>
62 UseDbg("g",
63 cl::desc("Print line information from debug info if available"));
64
65static cl::opt<std::string> DSYMFile("dsym",
66 cl::desc("Use .dSYM file for debug info"));
67
68static cl::opt<bool> FullLeadingAddr("full-leading-addr",
69 cl::desc("Print full leading address"));
70
71static cl::opt<bool> NoLeadingHeaders("no-leading-headers",
72 cl::desc("Print no leading headers"));
73
74cl::opt<bool> llvm::UniversalHeaders("universal-headers",
75 cl::desc("Print Mach-O universal headers "
76 "(requires -macho)"));
77
78cl::opt<bool>
79 llvm::ArchiveHeaders("archive-headers",
80 cl::desc("Print archive headers for Mach-O archives "
81 "(requires -macho)"));
82
83cl::opt<bool>
84 ArchiveMemberOffsets("archive-member-offsets",
85 cl::desc("Print the offset to each archive member for "
86 "Mach-O archives (requires -macho and "
87 "-archive-headers)"));
88
89cl::opt<bool>
90 llvm::IndirectSymbols("indirect-symbols",
91 cl::desc("Print indirect symbol table for Mach-O "
92 "objects (requires -macho)"));
93
94cl::opt<bool>
95 llvm::DataInCode("data-in-code",
96 cl::desc("Print the data in code table for Mach-O objects "
97 "(requires -macho)"));
98
99cl::opt<bool>
100 llvm::LinkOptHints("link-opt-hints",
101 cl::desc("Print the linker optimization hints for "
102 "Mach-O objects (requires -macho)"));
103
104cl::opt<bool>
105 llvm::InfoPlist("info-plist",
106 cl::desc("Print the info plist section as strings for "
107 "Mach-O objects (requires -macho)"));
108
109cl::opt<bool>
110 llvm::DylibsUsed("dylibs-used",
111 cl::desc("Print the shared libraries used for linked "
112 "Mach-O files (requires -macho)"));
113
114cl::opt<bool>
115 llvm::DylibId("dylib-id",
116 cl::desc("Print the shared library's id for the dylib Mach-O "
117 "file (requires -macho)"));
118
119cl::opt<bool>
120 llvm::NonVerbose("non-verbose",
121 cl::desc("Print the info for Mach-O objects in "
122 "non-verbose or numeric form (requires -macho)"));
123
124cl::opt<bool>
125 llvm::ObjcMetaData("objc-meta-data",
126 cl::desc("Print the Objective-C runtime meta data for "
127 "Mach-O files (requires -macho)"));
128
129cl::opt<std::string> llvm::DisSymName(
130 "dis-symname",
131 cl::desc("disassemble just this symbol's instructions (requires -macho)"));
132
133static cl::opt<bool> NoSymbolicOperands(
134 "no-symbolic-operands",
135 cl::desc("do not symbolic operands when disassembling (requires -macho)"));
136
137static cl::list<std::string>
138 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
139 cl::ZeroOrMore);
140
141bool ArchAll = false;
142
143static std::string ThumbTripleName;
144
145static const Target *GetTarget(const MachOObjectFile *MachOObj,
146 const char **McpuDefault,
147 const Target **ThumbTarget) {
148 // Figure out the target triple.
149 llvm::Triple TT(TripleName);
150 if (TripleName.empty()) {
151 TT = MachOObj->getArchTriple(McpuDefault);
152 TripleName = TT.str();
153 }
154
155 if (TT.getArch() == Triple::arm) {
156 // We've inferred a 32-bit ARM target from the object file. All MachO CPUs
157 // that support ARM are also capable of Thumb mode.
158 llvm::Triple ThumbTriple = TT;
159 std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();
160 ThumbTriple.setArchName(ThumbName);
161 ThumbTripleName = ThumbTriple.str();
162 }
163
164 // Get the target specific parser.
165 std::string Error;
166 const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
167 if (TheTarget && ThumbTripleName.empty())
168 return TheTarget;
169
170 *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
171 if (*ThumbTarget)
172 return TheTarget;
173
174 errs() << "llvm-objdump: error: unable to get target for '";
175 if (!TheTarget)
176 errs() << TripleName;
177 else
178 errs() << ThumbTripleName;
179 errs() << "', see --version and --triple.\n";
180 return nullptr;
181}
182
183struct SymbolSorter {
184 bool operator()(const SymbolRef &A, const SymbolRef &B) {
185 Expected<SymbolRef::Type> ATypeOrErr = A.getType();
186 if (!ATypeOrErr)
187 report_error(A.getObject()->getFileName(), ATypeOrErr.takeError());
188 SymbolRef::Type AType = *ATypeOrErr;
189 Expected<SymbolRef::Type> BTypeOrErr = B.getType();
190 if (!BTypeOrErr)
191 report_error(B.getObject()->getFileName(), BTypeOrErr.takeError());
192 SymbolRef::Type BType = *BTypeOrErr;
193 uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue();
194 uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue();
195 return AAddr < BAddr;
196 }
197};
198
199// Types for the storted data in code table that is built before disassembly
200// and the predicate function to sort them.
201typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
202typedef std::vector<DiceTableEntry> DiceTable;
203typedef DiceTable::iterator dice_table_iterator;
204
205#ifdef HAVE_LIBXAR
206namespace {
207struct ScopedXarFile {
208 xar_t xar;
209 ScopedXarFile(const char *filename, int32_t flags)
210 : xar(xar_open(filename, flags)) {}
211 ~ScopedXarFile() {
212 if (xar)
213 xar_close(xar);
214 }
215 ScopedXarFile(const ScopedXarFile &) = delete;
216 ScopedXarFile &operator=(const ScopedXarFile &) = delete;
217 operator xar_t() { return xar; }
218};
219
220struct ScopedXarIter {
221 xar_iter_t iter;
222 ScopedXarIter() : iter(xar_iter_new()) {}
223 ~ScopedXarIter() {
224 if (iter)
225 xar_iter_free(iter);
226 }
227 ScopedXarIter(const ScopedXarIter &) = delete;
228 ScopedXarIter &operator=(const ScopedXarIter &) = delete;
229 operator xar_iter_t() { return iter; }
230};
231} // namespace
232#endif // defined(HAVE_LIBXAR)
233
234// This is used to search for a data in code table entry for the PC being
235// disassembled. The j parameter has the PC in j.first. A single data in code
236// table entry can cover many bytes for each of its Kind's. So if the offset,
237// aka the i.first value, of the data in code table entry plus its Length
238// covers the PC being searched for this will return true. If not it will
239// return false.
240static bool compareDiceTableEntries(const DiceTableEntry &i,
241 const DiceTableEntry &j) {
242 uint16_t Length;
243 i.second.getLength(Length);
244
245 return j.first >= i.first && j.first < i.first + Length;
246}
247
248static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
249 unsigned short Kind) {
250 uint32_t Value, Size = 1;
251
252 switch (Kind) {
253 default:
254 case MachO::DICE_KIND_DATA:
255 if (Length >= 4) {
256 if (!NoShowRawInsn)
257 dumpBytes(makeArrayRef(bytes, 4), outs());
258 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
259 outs() << "\t.long " << Value;
260 Size = 4;
261 } else if (Length >= 2) {
262 if (!NoShowRawInsn)
263 dumpBytes(makeArrayRef(bytes, 2), outs());
264 Value = bytes[1] << 8 | bytes[0];
265 outs() << "\t.short " << Value;
266 Size = 2;
267 } else {
268 if (!NoShowRawInsn)
269 dumpBytes(makeArrayRef(bytes, 2), outs());
270 Value = bytes[0];
271 outs() << "\t.byte " << Value;
272 Size = 1;
273 }
274 if (Kind == MachO::DICE_KIND_DATA)
275 outs() << "\t@ KIND_DATA\n";
276 else
277 outs() << "\t@ data in code kind = " << Kind << "\n";
278 break;
279 case MachO::DICE_KIND_JUMP_TABLE8:
280 if (!NoShowRawInsn)
281 dumpBytes(makeArrayRef(bytes, 1), outs());
282 Value = bytes[0];
283 outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
284 Size = 1;
285 break;
286 case MachO::DICE_KIND_JUMP_TABLE16:
287 if (!NoShowRawInsn)
288 dumpBytes(makeArrayRef(bytes, 2), outs());
289 Value = bytes[1] << 8 | bytes[0];
290 outs() << "\t.short " << format("%5u", Value & 0xffff)
291 << "\t@ KIND_JUMP_TABLE16\n";
292 Size = 2;
293 break;
294 case MachO::DICE_KIND_JUMP_TABLE32:
295 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
296 if (!NoShowRawInsn)
297 dumpBytes(makeArrayRef(bytes, 4), outs());
298 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
299 outs() << "\t.long " << Value;
300 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
301 outs() << "\t@ KIND_JUMP_TABLE32\n";
302 else
303 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
304 Size = 4;
305 break;
306 }
307 return Size;
308}
309
310static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
311 std::vector<SectionRef> &Sections,
312 std::vector<SymbolRef> &Symbols,
313 SmallVectorImpl<uint64_t> &FoundFns,
314 uint64_t &BaseSegmentAddress) {
315 for (const SymbolRef &Symbol : MachOObj->symbols()) {
316 Expected<StringRef> SymName = Symbol.getName();
317 if (!SymName)
318 report_error(MachOObj->getFileName(), SymName.takeError());
319 if (!SymName->startswith("ltmp"))
320 Symbols.push_back(Symbol);
321 }
322
323 for (const SectionRef &Section : MachOObj->sections()) {
324 StringRef SectName;
325 Section.getName(SectName);
326 Sections.push_back(Section);
327 }
328
329 bool BaseSegmentAddressSet = false;
330 for (const auto &Command : MachOObj->load_commands()) {
331 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
332 // We found a function starts segment, parse the addresses for later
333 // consumption.
334 MachO::linkedit_data_command LLC =
335 MachOObj->getLinkeditDataLoadCommand(Command);
336
337 MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
338 } else if (Command.C.cmd == MachO::LC_SEGMENT) {
339 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
340 StringRef SegName = SLC.segname;
341 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
342 BaseSegmentAddressSet = true;
343 BaseSegmentAddress = SLC.vmaddr;
344 }
345 }
346 }
347}
348
349static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
350 uint32_t n, uint32_t count,
351 uint32_t stride, uint64_t addr) {
352 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
353 uint32_t nindirectsyms = Dysymtab.nindirectsyms;
354 if (n > nindirectsyms)
355 outs() << " (entries start past the end of the indirect symbol "
356 "table) (reserved1 field greater than the table size)";
357 else if (n + count > nindirectsyms)
358 outs() << " (entries extends past the end of the indirect symbol "
359 "table)";
360 outs() << "\n";
361 uint32_t cputype = O->getHeader().cputype;
362 if (cputype & MachO::CPU_ARCH_ABI64)
363 outs() << "address index";
364 else
365 outs() << "address index";
366 if (verbose)
367 outs() << " name\n";
368 else
369 outs() << "\n";
370 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
371 if (cputype & MachO::CPU_ARCH_ABI64)
372 outs() << format("0x%016" PRIx64"l" "x", addr + j * stride) << " ";
373 else
374 outs() << format("0x%08" PRIx32"x", (uint32_t)addr + j * stride) << " ";
375 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
376 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
377 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
378 outs() << "LOCAL\n";
379 continue;
380 }
381 if (indirect_symbol ==
382 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
383 outs() << "LOCAL ABSOLUTE\n";
384 continue;
385 }
386 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
387 outs() << "ABSOLUTE\n";
388 continue;
389 }
390 outs() << format("%5u ", indirect_symbol);
391 if (verbose) {
392 MachO::symtab_command Symtab = O->getSymtabLoadCommand();
393 if (indirect_symbol < Symtab.nsyms) {
394 symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
395 SymbolRef Symbol = *Sym;
396 Expected<StringRef> SymName = Symbol.getName();
397 if (!SymName)
398 report_error(O->getFileName(), SymName.takeError());
399 outs() << *SymName;
400 } else {
401 outs() << "?";
402 }
403 }
404 outs() << "\n";
405 }
406}
407
408static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
409 for (const auto &Load : O->load_commands()) {
410 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
411 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
412 for (unsigned J = 0; J < Seg.nsects; ++J) {
413 MachO::section_64 Sec = O->getSection64(Load, J);
414 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
415 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
416 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
417 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
418 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
419 section_type == MachO::S_SYMBOL_STUBS) {
420 uint32_t stride;
421 if (section_type == MachO::S_SYMBOL_STUBS)
422 stride = Sec.reserved2;
423 else
424 stride = 8;
425 if (stride == 0) {
426 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
427 << Sec.sectname << ") "
428 << "(size of stubs in reserved2 field is zero)\n";
429 continue;
430 }
431 uint32_t count = Sec.size / stride;
432 outs() << "Indirect symbols for (" << Sec.segname << ","
433 << Sec.sectname << ") " << count << " entries";
434 uint32_t n = Sec.reserved1;
435 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
436 }
437 }
438 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
439 MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
440 for (unsigned J = 0; J < Seg.nsects; ++J) {
441 MachO::section Sec = O->getSection(Load, J);
442 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
443 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
444 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
445 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
446 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
447 section_type == MachO::S_SYMBOL_STUBS) {
448 uint32_t stride;
449 if (section_type == MachO::S_SYMBOL_STUBS)
450 stride = Sec.reserved2;
451 else
452 stride = 4;
453 if (stride == 0) {
454 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
455 << Sec.sectname << ") "
456 << "(size of stubs in reserved2 field is zero)\n";
457 continue;
458 }
459 uint32_t count = Sec.size / stride;
460 outs() << "Indirect symbols for (" << Sec.segname << ","
461 << Sec.sectname << ") " << count << " entries";
462 uint32_t n = Sec.reserved1;
463 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
464 }
465 }
466 }
467 }
468}
469
470static void PrintRType(const uint64_t cputype, const unsigned r_type) {
471 static char const *generic_r_types[] = {
472 "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
473 " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
474 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
475 };
476 static char const *x86_64_r_types[] = {
477 "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
478 "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
479 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
480 };
481 static char const *arm_r_types[] = {
482 "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
483 "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
484 " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
485 };
486 static char const *arm64_r_types[] = {
487 "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
488 "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
489 "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
490 };
491
492 if (r_type > 0xf){
493 outs() << format("%-7u", r_type) << " ";
494 return;
495 }
496 switch (cputype) {
497 case MachO::CPU_TYPE_I386:
498 outs() << generic_r_types[r_type];
499 break;
500 case MachO::CPU_TYPE_X86_64:
501 outs() << x86_64_r_types[r_type];
502 break;
503 case MachO::CPU_TYPE_ARM:
504 outs() << arm_r_types[r_type];
505 break;
506 case MachO::CPU_TYPE_ARM64:
507 outs() << arm64_r_types[r_type];
508 break;
509 default:
510 outs() << format("%-7u ", r_type);
511 }
512}
513
514static void PrintRLength(const uint64_t cputype, const unsigned r_type,
515 const unsigned r_length, const bool previous_arm_half){
516 if (cputype == MachO::CPU_TYPE_ARM &&
517 (r_type == llvm::MachO::ARM_RELOC_HALF ||
518 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF ||
519 previous_arm_half == true)) {
520 if ((r_length & 0x1) == 0)
521 outs() << "lo/";
522 else
523 outs() << "hi/";
524 if ((r_length & 0x1) == 0)
525 outs() << "arm ";
526 else
527 outs() << "thm ";
528 } else {
529 switch (r_length) {
530 case 0:
531 outs() << "byte ";
532 break;
533 case 1:
534 outs() << "word ";
535 break;
536 case 2:
537 outs() << "long ";
538 break;
539 case 3:
540 if (cputype == MachO::CPU_TYPE_X86_64)
541 outs() << "quad ";
542 else
543 outs() << format("?(%2d) ", r_length);
544 break;
545 default:
546 outs() << format("?(%2d) ", r_length);
547 }
548 }
549}
550
551static void PrintRelocationEntries(const MachOObjectFile *O,
552 const relocation_iterator Begin,
553 const relocation_iterator End,
554 const uint64_t cputype,
555 const bool verbose) {
556 const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
557 bool previous_arm_half = false;
558 bool previous_sectdiff = false;
559 uint32_t sectdiff_r_type = 0;
560
561 for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
562 const DataRefImpl Rel = Reloc->getRawDataRefImpl();
563 const MachO::any_relocation_info RE = O->getRelocation(Rel);
564 const unsigned r_type = O->getAnyRelocationType(RE);
565 const bool r_scattered = O->isRelocationScattered(RE);
566 const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
567 const unsigned r_length = O->getAnyRelocationLength(RE);
568 const unsigned r_address = O->getAnyRelocationAddress(RE);
569 const bool r_extern = (r_scattered ? false :
570 O->getPlainRelocationExternal(RE));
571 const uint32_t r_value = (r_scattered ?
572 O->getScatteredRelocationValue(RE) : 0);
573 const unsigned r_symbolnum = (r_scattered ? 0 :
574 O->getPlainRelocationSymbolNum(RE));
575
576 if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
577 if (verbose) {
578 // scattered: address
579 if ((cputype == MachO::CPU_TYPE_I386 &&
580 r_type == llvm::MachO::GENERIC_RELOC_PAIR) ||
581 (cputype == MachO::CPU_TYPE_ARM &&
582 r_type == llvm::MachO::ARM_RELOC_PAIR))
583 outs() << " ";
584 else
585 outs() << format("%08x ", (unsigned int)r_address);
586
587 // scattered: pcrel
588 if (r_pcrel)
589 outs() << "True ";
590 else
591 outs() << "False ";
592
593 // scattered: length
594 PrintRLength(cputype, r_type, r_length, previous_arm_half);
595
596 // scattered: extern & type
597 outs() << "n/a ";
598 PrintRType(cputype, r_type);
599
600 // scattered: scattered & value
601 outs() << format("True 0x%08x", (unsigned int)r_value);
602 if (previous_sectdiff == false) {
603 if ((cputype == MachO::CPU_TYPE_ARM &&
604 r_type == llvm::MachO::ARM_RELOC_PAIR))
605 outs() << format(" half = 0x%04x ", (unsigned int)r_address);
606 }
607 else if (cputype == MachO::CPU_TYPE_ARM &&
608 sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)
609 outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
610 if ((cputype == MachO::CPU_TYPE_I386 &&
611 (r_type == llvm::MachO::GENERIC_RELOC_SECTDIFF ||
612 r_type == llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
613 (cputype == MachO::CPU_TYPE_ARM &&
614 (sectdiff_r_type == llvm::MachO::ARM_RELOC_SECTDIFF ||
615 sectdiff_r_type == llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF ||
616 sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))) {
617 previous_sectdiff = true;
618 sectdiff_r_type = r_type;
619 }
620 else {
621 previous_sectdiff = false;
622 sectdiff_r_type = 0;
623 }
624 if (cputype == MachO::CPU_TYPE_ARM &&
625 (r_type == llvm::MachO::ARM_RELOC_HALF ||
626 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
627 previous_arm_half = true;
628 else
629 previous_arm_half = false;
630 outs() << "\n";
631 }
632 else {
633 // scattered: address pcrel length extern type scattered value
634 outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",
635 (unsigned int)r_address, r_pcrel, r_length, r_type,
636 (unsigned int)r_value);
637 }
638 }
639 else {
640 if (verbose) {
641 // plain: address
642 if (cputype == MachO::CPU_TYPE_ARM &&
643 r_type == llvm::MachO::ARM_RELOC_PAIR)
644 outs() << " ";
645 else
646 outs() << format("%08x ", (unsigned int)r_address);
647
648 // plain: pcrel
649 if (r_pcrel)
650 outs() << "True ";
651 else
652 outs() << "False ";
653
654 // plain: length
655 PrintRLength(cputype, r_type, r_length, previous_arm_half);
656
657 if (r_extern) {
658 // plain: extern & type & scattered
659 outs() << "True ";
660 PrintRType(cputype, r_type);
661 outs() << "False ";
662
663 // plain: symbolnum/value
664 if (r_symbolnum > Symtab.nsyms)
665 outs() << format("?(%d)\n", r_symbolnum);
666 else {
667 SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);
668 Expected<StringRef> SymNameNext = Symbol.getName();
669 const char *name = NULL__null;
670 if (SymNameNext)
671 name = SymNameNext->data();
672 if (name == NULL__null)
673 outs() << format("?(%d)\n", r_symbolnum);
674 else
675 outs() << name << "\n";
676 }
677 }
678 else {
679 // plain: extern & type & scattered
680 outs() << "False ";
681 PrintRType(cputype, r_type);
682 outs() << "False ";
683
684 // plain: symbolnum/value
685 if (cputype == MachO::CPU_TYPE_ARM &&
686 r_type == llvm::MachO::ARM_RELOC_PAIR)
687 outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
688 else if (cputype == MachO::CPU_TYPE_ARM64 &&
689 r_type == llvm::MachO::ARM64_RELOC_ADDEND)
690 outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
691 else {
692 outs() << format("%d ", r_symbolnum);
693 if (r_symbolnum == llvm::MachO::R_ABS)
694 outs() << "R_ABS\n";
695 else {
696 // in this case, r_symbolnum is actually a 1-based section number
697 uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
698 if (r_symbolnum > 0 && r_symbolnum <= nsects) {
699 llvm::object::DataRefImpl DRI;
700 DRI.d.a = r_symbolnum-1;
701 StringRef SegName = O->getSectionFinalSegmentName(DRI);
702 StringRef SectName;
703 if (O->getSectionName(DRI, SectName))
704 outs() << "(?,?)\n";
705 else
706 outs() << "(" << SegName << "," << SectName << ")\n";
707 }
708 else {
709 outs() << "(?,?)\n";
710 }
711 }
712 }
713 }
714 if (cputype == MachO::CPU_TYPE_ARM &&
715 (r_type == llvm::MachO::ARM_RELOC_HALF ||
716 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
717 previous_arm_half = true;
718 else
719 previous_arm_half = false;
720 }
721 else {
722 // plain: address pcrel length extern type scattered symbolnum/section
723 outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",
724 (unsigned int)r_address, r_pcrel, r_length, r_extern,
725 r_type, r_symbolnum);
726 }
727 }
728 }
729}
730
731static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
732 const uint64_t cputype = O->getHeader().cputype;
733 const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
734 if (Dysymtab.nextrel != 0) {
735 outs() << "External relocation information " << Dysymtab.nextrel
736 << " entries";
737 outs() << "\naddress pcrel length extern type scattered "
738 "symbolnum/value\n";
739 PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,
740 verbose);
741 }
742 if (Dysymtab.nlocrel != 0) {
743 outs() << format("Local relocation information %u entries",
744 Dysymtab.nlocrel);
745 outs() << "\naddress pcrel length extern type scattered "
746 "symbolnum/value\n";
747 PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,
748 verbose);
749 }
750 for (const auto &Load : O->load_commands()) {
751 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
752 const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
753 for (unsigned J = 0; J < Seg.nsects; ++J) {
754 const MachO::section_64 Sec = O->getSection64(Load, J);
755 if (Sec.nreloc != 0) {
756 DataRefImpl DRI;
757 DRI.d.a = J;
758 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
759 StringRef SectName;
760 if (O->getSectionName(DRI, SectName))
761 outs() << "Relocation information (" << SegName << ",?) "
762 << format("%u entries", Sec.nreloc);
763 else
764 outs() << "Relocation information (" << SegName << ","
765 << SectName << format(") %u entries", Sec.nreloc);
766 outs() << "\naddress pcrel length extern type scattered "
767 "symbolnum/value\n";
768 PrintRelocationEntries(O, O->section_rel_begin(DRI),
769 O->section_rel_end(DRI), cputype, verbose);
770 }
771 }
772 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
773 const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
774 for (unsigned J = 0; J < Seg.nsects; ++J) {
775 const MachO::section Sec = O->getSection(Load, J);
776 if (Sec.nreloc != 0) {
777 DataRefImpl DRI;
778 DRI.d.a = J;
779 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
780 StringRef SectName;
781 if (O->getSectionName(DRI, SectName))
782 outs() << "Relocation information (" << SegName << ",?) "
783 << format("%u entries", Sec.nreloc);
784 else
785 outs() << "Relocation information (" << SegName << ","
786 << SectName << format(") %u entries", Sec.nreloc);
787 outs() << "\naddress pcrel length extern type scattered "
788 "symbolnum/value\n";
789 PrintRelocationEntries(O, O->section_rel_begin(DRI),
790 O->section_rel_end(DRI), cputype, verbose);
791 }
792 }
793 }
794 }
795}
796
797static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
798 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
799 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
800 outs() << "Data in code table (" << nentries << " entries)\n";
801 outs() << "offset length kind\n";
802 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
803 ++DI) {
804 uint32_t Offset;
805 DI->getOffset(Offset);
806 outs() << format("0x%08" PRIx32"x", Offset) << " ";
807 uint16_t Length;
808 DI->getLength(Length);
809 outs() << format("%6u", Length) << " ";
810 uint16_t Kind;
811 DI->getKind(Kind);
812 if (verbose) {
813 switch (Kind) {
814 case MachO::DICE_KIND_DATA:
815 outs() << "DATA";
816 break;
817 case MachO::DICE_KIND_JUMP_TABLE8:
818 outs() << "JUMP_TABLE8";
819 break;
820 case MachO::DICE_KIND_JUMP_TABLE16:
821 outs() << "JUMP_TABLE16";
822 break;
823 case MachO::DICE_KIND_JUMP_TABLE32:
824 outs() << "JUMP_TABLE32";
825 break;
826 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
827 outs() << "ABS_JUMP_TABLE32";
828 break;
829 default:
830 outs() << format("0x%04" PRIx32"x", Kind);
831 break;
832 }
833 } else
834 outs() << format("0x%04" PRIx32"x", Kind);
835 outs() << "\n";
836 }
837}
838
839static void PrintLinkOptHints(MachOObjectFile *O) {
840 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
841 const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
842 uint32_t nloh = LohLC.datasize;
843 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
844 for (uint32_t i = 0; i < nloh;) {
845 unsigned n;
846 uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
847 i += n;
848 outs() << " identifier " << identifier << " ";
849 if (i >= nloh)
850 return;
851 switch (identifier) {
852 case 1:
853 outs() << "AdrpAdrp\n";
854 break;
855 case 2:
856 outs() << "AdrpLdr\n";
857 break;
858 case 3:
859 outs() << "AdrpAddLdr\n";
860 break;
861 case 4:
862 outs() << "AdrpLdrGotLdr\n";
863 break;
864 case 5:
865 outs() << "AdrpAddStr\n";
866 break;
867 case 6:
868 outs() << "AdrpLdrGotStr\n";
869 break;
870 case 7:
871 outs() << "AdrpAdd\n";
872 break;
873 case 8:
874 outs() << "AdrpLdrGot\n";
875 break;
876 default:
877 outs() << "Unknown identifier value\n";
878 break;
879 }
880 uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
881 i += n;
882 outs() << " narguments " << narguments << "\n";
883 if (i >= nloh)
884 return;
885
886 for (uint32_t j = 0; j < narguments; j++) {
887 uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
888 i += n;
889 outs() << "\tvalue " << format("0x%" PRIx64"l" "x", value) << "\n";
890 if (i >= nloh)
891 return;
892 }
893 }
894}
895
896static void PrintDylibs(MachOObjectFile *O, bool JustId) {
897 unsigned Index = 0;
898 for (const auto &Load : O->load_commands()) {
899 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
900 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
901 Load.C.cmd == MachO::LC_LOAD_DYLIB ||
902 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
903 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
904 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
905 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
906 MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
907 if (dl.dylib.name < dl.cmdsize) {
908 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
909 if (JustId)
910 outs() << p << "\n";
911 else {
912 outs() << "\t" << p;
913 outs() << " (compatibility version "
914 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
915 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
916 << (dl.dylib.compatibility_version & 0xff) << ",";
917 outs() << " current version "
918 << ((dl.dylib.current_version >> 16) & 0xffff) << "."
919 << ((dl.dylib.current_version >> 8) & 0xff) << "."
920 << (dl.dylib.current_version & 0xff) << ")\n";
921 }
922 } else {
923 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
924 if (Load.C.cmd == MachO::LC_ID_DYLIB)
925 outs() << "LC_ID_DYLIB ";
926 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
927 outs() << "LC_LOAD_DYLIB ";
928 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
929 outs() << "LC_LOAD_WEAK_DYLIB ";
930 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
931 outs() << "LC_LAZY_LOAD_DYLIB ";
932 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
933 outs() << "LC_REEXPORT_DYLIB ";
934 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
935 outs() << "LC_LOAD_UPWARD_DYLIB ";
936 else
937 outs() << "LC_??? ";
938 outs() << "command " << Index++ << "\n";
939 }
940 }
941 }
942}
943
944typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
945
946static void CreateSymbolAddressMap(MachOObjectFile *O,
947 SymbolAddressMap *AddrMap) {
948 // Create a map of symbol addresses to symbol names.
949 for (const SymbolRef &Symbol : O->symbols()) {
950 Expected<SymbolRef::Type> STOrErr = Symbol.getType();
951 if (!STOrErr)
952 report_error(O->getFileName(), STOrErr.takeError());
953 SymbolRef::Type ST = *STOrErr;
954 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
955 ST == SymbolRef::ST_Other) {
956 uint64_t Address = Symbol.getValue();
957 Expected<StringRef> SymNameOrErr = Symbol.getName();
958 if (!SymNameOrErr)
959 report_error(O->getFileName(), SymNameOrErr.takeError());
960 StringRef SymName = *SymNameOrErr;
961 if (!SymName.startswith(".objc"))
962 (*AddrMap)[Address] = SymName;
963 }
964 }
965}
966
967// GuessSymbolName is passed the address of what might be a symbol and a
968// pointer to the SymbolAddressMap. It returns the name of a symbol
969// with that address or nullptr if no symbol is found with that address.
970static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
971 const char *SymbolName = nullptr;
972 // A DenseMap can't lookup up some values.
973 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
974 StringRef name = AddrMap->lookup(value);
975 if (!name.empty())
976 SymbolName = name.data();
977 }
978 return SymbolName;
979}
980
981static void DumpCstringChar(const char c) {
982 char p[2];
983 p[0] = c;
984 p[1] = '\0';
985 outs().write_escaped(p);
986}
987
988static void DumpCstringSection(MachOObjectFile *O, const char *sect,
989 uint32_t sect_size, uint64_t sect_addr,
990 bool print_addresses) {
991 for (uint32_t i = 0; i < sect_size; i++) {
992 if (print_addresses) {
993 if (O->is64Bit())
994 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
995 else
996 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
997 }
998 for (; i < sect_size && sect[i] != '\0'; i++)
999 DumpCstringChar(sect[i]);
1000 if (i < sect_size && sect[i] == '\0')
1001 outs() << "\n";
1002 }
1003}
1004
1005static void DumpLiteral4(uint32_t l, float f) {
1006 outs() << format("0x%08" PRIx32"x", l);
1007 if ((l & 0x7f800000) != 0x7f800000)
1008 outs() << format(" (%.16e)\n", f);
1009 else {
1010 if (l == 0x7f800000)
1011 outs() << " (+Infinity)\n";
1012 else if (l == 0xff800000)
1013 outs() << " (-Infinity)\n";
1014 else if ((l & 0x00400000) == 0x00400000)
1015 outs() << " (non-signaling Not-a-Number)\n";
1016 else
1017 outs() << " (signaling Not-a-Number)\n";
1018 }
1019}
1020
1021static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
1022 uint32_t sect_size, uint64_t sect_addr,
1023 bool print_addresses) {
1024 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
1025 if (print_addresses) {
1026 if (O->is64Bit())
1027 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
1028 else
1029 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
1030 }
1031 float f;
1032 memcpy(&f, sect + i, sizeof(float));
1033 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1034 sys::swapByteOrder(f);
1035 uint32_t l;
1036 memcpy(&l, sect + i, sizeof(uint32_t));
1037 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1038 sys::swapByteOrder(l);
1039 DumpLiteral4(l, f);
1040 }
1041}
1042
1043static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
1044 double d) {
1045 outs() << format("0x%08" PRIx32"x", l0) << " " << format("0x%08" PRIx32"x", l1);
1046 uint32_t Hi, Lo;
1047 Hi = (O->isLittleEndian()) ? l1 : l0;
1048 Lo = (O->isLittleEndian()) ? l0 : l1;
1049
1050 // Hi is the high word, so this is equivalent to if(isfinite(d))
1051 if ((Hi & 0x7ff00000) != 0x7ff00000)
1052 outs() << format(" (%.16e)\n", d);
1053 else {
1054 if (Hi == 0x7ff00000 && Lo == 0)
1055 outs() << " (+Infinity)\n";
1056 else if (Hi == 0xfff00000 && Lo == 0)
1057 outs() << " (-Infinity)\n";
1058 else if ((Hi & 0x00080000) == 0x00080000)
1059 outs() << " (non-signaling Not-a-Number)\n";
1060 else
1061 outs() << " (signaling Not-a-Number)\n";
1062 }
1063}
1064
1065static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
1066 uint32_t sect_size, uint64_t sect_addr,
1067 bool print_addresses) {
1068 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
1069 if (print_addresses) {
1070 if (O->is64Bit())
1071 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
1072 else
1073 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
1074 }
1075 double d;
1076 memcpy(&d, sect + i, sizeof(double));
1077 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1078 sys::swapByteOrder(d);
1079 uint32_t l0, l1;
1080 memcpy(&l0, sect + i, sizeof(uint32_t));
1081 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1082 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1083 sys::swapByteOrder(l0);
1084 sys::swapByteOrder(l1);
1085 }
1086 DumpLiteral8(O, l0, l1, d);
1087 }
1088}
1089
1090static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
1091 outs() << format("0x%08" PRIx32"x", l0) << " ";
1092 outs() << format("0x%08" PRIx32"x", l1) << " ";
1093 outs() << format("0x%08" PRIx32"x", l2) << " ";
1094 outs() << format("0x%08" PRIx32"x", l3) << "\n";
1095}
1096
1097static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
1098 uint32_t sect_size, uint64_t sect_addr,
1099 bool print_addresses) {
1100 for (uint32_t i = 0; i < sect_size; i += 16) {
1101 if (print_addresses) {
1102 if (O->is64Bit())
1103 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
1104 else
1105 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
1106 }
1107 uint32_t l0, l1, l2, l3;
1108 memcpy(&l0, sect + i, sizeof(uint32_t));
1109 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1110 memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
1111 memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
1112 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1113 sys::swapByteOrder(l0);
1114 sys::swapByteOrder(l1);
1115 sys::swapByteOrder(l2);
1116 sys::swapByteOrder(l3);
1117 }
1118 DumpLiteral16(l0, l1, l2, l3);
1119 }
1120}
1121
1122static void DumpLiteralPointerSection(MachOObjectFile *O,
1123 const SectionRef &Section,
1124 const char *sect, uint32_t sect_size,
1125 uint64_t sect_addr,
1126 bool print_addresses) {
1127 // Collect the literal sections in this Mach-O file.
1128 std::vector<SectionRef> LiteralSections;
1129 for (const SectionRef &Section : O->sections()) {
1130 DataRefImpl Ref = Section.getRawDataRefImpl();
1131 uint32_t section_type;
1132 if (O->is64Bit()) {
1133 const MachO::section_64 Sec = O->getSection64(Ref);
1134 section_type = Sec.flags & MachO::SECTION_TYPE;
1135 } else {
1136 const MachO::section Sec = O->getSection(Ref);
1137 section_type = Sec.flags & MachO::SECTION_TYPE;
1138 }
1139 if (section_type == MachO::S_CSTRING_LITERALS ||
1140 section_type == MachO::S_4BYTE_LITERALS ||
1141 section_type == MachO::S_8BYTE_LITERALS ||
1142 section_type == MachO::S_16BYTE_LITERALS)
1143 LiteralSections.push_back(Section);
1144 }
1145
1146 // Set the size of the literal pointer.
1147 uint32_t lp_size = O->is64Bit() ? 8 : 4;
1148
1149 // Collect the external relocation symbols for the literal pointers.
1150 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1151 for (const RelocationRef &Reloc : Section.relocations()) {
1152 DataRefImpl Rel;
1153 MachO::any_relocation_info RE;
1154 bool isExtern = false;
1155 Rel = Reloc.getRawDataRefImpl();
1156 RE = O->getRelocation(Rel);
1157 isExtern = O->getPlainRelocationExternal(RE);
1158 if (isExtern) {
1159 uint64_t RelocOffset = Reloc.getOffset();
1160 symbol_iterator RelocSym = Reloc.getSymbol();
1161 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1162 }
1163 }
1164 array_pod_sort(Relocs.begin(), Relocs.end());
1165
1166 // Dump each literal pointer.
1167 for (uint32_t i = 0; i < sect_size; i += lp_size) {
1168 if (print_addresses) {
1169 if (O->is64Bit())
1170 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
1171 else
1172 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
1173 }
1174 uint64_t lp;
1175 if (O->is64Bit()) {
1176 memcpy(&lp, sect + i, sizeof(uint64_t));
1177 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1178 sys::swapByteOrder(lp);
1179 } else {
1180 uint32_t li;
1181 memcpy(&li, sect + i, sizeof(uint32_t));
1182 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1183 sys::swapByteOrder(li);
1184 lp = li;
1185 }
1186
1187 // First look for an external relocation entry for this literal pointer.
1188 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1189 return P.first == i;
1190 });
1191 if (Reloc != Relocs.end()) {
1192 symbol_iterator RelocSym = Reloc->second;
1193 Expected<StringRef> SymName = RelocSym->getName();
1194 if (!SymName)
1195 report_error(O->getFileName(), SymName.takeError());
1196 outs() << "external relocation entry for symbol:" << *SymName << "\n";
1197 continue;
1198 }
1199
1200 // For local references see what the section the literal pointer points to.
1201 auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {
1202 return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();
1203 });
1204 if (Sect == LiteralSections.end()) {
1205 outs() << format("0x%" PRIx64"l" "x", lp) << " (not in a literal section)\n";
1206 continue;
1207 }
1208
1209 uint64_t SectAddress = Sect->getAddress();
1210 uint64_t SectSize = Sect->getSize();
1211
1212 StringRef SectName;
1213 Sect->getName(SectName);
1214 DataRefImpl Ref = Sect->getRawDataRefImpl();
1215 StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
1216 outs() << SegmentName << ":" << SectName << ":";
1217
1218 uint32_t section_type;
1219 if (O->is64Bit()) {
1220 const MachO::section_64 Sec = O->getSection64(Ref);
1221 section_type = Sec.flags & MachO::SECTION_TYPE;
1222 } else {
1223 const MachO::section Sec = O->getSection(Ref);
1224 section_type = Sec.flags & MachO::SECTION_TYPE;
1225 }
1226
1227 StringRef BytesStr;
1228 Sect->getContents(BytesStr);
1229 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
1230
1231 switch (section_type) {
1232 case MachO::S_CSTRING_LITERALS:
1233 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
1234 i++) {
1235 DumpCstringChar(Contents[i]);
1236 }
1237 outs() << "\n";
1238 break;
1239 case MachO::S_4BYTE_LITERALS:
1240 float f;
1241 memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
1242 uint32_t l;
1243 memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
1244 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1245 sys::swapByteOrder(f);
1246 sys::swapByteOrder(l);
1247 }
1248 DumpLiteral4(l, f);
1249 break;
1250 case MachO::S_8BYTE_LITERALS: {
1251 double d;
1252 memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
1253 uint32_t l0, l1;
1254 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1255 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1256 sizeof(uint32_t));
1257 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1258 sys::swapByteOrder(f);
1259 sys::swapByteOrder(l0);
1260 sys::swapByteOrder(l1);
1261 }
1262 DumpLiteral8(O, l0, l1, d);
1263 break;
1264 }
1265 case MachO::S_16BYTE_LITERALS: {
1266 uint32_t l0, l1, l2, l3;
1267 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1268 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1269 sizeof(uint32_t));
1270 memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
1271 sizeof(uint32_t));
1272 memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
1273 sizeof(uint32_t));
1274 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1275 sys::swapByteOrder(l0);
1276 sys::swapByteOrder(l1);
1277 sys::swapByteOrder(l2);
1278 sys::swapByteOrder(l3);
1279 }
1280 DumpLiteral16(l0, l1, l2, l3);
1281 break;
1282 }
1283 }
1284 }
1285}
1286
1287static void DumpInitTermPointerSection(MachOObjectFile *O,
1288 const SectionRef &Section,
1289 const char *sect,
1290 uint32_t sect_size, uint64_t sect_addr,
1291 SymbolAddressMap *AddrMap,
1292 bool verbose) {
1293 uint32_t stride;
1294 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
1295
1296 // Collect the external relocation symbols for the pointers.
1297 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1298 for (const RelocationRef &Reloc : Section.relocations()) {
1299 DataRefImpl Rel;
1300 MachO::any_relocation_info RE;
1301 bool isExtern = false;
1302 Rel = Reloc.getRawDataRefImpl();
1303 RE = O->getRelocation(Rel);
1304 isExtern = O->getPlainRelocationExternal(RE);
1305 if (isExtern) {
1306 uint64_t RelocOffset = Reloc.getOffset();
1307 symbol_iterator RelocSym = Reloc.getSymbol();
1308 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1309 }
1310 }
1311 array_pod_sort(Relocs.begin(), Relocs.end());
1312
1313 for (uint32_t i = 0; i < sect_size; i += stride) {
1314 const char *SymbolName = nullptr;
1315 uint64_t p;
1316 if (O->is64Bit()) {
1317 outs() << format("0x%016" PRIx64"l" "x", sect_addr + i * stride) << " ";
1318 uint64_t pointer_value;
1319 memcpy(&pointer_value, sect + i, stride);
1320 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1321 sys::swapByteOrder(pointer_value);
1322 outs() << format("0x%016" PRIx64"l" "x", pointer_value);
1323 p = pointer_value;
1324 } else {
1325 outs() << format("0x%08" PRIx64"l" "x", sect_addr + i * stride) << " ";
1326 uint32_t pointer_value;
1327 memcpy(&pointer_value, sect + i, stride);
1328 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1329 sys::swapByteOrder(pointer_value);
1330 outs() << format("0x%08" PRIx32"x", pointer_value);
1331 p = pointer_value;
1332 }
1333 if (verbose) {
1334 // First look for an external relocation entry for this pointer.
1335 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1336 return P.first == i;
1337 });
1338 if (Reloc != Relocs.end()) {
1339 symbol_iterator RelocSym = Reloc->second;
1340 Expected<StringRef> SymName = RelocSym->getName();
1341 if (!SymName)
1342 report_error(O->getFileName(), SymName.takeError());
1343 outs() << " " << *SymName;
1344 } else {
1345 SymbolName = GuessSymbolName(p, AddrMap);
1346 if (SymbolName)
1347 outs() << " " << SymbolName;
1348 }
1349 }
1350 outs() << "\n";
1351 }
1352}
1353
1354static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
1355 uint32_t size, uint64_t addr) {
1356 uint32_t cputype = O->getHeader().cputype;
1357 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
1358 uint32_t j;
1359 for (uint32_t i = 0; i < size; i += j, addr += j) {
1360 if (O->is64Bit())
1361 outs() << format("%016" PRIx64"l" "x", addr) << "\t";
1362 else
1363 outs() << format("%08" PRIx64"l" "x", addr) << "\t";
1364 for (j = 0; j < 16 && i + j < size; j++) {
1365 uint8_t byte_word = *(sect + i + j);
1366 outs() << format("%02" PRIx32"x", (uint32_t)byte_word) << " ";
1367 }
1368 outs() << "\n";
1369 }
1370 } else {
1371 uint32_t j;
1372 for (uint32_t i = 0; i < size; i += j, addr += j) {
1373 if (O->is64Bit())
1374 outs() << format("%016" PRIx64"l" "x", addr) << "\t";
1375 else
1376 outs() << format("%08" PRIx64"l" "x", addr) << "\t";
1377 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
1378 j += sizeof(int32_t)) {
1379 if (i + j + sizeof(int32_t) <= size) {
1380 uint32_t long_word;
1381 memcpy(&long_word, sect + i + j, sizeof(int32_t));
1382 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1383 sys::swapByteOrder(long_word);
1384 outs() << format("%08" PRIx32"x", long_word) << " ";
1385 } else {
1386 for (uint32_t k = 0; i + j + k < size; k++) {
1387 uint8_t byte_word = *(sect + i + j + k);
1388 outs() << format("%02" PRIx32"x", (uint32_t)byte_word) << " ";
1389 }
1390 }
1391 }
1392 outs() << "\n";
1393 }
1394 }
1395}
1396
1397static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
1398 StringRef DisSegName, StringRef DisSectName);
1399static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1400 uint32_t size, uint32_t addr);
1401#ifdef HAVE_LIBXAR
1402static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
1403 uint32_t size, bool verbose,
1404 bool PrintXarHeader, bool PrintXarFileHeaders,
1405 std::string XarMemberName);
1406#endif // defined(HAVE_LIBXAR)
1407
1408static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1409 bool verbose) {
1410 SymbolAddressMap AddrMap;
1411 if (verbose)
1412 CreateSymbolAddressMap(O, &AddrMap);
1413
1414 for (unsigned i = 0; i < FilterSections.size(); ++i) {
1415 StringRef DumpSection = FilterSections[i];
1416 std::pair<StringRef, StringRef> DumpSegSectName;
1417 DumpSegSectName = DumpSection.split(',');
1418 StringRef DumpSegName, DumpSectName;
1419 if (DumpSegSectName.second.size()) {
1420 DumpSegName = DumpSegSectName.first;
1421 DumpSectName = DumpSegSectName.second;
1422 } else {
1423 DumpSegName = "";
1424 DumpSectName = DumpSegSectName.first;
1425 }
1426 for (const SectionRef &Section : O->sections()) {
1427 StringRef SectName;
1428 Section.getName(SectName);
1429 DataRefImpl Ref = Section.getRawDataRefImpl();
1430 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1431 if ((DumpSegName.empty() || SegName == DumpSegName) &&
1432 (SectName == DumpSectName)) {
1433
1434 uint32_t section_flags;
1435 if (O->is64Bit()) {
1436 const MachO::section_64 Sec = O->getSection64(Ref);
1437 section_flags = Sec.flags;
1438
1439 } else {
1440 const MachO::section Sec = O->getSection(Ref);
1441 section_flags = Sec.flags;
1442 }
1443 uint32_t section_type = section_flags & MachO::SECTION_TYPE;
1444
1445 StringRef BytesStr;
1446 Section.getContents(BytesStr);
1447 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1448 uint32_t sect_size = BytesStr.size();
1449 uint64_t sect_addr = Section.getAddress();
1450
1451 outs() << "Contents of (" << SegName << "," << SectName
1452 << ") section\n";
1453
1454 if (verbose) {
1455 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1456 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1457 DisassembleMachO(Filename, O, SegName, SectName);
1458 continue;
1459 }
1460 if (SegName == "__TEXT" && SectName == "__info_plist") {
1461 outs() << sect;
1462 continue;
1463 }
1464 if (SegName == "__OBJC" && SectName == "__protocol") {
1465 DumpProtocolSection(O, sect, sect_size, sect_addr);
1466 continue;
1467 }
1468#ifdef HAVE_LIBXAR
1469 if (SegName == "__LLVM" && SectName == "__bundle") {
1470 DumpBitcodeSection(O, sect, sect_size, verbose, !NoSymbolicOperands,
1471 ArchiveHeaders, "");
1472 continue;
1473 }
1474#endif // defined(HAVE_LIBXAR)
1475 switch (section_type) {
1476 case MachO::S_REGULAR:
1477 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1478 break;
1479 case MachO::S_ZEROFILL:
1480 outs() << "zerofill section and has no contents in the file\n";
1481 break;
1482 case MachO::S_CSTRING_LITERALS:
1483 DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1484 break;
1485 case MachO::S_4BYTE_LITERALS:
1486 DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1487 break;
1488 case MachO::S_8BYTE_LITERALS:
1489 DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1490 break;
1491 case MachO::S_16BYTE_LITERALS:
1492 DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1493 break;
1494 case MachO::S_LITERAL_POINTERS:
1495 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
1496 !NoLeadingAddr);
1497 break;
1498 case MachO::S_MOD_INIT_FUNC_POINTERS:
1499 case MachO::S_MOD_TERM_FUNC_POINTERS:
1500 DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,
1501 &AddrMap, verbose);
1502 break;
1503 default:
1504 outs() << "Unknown section type ("
1505 << format("0x%08" PRIx32"x", section_type) << ")\n";
1506 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1507 break;
1508 }
1509 } else {
1510 if (section_type == MachO::S_ZEROFILL)
1511 outs() << "zerofill section and has no contents in the file\n";
1512 else
1513 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1514 }
1515 }
1516 }
1517 }
1518}
1519
1520static void DumpInfoPlistSectionContents(StringRef Filename,
1521 MachOObjectFile *O) {
1522 for (const SectionRef &Section : O->sections()) {
1523 StringRef SectName;
1524 Section.getName(SectName);
1525 DataRefImpl Ref = Section.getRawDataRefImpl();
1526 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1527 if (SegName == "__TEXT" && SectName == "__info_plist") {
1528 if (!NoLeadingHeaders)
1529 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
1530 StringRef BytesStr;
1531 Section.getContents(BytesStr);
1532 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1533 outs() << format("%.*s", BytesStr.size(), sect) << "\n";
1534 return;
1535 }
1536 }
1537}
1538
1539// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
1540// and if it is and there is a list of architecture flags is specified then
1541// check to make sure this Mach-O file is one of those architectures or all
1542// architectures were specified. If not then an error is generated and this
1543// routine returns false. Else it returns true.
1544static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
1545 auto *MachO = dyn_cast<MachOObjectFile>(O);
1546
1547 if (!MachO || ArchAll || ArchFlags.empty())
1548 return true;
1549
1550 MachO::mach_header H;
1551 MachO::mach_header_64 H_64;
1552 Triple T;
1553 const char *McpuDefault, *ArchFlag;
1554 if (MachO->is64Bit()) {
1555 H_64 = MachO->MachOObjectFile::getHeader64();
1556 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
1557 &McpuDefault, &ArchFlag);
1558 } else {
1559 H = MachO->MachOObjectFile::getHeader();
1560 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
1561 &McpuDefault, &ArchFlag);
1562 }
1563 const std::string ArchFlagName(ArchFlag);
1564 if (none_of(ArchFlags, [&](const std::string &Name) {
1565 return Name == ArchFlagName;
1566 })) {
1567 errs() << "llvm-objdump: " + Filename + ": No architecture specified.\n";
1568 return false;
1569 }
1570 return true;
1571}
1572
1573static void printObjcMetaData(MachOObjectFile *O, bool verbose);
1574
1575// ProcessMachO() is passed a single opened Mach-O file, which may be an
1576// archive member and or in a slice of a universal file. It prints the
1577// the file name and header info and then processes it according to the
1578// command line options.
1579static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
1580 StringRef ArchiveMemberName = StringRef(),
1581 StringRef ArchitectureName = StringRef()) {
1582 // If we are doing some processing here on the Mach-O file print the header
1583 // info. And don't print it otherwise like in the case of printing the
1584 // UniversalHeaders or ArchiveHeaders.
1585 if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
26
Assuming the condition is false
27
Assuming the condition is false
28
Assuming the condition is false
29
Assuming the condition is false
30
Assuming the condition is false
42
Taking false branch
1586 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
31
Assuming the condition is false
32
Assuming the condition is false
33
Assuming the condition is false
34
Assuming the condition is false
35
Assuming the condition is false
1587 DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData ||
36
Assuming the condition is false
37
Assuming the condition is false
38
Assuming the condition is false
39
Assuming the condition is false
40
Assuming the condition is false
1588 (FilterSections.size() != 0)) {
41
Assuming the condition is false
1589 if (!NoLeadingHeaders) {
1590 outs() << Name;
1591 if (!ArchiveMemberName.empty())
1592 outs() << '(' << ArchiveMemberName << ')';
1593 if (!ArchitectureName.empty())
1594 outs() << " (architecture " << ArchitectureName << ")";
1595 outs() << ":\n";
1596 }
1597 }
1598 // To use the report_error() form with an ArchiveName and FileName set
1599 // these up based on what is passed for Name and ArchiveMemberName.
1600 StringRef ArchiveName;
1601 StringRef FileName;
1602 if (!ArchiveMemberName.empty()) {
43
Assuming the condition is false
44
Taking false branch
1603 ArchiveName = Name;
1604 FileName = ArchiveMemberName;
1605 } else {
1606 ArchiveName = StringRef();
1607 FileName = Name;
1608 }
1609
1610 // If we need the symbol table to do the operation then check it here to
1611 // produce a good error message as to where the Mach-O file comes from in
1612 // the error message.
1613 if (Disassemble || IndirectSymbols || FilterSections.size() != 0 ||
45
Assuming the condition is false
46
Assuming the condition is false
47
Assuming the condition is false
49
Taking false branch
1614 UnwindInfo)
48
Assuming the condition is false
1615 if (Error Err = MachOOF->checkSymbolTable())
1616 report_error(ArchiveName, FileName, std::move(Err), ArchitectureName);
1617
1618 if (Disassemble) {
50
Assuming the condition is false
51
Taking false branch
1619 if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
1620 MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
1621 DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
1622 else
1623 DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
1624 }
1625 if (IndirectSymbols)
52
Assuming the condition is false
53
Taking false branch
1626 PrintIndirectSymbols(MachOOF, !NonVerbose);
1627 if (DataInCode)
54
Assuming the condition is false
55
Taking false branch
1628 PrintDataInCodeTable(MachOOF, !NonVerbose);
1629 if (LinkOptHints)
56
Assuming the condition is false
57
Taking false branch
1630 PrintLinkOptHints(MachOOF);
1631 if (Relocations)
58
Assuming the condition is false
59
Taking false branch
1632 PrintRelocations(MachOOF, !NonVerbose);
1633 if (SectionHeaders)
60
Assuming the condition is false
61
Taking false branch
1634 PrintSectionHeaders(MachOOF);
1635 if (SectionContents)
62
Assuming the condition is false
63
Taking false branch
1636 PrintSectionContents(MachOOF);
1637 if (FilterSections.size() != 0)
64
Assuming the condition is false
65
Taking false branch
1638 DumpSectionContents(FileName, MachOOF, !NonVerbose);
1639 if (InfoPlist)
66
Assuming the condition is false
67
Taking false branch
1640 DumpInfoPlistSectionContents(FileName, MachOOF);
1641 if (DylibsUsed)
68
Assuming the condition is false
69
Taking false branch
1642 PrintDylibs(MachOOF, false);
1643 if (DylibId)
70
Assuming the condition is false
71
Taking false branch
1644 PrintDylibs(MachOOF, true);
1645 if (SymbolTable)
72
Assuming the condition is false
73
Taking false branch
1646 PrintSymbolTable(MachOOF, ArchiveName, ArchitectureName);
1647 if (UnwindInfo)
74
Assuming the condition is false
75
Taking false branch
1648 printMachOUnwindInfo(MachOOF);
1649 if (PrivateHeaders) {
76
Assuming the condition is false
77
Taking false branch
1650 printMachOFileHeader(MachOOF);
1651 printMachOLoadCommands(MachOOF);
1652 }
1653 if (FirstPrivateHeader)
78
Assuming the condition is false
79
Taking false branch
1654 printMachOFileHeader(MachOOF);
1655 if (ObjcMetaData)
80
Assuming the condition is true
81
Taking true branch
1656 printObjcMetaData(MachOOF, !NonVerbose);
82
Assuming the condition is false
83
Calling 'printObjcMetaData'
1657 if (ExportsTrie)
1658 printExportsTrie(MachOOF);
1659 if (Rebase)
1660 printRebaseTable(MachOOF);
1661 if (Bind)
1662 printBindTable(MachOOF);
1663 if (LazyBind)
1664 printLazyBindTable(MachOOF);
1665 if (WeakBind)
1666 printWeakBindTable(MachOOF);
1667
1668 if (DwarfDumpType != DIDT_Null) {
1669 std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);
1670 // Dump the complete DWARF structure.
1671 DIDumpOptions DumpOpts;
1672 DumpOpts.DumpType = DwarfDumpType;
1673 DICtx->dump(outs(), DumpOpts);
1674 }
1675}
1676
1677// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
1678static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
1679 outs() << " cputype (" << cputype << ")\n";
1680 outs() << " cpusubtype (" << cpusubtype << ")\n";
1681}
1682
1683// printCPUType() helps print_fat_headers by printing the cputype and
1684// pusubtype (symbolically for the one's it knows about).
1685static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
1686 switch (cputype) {
1687 case MachO::CPU_TYPE_I386:
1688 switch (cpusubtype) {
1689 case MachO::CPU_SUBTYPE_I386_ALL:
1690 outs() << " cputype CPU_TYPE_I386\n";
1691 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
1692 break;
1693 default:
1694 printUnknownCPUType(cputype, cpusubtype);
1695 break;
1696 }
1697 break;
1698 case MachO::CPU_TYPE_X86_64:
1699 switch (cpusubtype) {
1700 case MachO::CPU_SUBTYPE_X86_64_ALL:
1701 outs() << " cputype CPU_TYPE_X86_64\n";
1702 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
1703 break;
1704 case MachO::CPU_SUBTYPE_X86_64_H:
1705 outs() << " cputype CPU_TYPE_X86_64\n";
1706 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
1707 break;
1708 default:
1709 printUnknownCPUType(cputype, cpusubtype);
1710 break;
1711 }
1712 break;
1713 case MachO::CPU_TYPE_ARM:
1714 switch (cpusubtype) {
1715 case MachO::CPU_SUBTYPE_ARM_ALL:
1716 outs() << " cputype CPU_TYPE_ARM\n";
1717 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
1718 break;
1719 case MachO::CPU_SUBTYPE_ARM_V4T:
1720 outs() << " cputype CPU_TYPE_ARM\n";
1721 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
1722 break;
1723 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
1724 outs() << " cputype CPU_TYPE_ARM\n";
1725 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
1726 break;
1727 case MachO::CPU_SUBTYPE_ARM_XSCALE:
1728 outs() << " cputype CPU_TYPE_ARM\n";
1729 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
1730 break;
1731 case MachO::CPU_SUBTYPE_ARM_V6:
1732 outs() << " cputype CPU_TYPE_ARM\n";
1733 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
1734 break;
1735 case MachO::CPU_SUBTYPE_ARM_V6M:
1736 outs() << " cputype CPU_TYPE_ARM\n";
1737 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
1738 break;
1739 case MachO::CPU_SUBTYPE_ARM_V7:
1740 outs() << " cputype CPU_TYPE_ARM\n";
1741 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
1742 break;
1743 case MachO::CPU_SUBTYPE_ARM_V7EM:
1744 outs() << " cputype CPU_TYPE_ARM\n";
1745 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
1746 break;
1747 case MachO::CPU_SUBTYPE_ARM_V7K:
1748 outs() << " cputype CPU_TYPE_ARM\n";
1749 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
1750 break;
1751 case MachO::CPU_SUBTYPE_ARM_V7M:
1752 outs() << " cputype CPU_TYPE_ARM\n";
1753 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
1754 break;
1755 case MachO::CPU_SUBTYPE_ARM_V7S:
1756 outs() << " cputype CPU_TYPE_ARM\n";
1757 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
1758 break;
1759 default:
1760 printUnknownCPUType(cputype, cpusubtype);
1761 break;
1762 }
1763 break;
1764 case MachO::CPU_TYPE_ARM64:
1765 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
1766 case MachO::CPU_SUBTYPE_ARM64_ALL:
1767 outs() << " cputype CPU_TYPE_ARM64\n";
1768 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
1769 break;
1770 default:
1771 printUnknownCPUType(cputype, cpusubtype);
1772 break;
1773 }
1774 break;
1775 default:
1776 printUnknownCPUType(cputype, cpusubtype);
1777 break;
1778 }
1779}
1780
1781static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
1782 bool verbose) {
1783 outs() << "Fat headers\n";
1784 if (verbose) {
1785 if (UB->getMagic() == MachO::FAT_MAGIC)
1786 outs() << "fat_magic FAT_MAGIC\n";
1787 else // UB->getMagic() == MachO::FAT_MAGIC_64
1788 outs() << "fat_magic FAT_MAGIC_64\n";
1789 } else
1790 outs() << "fat_magic " << format("0x%" PRIx32"x", MachO::FAT_MAGIC) << "\n";
1791
1792 uint32_t nfat_arch = UB->getNumberOfObjects();
1793 StringRef Buf = UB->getData();
1794 uint64_t size = Buf.size();
1795 uint64_t big_size = sizeof(struct MachO::fat_header) +
1796 nfat_arch * sizeof(struct MachO::fat_arch);
1797 outs() << "nfat_arch " << UB->getNumberOfObjects();
1798 if (nfat_arch == 0)
1799 outs() << " (malformed, contains zero architecture types)\n";
1800 else if (big_size > size)
1801 outs() << " (malformed, architectures past end of file)\n";
1802 else
1803 outs() << "\n";
1804
1805 for (uint32_t i = 0; i < nfat_arch; ++i) {
1806 MachOUniversalBinary::ObjectForArch OFA(UB, i);
1807 uint32_t cputype = OFA.getCPUType();
1808 uint32_t cpusubtype = OFA.getCPUSubType();
1809 outs() << "architecture ";
1810 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
1811 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
1812 uint32_t other_cputype = other_OFA.getCPUType();
1813 uint32_t other_cpusubtype = other_OFA.getCPUSubType();
1814 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
1815 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
1816 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
1817 outs() << "(illegal duplicate architecture) ";
1818 break;
1819 }
1820 }
1821 if (verbose) {
1822 outs() << OFA.getArchFlagName() << "\n";
1823 printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
1824 } else {
1825 outs() << i << "\n";
1826 outs() << " cputype " << cputype << "\n";
1827 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
1828 << "\n";
1829 }
1830 if (verbose &&
1831 (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
1832 outs() << " capabilities CPU_SUBTYPE_LIB64\n";
1833 else
1834 outs() << " capabilities "
1835 << format("0x%" PRIx32"x",
1836 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
1837 outs() << " offset " << OFA.getOffset();
1838 if (OFA.getOffset() > size)
1839 outs() << " (past end of file)";
1840 if (OFA.getOffset() % (1 << OFA.getAlign()) != 0)
1841 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
1842 outs() << "\n";
1843 outs() << " size " << OFA.getSize();
1844 big_size = OFA.getOffset() + OFA.getSize();
1845 if (big_size > size)
1846 outs() << " (past end of file)";
1847 outs() << "\n";
1848 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
1849 << ")\n";
1850 }
1851}
1852
1853static void printArchiveChild(StringRef Filename, const Archive::Child &C,
1854 bool verbose, bool print_offset,
1855 StringRef ArchitectureName = StringRef()) {
1856 if (print_offset)
1857 outs() << C.getChildOffset() << "\t";
1858 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
1859 if (!ModeOrErr)
1860 report_error(Filename, C, ModeOrErr.takeError(), ArchitectureName);
1861 sys::fs::perms Mode = ModeOrErr.get();
1862 if (verbose) {
1863 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
1864 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
1865 outs() << "-";
1866 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
1867 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
1868 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
1869 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
1870 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
1871 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
1872 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
1873 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
1874 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
1875 } else {
1876 outs() << format("0%o ", Mode);
1877 }
1878
1879 Expected<unsigned> UIDOrErr = C.getUID();
1880 if (!UIDOrErr)
1881 report_error(Filename, C, UIDOrErr.takeError(), ArchitectureName);
1882 unsigned UID = UIDOrErr.get();
1883 outs() << format("%3d/", UID);
1884 Expected<unsigned> GIDOrErr = C.getGID();
1885 if (!GIDOrErr)
1886 report_error(Filename, C, GIDOrErr.takeError(), ArchitectureName);
1887 unsigned GID = GIDOrErr.get();
1888 outs() << format("%-3d ", GID);
1889 Expected<uint64_t> Size = C.getRawSize();
1890 if (!Size)
1891 report_error(Filename, C, Size.takeError(), ArchitectureName);
1892 outs() << format("%5" PRId64"l" "d", Size.get()) << " ";
1893
1894 StringRef RawLastModified = C.getRawLastModified();
1895 if (verbose) {
1896 unsigned Seconds;
1897 if (RawLastModified.getAsInteger(10, Seconds))
1898 outs() << "(date: \"" << RawLastModified
1899 << "\" contains non-decimal chars) ";
1900 else {
1901 // Since cime(3) returns a 26 character string of the form:
1902 // "Sun Sep 16 01:03:52 1973\n\0"
1903 // just print 24 characters.
1904 time_t t = Seconds;
1905 outs() << format("%.24s ", ctime(&t));
1906 }
1907 } else {
1908 outs() << RawLastModified << " ";
1909 }
1910
1911 if (verbose) {
1912 Expected<StringRef> NameOrErr = C.getName();
1913 if (!NameOrErr) {
1914 consumeError(NameOrErr.takeError());
1915 Expected<StringRef> NameOrErr = C.getRawName();
1916 if (!NameOrErr)
1917 report_error(Filename, C, NameOrErr.takeError(), ArchitectureName);
1918 StringRef RawName = NameOrErr.get();
1919 outs() << RawName << "\n";
1920 } else {
1921 StringRef Name = NameOrErr.get();
1922 outs() << Name << "\n";
1923 }
1924 } else {
1925 Expected<StringRef> NameOrErr = C.getRawName();
1926 if (!NameOrErr)
1927 report_error(Filename, C, NameOrErr.takeError(), ArchitectureName);
1928 StringRef RawName = NameOrErr.get();
1929 outs() << RawName << "\n";
1930 }
1931}
1932
1933static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
1934 bool print_offset,
1935 StringRef ArchitectureName = StringRef()) {
1936 Error Err = Error::success();
1937 ;
1938 for (const auto &C : A->children(Err, false))
1939 printArchiveChild(Filename, C, verbose, print_offset, ArchitectureName);
1940
1941 if (Err)
1942 report_error(StringRef(), Filename, std::move(Err), ArchitectureName);
1943}
1944
1945// ParseInputMachO() parses the named Mach-O file in Filename and handles the
1946// -arch flags selecting just those slices as specified by them and also parses
1947// archive files. Then for each individual Mach-O file ProcessMachO() is
1948// called to process the file based on the command line options.
1949void llvm::ParseInputMachO(StringRef Filename) {
1950 // Check for -arch all and verifiy the -arch flags are valid.
1951 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 1964
1952 if (ArchFlags[i] == "all") {
1953 ArchAll = true;
1954 } else {
1955 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
1956 errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] +
1957 "'for the -arch option\n";
1958 return;
1959 }
1960 }
1961 }
1962
1963 // Attempt to open the binary.
1964 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
1965 if (!BinaryOrErr) {
3
Taking false branch
1966 if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
1967 report_error(Filename, std::move(E));
1968 else
1969 outs() << Filename << ": is not an object file\n";
1970 return;
1971 }
1972 Binary &Bin = *BinaryOrErr.get().getBinary();
1973
1974 if (Archive *A = dyn_cast<Archive>(&Bin)) {
4
Taking false branch
1975 outs() << "Archive : " << Filename << "\n";
1976 if (ArchiveHeaders)
1977 printArchiveHeaders(Filename, A, !NonVerbose, ArchiveMemberOffsets);
1978
1979 Error Err = Error::success();
1980 for (auto &C : A->children(Err)) {
1981 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1982 if (!ChildOrErr) {
1983 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
1984 report_error(Filename, C, std::move(E));
1985 continue;
1986 }
1987 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
1988 if (!checkMachOAndArchFlags(O, Filename))
1989 return;
1990 ProcessMachO(Filename, O, O->getFileName());
1991 }
1992 }
1993 if (Err)
1994 report_error(Filename, std::move(Err));
1995 return;
1996 }
1997 if (UniversalHeaders) {
5
Assuming the condition is false
6
Taking false branch
1998 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
1999 printMachOUniversalHeaders(UB, !NonVerbose);
2000 }
2001 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
7
Assuming 'UB' is non-null
8
Taking true branch
2002 // If we have a list of architecture flags specified dump only those.
2003 if (!ArchAll && ArchFlags.size() != 0) {
9
Assuming 'ArchAll' is not equal to 0
2004 // Look for a slice in the universal binary that matches each ArchFlag.
2005 bool ArchFound;
2006 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2007 ArchFound = false;
2008 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2009 E = UB->end_objects();
2010 I != E; ++I) {
2011 if (ArchFlags[i] == I->getArchFlagName()) {
2012 ArchFound = true;
2013 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2014 I->getAsObjectFile();
2015 std::string ArchitectureName = "";
2016 if (ArchFlags.size() > 1)
2017 ArchitectureName = I->getArchFlagName();
2018 if (ObjOrErr) {
2019 ObjectFile &O = *ObjOrErr.get();
2020 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2021 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2022 } else if (auto E = isNotObjectErrorInvalidFileType(
2023 ObjOrErr.takeError())) {
2024 report_error(Filename, StringRef(), std::move(E),
2025 ArchitectureName);
2026 continue;
2027 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2028 I->getAsArchive()) {
2029 std::unique_ptr<Archive> &A = *AOrErr;
2030 outs() << "Archive : " << Filename;
2031 if (!ArchitectureName.empty())
2032 outs() << " (architecture " << ArchitectureName << ")";
2033 outs() << "\n";
2034 if (ArchiveHeaders)
2035 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2036 ArchiveMemberOffsets, ArchitectureName);
2037 Error Err = Error::success();
2038 for (auto &C : A->children(Err)) {
2039 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2040 if (!ChildOrErr) {
2041 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2042 report_error(Filename, C, std::move(E), ArchitectureName);
2043 continue;
2044 }
2045 if (MachOObjectFile *O =
2046 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2047 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
2048 }
2049 if (Err)
2050 report_error(Filename, std::move(Err));
2051 } else {
2052 consumeError(AOrErr.takeError());
2053 error("Mach-O universal file: " + Filename + " for " +
2054 "architecture " + StringRef(I->getArchFlagName()) +
2055 " is not a Mach-O file or an archive file");
2056 }
2057 }
2058 }
2059 if (!ArchFound) {
2060 errs() << "llvm-objdump: file: " + Filename + " does not contain "
2061 << "architecture: " + ArchFlags[i] + "\n";
2062 return;
2063 }
2064 }
2065 return;
2066 }
2067 // No architecture flags were specified so if this contains a slice that
2068 // matches the host architecture dump only that.
2069 if (!ArchAll) {
10
Taking false branch
2070 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2071 E = UB->end_objects();
2072 I != E; ++I) {
2073 if (MachOObjectFile::getHostArch().getArchName() ==
2074 I->getArchFlagName()) {
2075 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2076 std::string ArchiveName;
2077 ArchiveName.clear();
2078 if (ObjOrErr) {
2079 ObjectFile &O = *ObjOrErr.get();
2080 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2081 ProcessMachO(Filename, MachOOF);
2082 } else if (auto E = isNotObjectErrorInvalidFileType(
2083 ObjOrErr.takeError())) {
2084 report_error(Filename, std::move(E));
2085 continue;
2086 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2087 I->getAsArchive()) {
2088 std::unique_ptr<Archive> &A = *AOrErr;
2089 outs() << "Archive : " << Filename << "\n";
2090 if (ArchiveHeaders)
2091 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2092 ArchiveMemberOffsets);
2093 Error Err = Error::success();
2094 for (auto &C : A->children(Err)) {
2095 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2096 if (!ChildOrErr) {
2097 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2098 report_error(Filename, C, std::move(E));
2099 continue;
2100 }
2101 if (MachOObjectFile *O =
2102 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2103 ProcessMachO(Filename, O, O->getFileName());
2104 }
2105 if (Err)
2106 report_error(Filename, std::move(Err));
2107 } else {
2108 consumeError(AOrErr.takeError());
2109 error("Mach-O universal file: " + Filename + " for architecture " +
2110 StringRef(I->getArchFlagName()) +
2111 " is not a Mach-O file or an archive file");
2112 }
2113 return;
2114 }
2115 }
2116 }
2117 // Either all architectures have been specified or none have been specified
2118 // and this does not contain the host architecture so dump all the slices.
2119 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
11
Assuming the condition is false
2120 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
12
Loop condition is true. Entering loop body
2121 E = UB->end_objects();
2122 I != E; ++I) {
2123 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2124 std::string ArchitectureName = "";
2125 if (moreThanOneArch)
13
Taking false branch
2126 ArchitectureName = I->getArchFlagName();
2127 if (ObjOrErr) {
14
Taking false branch
2128 ObjectFile &Obj = *ObjOrErr.get();
2129 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
2130 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2131 } else if (auto E = isNotObjectErrorInvalidFileType(
15
Taking false branch
2132 ObjOrErr.takeError())) {
2133 report_error(StringRef(), Filename, std::move(E), ArchitectureName);
2134 continue;
2135 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
16
Taking true branch
2136 I->getAsArchive()) {
2137 std::unique_ptr<Archive> &A = *AOrErr;
2138 outs() << "Archive : " << Filename;
2139 if (!ArchitectureName.empty())
17
Assuming the condition is false
18
Taking false branch
2140 outs() << " (architecture " << ArchitectureName << ")";
2141 outs() << "\n";
2142 if (ArchiveHeaders)
19
Assuming the condition is false
20
Taking false branch
2143 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2144 ArchiveMemberOffsets, ArchitectureName);
2145 Error Err = Error::success();
2146 for (auto &C : A->children(Err)) {
2147 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2148 if (!ChildOrErr) {
21
Taking false branch
2149 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2150 report_error(Filename, C, std::move(E), ArchitectureName);
2151 continue;
2152 }
2153 if (MachOObjectFile *O =
22
Assuming 'O' is non-null
23
Taking true branch
2154 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2155 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
24
Taking true branch
2156 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
25
Calling 'ProcessMachO'
2157 ArchitectureName);
2158 }
2159 }
2160 if (Err)
2161 report_error(Filename, std::move(Err));
2162 } else {
2163 consumeError(AOrErr.takeError());
2164 error("Mach-O universal file: " + Filename + " for architecture " +
2165 StringRef(I->getArchFlagName()) +
2166 " is not a Mach-O file or an archive file");
2167 }
2168 }
2169 return;
2170 }
2171 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
2172 if (!checkMachOAndArchFlags(O, Filename))
2173 return;
2174 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O)) {
2175 ProcessMachO(Filename, MachOOF);
2176 } else
2177 errs() << "llvm-objdump: '" << Filename << "': "
2178 << "Object is not a Mach-O file type.\n";
2179 return;
2180 }
2181 llvm_unreachable("Input object can't be invalid at this point")::llvm::llvm_unreachable_internal("Input object can't be invalid at this point"
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-objdump/MachODump.cpp"
, 2181)
;
2182}
2183
2184// The block of info used by the Symbolizer call backs.
2185struct DisassembleInfo {
2186 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2187 std::vector<SectionRef> *Sections, bool verbose)
2188 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
2189 bool verbose;
2190 MachOObjectFile *O;
2191 SectionRef S;
2192 SymbolAddressMap *AddrMap;
2193 std::vector<SectionRef> *Sections;
2194 const char *class_name = nullptr;
2195 const char *selector_name = nullptr;
2196 std::unique_ptr<char[]> method = nullptr;
2197 char *demangled_name = nullptr;
2198 uint64_t adrp_addr = 0;
2199 uint32_t adrp_inst = 0;
2200 std::unique_ptr<SymbolAddressMap> bindtable;
2201 uint32_t depth = 0;
2202};
2203
2204// SymbolizerGetOpInfo() is the operand information call back function.
2205// This is called to get the symbolic information for operand(s) of an
2206// instruction when it is being done. This routine does this from
2207// the relocation information, symbol table, etc. That block of information
2208// is a pointer to the struct DisassembleInfo that was passed when the
2209// disassembler context was created and passed to back to here when
2210// called back by the disassembler for instruction operands that could have
2211// relocation information. The address of the instruction containing operand is
2212// at the Pc parameter. The immediate value the operand has is passed in
2213// op_info->Value and is at Offset past the start of the instruction and has a
2214// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2215// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2216// names and addends of the symbolic expression to add for the operand. The
2217// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2218// information is returned then this function returns 1 else it returns 0.
2219static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2220 uint64_t Size, int TagType, void *TagBuf) {
2221 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2222 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
2223 uint64_t value = op_info->Value;
2224
2225 // Make sure all fields returned are zero if we don't set them.
2226 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
2227 op_info->Value = value;
2228
2229 // If the TagType is not the value 1 which it code knows about or if no
2230 // verbose symbolic information is wanted then just return 0, indicating no
2231 // information is being returned.
2232 if (TagType != 1 || !info->verbose)
2233 return 0;
2234
2235 unsigned int Arch = info->O->getArch();
2236 if (Arch == Triple::x86) {
2237 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2238 return 0;
2239 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2240 // TODO:
2241 // Search the external relocation entries of a fully linked image
2242 // (if any) for an entry that matches this segment offset.
2243 // uint32_t seg_offset = (Pc + Offset);
2244 return 0;
2245 }
2246 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2247 // for an entry for this section offset.
2248 uint32_t sect_addr = info->S.getAddress();
2249 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2250 bool reloc_found = false;
2251 DataRefImpl Rel;
2252 MachO::any_relocation_info RE;
2253 bool isExtern = false;
2254 SymbolRef Symbol;
2255 bool r_scattered = false;
2256 uint32_t r_value, pair_r_value, r_type;
2257 for (const RelocationRef &Reloc : info->S.relocations()) {
2258 uint64_t RelocOffset = Reloc.getOffset();
2259 if (RelocOffset == sect_offset) {
2260 Rel = Reloc.getRawDataRefImpl();
2261 RE = info->O->getRelocation(Rel);
2262 r_type = info->O->getAnyRelocationType(RE);
2263 r_scattered = info->O->isRelocationScattered(RE);
2264 if (r_scattered) {
2265 r_value = info->O->getScatteredRelocationValue(RE);
2266 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2267 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2268 DataRefImpl RelNext = Rel;
2269 info->O->moveRelocationNext(RelNext);
2270 MachO::any_relocation_info RENext;
2271 RENext = info->O->getRelocation(RelNext);
2272 if (info->O->isRelocationScattered(RENext))
2273 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2274 else
2275 return 0;
2276 }
2277 } else {
2278 isExtern = info->O->getPlainRelocationExternal(RE);
2279 if (isExtern) {
2280 symbol_iterator RelocSym = Reloc.getSymbol();
2281 Symbol = *RelocSym;
2282 }
2283 }
2284 reloc_found = true;
2285 break;
2286 }
2287 }
2288 if (reloc_found && isExtern) {
2289 Expected<StringRef> SymName = Symbol.getName();
2290 if (!SymName)
2291 report_error(info->O->getFileName(), SymName.takeError());
2292 const char *name = SymName->data();
2293 op_info->AddSymbol.Present = 1;
2294 op_info->AddSymbol.Name = name;
2295 // For i386 extern relocation entries the value in the instruction is
2296 // the offset from the symbol, and value is already set in op_info->Value.
2297 return 1;
2298 }
2299 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2300 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
2301 const char *add = GuessSymbolName(r_value, info->AddrMap);
2302 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2303 uint32_t offset = value - (r_value - pair_r_value);
2304 op_info->AddSymbol.Present = 1;
2305 if (add != nullptr)
2306 op_info->AddSymbol.Name = add;
2307 else
2308 op_info->AddSymbol.Value = r_value;
2309 op_info->SubtractSymbol.Present = 1;
2310 if (sub != nullptr)
2311 op_info->SubtractSymbol.Name = sub;
2312 else
2313 op_info->SubtractSymbol.Value = pair_r_value;
2314 op_info->Value = offset;
2315 return 1;
2316 }
2317 return 0;
2318 }
2319 if (Arch == Triple::x86_64) {
2320 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2321 return 0;
2322 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2323 // relocation entries of a linked image (if any) for an entry that matches
2324 // this segment offset.
2325 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2326 uint64_t seg_offset = Pc + Offset;
2327 bool reloc_found = false;
2328 DataRefImpl Rel;
2329 MachO::any_relocation_info RE;
2330 bool isExtern = false;
2331 SymbolRef Symbol;
2332 for (const RelocationRef &Reloc : info->O->external_relocations()) {
2333 uint64_t RelocOffset = Reloc.getOffset();
2334 if (RelocOffset == seg_offset) {
2335 Rel = Reloc.getRawDataRefImpl();
2336 RE = info->O->getRelocation(Rel);
2337 // external relocation entries should always be external.
2338 isExtern = info->O->getPlainRelocationExternal(RE);
2339 if (isExtern) {
2340 symbol_iterator RelocSym = Reloc.getSymbol();
2341 Symbol = *RelocSym;
2342 }
2343 reloc_found = true;
2344 break;
2345 }
2346 }
2347 if (reloc_found && isExtern) {
2348 // The Value passed in will be adjusted by the Pc if the instruction
2349 // adds the Pc. But for x86_64 external relocation entries the Value
2350 // is the offset from the external symbol.
2351 if (info->O->getAnyRelocationPCRel(RE))
2352 op_info->Value -= Pc + Offset + Size;
2353 Expected<StringRef> SymName = Symbol.getName();
2354 if (!SymName)
2355 report_error(info->O->getFileName(), SymName.takeError());
2356 const char *name = SymName->data();
2357 op_info->AddSymbol.Present = 1;
2358 op_info->AddSymbol.Name = name;
2359 return 1;
2360 }
2361 return 0;
2362 }
2363 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2364 // for an entry for this section offset.
2365 uint64_t sect_addr = info->S.getAddress();
2366 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2367 bool reloc_found = false;
2368 DataRefImpl Rel;
2369 MachO::any_relocation_info RE;
2370 bool isExtern = false;
2371 SymbolRef Symbol;
2372 for (const RelocationRef &Reloc : info->S.relocations()) {
2373 uint64_t RelocOffset = Reloc.getOffset();
2374 if (RelocOffset == sect_offset) {
2375 Rel = Reloc.getRawDataRefImpl();
2376 RE = info->O->getRelocation(Rel);
2377 // NOTE: Scattered relocations don't exist on x86_64.
2378 isExtern = info->O->getPlainRelocationExternal(RE);
2379 if (isExtern) {
2380 symbol_iterator RelocSym = Reloc.getSymbol();
2381 Symbol = *RelocSym;
2382 }
2383 reloc_found = true;
2384 break;
2385 }
2386 }
2387 if (reloc_found && isExtern) {
2388 // The Value passed in will be adjusted by the Pc if the instruction
2389 // adds the Pc. But for x86_64 external relocation entries the Value
2390 // is the offset from the external symbol.
2391 if (info->O->getAnyRelocationPCRel(RE))
2392 op_info->Value -= Pc + Offset + Size;
2393 Expected<StringRef> SymName = Symbol.getName();
2394 if (!SymName)
2395 report_error(info->O->getFileName(), SymName.takeError());
2396 const char *name = SymName->data();
2397 unsigned Type = info->O->getAnyRelocationType(RE);
2398 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2399 DataRefImpl RelNext = Rel;
2400 info->O->moveRelocationNext(RelNext);
2401 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2402 unsigned TypeNext = info->O->getAnyRelocationType(RENext);
2403 bool isExternNext = info->O->getPlainRelocationExternal(RENext);
2404 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
2405 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
2406 op_info->SubtractSymbol.Present = 1;
2407 op_info->SubtractSymbol.Name = name;
2408 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
2409 Symbol = *RelocSymNext;
2410 Expected<StringRef> SymNameNext = Symbol.getName();
2411 if (!SymNameNext)
2412 report_error(info->O->getFileName(), SymNameNext.takeError());
2413 name = SymNameNext->data();
2414 }
2415 }
2416 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
2417 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
2418 op_info->AddSymbol.Present = 1;
2419 op_info->AddSymbol.Name = name;
2420 return 1;
2421 }
2422 return 0;
2423 }
2424 if (Arch == Triple::arm) {
2425 if (Offset != 0 || (Size != 4 && Size != 2))
2426 return 0;
2427 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2428 // TODO:
2429 // Search the external relocation entries of a fully linked image
2430 // (if any) for an entry that matches this segment offset.
2431 // uint32_t seg_offset = (Pc + Offset);
2432 return 0;
2433 }
2434 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2435 // for an entry for this section offset.
2436 uint32_t sect_addr = info->S.getAddress();
2437 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2438 DataRefImpl Rel;
2439 MachO::any_relocation_info RE;
2440 bool isExtern = false;
2441 SymbolRef Symbol;
2442 bool r_scattered = false;
2443 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
2444 auto Reloc =
2445 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2446 uint64_t RelocOffset = Reloc.getOffset();
2447 return RelocOffset == sect_offset;
2448 });
2449
2450 if (Reloc == info->S.relocations().end())
2451 return 0;
2452
2453 Rel = Reloc->getRawDataRefImpl();
2454 RE = info->O->getRelocation(Rel);
2455 r_length = info->O->getAnyRelocationLength(RE);
2456 r_scattered = info->O->isRelocationScattered(RE);
2457 if (r_scattered) {
2458 r_value = info->O->getScatteredRelocationValue(RE);
2459 r_type = info->O->getScatteredRelocationType(RE);
2460 } else {
2461 r_type = info->O->getAnyRelocationType(RE);
2462 isExtern = info->O->getPlainRelocationExternal(RE);
2463 if (isExtern) {
2464 symbol_iterator RelocSym = Reloc->getSymbol();
2465 Symbol = *RelocSym;
2466 }
2467 }
2468 if (r_type == MachO::ARM_RELOC_HALF ||
2469 r_type == MachO::ARM_RELOC_SECTDIFF ||
2470 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
2471 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2472 DataRefImpl RelNext = Rel;
2473 info->O->moveRelocationNext(RelNext);
2474 MachO::any_relocation_info RENext;
2475 RENext = info->O->getRelocation(RelNext);
2476 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
2477 if (info->O->isRelocationScattered(RENext))
2478 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2479 }
2480
2481 if (isExtern) {
2482 Expected<StringRef> SymName = Symbol.getName();
2483 if (!SymName)
2484 report_error(info->O->getFileName(), SymName.takeError());
2485 const char *name = SymName->data();
2486 op_info->AddSymbol.Present = 1;
2487 op_info->AddSymbol.Name = name;
2488 switch (r_type) {
2489 case MachO::ARM_RELOC_HALF:
2490 if ((r_length & 0x1) == 1) {
2491 op_info->Value = value << 16 | other_half;
2492 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2493 } else {
2494 op_info->Value = other_half << 16 | value;
2495 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2496 }
2497 break;
2498 default:
2499 break;
2500 }
2501 return 1;
2502 }
2503 // If we have a branch that is not an external relocation entry then
2504 // return 0 so the code in tryAddingSymbolicOperand() can use the
2505 // SymbolLookUp call back with the branch target address to look up the
2506 // symbol and possibility add an annotation for a symbol stub.
2507 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
2508 r_type == MachO::ARM_THUMB_RELOC_BR22))
2509 return 0;
2510
2511 uint32_t offset = 0;
2512 if (r_type == MachO::ARM_RELOC_HALF ||
2513 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2514 if ((r_length & 0x1) == 1)
2515 value = value << 16 | other_half;
2516 else
2517 value = other_half << 16 | value;
2518 }
2519 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
2520 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
2521 offset = value - r_value;
2522 value = r_value;
2523 }
2524
2525 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2526 if ((r_length & 0x1) == 1)
2527 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2528 else
2529 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2530 const char *add = GuessSymbolName(r_value, info->AddrMap);
2531 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2532 int32_t offset = value - (r_value - pair_r_value);
2533 op_info->AddSymbol.Present = 1;
2534 if (add != nullptr)
2535 op_info->AddSymbol.Name = add;
2536 else
2537 op_info->AddSymbol.Value = r_value;
2538 op_info->SubtractSymbol.Present = 1;
2539 if (sub != nullptr)
2540 op_info->SubtractSymbol.Name = sub;
2541 else
2542 op_info->SubtractSymbol.Value = pair_r_value;
2543 op_info->Value = offset;
2544 return 1;
2545 }
2546
2547 op_info->AddSymbol.Present = 1;
2548 op_info->Value = offset;
2549 if (r_type == MachO::ARM_RELOC_HALF) {
2550 if ((r_length & 0x1) == 1)
2551 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2552 else
2553 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2554 }
2555 const char *add = GuessSymbolName(value, info->AddrMap);
2556 if (add != nullptr) {
2557 op_info->AddSymbol.Name = add;
2558 return 1;
2559 }
2560 op_info->AddSymbol.Value = value;
2561 return 1;
2562 }
2563 if (Arch == Triple::aarch64) {
2564 if (Offset != 0 || Size != 4)
2565 return 0;
2566 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2567 // TODO:
2568 // Search the external relocation entries of a fully linked image
2569 // (if any) for an entry that matches this segment offset.
2570 // uint64_t seg_offset = (Pc + Offset);
2571 return 0;
2572 }
2573 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2574 // for an entry for this section offset.
2575 uint64_t sect_addr = info->S.getAddress();
2576 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2577 auto Reloc =
2578 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2579 uint64_t RelocOffset = Reloc.getOffset();
2580 return RelocOffset == sect_offset;
2581 });
2582
2583 if (Reloc == info->S.relocations().end())
2584 return 0;
2585
2586 DataRefImpl Rel = Reloc->getRawDataRefImpl();
2587 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
2588 uint32_t r_type = info->O->getAnyRelocationType(RE);
2589 if (r_type == MachO::ARM64_RELOC_ADDEND) {
2590 DataRefImpl RelNext = Rel;
2591 info->O->moveRelocationNext(RelNext);
2592 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2593 if (value == 0) {
2594 value = info->O->getPlainRelocationSymbolNum(RENext);
2595 op_info->Value = value;
2596 }
2597 }
2598 // NOTE: Scattered relocations don't exist on arm64.
2599 if (!info->O->getPlainRelocationExternal(RE))
2600 return 0;
2601 Expected<StringRef> SymName = Reloc->getSymbol()->getName();
2602 if (!SymName)
2603 report_error(info->O->getFileName(), SymName.takeError());
2604 const char *name = SymName->data();
2605 op_info->AddSymbol.Present = 1;
2606 op_info->AddSymbol.Name = name;
2607
2608 switch (r_type) {
2609 case MachO::ARM64_RELOC_PAGE21:
2610 /* @page */
2611 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE1;
2612 break;
2613 case MachO::ARM64_RELOC_PAGEOFF12:
2614 /* @pageoff */
2615 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF2;
2616 break;
2617 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
2618 /* @gotpage */
2619 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE3;
2620 break;
2621 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
2622 /* @gotpageoff */
2623 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF4;
2624 break;
2625 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
2626 /* @tvlppage is not implemented in llvm-mc */
2627 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP5;
2628 break;
2629 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
2630 /* @tvlppageoff is not implemented in llvm-mc */
2631 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF6;
2632 break;
2633 default:
2634 case MachO::ARM64_RELOC_BRANCH26:
2635 op_info->VariantKind = LLVMDisassembler_VariantKind_None0;
2636 break;
2637 }
2638 return 1;
2639 }
2640 return 0;
2641}
2642
2643// GuessCstringPointer is passed the address of what might be a pointer to a
2644// literal string in a cstring section. If that address is in a cstring section
2645// it returns a pointer to that string. Else it returns nullptr.
2646static const char *GuessCstringPointer(uint64_t ReferenceValue,
2647 struct DisassembleInfo *info) {
2648 for (const auto &Load : info->O->load_commands()) {
2649 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2650 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2651 for (unsigned J = 0; J < Seg.nsects; ++J) {
2652 MachO::section_64 Sec = info->O->getSection64(Load, J);
2653 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2654 if (section_type == MachO::S_CSTRING_LITERALS &&
2655 ReferenceValue >= Sec.addr &&
2656 ReferenceValue < Sec.addr + Sec.size) {
2657 uint64_t sect_offset = ReferenceValue - Sec.addr;
2658 uint64_t object_offset = Sec.offset + sect_offset;
2659 StringRef MachOContents = info->O->getData();
2660 uint64_t object_size = MachOContents.size();
2661 const char *object_addr = (const char *)MachOContents.data();
2662 if (object_offset < object_size) {
2663 const char *name = object_addr + object_offset;
2664 return name;
2665 } else {
2666 return nullptr;
2667 }
2668 }
2669 }
2670 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2671 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2672 for (unsigned J = 0; J < Seg.nsects; ++J) {
2673 MachO::section Sec = info->O->getSection(Load, J);
2674 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2675 if (section_type == MachO::S_CSTRING_LITERALS &&
2676 ReferenceValue >= Sec.addr &&
2677 ReferenceValue < Sec.addr + Sec.size) {
2678 uint64_t sect_offset = ReferenceValue - Sec.addr;
2679 uint64_t object_offset = Sec.offset + sect_offset;
2680 StringRef MachOContents = info->O->getData();
2681 uint64_t object_size = MachOContents.size();
2682 const char *object_addr = (const char *)MachOContents.data();
2683 if (object_offset < object_size) {
2684 const char *name = object_addr + object_offset;
2685 return name;
2686 } else {
2687 return nullptr;
2688 }
2689 }
2690 }
2691 }
2692 }
2693 return nullptr;
2694}
2695
2696// GuessIndirectSymbol returns the name of the indirect symbol for the
2697// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
2698// an address of a symbol stub or a lazy or non-lazy pointer to associate the
2699// symbol name being referenced by the stub or pointer.
2700static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
2701 struct DisassembleInfo *info) {
2702 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
2703 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
2704 for (const auto &Load : info->O->load_commands()) {
2705 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2706 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2707 for (unsigned J = 0; J < Seg.nsects; ++J) {
2708 MachO::section_64 Sec = info->O->getSection64(Load, J);
2709 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2710 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2711 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2712 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2713 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2714 section_type == MachO::S_SYMBOL_STUBS) &&
2715 ReferenceValue >= Sec.addr &&
2716 ReferenceValue < Sec.addr + Sec.size) {
2717 uint32_t stride;
2718 if (section_type == MachO::S_SYMBOL_STUBS)
2719 stride = Sec.reserved2;
2720 else
2721 stride = 8;
2722 if (stride == 0)
2723 return nullptr;
2724 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2725 if (index < Dysymtab.nindirectsyms) {
2726 uint32_t indirect_symbol =
2727 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2728 if (indirect_symbol < Symtab.nsyms) {
2729 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2730 SymbolRef Symbol = *Sym;
2731 Expected<StringRef> SymName = Symbol.getName();
2732 if (!SymName)
2733 report_error(info->O->getFileName(), SymName.takeError());
2734 const char *name = SymName->data();
2735 return name;
2736 }
2737 }
2738 }
2739 }
2740 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2741 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2742 for (unsigned J = 0; J < Seg.nsects; ++J) {
2743 MachO::section Sec = info->O->getSection(Load, J);
2744 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2745 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2746 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2747 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2748 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2749 section_type == MachO::S_SYMBOL_STUBS) &&
2750 ReferenceValue >= Sec.addr &&
2751 ReferenceValue < Sec.addr + Sec.size) {
2752 uint32_t stride;
2753 if (section_type == MachO::S_SYMBOL_STUBS)
2754 stride = Sec.reserved2;
2755 else
2756 stride = 4;
2757 if (stride == 0)
2758 return nullptr;
2759 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2760 if (index < Dysymtab.nindirectsyms) {
2761 uint32_t indirect_symbol =
2762 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2763 if (indirect_symbol < Symtab.nsyms) {
2764 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2765 SymbolRef Symbol = *Sym;
2766 Expected<StringRef> SymName = Symbol.getName();
2767 if (!SymName)
2768 report_error(info->O->getFileName(), SymName.takeError());
2769 const char *name = SymName->data();
2770 return name;
2771 }
2772 }
2773 }
2774 }
2775 }
2776 }
2777 return nullptr;
2778}
2779
2780// method_reference() is called passing it the ReferenceName that might be
2781// a reference it to an Objective-C method call. If so then it allocates and
2782// assembles a method call string with the values last seen and saved in
2783// the DisassembleInfo's class_name and selector_name fields. This is saved
2784// into the method field of the info and any previous string is free'ed.
2785// Then the class_name field in the info is set to nullptr. The method call
2786// string is set into ReferenceName and ReferenceType is set to
2787// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
2788// then both ReferenceType and ReferenceName are left unchanged.
2789static void method_reference(struct DisassembleInfo *info,
2790 uint64_t *ReferenceType,
2791 const char **ReferenceName) {
2792 unsigned int Arch = info->O->getArch();
2793 if (*ReferenceName != nullptr) {
2794 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
2795 if (info->selector_name != nullptr) {
2796 if (info->class_name != nullptr) {
2797 info->method = llvm::make_unique<char[]>(
2798 5 + strlen(info->class_name) + strlen(info->selector_name));
2799 char *method = info->method.get();
2800 if (method != nullptr) {
2801 strcpy(method, "+[");
2802 strcat(method, info->class_name);
2803 strcat(method, " ");
2804 strcat(method, info->selector_name);
2805 strcat(method, "]");
2806 *ReferenceName = method;
2807 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2808 }
2809 } else {
2810 info->method =
2811 llvm::make_unique<char[]>(9 + strlen(info->selector_name));
2812 char *method = info->method.get();
2813 if (method != nullptr) {
2814 if (Arch == Triple::x86_64)
2815 strcpy(method, "-[%rdi ");
2816 else if (Arch == Triple::aarch64)
2817 strcpy(method, "-[x0 ");
2818 else
2819 strcpy(method, "-[r? ");
2820 strcat(method, info->selector_name);
2821 strcat(method, "]");
2822 *ReferenceName = method;
2823 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2824 }
2825 }
2826 info->class_name = nullptr;
2827 }
2828 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
2829 if (info->selector_name != nullptr) {
2830 info->method =
2831 llvm::make_unique<char[]>(17 + strlen(info->selector_name));
2832 char *method = info->method.get();
2833 if (method != nullptr) {
2834 if (Arch == Triple::x86_64)
2835 strcpy(method, "-[[%rdi super] ");
2836 else if (Arch == Triple::aarch64)
2837 strcpy(method, "-[[x0 super] ");
2838 else
2839 strcpy(method, "-[[r? super] ");
2840 strcat(method, info->selector_name);
2841 strcat(method, "]");
2842 *ReferenceName = method;
2843 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2844 }
2845 info->class_name = nullptr;
2846 }
2847 }
2848 }
2849}
2850
2851// GuessPointerPointer() is passed the address of what might be a pointer to
2852// a reference to an Objective-C class, selector, message ref or cfstring.
2853// If so the value of the pointer is returned and one of the booleans are set
2854// to true. If not zero is returned and all the booleans are set to false.
2855static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
2856 struct DisassembleInfo *info,
2857 bool &classref, bool &selref, bool &msgref,
2858 bool &cfstring) {
2859 classref = false;
2860 selref = false;
2861 msgref = false;
2862 cfstring = false;
2863 for (const auto &Load : info->O->load_commands()) {
2864 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2865 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2866 for (unsigned J = 0; J < Seg.nsects; ++J) {
2867 MachO::section_64 Sec = info->O->getSection64(Load, J);
2868 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
2869 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2870 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
2871 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
2872 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
2873 ReferenceValue >= Sec.addr &&
2874 ReferenceValue < Sec.addr + Sec.size) {
2875 uint64_t sect_offset = ReferenceValue - Sec.addr;
2876 uint64_t object_offset = Sec.offset + sect_offset;
2877 StringRef MachOContents = info->O->getData();
2878 uint64_t object_size = MachOContents.size();
2879 const char *object_addr = (const char *)MachOContents.data();
2880 if (object_offset < object_size) {
2881 uint64_t pointer_value;
2882 memcpy(&pointer_value, object_addr + object_offset,
2883 sizeof(uint64_t));
2884 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2885 sys::swapByteOrder(pointer_value);
2886 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
2887 selref = true;
2888 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2889 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
2890 classref = true;
2891 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
2892 ReferenceValue + 8 < Sec.addr + Sec.size) {
2893 msgref = true;
2894 memcpy(&pointer_value, object_addr + object_offset + 8,
2895 sizeof(uint64_t));
2896 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2897 sys::swapByteOrder(pointer_value);
2898 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
2899 cfstring = true;
2900 return pointer_value;
2901 } else {
2902 return 0;
2903 }
2904 }
2905 }
2906 }
2907 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
2908 }
2909 return 0;
2910}
2911
2912// get_pointer_64 returns a pointer to the bytes in the object file at the
2913// Address from a section in the Mach-O file. And indirectly returns the
2914// offset into the section, number of bytes left in the section past the offset
2915// and which section is was being referenced. If the Address is not in a
2916// section nullptr is returned.
2917static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
2918 uint32_t &left, SectionRef &S,
2919 DisassembleInfo *info,
2920 bool objc_only = false) {
2921 offset = 0;
2922 left = 0;
2923 S = SectionRef();
2924 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
2925 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
2926 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
2927 if (SectSize == 0)
2928 continue;
2929 if (objc_only) {
2930 StringRef SectName;
2931 ((*(info->Sections))[SectIdx]).getName(SectName);
2932 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
2933 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
2934 if (SegName != "__OBJC" && SectName != "__cstring")
2935 continue;
2936 }
2937 if (Address >= SectAddress && Address < SectAddress + SectSize) {
2938 S = (*(info->Sections))[SectIdx];
2939 offset = Address - SectAddress;
2940 left = SectSize - offset;
2941 StringRef SectContents;
2942 ((*(info->Sections))[SectIdx]).getContents(SectContents);
2943 return SectContents.data() + offset;
2944 }
2945 }
2946 return nullptr;
2947}
2948
2949static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
2950 uint32_t &left, SectionRef &S,
2951 DisassembleInfo *info,
2952 bool objc_only = false) {
2953 return get_pointer_64(Address, offset, left, S, info, objc_only);
2954}
2955
2956// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
2957// the symbol indirectly through n_value. Based on the relocation information
2958// for the specified section offset in the specified section reference.
2959// If no relocation information is found and a non-zero ReferenceValue for the
2960// symbol is passed, look up that address in the info's AddrMap.
2961static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
2962 DisassembleInfo *info, uint64_t &n_value,
2963 uint64_t ReferenceValue = 0) {
2964 n_value = 0;
2965 if (!info->verbose)
2966 return nullptr;
2967
2968 // See if there is an external relocation entry at the sect_offset.
2969 bool reloc_found = false;
2970 DataRefImpl Rel;
2971 MachO::any_relocation_info RE;
2972 bool isExtern = false;
2973 SymbolRef Symbol;
2974 for (const RelocationRef &Reloc : S.relocations()) {
2975 uint64_t RelocOffset = Reloc.getOffset();
2976 if (RelocOffset == sect_offset) {
2977 Rel = Reloc.getRawDataRefImpl();
2978 RE = info->O->getRelocation(Rel);
2979 if (info->O->isRelocationScattered(RE))
2980 continue;
2981 isExtern = info->O->getPlainRelocationExternal(RE);
2982 if (isExtern) {
2983 symbol_iterator RelocSym = Reloc.getSymbol();
2984 Symbol = *RelocSym;
2985 }
2986 reloc_found = true;
2987 break;
2988 }
2989 }
2990 // If there is an external relocation entry for a symbol in this section
2991 // at this section_offset then use that symbol's value for the n_value
2992 // and return its name.
2993 const char *SymbolName = nullptr;
2994 if (reloc_found && isExtern) {
2995 n_value = Symbol.getValue();
2996 Expected<StringRef> NameOrError = Symbol.getName();
2997 if (!NameOrError)
2998 report_error(info->O->getFileName(), NameOrError.takeError());
2999 StringRef Name = *NameOrError;
3000 if (!Name.empty()) {
3001 SymbolName = Name.data();
3002 return SymbolName;
3003 }
3004 }
3005
3006 // TODO: For fully linked images, look through the external relocation
3007 // entries off the dynamic symtab command. For these the r_offset is from the
3008 // start of the first writeable segment in the Mach-O file. So the offset
3009 // to this section from that segment is passed to this routine by the caller,
3010 // as the database_offset. Which is the difference of the section's starting
3011 // address and the first writable segment.
3012 //
3013 // NOTE: need add passing the database_offset to this routine.
3014
3015 // We did not find an external relocation entry so look up the ReferenceValue
3016 // as an address of a symbol and if found return that symbol's name.
3017 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
3018
3019 return SymbolName;
3020}
3021
3022static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3023 DisassembleInfo *info,
3024 uint32_t ReferenceValue) {
3025 uint64_t n_value64;
3026 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
3027}
3028
3029// These are structs in the Objective-C meta data and read to produce the
3030// comments for disassembly. While these are part of the ABI they are no
3031// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
3032// .
3033
3034// The cfstring object in a 64-bit Mach-O file.
3035struct cfstring64_t {
3036 uint64_t isa; // class64_t * (64-bit pointer)
3037 uint64_t flags; // flag bits
3038 uint64_t characters; // char * (64-bit pointer)
3039 uint64_t length; // number of non-NULL characters in above
3040};
3041
3042// The class object in a 64-bit Mach-O file.
3043struct class64_t {
3044 uint64_t isa; // class64_t * (64-bit pointer)
3045 uint64_t superclass; // class64_t * (64-bit pointer)
3046 uint64_t cache; // Cache (64-bit pointer)
3047 uint64_t vtable; // IMP * (64-bit pointer)
3048 uint64_t data; // class_ro64_t * (64-bit pointer)
3049};
3050
3051struct class32_t {
3052 uint32_t isa; /* class32_t * (32-bit pointer) */
3053 uint32_t superclass; /* class32_t * (32-bit pointer) */
3054 uint32_t cache; /* Cache (32-bit pointer) */
3055 uint32_t vtable; /* IMP * (32-bit pointer) */
3056 uint32_t data; /* class_ro32_t * (32-bit pointer) */
3057};
3058
3059struct class_ro64_t {
3060 uint32_t flags;
3061 uint32_t instanceStart;
3062 uint32_t instanceSize;
3063 uint32_t reserved;
3064 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3065 uint64_t name; // const char * (64-bit pointer)
3066 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3067 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3068 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3069 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3070 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3071};
3072
3073struct class_ro32_t {
3074 uint32_t flags;
3075 uint32_t instanceStart;
3076 uint32_t instanceSize;
3077 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3078 uint32_t name; /* const char * (32-bit pointer) */
3079 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3080 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3081 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3082 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3083 uint32_t baseProperties; /* const struct objc_property_list *
3084 (32-bit pointer) */
3085};
3086
3087/* Values for class_ro{64,32}_t->flags */
3088#define RO_META(1 << 0) (1 << 0)
3089#define RO_ROOT(1 << 1) (1 << 1)
3090#define RO_HAS_CXX_STRUCTORS(1 << 2) (1 << 2)
3091
3092struct method_list64_t {
3093 uint32_t entsize;
3094 uint32_t count;
3095 /* struct method64_t first; These structures follow inline */
3096};
3097
3098struct method_list32_t {
3099 uint32_t entsize;
3100 uint32_t count;
3101 /* struct method32_t first; These structures follow inline */
3102};
3103
3104struct method64_t {
3105 uint64_t name; /* SEL (64-bit pointer) */
3106 uint64_t types; /* const char * (64-bit pointer) */
3107 uint64_t imp; /* IMP (64-bit pointer) */
3108};
3109
3110struct method32_t {
3111 uint32_t name; /* SEL (32-bit pointer) */
3112 uint32_t types; /* const char * (32-bit pointer) */
3113 uint32_t imp; /* IMP (32-bit pointer) */
3114};
3115
3116struct protocol_list64_t {
3117 uint64_t count; /* uintptr_t (a 64-bit value) */
3118 /* struct protocol64_t * list[0]; These pointers follow inline */
3119};
3120
3121struct protocol_list32_t {
3122 uint32_t count; /* uintptr_t (a 32-bit value) */
3123 /* struct protocol32_t * list[0]; These pointers follow inline */
3124};
3125
3126struct protocol64_t {
3127 uint64_t isa; /* id * (64-bit pointer) */
3128 uint64_t name; /* const char * (64-bit pointer) */
3129 uint64_t protocols; /* struct protocol_list64_t *
3130 (64-bit pointer) */
3131 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3132 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3133 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3134 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3135 uint64_t instanceProperties; /* struct objc_property_list *
3136 (64-bit pointer) */
3137};
3138
3139struct protocol32_t {
3140 uint32_t isa; /* id * (32-bit pointer) */
3141 uint32_t name; /* const char * (32-bit pointer) */
3142 uint32_t protocols; /* struct protocol_list_t *
3143 (32-bit pointer) */
3144 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3145 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3146 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3147 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3148 uint32_t instanceProperties; /* struct objc_property_list *
3149 (32-bit pointer) */
3150};
3151
3152struct ivar_list64_t {
3153 uint32_t entsize;
3154 uint32_t count;
3155 /* struct ivar64_t first; These structures follow inline */
3156};
3157
3158struct ivar_list32_t {
3159 uint32_t entsize;
3160 uint32_t count;
3161 /* struct ivar32_t first; These structures follow inline */
3162};
3163
3164struct ivar64_t {
3165 uint64_t offset; /* uintptr_t * (64-bit pointer) */
3166 uint64_t name; /* const char * (64-bit pointer) */
3167 uint64_t type; /* const char * (64-bit pointer) */
3168 uint32_t alignment;
3169 uint32_t size;
3170};
3171
3172struct ivar32_t {
3173 uint32_t offset; /* uintptr_t * (32-bit pointer) */
3174 uint32_t name; /* const char * (32-bit pointer) */
3175 uint32_t type; /* const char * (32-bit pointer) */
3176 uint32_t alignment;
3177 uint32_t size;
3178};
3179
3180struct objc_property_list64 {
3181 uint32_t entsize;
3182 uint32_t count;
3183 /* struct objc_property64 first; These structures follow inline */
3184};
3185
3186struct objc_property_list32 {
3187 uint32_t entsize;
3188 uint32_t count;
3189 /* struct objc_property32 first; These structures follow inline */
3190};
3191
3192struct objc_property64 {
3193 uint64_t name; /* const char * (64-bit pointer) */
3194 uint64_t attributes; /* const char * (64-bit pointer) */
3195};
3196
3197struct objc_property32 {
3198 uint32_t name; /* const char * (32-bit pointer) */
3199 uint32_t attributes; /* const char * (32-bit pointer) */
3200};
3201
3202struct category64_t {
3203 uint64_t name; /* const char * (64-bit pointer) */
3204 uint64_t cls; /* struct class_t * (64-bit pointer) */
3205 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3206 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3207 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3208 uint64_t instanceProperties; /* struct objc_property_list *
3209 (64-bit pointer) */
3210};
3211
3212struct category32_t {
3213 uint32_t name; /* const char * (32-bit pointer) */
3214 uint32_t cls; /* struct class_t * (32-bit pointer) */
3215 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3216 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3217 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3218 uint32_t instanceProperties; /* struct objc_property_list *
3219 (32-bit pointer) */
3220};
3221
3222struct objc_image_info64 {
3223 uint32_t version;
3224 uint32_t flags;
3225};
3226struct objc_image_info32 {
3227 uint32_t version;
3228 uint32_t flags;
3229};
3230struct imageInfo_t {
3231 uint32_t version;
3232 uint32_t flags;
3233};
3234/* masks for objc_image_info.flags */
3235#define OBJC_IMAGE_IS_REPLACEMENT(1 << 0) (1 << 0)
3236#define OBJC_IMAGE_SUPPORTS_GC(1 << 1) (1 << 1)
3237
3238struct message_ref64 {
3239 uint64_t imp; /* IMP (64-bit pointer) */
3240 uint64_t sel; /* SEL (64-bit pointer) */
3241};
3242
3243struct message_ref32 {
3244 uint32_t imp; /* IMP (32-bit pointer) */
3245 uint32_t sel; /* SEL (32-bit pointer) */
3246};
3247
3248// Objective-C 1 (32-bit only) meta data structs.
3249
3250struct objc_module_t {
3251 uint32_t version;
3252 uint32_t size;
3253 uint32_t name; /* char * (32-bit pointer) */
3254 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3255};
3256
3257struct objc_symtab_t {
3258 uint32_t sel_ref_cnt;
3259 uint32_t refs; /* SEL * (32-bit pointer) */
3260 uint16_t cls_def_cnt;
3261 uint16_t cat_def_cnt;
3262 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3263};
3264
3265struct objc_class_t {
3266 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3267 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3268 uint32_t name; /* const char * (32-bit pointer) */
3269 int32_t version;
3270 int32_t info;
3271 int32_t instance_size;
3272 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3273 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3274 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3275 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3276};
3277
3278#define CLS_GETINFO(cls, infomask)((cls)->info & (infomask)) ((cls)->info & (infomask))
3279// class is not a metaclass
3280#define CLS_CLASS0x1 0x1
3281// class is a metaclass
3282#define CLS_META0x2 0x2
3283
3284struct objc_category_t {
3285 uint32_t category_name; /* char * (32-bit pointer) */
3286 uint32_t class_name; /* char * (32-bit pointer) */
3287 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3288 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3289 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3290};
3291
3292struct objc_ivar_t {
3293 uint32_t ivar_name; /* char * (32-bit pointer) */
3294 uint32_t ivar_type; /* char * (32-bit pointer) */
3295 int32_t ivar_offset;
3296};
3297
3298struct objc_ivar_list_t {
3299 int32_t ivar_count;
3300 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
3301};
3302
3303struct objc_method_list_t {
3304 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3305 int32_t method_count;
3306 // struct objc_method_t method_list[1]; /* variable length structure */
3307};
3308
3309struct objc_method_t {
3310 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3311 uint32_t method_types; /* char * (32-bit pointer) */
3312 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3313 (32-bit pointer) */
3314};
3315
3316struct objc_protocol_list_t {
3317 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3318 int32_t count;
3319 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3320 // (32-bit pointer) */
3321};
3322
3323struct objc_protocol_t {
3324 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3325 uint32_t protocol_name; /* char * (32-bit pointer) */
3326 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3327 uint32_t instance_methods; /* struct objc_method_description_list *
3328 (32-bit pointer) */
3329 uint32_t class_methods; /* struct objc_method_description_list *
3330 (32-bit pointer) */
3331};
3332
3333struct objc_method_description_list_t {
3334 int32_t count;
3335 // struct objc_method_description_t list[1];
3336};
3337
3338struct objc_method_description_t {
3339 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3340 uint32_t types; /* char * (32-bit pointer) */
3341};
3342
3343inline void swapStruct(struct cfstring64_t &cfs) {
3344 sys::swapByteOrder(cfs.isa);
3345 sys::swapByteOrder(cfs.flags);
3346 sys::swapByteOrder(cfs.characters);
3347 sys::swapByteOrder(cfs.length);
3348}
3349
3350inline void swapStruct(struct class64_t &c) {
3351 sys::swapByteOrder(c.isa);
3352 sys::swapByteOrder(c.superclass);
3353 sys::swapByteOrder(c.cache);
3354 sys::swapByteOrder(c.vtable);
3355 sys::swapByteOrder(c.data);
3356}
3357
3358inline void swapStruct(struct class32_t &c) {
3359 sys::swapByteOrder(c.isa);
3360 sys::swapByteOrder(c.superclass);
3361 sys::swapByteOrder(c.cache);
3362 sys::swapByteOrder(c.vtable);
3363 sys::swapByteOrder(c.data);
3364}
3365
3366inline void swapStruct(struct class_ro64_t &cro) {
3367 sys::swapByteOrder(cro.flags);
3368 sys::swapByteOrder(cro.instanceStart);
3369 sys::swapByteOrder(cro.instanceSize);
3370 sys::swapByteOrder(cro.reserved);
3371 sys::swapByteOrder(cro.ivarLayout);
3372 sys::swapByteOrder(cro.name);
3373 sys::swapByteOrder(cro.baseMethods);
3374 sys::swapByteOrder(cro.baseProtocols);
3375 sys::swapByteOrder(cro.ivars);
3376 sys::swapByteOrder(cro.weakIvarLayout);
3377 sys::swapByteOrder(cro.baseProperties);
3378}
3379
3380inline void swapStruct(struct class_ro32_t &cro) {
3381 sys::swapByteOrder(cro.flags);
3382 sys::swapByteOrder(cro.instanceStart);
3383 sys::swapByteOrder(cro.instanceSize);
3384 sys::swapByteOrder(cro.ivarLayout);
3385 sys::swapByteOrder(cro.name);
3386 sys::swapByteOrder(cro.baseMethods);
3387 sys::swapByteOrder(cro.baseProtocols);
3388 sys::swapByteOrder(cro.ivars);
3389 sys::swapByteOrder(cro.weakIvarLayout);
3390 sys::swapByteOrder(cro.baseProperties);
3391}
3392
3393inline void swapStruct(struct method_list64_t &ml) {
3394 sys::swapByteOrder(ml.entsize);
3395 sys::swapByteOrder(ml.count);
3396}
3397
3398inline void swapStruct(struct method_list32_t &ml) {
3399 sys::swapByteOrder(ml.entsize);
3400 sys::swapByteOrder(ml.count);
3401}
3402
3403inline void swapStruct(struct method64_t &m) {
3404 sys::swapByteOrder(m.name);
3405 sys::swapByteOrder(m.types);
3406 sys::swapByteOrder(m.imp);
3407}
3408
3409inline void swapStruct(struct method32_t &m) {
3410 sys::swapByteOrder(m.name);
3411 sys::swapByteOrder(m.types);
3412 sys::swapByteOrder(m.imp);
3413}
3414
3415inline void swapStruct(struct protocol_list64_t &pl) {
3416 sys::swapByteOrder(pl.count);
3417}
3418
3419inline void swapStruct(struct protocol_list32_t &pl) {
3420 sys::swapByteOrder(pl.count);
3421}
3422
3423inline void swapStruct(struct protocol64_t &p) {
3424 sys::swapByteOrder(p.isa);
3425 sys::swapByteOrder(p.name);
3426 sys::swapByteOrder(p.protocols);
3427 sys::swapByteOrder(p.instanceMethods);
3428 sys::swapByteOrder(p.classMethods);
3429 sys::swapByteOrder(p.optionalInstanceMethods);
3430 sys::swapByteOrder(p.optionalClassMethods);
3431 sys::swapByteOrder(p.instanceProperties);
3432}
3433
3434inline void swapStruct(struct protocol32_t &p) {
3435 sys::swapByteOrder(p.isa);
3436 sys::swapByteOrder(p.name);
3437 sys::swapByteOrder(p.protocols);
3438 sys::swapByteOrder(p.instanceMethods);
3439 sys::swapByteOrder(p.classMethods);
3440 sys::swapByteOrder(p.optionalInstanceMethods);
3441 sys::swapByteOrder(p.optionalClassMethods);
3442 sys::swapByteOrder(p.instanceProperties);
3443}
3444
3445inline void swapStruct(struct ivar_list64_t &il) {
3446 sys::swapByteOrder(il.entsize);
3447 sys::swapByteOrder(il.count);
3448}
3449
3450inline void swapStruct(struct ivar_list32_t &il) {
3451 sys::swapByteOrder(il.entsize);
3452 sys::swapByteOrder(il.count);
3453}
3454
3455inline void swapStruct(struct ivar64_t &i) {
3456 sys::swapByteOrder(i.offset);
3457 sys::swapByteOrder(i.name);
3458 sys::swapByteOrder(i.type);
3459 sys::swapByteOrder(i.alignment);
3460 sys::swapByteOrder(i.size);
3461}
3462
3463inline void swapStruct(struct ivar32_t &i) {
3464 sys::swapByteOrder(i.offset);
3465 sys::swapByteOrder(i.name);
3466 sys::swapByteOrder(i.type);
3467 sys::swapByteOrder(i.alignment);
3468 sys::swapByteOrder(i.size);
3469}
3470
3471inline void swapStruct(struct objc_property_list64 &pl) {
3472 sys::swapByteOrder(pl.entsize);
3473 sys::swapByteOrder(pl.count);
3474}
3475
3476inline void swapStruct(struct objc_property_list32 &pl) {
3477 sys::swapByteOrder(pl.entsize);
3478 sys::swapByteOrder(pl.count);
3479}
3480
3481inline void swapStruct(struct objc_property64 &op) {
3482 sys::swapByteOrder(op.name);
3483 sys::swapByteOrder(op.attributes);
3484}
3485
3486inline void swapStruct(struct objc_property32 &op) {
3487 sys::swapByteOrder(op.name);
3488 sys::swapByteOrder(op.attributes);
3489}
3490
3491inline void swapStruct(struct category64_t &c) {
3492 sys::swapByteOrder(c.name);
3493 sys::swapByteOrder(c.cls);
3494 sys::swapByteOrder(c.instanceMethods);
3495 sys::swapByteOrder(c.classMethods);
3496 sys::swapByteOrder(c.protocols);
3497 sys::swapByteOrder(c.instanceProperties);
3498}
3499
3500inline void swapStruct(struct category32_t &c) {
3501 sys::swapByteOrder(c.name);
3502 sys::swapByteOrder(c.cls);
3503 sys::swapByteOrder(c.instanceMethods);
3504 sys::swapByteOrder(c.classMethods);
3505 sys::swapByteOrder(c.protocols);
3506 sys::swapByteOrder(c.instanceProperties);
3507}
3508
3509inline void swapStruct(struct objc_image_info64 &o) {
3510 sys::swapByteOrder(o.version);
3511 sys::swapByteOrder(o.flags);
3512}
3513
3514inline void swapStruct(struct objc_image_info32 &o) {
3515 sys::swapByteOrder(o.version);
3516 sys::swapByteOrder(o.flags);
3517}
3518
3519inline void swapStruct(struct imageInfo_t &o) {
3520 sys::swapByteOrder(o.version);
3521 sys::swapByteOrder(o.flags);
3522}
3523
3524inline void swapStruct(struct message_ref64 &mr) {
3525 sys::swapByteOrder(mr.imp);
3526 sys::swapByteOrder(mr.sel);
3527}
3528
3529inline void swapStruct(struct message_ref32 &mr) {
3530 sys::swapByteOrder(mr.imp);
3531 sys::swapByteOrder(mr.sel);
3532}
3533
3534inline void swapStruct(struct objc_module_t &module) {
3535 sys::swapByteOrder(module.version);
3536 sys::swapByteOrder(module.size);
3537 sys::swapByteOrder(module.name);
3538 sys::swapByteOrder(module.symtab);
3539}
3540
3541inline void swapStruct(struct objc_symtab_t &symtab) {
3542 sys::swapByteOrder(symtab.sel_ref_cnt);
3543 sys::swapByteOrder(symtab.refs);
3544 sys::swapByteOrder(symtab.cls_def_cnt);
3545 sys::swapByteOrder(symtab.cat_def_cnt);
3546}
3547
3548inline void swapStruct(struct objc_class_t &objc_class) {
3549 sys::swapByteOrder(objc_class.isa);
3550 sys::swapByteOrder(objc_class.super_class);
3551 sys::swapByteOrder(objc_class.name);
3552 sys::swapByteOrder(objc_class.version);
3553 sys::swapByteOrder(objc_class.info);
3554 sys::swapByteOrder(objc_class.instance_size);
3555 sys::swapByteOrder(objc_class.ivars);
3556 sys::swapByteOrder(objc_class.methodLists);
3557 sys::swapByteOrder(objc_class.cache);
3558 sys::swapByteOrder(objc_class.protocols);
3559}
3560
3561inline void swapStruct(struct objc_category_t &objc_category) {
3562 sys::swapByteOrder(objc_category.category_name);
3563 sys::swapByteOrder(objc_category.class_name);
3564 sys::swapByteOrder(objc_category.instance_methods);
3565 sys::swapByteOrder(objc_category.class_methods);
3566 sys::swapByteOrder(objc_category.protocols);
3567}
3568
3569inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
3570 sys::swapByteOrder(objc_ivar_list.ivar_count);
3571}
3572
3573inline void swapStruct(struct objc_ivar_t &objc_ivar) {
3574 sys::swapByteOrder(objc_ivar.ivar_name);
3575 sys::swapByteOrder(objc_ivar.ivar_type);
3576 sys::swapByteOrder(objc_ivar.ivar_offset);
3577}
3578
3579inline void swapStruct(struct objc_method_list_t &method_list) {
3580 sys::swapByteOrder(method_list.obsolete);
3581 sys::swapByteOrder(method_list.method_count);
3582}
3583
3584inline void swapStruct(struct objc_method_t &method) {
3585 sys::swapByteOrder(method.method_name);
3586 sys::swapByteOrder(method.method_types);
3587 sys::swapByteOrder(method.method_imp);
3588}
3589
3590inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
3591 sys::swapByteOrder(protocol_list.next);
3592 sys::swapByteOrder(protocol_list.count);
3593}
3594
3595inline void swapStruct(struct objc_protocol_t &protocol) {
3596 sys::swapByteOrder(protocol.isa);
3597 sys::swapByteOrder(protocol.protocol_name);
3598 sys::swapByteOrder(protocol.protocol_list);
3599 sys::swapByteOrder(protocol.instance_methods);
3600 sys::swapByteOrder(protocol.class_methods);
3601}
3602
3603inline void swapStruct(struct objc_method_description_list_t &mdl) {
3604 sys::swapByteOrder(mdl.count);
3605}
3606
3607inline void swapStruct(struct objc_method_description_t &md) {
3608 sys::swapByteOrder(md.name);
3609 sys::swapByteOrder(md.types);
3610}
3611
3612static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
3613 struct DisassembleInfo *info);
3614
3615// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
3616// to an Objective-C class and returns the class name. It is also passed the
3617// address of the pointer, so when the pointer is zero as it can be in an .o
3618// file, that is used to look for an external relocation entry with a symbol
3619// name.
3620static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
3621 uint64_t ReferenceValue,
3622 struct DisassembleInfo *info) {
3623 const char *r;
3624 uint32_t offset, left;
3625 SectionRef S;
3626
3627 // The pointer_value can be 0 in an object file and have a relocation
3628 // entry for the class symbol at the ReferenceValue (the address of the
3629 // pointer).
3630 if (pointer_value == 0) {
3631 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3632 if (r == nullptr || left < sizeof(uint64_t))
3633 return nullptr;
3634 uint64_t n_value;
3635 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3636 if (symbol_name == nullptr)
3637 return nullptr;
3638 const char *class_name = strrchr(symbol_name, '$');
3639 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
3640 return class_name + 2;
3641 else
3642 return nullptr;
3643 }
3644
3645 // The case were the pointer_value is non-zero and points to a class defined
3646 // in this Mach-O file.
3647 r = get_pointer_64(pointer_value, offset, left, S, info);
3648 if (r == nullptr || left < sizeof(struct class64_t))
3649 return nullptr;
3650 struct class64_t c;
3651 memcpy(&c, r, sizeof(struct class64_t));
3652 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3653 swapStruct(c);
3654 if (c.data == 0)
3655 return nullptr;
3656 r = get_pointer_64(c.data, offset, left, S, info);
3657 if (r == nullptr || left < sizeof(struct class_ro64_t))
3658 return nullptr;
3659 struct class_ro64_t cro;
3660 memcpy(&cro, r, sizeof(struct class_ro64_t));
3661 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3662 swapStruct(cro);
3663 if (cro.name == 0)
3664 return nullptr;
3665 const char *name = get_pointer_64(cro.name, offset, left, S, info);
3666 return name;
3667}
3668
3669// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
3670// pointer to a cfstring and returns its name or nullptr.
3671static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
3672 struct DisassembleInfo *info) {
3673 const char *r, *name;
3674 uint32_t offset, left;
3675 SectionRef S;
3676 struct cfstring64_t cfs;
3677 uint64_t cfs_characters;
3678
3679 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3680 if (r == nullptr || left < sizeof(struct cfstring64_t))
3681 return nullptr;
3682 memcpy(&cfs, r, sizeof(struct cfstring64_t));
3683 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3684 swapStruct(cfs);
3685 if (cfs.characters == 0) {
3686 uint64_t n_value;
3687 const char *symbol_name = get_symbol_64(
3688 offset + offsetof(struct cfstring64_t, characters)__builtin_offsetof(struct cfstring64_t, characters), S, info, n_value);
3689 if (symbol_name == nullptr)
3690 return nullptr;
3691 cfs_characters = n_value;
3692 } else
3693 cfs_characters = cfs.characters;
3694 name = get_pointer_64(cfs_characters, offset, left, S, info);
3695
3696 return name;
3697}
3698
3699// get_objc2_64bit_selref() is used for disassembly and is passed a the address
3700// of a pointer to an Objective-C selector reference when the pointer value is
3701// zero as in a .o file and is likely to have a external relocation entry with
3702// who's symbol's n_value is the real pointer to the selector name. If that is
3703// the case the real pointer to the selector name is returned else 0 is
3704// returned
3705static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
3706 struct DisassembleInfo *info) {
3707 uint32_t offset, left;
3708 SectionRef S;
3709
3710 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
3711 if (r == nullptr || left < sizeof(uint64_t))
3712 return 0;
3713 uint64_t n_value;
3714 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3715 if (symbol_name == nullptr)
3716 return 0;
3717 return n_value;
3718}
3719
3720static const SectionRef get_section(MachOObjectFile *O, const char *segname,
3721 const char *sectname) {
3722 for (const SectionRef &Section : O->sections()) {
3723 StringRef SectName;
3724 Section.getName(SectName);
3725 DataRefImpl Ref = Section.getRawDataRefImpl();
3726 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3727 if (SegName == segname && SectName == sectname)
3728 return Section;
3729 }
3730 return SectionRef();
3731}
3732
3733static void
3734walk_pointer_list_64(const char *listname, const SectionRef S,
3735 MachOObjectFile *O, struct DisassembleInfo *info,
3736 void (*func)(uint64_t, struct DisassembleInfo *info)) {
3737 if (S == SectionRef())
3738 return;
3739
3740 StringRef SectName;
3741 S.getName(SectName);
3742 DataRefImpl Ref = S.getRawDataRefImpl();
3743 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3744 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3745
3746 StringRef BytesStr;
3747 S.getContents(BytesStr);
3748 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3749
3750 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
3751 uint32_t left = S.getSize() - i;
3752 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
3753 uint64_t p = 0;
3754 memcpy(&p, Contents + i, size);
3755 if (i + sizeof(uint64_t) > S.getSize())
3756 outs() << listname << " list pointer extends past end of (" << SegName
3757 << "," << SectName << ") section\n";
3758 outs() << format("%016" PRIx64"l" "x", S.getAddress() + i) << " ";
3759
3760 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3761 sys::swapByteOrder(p);
3762
3763 uint64_t n_value = 0;
3764 const char *name = get_symbol_64(i, S, info, n_value, p);
3765 if (name == nullptr)
3766 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
3767
3768 if (n_value != 0) {
3769 outs() << format("0x%" PRIx64"l" "x", n_value);
3770 if (p != 0)
3771 outs() << " + " << format("0x%" PRIx64"l" "x", p);
3772 } else
3773 outs() << format("0x%" PRIx64"l" "x", p);
3774 if (name != nullptr)
3775 outs() << " " << name;
3776 outs() << "\n";
3777
3778 p += n_value;
3779 if (func)
3780 func(p, info);
3781 }
3782}
3783
3784static void
3785walk_pointer_list_32(const char *listname, const SectionRef S,
3786 MachOObjectFile *O, struct DisassembleInfo *info,
3787 void (*func)(uint32_t, struct DisassembleInfo *info)) {
3788 if (S == SectionRef())
3789 return;
3790
3791 StringRef SectName;
3792 S.getName(SectName);
3793 DataRefImpl Ref = S.getRawDataRefImpl();
3794 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3795 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3796
3797 StringRef BytesStr;
3798 S.getContents(BytesStr);
3799 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3800
3801 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
3802 uint32_t left = S.getSize() - i;
3803 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
3804 uint32_t p = 0;
3805 memcpy(&p, Contents + i, size);
3806 if (i + sizeof(uint32_t) > S.getSize())
3807 outs() << listname << " list pointer extends past end of (" << SegName
3808 << "," << SectName << ") section\n";
3809 uint32_t Address = S.getAddress() + i;
3810 outs() << format("%08" PRIx32"x", Address) << " ";
3811
3812 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3813 sys::swapByteOrder(p);
3814 outs() << format("0x%" PRIx32"x", p);
3815
3816 const char *name = get_symbol_32(i, S, info, p);
3817 if (name != nullptr)
3818 outs() << " " << name;
3819 outs() << "\n";
3820
3821 if (func)
3822 func(p, info);
3823 }
3824}
3825
3826static void print_layout_map(const char *layout_map, uint32_t left) {
3827 if (layout_map == nullptr)
3828 return;
3829 outs() << " layout map: ";
3830 do {
3831 outs() << format("0x%02" PRIx32"x", (*layout_map) & 0xff) << " ";
3832 left--;
3833 layout_map++;
3834 } while (*layout_map != '\0' && left != 0);
3835 outs() << "\n";
3836}
3837
3838static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
3839 uint32_t offset, left;
3840 SectionRef S;
3841 const char *layout_map;
3842
3843 if (p == 0)
3844 return;
3845 layout_map = get_pointer_64(p, offset, left, S, info);
3846 print_layout_map(layout_map, left);
3847}
3848
3849static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
3850 uint32_t offset, left;
3851 SectionRef S;
3852 const char *layout_map;
3853
3854 if (p == 0)
3855 return;
3856 layout_map = get_pointer_32(p, offset, left, S, info);
3857 print_layout_map(layout_map, left);
3858}
3859
3860static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
3861 const char *indent) {
3862 struct method_list64_t ml;
3863 struct method64_t m;
3864 const char *r;
3865 uint32_t offset, xoffset, left, i;
3866 SectionRef S, xS;
3867 const char *name, *sym_name;
3868 uint64_t n_value;
3869
3870 r = get_pointer_64(p, offset, left, S, info);
3871 if (r == nullptr)
3872 return;
3873 memset(&ml, '\0', sizeof(struct method_list64_t));
3874 if (left < sizeof(struct method_list64_t)) {
3875 memcpy(&ml, r, left);
3876 outs() << " (method_list_t entends past the end of the section)\n";
3877 } else
3878 memcpy(&ml, r, sizeof(struct method_list64_t));
3879 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3880 swapStruct(ml);
3881 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3882 outs() << indent << "\t\t count " << ml.count << "\n";
3883
3884 p += sizeof(struct method_list64_t);
3885 offset += sizeof(struct method_list64_t);
3886 for (i = 0; i < ml.count; i++) {
3887 r = get_pointer_64(p, offset, left, S, info);
3888 if (r == nullptr)
3889 return;
3890 memset(&m, '\0', sizeof(struct method64_t));
3891 if (left < sizeof(struct method64_t)) {
3892 memcpy(&m, r, left);
3893 outs() << indent << " (method_t extends past the end of the section)\n";
3894 } else
3895 memcpy(&m, r, sizeof(struct method64_t));
3896 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3897 swapStruct(m);
3898
3899 outs() << indent << "\t\t name ";
3900 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name)__builtin_offsetof(struct method64_t, name), S,
3901 info, n_value, m.name);
3902 if (n_value != 0) {
3903 if (info->verbose && sym_name != nullptr)
3904 outs() << sym_name;
3905 else
3906 outs() << format("0x%" PRIx64"l" "x", n_value);
3907 if (m.name != 0)
3908 outs() << " + " << format("0x%" PRIx64"l" "x", m.name);
3909 } else
3910 outs() << format("0x%" PRIx64"l" "x", m.name);
3911 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
3912 if (name != nullptr)
3913 outs() << format(" %.*s", left, name);
3914 outs() << "\n";
3915
3916 outs() << indent << "\t\t types ";
3917 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types)__builtin_offsetof(struct method64_t, types), S,
3918 info, n_value, m.types);
3919 if (n_value != 0) {
3920 if (info->verbose && sym_name != nullptr)
3921 outs() << sym_name;
3922 else
3923 outs() << format("0x%" PRIx64"l" "x", n_value);
3924 if (m.types != 0)
3925 outs() << " + " << format("0x%" PRIx64"l" "x", m.types);
3926 } else
3927 outs() << format("0x%" PRIx64"l" "x", m.types);
3928 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
3929 if (name != nullptr)
3930 outs() << format(" %.*s", left, name);
3931 outs() << "\n";
3932
3933 outs() << indent << "\t\t imp ";
3934 name = get_symbol_64(offset + offsetof(struct method64_t, imp)__builtin_offsetof(struct method64_t, imp), S, info,
3935 n_value, m.imp);
3936 if (info->verbose && name == nullptr) {
3937 if (n_value != 0) {
3938 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
3939 if (m.imp != 0)
3940 outs() << "+ " << format("0x%" PRIx64"l" "x", m.imp) << " ";
3941 } else
3942 outs() << format("0x%" PRIx64"l" "x", m.imp) << " ";
3943 }
3944 if (name != nullptr)
3945 outs() << name;
3946 outs() << "\n";
3947
3948 p += sizeof(struct method64_t);
3949 offset += sizeof(struct method64_t);
3950 }
3951}
3952
3953static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
3954 const char *indent) {
3955 struct method_list32_t ml;
3956 struct method32_t m;
3957 const char *r, *name;
3958 uint32_t offset, xoffset, left, i;
3959 SectionRef S, xS;
3960
3961 r = get_pointer_32(p, offset, left, S, info);
3962 if (r == nullptr)
3963 return;
3964 memset(&ml, '\0', sizeof(struct method_list32_t));
3965 if (left < sizeof(struct method_list32_t)) {
3966 memcpy(&ml, r, left);
3967 outs() << " (method_list_t entends past the end of the section)\n";
3968 } else
3969 memcpy(&ml, r, sizeof(struct method_list32_t));
3970 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3971 swapStruct(ml);
3972 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3973 outs() << indent << "\t\t count " << ml.count << "\n";
3974
3975 p += sizeof(struct method_list32_t);
3976 offset += sizeof(struct method_list32_t);
3977 for (i = 0; i < ml.count; i++) {
3978 r = get_pointer_32(p, offset, left, S, info);
3979 if (r == nullptr)
3980 return;
3981 memset(&m, '\0', sizeof(struct method32_t));
3982 if (left < sizeof(struct method32_t)) {
3983 memcpy(&ml, r, left);
3984 outs() << indent << " (method_t entends past the end of the section)\n";
3985 } else
3986 memcpy(&m, r, sizeof(struct method32_t));
3987 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3988 swapStruct(m);
3989
3990 outs() << indent << "\t\t name " << format("0x%" PRIx32"x", m.name);
3991 name = get_pointer_32(m.name, xoffset, left, xS, info);
3992 if (name != nullptr)
3993 outs() << format(" %.*s", left, name);
3994 outs() << "\n";
3995
3996 outs() << indent << "\t\t types " << format("0x%" PRIx32"x", m.types);
3997 name = get_pointer_32(m.types, xoffset, left, xS, info);
3998 if (name != nullptr)
3999 outs() << format(" %.*s", left, name);
4000 outs() << "\n";
4001
4002 outs() << indent << "\t\t imp " << format("0x%" PRIx32"x", m.imp);
4003 name = get_symbol_32(offset + offsetof(struct method32_t, imp)__builtin_offsetof(struct method32_t, imp), S, info,
4004 m.imp);
4005 if (name != nullptr)
4006 outs() << " " << name;
4007 outs() << "\n";
4008
4009 p += sizeof(struct method32_t);
4010 offset += sizeof(struct method32_t);
4011 }
4012}
4013
4014static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4015 uint32_t offset, left, xleft;
4016 SectionRef S;
4017 struct objc_method_list_t method_list;
4018 struct objc_method_t method;
4019 const char *r, *methods, *name, *SymbolName;
4020 int32_t i;
4021
4022 r = get_pointer_32(p, offset, left, S, info, true);
4023 if (r == nullptr)
4024 return true;
4025
4026 outs() << "\n";
4027 if (left > sizeof(struct objc_method_list_t)) {
4028 memcpy(&method_list, r, sizeof(struct objc_method_list_t));
4029 } else {
4030 outs() << "\t\t objc_method_list extends past end of the section\n";
4031 memset(&method_list, '\0', sizeof(struct objc_method_list_t));
4032 memcpy(&method_list, r, left);
4033 }
4034 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4035 swapStruct(method_list);
4036
4037 outs() << "\t\t obsolete "
4038 << format("0x%08" PRIx32"x", method_list.obsolete) << "\n";
4039 outs() << "\t\t method_count " << method_list.method_count << "\n";
4040
4041 methods = r + sizeof(struct objc_method_list_t);
4042 for (i = 0; i < method_list.method_count; i++) {
4043 if ((i + 1) * sizeof(struct objc_method_t) > left) {
4044 outs() << "\t\t remaining method's extend past the of the section\n";
4045 break;
4046 }
4047 memcpy(&method, methods + i * sizeof(struct objc_method_t),
4048 sizeof(struct objc_method_t));
4049 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4050 swapStruct(method);
4051
4052 outs() << "\t\t method_name "
4053 << format("0x%08" PRIx32"x", method.method_name);
4054 if (info->verbose) {
4055 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
4056 if (name != nullptr)
4057 outs() << format(" %.*s", xleft, name);
4058 else
4059 outs() << " (not in an __OBJC section)";
4060 }
4061 outs() << "\n";
4062
4063 outs() << "\t\t method_types "
4064 << format("0x%08" PRIx32"x", method.method_types);
4065 if (info->verbose) {
4066 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
4067 if (name != nullptr)
4068 outs() << format(" %.*s", xleft, name);
4069 else
4070 outs() << " (not in an __OBJC section)";
4071 }
4072 outs() << "\n";
4073
4074 outs() << "\t\t method_imp "
4075 << format("0x%08" PRIx32"x", method.method_imp) << " ";
4076 if (info->verbose) {
4077 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
4078 if (SymbolName != nullptr)
4079 outs() << SymbolName;
4080 }
4081 outs() << "\n";
4082 }
4083 return false;
4084}
4085
4086static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4087 struct protocol_list64_t pl;
4088 uint64_t q, n_value;
4089 struct protocol64_t pc;
4090 const char *r;
4091 uint32_t offset, xoffset, left, i;
4092 SectionRef S, xS;
4093 const char *name, *sym_name;
4094
4095 r = get_pointer_64(p, offset, left, S, info);
4096 if (r == nullptr)
4097 return;
4098 memset(&pl, '\0', sizeof(struct protocol_list64_t));
4099 if (left < sizeof(struct protocol_list64_t)) {
4100 memcpy(&pl, r, left);
4101 outs() << " (protocol_list_t entends past the end of the section)\n";
4102 } else
4103 memcpy(&pl, r, sizeof(struct protocol_list64_t));
4104 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4105 swapStruct(pl);
4106 outs() << " count " << pl.count << "\n";
4107
4108 p += sizeof(struct protocol_list64_t);
4109 offset += sizeof(struct protocol_list64_t);
4110 for (i = 0; i < pl.count; i++) {
4111 r = get_pointer_64(p, offset, left, S, info);
4112 if (r == nullptr)
4113 return;
4114 q = 0;
4115 if (left < sizeof(uint64_t)) {
4116 memcpy(&q, r, left);
4117 outs() << " (protocol_t * entends past the end of the section)\n";
4118 } else
4119 memcpy(&q, r, sizeof(uint64_t));
4120 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4121 sys::swapByteOrder(q);
4122
4123 outs() << "\t\t list[" << i << "] ";
4124 sym_name = get_symbol_64(offset, S, info, n_value, q);
4125 if (n_value != 0) {
4126 if (info->verbose && sym_name != nullptr)
4127 outs() << sym_name;
4128 else
4129 outs() << format("0x%" PRIx64"l" "x", n_value);
4130 if (q != 0)
4131 outs() << " + " << format("0x%" PRIx64"l" "x", q);
4132 } else
4133 outs() << format("0x%" PRIx64"l" "x", q);
4134 outs() << " (struct protocol_t *)\n";
4135
4136 r = get_pointer_64(q + n_value, offset, left, S, info);
4137 if (r == nullptr)
4138 return;
4139 memset(&pc, '\0', sizeof(struct protocol64_t));
4140 if (left < sizeof(struct protocol64_t)) {
4141 memcpy(&pc, r, left);
4142 outs() << " (protocol_t entends past the end of the section)\n";
4143 } else
4144 memcpy(&pc, r, sizeof(struct protocol64_t));
4145 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4146 swapStruct(pc);
4147
4148 outs() << "\t\t\t isa " << format("0x%" PRIx64"l" "x", pc.isa) << "\n";
4149
4150 outs() << "\t\t\t name ";
4151 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name)__builtin_offsetof(struct protocol64_t, name), S,
4152 info, n_value, pc.name);
4153 if (n_value != 0) {
4154 if (info->verbose && sym_name != nullptr)
4155 outs() << sym_name;
4156 else
4157 outs() << format("0x%" PRIx64"l" "x", n_value);
4158 if (pc.name != 0)
4159 outs() << " + " << format("0x%" PRIx64"l" "x", pc.name);
4160 } else
4161 outs() << format("0x%" PRIx64"l" "x", pc.name);
4162 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
4163 if (name != nullptr)
4164 outs() << format(" %.*s", left, name);
4165 outs() << "\n";
4166
4167 outs() << "\t\t\tprotocols " << format("0x%" PRIx64"l" "x", pc.protocols) << "\n";
4168
4169 outs() << "\t\t instanceMethods ";
4170 sym_name =
4171 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods)__builtin_offsetof(struct protocol64_t, instanceMethods),
4172 S, info, n_value, pc.instanceMethods);
4173 if (n_value != 0) {
4174 if (info->verbose && sym_name != nullptr)
4175 outs() << sym_name;
4176 else
4177 outs() << format("0x%" PRIx64"l" "x", n_value);
4178 if (pc.instanceMethods != 0)
4179 outs() << " + " << format("0x%" PRIx64"l" "x", pc.instanceMethods);
4180 } else
4181 outs() << format("0x%" PRIx64"l" "x", pc.instanceMethods);
4182 outs() << " (struct method_list_t *)\n";
4183 if (pc.instanceMethods + n_value != 0)
4184 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
4185
4186 outs() << "\t\t classMethods ";
4187 sym_name =
4188 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods)__builtin_offsetof(struct protocol64_t, classMethods), S,
4189 info, n_value, pc.classMethods);
4190 if (n_value != 0) {
4191 if (info->verbose && sym_name != nullptr)
4192 outs() << sym_name;
4193 else
4194 outs() << format("0x%" PRIx64"l" "x", n_value);
4195 if (pc.classMethods != 0)
4196 outs() << " + " << format("0x%" PRIx64"l" "x", pc.classMethods);
4197 } else
4198 outs() << format("0x%" PRIx64"l" "x", pc.classMethods);
4199 outs() << " (struct method_list_t *)\n";
4200 if (pc.classMethods + n_value != 0)
4201 print_method_list64_t(pc.classMethods + n_value, info, "\t");
4202
4203 outs() << "\t optionalInstanceMethods "
4204 << format("0x%" PRIx64"l" "x", pc.optionalInstanceMethods) << "\n";
4205 outs() << "\t optionalClassMethods "
4206 << format("0x%" PRIx64"l" "x", pc.optionalClassMethods) << "\n";
4207 outs() << "\t instanceProperties "
4208 << format("0x%" PRIx64"l" "x", pc.instanceProperties) << "\n";
4209
4210 p += sizeof(uint64_t);
4211 offset += sizeof(uint64_t);
4212 }
4213}
4214
4215static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4216 struct protocol_list32_t pl;
4217 uint32_t q;
4218 struct protocol32_t pc;
4219 const char *r;
4220 uint32_t offset, xoffset, left, i;
4221 SectionRef S, xS;
4222 const char *name;
4223
4224 r = get_pointer_32(p, offset, left, S, info);
4225 if (r == nullptr)
4226 return;
4227 memset(&pl, '\0', sizeof(struct protocol_list32_t));
4228 if (left < sizeof(struct protocol_list32_t)) {
4229 memcpy(&pl, r, left);
4230 outs() << " (protocol_list_t entends past the end of the section)\n";
4231 } else
4232 memcpy(&pl, r, sizeof(struct protocol_list32_t));
4233 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4234 swapStruct(pl);
4235 outs() << " count " << pl.count << "\n";
4236
4237 p += sizeof(struct protocol_list32_t);
4238 offset += sizeof(struct protocol_list32_t);
4239 for (i = 0; i < pl.count; i++) {
4240 r = get_pointer_32(p, offset, left, S, info);
4241 if (r == nullptr)
4242 return;
4243 q = 0;
4244 if (left < sizeof(uint32_t)) {
4245 memcpy(&q, r, left);
4246 outs() << " (protocol_t * entends past the end of the section)\n";
4247 } else
4248 memcpy(&q, r, sizeof(uint32_t));
4249 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4250 sys::swapByteOrder(q);
4251 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32"x", q)
4252 << " (struct protocol_t *)\n";
4253 r = get_pointer_32(q, offset, left, S, info);
4254 if (r == nullptr)
4255 return;
4256 memset(&pc, '\0', sizeof(struct protocol32_t));
4257 if (left < sizeof(struct protocol32_t)) {
4258 memcpy(&pc, r, left);
4259 outs() << " (protocol_t entends past the end of the section)\n";
4260 } else
4261 memcpy(&pc, r, sizeof(struct protocol32_t));
4262 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4263 swapStruct(pc);
4264 outs() << "\t\t\t isa " << format("0x%" PRIx32"x", pc.isa) << "\n";
4265 outs() << "\t\t\t name " << format("0x%" PRIx32"x", pc.name);
4266 name = get_pointer_32(pc.name, xoffset, left, xS, info);
4267 if (name != nullptr)
4268 outs() << format(" %.*s", left, name);
4269 outs() << "\n";
4270 outs() << "\t\t\tprotocols " << format("0x%" PRIx32"x", pc.protocols) << "\n";
4271 outs() << "\t\t instanceMethods "
4272 << format("0x%" PRIx32"x", pc.instanceMethods)
4273 << " (struct method_list_t *)\n";
4274 if (pc.instanceMethods != 0)
4275 print_method_list32_t(pc.instanceMethods, info, "\t");
4276 outs() << "\t\t classMethods " << format("0x%" PRIx32"x", pc.classMethods)
4277 << " (struct method_list_t *)\n";
4278 if (pc.classMethods != 0)
4279 print_method_list32_t(pc.classMethods, info, "\t");
4280 outs() << "\t optionalInstanceMethods "
4281 << format("0x%" PRIx32"x", pc.optionalInstanceMethods) << "\n";
4282 outs() << "\t optionalClassMethods "
4283 << format("0x%" PRIx32"x", pc.optionalClassMethods) << "\n";
4284 outs() << "\t instanceProperties "
4285 << format("0x%" PRIx32"x", pc.instanceProperties) << "\n";
4286 p += sizeof(uint32_t);
4287 offset += sizeof(uint32_t);
4288 }
4289}
4290
4291static void print_indent(uint32_t indent) {
4292 for (uint32_t i = 0; i < indent;) {
4293 if (indent - i >= 8) {
4294 outs() << "\t";
4295 i += 8;
4296 } else {
4297 for (uint32_t j = i; j < indent; j++)
4298 outs() << " ";
4299 return;
4300 }
4301 }
4302}
4303
4304static bool print_method_description_list(uint32_t p, uint32_t indent,
4305 struct DisassembleInfo *info) {
4306 uint32_t offset, left, xleft;
4307 SectionRef S;
4308 struct objc_method_description_list_t mdl;
4309 struct objc_method_description_t md;
4310 const char *r, *list, *name;
4311 int32_t i;
4312
4313 r = get_pointer_32(p, offset, left, S, info, true);
4314 if (r == nullptr)
4315 return true;
4316
4317 outs() << "\n";
4318 if (left > sizeof(struct objc_method_description_list_t)) {
4319 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
4320 } else {
4321 print_indent(indent);
4322 outs() << " objc_method_description_list extends past end of the section\n";
4323 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
4324 memcpy(&mdl, r, left);
4325 }
4326 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4327 swapStruct(mdl);
4328
4329 print_indent(indent);
4330 outs() << " count " << mdl.count << "\n";
4331
4332 list = r + sizeof(struct objc_method_description_list_t);
4333 for (i = 0; i < mdl.count; i++) {
4334 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
4335 print_indent(indent);
4336 outs() << " remaining list entries extend past the of the section\n";
4337 break;
4338 }
4339 print_indent(indent);
4340 outs() << " list[" << i << "]\n";
4341 memcpy(&md, list + i * sizeof(struct objc_method_description_t),
4342 sizeof(struct objc_method_description_t));
4343 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4344 swapStruct(md);
4345
4346 print_indent(indent);
4347 outs() << " name " << format("0x%08" PRIx32"x", md.name);
4348 if (info->verbose) {
4349 name = get_pointer_32(md.name, offset, xleft, S, info, true);
4350 if (name != nullptr)
4351 outs() << format(" %.*s", xleft, name);
4352 else
4353 outs() << " (not in an __OBJC section)";
4354 }
4355 outs() << "\n";
4356
4357 print_indent(indent);
4358 outs() << " types " << format("0x%08" PRIx32"x", md.types);
4359 if (info->verbose) {
4360 name = get_pointer_32(md.types, offset, xleft, S, info, true);
4361 if (name != nullptr)
4362 outs() << format(" %.*s", xleft, name);
4363 else
4364 outs() << " (not in an __OBJC section)";
4365 }
4366 outs() << "\n";
4367 }
4368 return false;
4369}
4370
4371static bool print_protocol_list(uint32_t p, uint32_t indent,
4372 struct DisassembleInfo *info);
4373
4374static bool print_protocol(uint32_t p, uint32_t indent,
4375 struct DisassembleInfo *info) {
4376 uint32_t offset, left;
4377 SectionRef S;
4378 struct objc_protocol_t protocol;
4379 const char *r, *name;
4380
4381 r = get_pointer_32(p, offset, left, S, info, true);
4382 if (r == nullptr)
4383 return true;
4384
4385 outs() << "\n";
4386 if (left >= sizeof(struct objc_protocol_t)) {
4387 memcpy(&protocol, r, sizeof(struct objc_protocol_t));
4388 } else {
4389 print_indent(indent);
4390 outs() << " Protocol extends past end of the section\n";
4391 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
4392 memcpy(&protocol, r, left);
4393 }
4394 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4395 swapStruct(protocol);
4396
4397 print_indent(indent);
4398 outs() << " isa " << format("0x%08" PRIx32"x", protocol.isa)
4399 << "\n";
4400
4401 print_indent(indent);
4402 outs() << " protocol_name "
4403 << format("0x%08" PRIx32"x", protocol.protocol_name);
4404 if (info->verbose) {
4405 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
4406 if (name != nullptr)
4407 outs() << format(" %.*s", left, name);
4408 else
4409 outs() << " (not in an __OBJC section)";
4410 }
4411 outs() << "\n";
4412
4413 print_indent(indent);
4414 outs() << " protocol_list "
4415 << format("0x%08" PRIx32"x", protocol.protocol_list);
4416 if (print_protocol_list(protocol.protocol_list, indent + 4, info))
4417 outs() << " (not in an __OBJC section)\n";
4418
4419 print_indent(indent);
4420 outs() << " instance_methods "
4421 << format("0x%08" PRIx32"x", protocol.instance_methods);
4422 if (print_method_description_list(protocol.instance_methods, indent, info))
4423 outs() << " (not in an __OBJC section)\n";
4424
4425 print_indent(indent);
4426 outs() << " class_methods "
4427 << format("0x%08" PRIx32"x", protocol.class_methods);
4428 if (print_method_description_list(protocol.class_methods, indent, info))
4429 outs() << " (not in an __OBJC section)\n";
4430
4431 return false;
4432}
4433
4434static bool print_protocol_list(uint32_t p, uint32_t indent,
4435 struct DisassembleInfo *info) {
4436 uint32_t offset, left, l;
4437 SectionRef S;
4438 struct objc_protocol_list_t protocol_list;
4439 const char *r, *list;
4440 int32_t i;
4441
4442 r = get_pointer_32(p, offset, left, S, info, true);
4443 if (r == nullptr)
4444 return true;
4445
4446 outs() << "\n";
4447 if (left > sizeof(struct objc_protocol_list_t)) {
4448 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
4449 } else {
4450 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
4451 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
4452 memcpy(&protocol_list, r, left);
4453 }
4454 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4455 swapStruct(protocol_list);
4456
4457 print_indent(indent);
4458 outs() << " next " << format("0x%08" PRIx32"x", protocol_list.next)
4459 << "\n";
4460 print_indent(indent);
4461 outs() << " count " << protocol_list.count << "\n";
4462
4463 list = r + sizeof(struct objc_protocol_list_t);
4464 for (i = 0; i < protocol_list.count; i++) {
4465 if ((i + 1) * sizeof(uint32_t) > left) {
4466 outs() << "\t\t remaining list entries extend past the of the section\n";
4467 break;
4468 }
4469 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
4470 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4471 sys::swapByteOrder(l);
4472
4473 print_indent(indent);
4474 outs() << " list[" << i << "] " << format("0x%08" PRIx32"x", l);
4475 if (print_protocol(l, indent, info))
4476 outs() << "(not in an __OBJC section)\n";
4477 }
4478 return false;
4479}
4480
4481static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
4482 struct ivar_list64_t il;
4483 struct ivar64_t i;
4484 const char *r;
4485 uint32_t offset, xoffset, left, j;
4486 SectionRef S, xS;
4487 const char *name, *sym_name, *ivar_offset_p;
4488 uint64_t ivar_offset, n_value;
4489
4490 r = get_pointer_64(p, offset, left, S, info);
4491 if (r == nullptr)
4492 return;
4493 memset(&il, '\0', sizeof(struct ivar_list64_t));
4494 if (left < sizeof(struct ivar_list64_t)) {
4495 memcpy(&il, r, left);
4496 outs() << " (ivar_list_t entends past the end of the section)\n";
4497 } else
4498 memcpy(&il, r, sizeof(struct ivar_list64_t));
4499 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4500 swapStruct(il);
4501 outs() << " entsize " << il.entsize << "\n";
4502 outs() << " count " << il.count << "\n";
4503
4504 p += sizeof(struct ivar_list64_t);
4505 offset += sizeof(struct ivar_list64_t);
4506 for (j = 0; j < il.count; j++) {
4507 r = get_pointer_64(p, offset, left, S, info);
4508 if (r == nullptr)
4509 return;
4510 memset(&i, '\0', sizeof(struct ivar64_t));
4511 if (left < sizeof(struct ivar64_t)) {
4512 memcpy(&i, r, left);
4513 outs() << " (ivar_t entends past the end of the section)\n";
4514 } else
4515 memcpy(&i, r, sizeof(struct ivar64_t));
4516 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4517 swapStruct(i);
4518
4519 outs() << "\t\t\t offset ";
4520 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset)__builtin_offsetof(struct ivar64_t, offset), S,
4521 info, n_value, i.offset);
4522 if (n_value != 0) {
4523 if (info->verbose && sym_name != nullptr)
4524 outs() << sym_name;
4525 else
4526 outs() << format("0x%" PRIx64"l" "x", n_value);
4527 if (i.offset != 0)
4528 outs() << " + " << format("0x%" PRIx64"l" "x", i.offset);
4529 } else
4530 outs() << format("0x%" PRIx64"l" "x", i.offset);
4531 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
4532 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4533 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4534 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4535 sys::swapByteOrder(ivar_offset);
4536 outs() << " " << ivar_offset << "\n";
4537 } else
4538 outs() << "\n";
4539
4540 outs() << "\t\t\t name ";
4541 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name)__builtin_offsetof(struct ivar64_t, name), S, info,
4542 n_value, i.name);
4543 if (n_value != 0) {
4544 if (info->verbose && sym_name != nullptr)
4545 outs() << sym_name;
4546 else
4547 outs() << format("0x%" PRIx64"l" "x", n_value);
4548 if (i.name != 0)
4549 outs() << " + " << format("0x%" PRIx64"l" "x", i.name);
4550 } else
4551 outs() << format("0x%" PRIx64"l" "x", i.name);
4552 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
4553 if (name != nullptr)
4554 outs() << format(" %.*s", left, name);
4555 outs() << "\n";
4556
4557 outs() << "\t\t\t type ";
4558 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type)__builtin_offsetof(struct ivar64_t, type), S, info,
4559 n_value, i.name);
4560 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
4561 if (n_value != 0) {
4562 if (info->verbose && sym_name != nullptr)
4563 outs() << sym_name;
4564 else
4565 outs() << format("0x%" PRIx64"l" "x", n_value);
4566 if (i.type != 0)
4567 outs() << " + " << format("0x%" PRIx64"l" "x", i.type);
4568 } else
4569 outs() << format("0x%" PRIx64"l" "x", i.type);
4570 if (name != nullptr)
4571 outs() << format(" %.*s", left, name);
4572 outs() << "\n";
4573
4574 outs() << "\t\t\talignment " << i.alignment << "\n";
4575 outs() << "\t\t\t size " << i.size << "\n";
4576
4577 p += sizeof(struct ivar64_t);
4578 offset += sizeof(struct ivar64_t);
4579 }
4580}
4581
4582static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
4583 struct ivar_list32_t il;
4584 struct ivar32_t i;
4585 const char *r;
4586 uint32_t offset, xoffset, left, j;
4587 SectionRef S, xS;
4588 const char *name, *ivar_offset_p;
4589 uint32_t ivar_offset;
4590
4591 r = get_pointer_32(p, offset, left, S, info);
4592 if (r == nullptr)
4593 return;
4594 memset(&il, '\0', sizeof(struct ivar_list32_t));
4595 if (left < sizeof(struct ivar_list32_t)) {
4596 memcpy(&il, r, left);
4597 outs() << " (ivar_list_t entends past the end of the section)\n";
4598 } else
4599 memcpy(&il, r, sizeof(struct ivar_list32_t));
4600 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4601 swapStruct(il);
4602 outs() << " entsize " << il.entsize << "\n";
4603 outs() << " count " << il.count << "\n";
4604
4605 p += sizeof(struct ivar_list32_t);
4606 offset += sizeof(struct ivar_list32_t);
4607 for (j = 0; j < il.count; j++) {
4608 r = get_pointer_32(p, offset, left, S, info);
4609 if (r == nullptr)
4610 return;
4611 memset(&i, '\0', sizeof(struct ivar32_t));
4612 if (left < sizeof(struct ivar32_t)) {
4613 memcpy(&i, r, left);
4614 outs() << " (ivar_t entends past the end of the section)\n";
4615 } else
4616 memcpy(&i, r, sizeof(struct ivar32_t));
4617 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4618 swapStruct(i);
4619
4620 outs() << "\t\t\t offset " << format("0x%" PRIx32"x", i.offset);
4621 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
4622 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4623 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4624 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4625 sys::swapByteOrder(ivar_offset);
4626 outs() << " " << ivar_offset << "\n";
4627 } else
4628 outs() << "\n";
4629
4630 outs() << "\t\t\t name " << format("0x%" PRIx32"x", i.name);
4631 name = get_pointer_32(i.name, xoffset, left, xS, info);
4632 if (name != nullptr)
4633 outs() << format(" %.*s", left, name);
4634 outs() << "\n";
4635
4636 outs() << "\t\t\t type " << format("0x%" PRIx32"x", i.type);
4637 name = get_pointer_32(i.type, xoffset, left, xS, info);
4638 if (name != nullptr)
4639 outs() << format(" %.*s", left, name);
4640 outs() << "\n";
4641
4642 outs() << "\t\t\talignment " << i.alignment << "\n";
4643 outs() << "\t\t\t size " << i.size << "\n";
4644
4645 p += sizeof(struct ivar32_t);
4646 offset += sizeof(struct ivar32_t);
4647 }
4648}
4649
4650static void print_objc_property_list64(uint64_t p,
4651 struct DisassembleInfo *info) {
4652 struct objc_property_list64 opl;
4653 struct objc_property64 op;
4654 const char *r;
4655 uint32_t offset, xoffset, left, j;
4656 SectionRef S, xS;
4657 const char *name, *sym_name;
4658 uint64_t n_value;
4659
4660 r = get_pointer_64(p, offset, left, S, info);
4661 if (r == nullptr)
4662 return;
4663 memset(&opl, '\0', sizeof(struct objc_property_list64));
4664 if (left < sizeof(struct objc_property_list64)) {
4665 memcpy(&opl, r, left);
4666 outs() << " (objc_property_list entends past the end of the section)\n";
4667 } else
4668 memcpy(&opl, r, sizeof(struct objc_property_list64));
4669 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4670 swapStruct(opl);
4671 outs() << " entsize " << opl.entsize << "\n";
4672 outs() << " count " << opl.count << "\n";
4673
4674 p += sizeof(struct objc_property_list64);
4675 offset += sizeof(struct objc_property_list64);
4676 for (j = 0; j < opl.count; j++) {
4677 r = get_pointer_64(p, offset, left, S, info);
4678 if (r == nullptr)
4679 return;
4680 memset(&op, '\0', sizeof(struct objc_property64));
4681 if (left < sizeof(struct objc_property64)) {
4682 memcpy(&op, r, left);
4683 outs() << " (objc_property entends past the end of the section)\n";
4684 } else
4685 memcpy(&op, r, sizeof(struct objc_property64));
4686 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4687 swapStruct(op);
4688
4689 outs() << "\t\t\t name ";
4690 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name)__builtin_offsetof(struct objc_property64, name), S,
4691 info, n_value, op.name);
4692 if (n_value != 0) {
4693 if (info->verbose && sym_name != nullptr)
4694 outs() << sym_name;
4695 else
4696 outs() << format("0x%" PRIx64"l" "x", n_value);
4697 if (op.name != 0)
4698 outs() << " + " << format("0x%" PRIx64"l" "x", op.name);
4699 } else
4700 outs() << format("0x%" PRIx64"l" "x", op.name);
4701 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
4702 if (name != nullptr)
4703 outs() << format(" %.*s", left, name);
4704 outs() << "\n";
4705
4706 outs() << "\t\t\tattributes ";
4707 sym_name =
4708 get_symbol_64(offset + offsetof(struct objc_property64, attributes)__builtin_offsetof(struct objc_property64, attributes), S,
4709 info, n_value, op.attributes);
4710 if (n_value != 0) {
4711 if (info->verbose && sym_name != nullptr)
4712 outs() << sym_name;
4713 else
4714 outs() << format("0x%" PRIx64"l" "x", n_value);
4715 if (op.attributes != 0)
4716 outs() << " + " << format("0x%" PRIx64"l" "x", op.attributes);
4717 } else
4718 outs() << format("0x%" PRIx64"l" "x", op.attributes);
4719 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
4720 if (name != nullptr)
4721 outs() << format(" %.*s", left, name);
4722 outs() << "\n";
4723
4724 p += sizeof(struct objc_property64);
4725 offset += sizeof(struct objc_property64);
4726 }
4727}
4728
4729static void print_objc_property_list32(uint32_t p,
4730 struct DisassembleInfo *info) {
4731 struct objc_property_list32 opl;
4732 struct objc_property32 op;
4733 const char *r;
4734 uint32_t offset, xoffset, left, j;
4735 SectionRef S, xS;
4736 const char *name;
4737
4738 r = get_pointer_32(p, offset, left, S, info);
4739 if (r == nullptr)
4740 return;
4741 memset(&opl, '\0', sizeof(struct objc_property_list32));
4742 if (left < sizeof(struct objc_property_list32)) {
4743 memcpy(&opl, r, left);
4744 outs() << " (objc_property_list entends past the end of the section)\n";
4745 } else
4746 memcpy(&opl, r, sizeof(struct objc_property_list32));
4747 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4748 swapStruct(opl);
4749 outs() << " entsize " << opl.entsize << "\n";
4750 outs() << " count " << opl.count << "\n";
4751
4752 p += sizeof(struct objc_property_list32);
4753 offset += sizeof(struct objc_property_list32);
4754 for (j = 0; j < opl.count; j++) {
4755 r = get_pointer_32(p, offset, left, S, info);
4756 if (r == nullptr)
4757 return;
4758 memset(&op, '\0', sizeof(struct objc_property32));
4759 if (left < sizeof(struct objc_property32)) {
4760 memcpy(&op, r, left);
4761 outs() << " (objc_property entends past the end of the section)\n";
4762 } else
4763 memcpy(&op, r, sizeof(struct objc_property32));
4764 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4765 swapStruct(op);
4766
4767 outs() << "\t\t\t name " << format("0x%" PRIx32"x", op.name);
4768 name = get_pointer_32(op.name, xoffset, left, xS, info);
4769 if (name != nullptr)
4770 outs() << format(" %.*s", left, name);
4771 outs() << "\n";
4772
4773 outs() << "\t\t\tattributes " << format("0x%" PRIx32"x", op.attributes);
4774 name = get_pointer_32(op.attributes, xoffset, left, xS, info);
4775 if (name != nullptr)
4776 outs() << format(" %.*s", left, name);
4777 outs() << "\n";
4778
4779 p += sizeof(struct objc_property32);
4780 offset += sizeof(struct objc_property32);
4781 }
4782}
4783
4784static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
4785 bool &is_meta_class) {
4786 struct class_ro64_t cro;
4787 const char *r;
4788 uint32_t offset, xoffset, left;
4789 SectionRef S, xS;
4790 const char *name, *sym_name;
4791 uint64_t n_value;
4792
4793 r = get_pointer_64(p, offset, left, S, info);
4794 if (r == nullptr || left < sizeof(struct class_ro64_t))
4795 return false;
4796 memcpy(&cro, r, sizeof(struct class_ro64_t));
4797 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4798 swapStruct(cro);
4799 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4800 if (cro.flags & RO_META(1 << 0))
4801 outs() << " RO_META";
4802 if (cro.flags & RO_ROOT(1 << 1))
4803 outs() << " RO_ROOT";
4804 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4805 outs() << " RO_HAS_CXX_STRUCTORS";
4806 outs() << "\n";
4807 outs() << " instanceStart " << cro.instanceStart << "\n";
4808 outs() << " instanceSize " << cro.instanceSize << "\n";
4809 outs() << " reserved " << format("0x%" PRIx32"x", cro.reserved)
4810 << "\n";
4811 outs() << " ivarLayout " << format("0x%" PRIx64"l" "x", cro.ivarLayout)
4812 << "\n";
4813 print_layout_map64(cro.ivarLayout, info);
4814
4815 outs() << " name ";
4816 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name)__builtin_offsetof(struct class_ro64_t, name), S,
4817 info, n_value, cro.name);
4818 if (n_value != 0) {
4819 if (info->verbose && sym_name != nullptr)
4820 outs() << sym_name;
4821 else
4822 outs() << format("0x%" PRIx64"l" "x", n_value);
4823 if (cro.name != 0)
4824 outs() << " + " << format("0x%" PRIx64"l" "x", cro.name);
4825 } else
4826 outs() << format("0x%" PRIx64"l" "x", cro.name);
4827 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
4828 if (name != nullptr)
4829 outs() << format(" %.*s", left, name);
4830 outs() << "\n";
4831
4832 outs() << " baseMethods ";
4833 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods)__builtin_offsetof(struct class_ro64_t, baseMethods),
4834 S, info, n_value, cro.baseMethods);
4835 if (n_value != 0) {
4836 if (info->verbose && sym_name != nullptr)
4837 outs() << sym_name;
4838 else
4839 outs() << format("0x%" PRIx64"l" "x", n_value);
4840 if (cro.baseMethods != 0)
4841 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseMethods);
4842 } else
4843 outs() << format("0x%" PRIx64"l" "x", cro.baseMethods);
4844 outs() << " (struct method_list_t *)\n";
4845 if (cro.baseMethods + n_value != 0)
4846 print_method_list64_t(cro.baseMethods + n_value, info, "");
4847
4848 outs() << " baseProtocols ";
4849 sym_name =
4850 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols)__builtin_offsetof(struct class_ro64_t, baseProtocols), S,
4851 info, n_value, cro.baseProtocols);
4852 if (n_value != 0) {
4853 if (info->verbose && sym_name != nullptr)
4854 outs() << sym_name;
4855 else
4856 outs() << format("0x%" PRIx64"l" "x", n_value);
4857 if (cro.baseProtocols != 0)
4858 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4859 } else
4860 outs() << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4861 outs() << "\n";
4862 if (cro.baseProtocols + n_value != 0)
4863 print_protocol_list64_t(cro.baseProtocols + n_value, info);
4864
4865 outs() << " ivars ";
4866 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars)__builtin_offsetof(struct class_ro64_t, ivars), S,
4867 info, n_value, cro.ivars);
4868 if (n_value != 0) {
4869 if (info->verbose && sym_name != nullptr)
4870 outs() << sym_name;
4871 else
4872 outs() << format("0x%" PRIx64"l" "x", n_value);
4873 if (cro.ivars != 0)
4874 outs() << " + " << format("0x%" PRIx64"l" "x", cro.ivars);
4875 } else
4876 outs() << format("0x%" PRIx64"l" "x", cro.ivars);
4877 outs() << "\n";
4878 if (cro.ivars + n_value != 0)
4879 print_ivar_list64_t(cro.ivars + n_value, info);
4880
4881 outs() << " weakIvarLayout ";
4882 sym_name =
4883 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout)__builtin_offsetof(struct class_ro64_t, weakIvarLayout), S,
4884 info, n_value, cro.weakIvarLayout);
4885 if (n_value != 0) {
4886 if (info->verbose && sym_name != nullptr)
4887 outs() << sym_name;
4888 else
4889 outs() << format("0x%" PRIx64"l" "x", n_value);
4890 if (cro.weakIvarLayout != 0)
4891 outs() << " + " << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4892 } else
4893 outs() << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4894 outs() << "\n";
4895 print_layout_map64(cro.weakIvarLayout + n_value, info);
4896
4897 outs() << " baseProperties ";
4898 sym_name =
4899 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties)__builtin_offsetof(struct class_ro64_t, baseProperties), S,
4900 info, n_value, cro.baseProperties);
4901 if (n_value != 0) {
4902 if (info->verbose && sym_name != nullptr)
4903 outs() << sym_name;
4904 else
4905 outs() << format("0x%" PRIx64"l" "x", n_value);
4906 if (cro.baseProperties != 0)
4907 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProperties);
4908 } else
4909 outs() << format("0x%" PRIx64"l" "x", cro.baseProperties);
4910 outs() << "\n";
4911 if (cro.baseProperties + n_value != 0)
4912 print_objc_property_list64(cro.baseProperties + n_value, info);
4913
4914 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4915 return true;
4916}
4917
4918static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
4919 bool &is_meta_class) {
4920 struct class_ro32_t cro;
4921 const char *r;
4922 uint32_t offset, xoffset, left;
4923 SectionRef S, xS;
4924 const char *name;
4925
4926 r = get_pointer_32(p, offset, left, S, info);
4927 if (r == nullptr)
4928 return false;
4929 memset(&cro, '\0', sizeof(struct class_ro32_t));
4930 if (left < sizeof(struct class_ro32_t)) {
4931 memcpy(&cro, r, left);
4932 outs() << " (class_ro_t entends past the end of the section)\n";
4933 } else
4934 memcpy(&cro, r, sizeof(struct class_ro32_t));
4935 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4936 swapStruct(cro);
4937 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4938 if (cro.flags & RO_META(1 << 0))
4939 outs() << " RO_META";
4940 if (cro.flags & RO_ROOT(1 << 1))
4941 outs() << " RO_ROOT";
4942 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4943 outs() << " RO_HAS_CXX_STRUCTORS";
4944 outs() << "\n";
4945 outs() << " instanceStart " << cro.instanceStart << "\n";
4946 outs() << " instanceSize " << cro.instanceSize << "\n";
4947 outs() << " ivarLayout " << format("0x%" PRIx32"x", cro.ivarLayout)
4948 << "\n";
4949 print_layout_map32(cro.ivarLayout, info);
4950
4951 outs() << " name " << format("0x%" PRIx32"x", cro.name);
4952 name = get_pointer_32(cro.name, xoffset, left, xS, info);
4953 if (name != nullptr)
4954 outs() << format(" %.*s", left, name);
4955 outs() << "\n";
4956
4957 outs() << " baseMethods "
4958 << format("0x%" PRIx32"x", cro.baseMethods)
4959 << " (struct method_list_t *)\n";
4960 if (cro.baseMethods != 0)
4961 print_method_list32_t(cro.baseMethods, info, "");
4962
4963 outs() << " baseProtocols "
4964 << format("0x%" PRIx32"x", cro.baseProtocols) << "\n";
4965 if (cro.baseProtocols != 0)
4966 print_protocol_list32_t(cro.baseProtocols, info);
4967 outs() << " ivars " << format("0x%" PRIx32"x", cro.ivars)
4968 << "\n";
4969 if (cro.ivars != 0)
4970 print_ivar_list32_t(cro.ivars, info);
4971 outs() << " weakIvarLayout "
4972 << format("0x%" PRIx32"x", cro.weakIvarLayout) << "\n";
4973 print_layout_map32(cro.weakIvarLayout, info);
4974 outs() << " baseProperties "
4975 << format("0x%" PRIx32"x", cro.baseProperties) << "\n";
4976 if (cro.baseProperties != 0)
4977 print_objc_property_list32(cro.baseProperties, info);
4978 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4979 return true;
4980}
4981
4982static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
4983 struct class64_t c;
4984 const char *r;
4985 uint32_t offset, left;
4986 SectionRef S;
4987 const char *name;
4988 uint64_t isa_n_value, n_value;
4989
4990 r = get_pointer_64(p, offset, left, S, info);
4991 if (r == nullptr || left < sizeof(struct class64_t))
4992 return;
4993 memcpy(&c, r, sizeof(struct class64_t));
4994 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4995 swapStruct(c);
4996
4997 outs() << " isa " << format("0x%" PRIx64"l" "x", c.isa);
4998 name = get_symbol_64(offset + offsetof(struct class64_t, isa)__builtin_offsetof(struct class64_t, isa), S, info,
4999 isa_n_value, c.isa);
5000 if (name != nullptr)
5001 outs() << " " << name;
5002 outs() << "\n";
5003
5004 outs() << " superclass " << format("0x%" PRIx64"l" "x", c.superclass);
5005 name = get_symbol_64(offset + offsetof(struct class64_t, superclass)__builtin_offsetof(struct class64_t, superclass), S, info,
5006 n_value, c.superclass);
5007 if (name != nullptr)
5008 outs() << " " << name;
5009 else {
5010 name = get_dyld_bind_info_symbolname(S.getAddress() +
5011 offset + offsetof(struct class64_t, superclass)__builtin_offsetof(struct class64_t, superclass), info);
5012 if (name != nullptr)
5013 outs() << " " << name;
5014 }
5015 outs() << "\n";
5016
5017 outs() << " cache " << format("0x%" PRIx64"l" "x", c.cache);
5018 name = get_symbol_64(offset + offsetof(struct class64_t, cache)__builtin_offsetof(struct class64_t, cache), S, info,
5019 n_value, c.cache);
5020 if (name != nullptr)
5021 outs() << " " << name;
5022 outs() << "\n";
5023
5024 outs() << " vtable " << format("0x%" PRIx64"l" "x", c.vtable);
5025 name = get_symbol_64(offset + offsetof(struct class64_t, vtable)__builtin_offsetof(struct class64_t, vtable), S, info,
5026 n_value, c.vtable);
5027 if (name != nullptr)
5028 outs() << " " << name;
5029 outs() << "\n";
5030
5031 name = get_symbol_64(offset + offsetof(struct class64_t, data)__builtin_offsetof(struct class64_t, data), S, info,
5032 n_value, c.data);
5033 outs() << " data ";
5034 if (n_value != 0) {
5035 if (info->verbose && name != nullptr)
5036 outs() << name;
5037 else
5038 outs() << format("0x%" PRIx64"l" "x", n_value);
5039 if (c.data != 0)
5040 outs() << " + " << format("0x%" PRIx64"l" "x", c.data);
5041 } else
5042 outs() << format("0x%" PRIx64"l" "x", c.data);
5043 outs() << " (struct class_ro_t *)";
5044
5045 // This is a Swift class if some of the low bits of the pointer are set.
5046 if ((c.data + n_value) & 0x7)
5047 outs() << " Swift class";
5048 outs() << "\n";
5049 bool is_meta_class;
5050 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
5051 return;
5052
5053 if (!is_meta_class &&
5054 c.isa + isa_n_value != p &&
5055 c.isa + isa_n_value != 0 &&
5056 info->depth < 100) {
5057 info->depth++;
5058 outs() << "Meta Class\n";
5059 print_class64_t(c.isa + isa_n_value, info);
5060 }
5061}
5062
5063static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5064 struct class32_t c;
5065 const char *r;
5066 uint32_t offset, left;
5067 SectionRef S;
5068 const char *name;
5069
5070 r = get_pointer_32(p, offset, left, S, info);
5071 if (r == nullptr)
5072 return;
5073 memset(&c, '\0', sizeof(struct class32_t));
5074 if (left < sizeof(struct class32_t)) {
5075 memcpy(&c, r, left);
5076 outs() << " (class_t entends past the end of the section)\n";
5077 } else
5078 memcpy(&c, r, sizeof(struct class32_t));
5079 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5080 swapStruct(c);
5081
5082 outs() << " isa " << format("0x%" PRIx32"x", c.isa);
5083 name =
5084 get_symbol_32(offset + offsetof(struct class32_t, isa)__builtin_offsetof(struct class32_t, isa), S, info, c.isa);
5085 if (name != nullptr)
5086 outs() << " " << name;
5087 outs() << "\n";
5088
5089 outs() << " superclass " << format("0x%" PRIx32"x", c.superclass);
5090 name = get_symbol_32(offset + offsetof(struct class32_t, superclass)__builtin_offsetof(struct class32_t, superclass), S, info,
5091 c.superclass);
5092 if (name != nullptr)
5093 outs() << " " << name;
5094 outs() << "\n";
5095
5096 outs() << " cache " << format("0x%" PRIx32"x", c.cache);
5097 name = get_symbol_32(offset + offsetof(struct class32_t, cache)__builtin_offsetof(struct class32_t, cache), S, info,
5098 c.cache);
5099 if (name != nullptr)
5100 outs() << " " << name;
5101 outs() << "\n";
5102
5103 outs() << " vtable " << format("0x%" PRIx32"x", c.vtable);
5104 name = get_symbol_32(offset + offsetof(struct class32_t, vtable)__builtin_offsetof(struct class32_t, vtable), S, info,
5105 c.vtable);
5106 if (name != nullptr)
5107 outs() << " " << name;
5108 outs() << "\n";
5109
5110 name =
5111 get_symbol_32(offset + offsetof(struct class32_t, data)__builtin_offsetof(struct class32_t, data), S, info, c.data);
5112 outs() << " data " << format("0x%" PRIx32"x", c.data)
5113 << " (struct class_ro_t *)";
5114
5115 // This is a Swift class if some of the low bits of the pointer are set.
5116 if (c.data & 0x3)
5117 outs() << " Swift class";
5118 outs() << "\n";
5119 bool is_meta_class;
5120 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
5121 return;
5122
5123 if (!is_meta_class) {
5124 outs() << "Meta Class\n";
5125 print_class32_t(c.isa, info);
5126 }
5127}
5128
5129static void print_objc_class_t(struct objc_class_t *objc_class,
5130 struct DisassembleInfo *info) {
5131 uint32_t offset, left, xleft;
5132 const char *name, *p, *ivar_list;
5133 SectionRef S;
5134 int32_t i;
5135 struct objc_ivar_list_t objc_ivar_list;
5136 struct objc_ivar_t ivar;
5137
5138 outs() << "\t\t isa " << format("0x%08" PRIx32"x", objc_class->isa);
5139 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2))) {
5140 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
5141 if (name != nullptr)
5142 outs() << format(" %.*s", left, name);
5143 else
5144 outs() << " (not in an __OBJC section)";
5145 }
5146 outs() << "\n";
5147
5148 outs() << "\t super_class "
5149 << format("0x%08" PRIx32"x", objc_class->super_class);
5150 if (info->verbose) {
5151 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
5152 if (name != nullptr)
5153 outs() << format(" %.*s", left, name);
5154 else
5155 outs() << " (not in an __OBJC section)";
5156 }
5157 outs() << "\n";
5158
5159 outs() << "\t\t name " << format("0x%08" PRIx32"x", objc_class->name);
5160 if (info->verbose) {
5161 name = get_pointer_32(objc_class->name, offset, left, S, info, true);
5162 if (name != nullptr)
5163 outs() << format(" %.*s", left, name);
5164 else
5165 outs() << " (not in an __OBJC section)";
5166 }
5167 outs() << "\n";
5168
5169 outs() << "\t\t version " << format("0x%08" PRIx32"x", objc_class->version)
5170 << "\n";
5171
5172 outs() << "\t\t info " << format("0x%08" PRIx32"x", objc_class->info);
5173 if (info->verbose) {
5174 if (CLS_GETINFO(objc_class, CLS_CLASS)((objc_class)->info & (0x1)))
5175 outs() << " CLS_CLASS";
5176 else if (CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2)))
5177 outs() << " CLS_META";
5178 }
5179 outs() << "\n";
5180
5181 outs() << "\t instance_size "
5182 << format("0x%08" PRIx32"x", objc_class->instance_size) << "\n";
5183
5184 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
5185 outs() << "\t\t ivars " << format("0x%08" PRIx32"x", objc_class->ivars);
5186 if (p != nullptr) {
5187 if (left > sizeof(struct objc_ivar_list_t)) {
5188 outs() << "\n";
5189 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
5190 } else {
5191 outs() << " (entends past the end of the section)\n";
5192 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
5193 memcpy(&objc_ivar_list, p, left);
5194 }
5195 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5196 swapStruct(objc_ivar_list);
5197 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5198 ivar_list = p + sizeof(struct objc_ivar_list_t);
5199 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5200 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5201 outs() << "\t\t remaining ivar's extend past the of the section\n";
5202 break;
5203 }
5204 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
5205 sizeof(struct objc_ivar_t));
5206 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5207 swapStruct(ivar);
5208
5209 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32"x", ivar.ivar_name);
5210 if (info->verbose) {
5211 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
5212 if (name != nullptr)
5213 outs() << format(" %.*s", xleft, name);
5214 else
5215 outs() << " (not in an __OBJC section)";
5216 }
5217 outs() << "\n";
5218
5219 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32"x", ivar.ivar_type);
5220 if (info->verbose) {
5221 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
5222 if (name != nullptr)
5223 outs() << format(" %.*s", xleft, name);
5224 else
5225 outs() << " (not in an __OBJC section)";
5226 }
5227 outs() << "\n";
5228
5229 outs() << "\t\t ivar_offset "
5230 << format("0x%08" PRIx32"x", ivar.ivar_offset) << "\n";
5231 }
5232 } else {
5233 outs() << " (not in an __OBJC section)\n";
5234 }
5235
5236 outs() << "\t\t methods " << format("0x%08" PRIx32"x", objc_class->methodLists);
5237 if (print_method_list(objc_class->methodLists, info))
5238 outs() << " (not in an __OBJC section)\n";
5239
5240 outs() << "\t\t cache " << format("0x%08" PRIx32"x", objc_class->cache)
5241 << "\n";
5242
5243 outs() << "\t\tprotocols " << format("0x%08" PRIx32"x", objc_class->protocols);
5244 if (print_protocol_list(objc_class->protocols, 16, info))
5245 outs() << " (not in an __OBJC section)\n";
5246}
5247
5248static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5249 struct DisassembleInfo *info) {
5250 uint32_t offset, left;
5251 const char *name;
5252 SectionRef S;
5253
5254 outs() << "\t category name "
5255 << format("0x%08" PRIx32"x", objc_category->category_name);
5256 if (info->verbose) {
5257 name = get_pointer_32(objc_category->category_name, offset, left, S, info,
5258 true);
5259 if (name != nullptr)
5260 outs() << format(" %.*s", left, name);
5261 else
5262 outs() << " (not in an __OBJC section)";
5263 }
5264 outs() << "\n";
5265
5266 outs() << "\t\t class name "
5267 << format("0x%08" PRIx32"x", objc_category->class_name);
5268 if (info->verbose) {
5269 name =
5270 get_pointer_32(objc_category->class_name, offset, left, S, info, true);
5271 if (name != nullptr)
5272 outs() << format(" %.*s", left, name);
5273 else
5274 outs() << " (not in an __OBJC section)";
5275 }
5276 outs() << "\n";
5277
5278 outs() << "\t instance methods "
5279 << format("0x%08" PRIx32"x", objc_category->instance_methods);
5280 if (print_method_list(objc_category->instance_methods, info))
5281 outs() << " (not in an __OBJC section)\n";
5282
5283 outs() << "\t class methods "
5284 << format("0x%08" PRIx32"x", objc_category->class_methods);
5285 if (print_method_list(objc_category->class_methods, info))
5286 outs() << " (not in an __OBJC section)\n";
5287}
5288
5289static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
5290 struct category64_t c;
5291 const char *r;
5292 uint32_t offset, xoffset, left;
5293 SectionRef S, xS;
5294 const char *name, *sym_name;
5295 uint64_t n_value;
5296
5297 r = get_pointer_64(p, offset, left, S, info);
5298 if (r == nullptr)
5299 return;
5300 memset(&c, '\0', sizeof(struct category64_t));
5301 if (left < sizeof(struct category64_t)) {
5302 memcpy(&c, r, left);
5303 outs() << " (category_t entends past the end of the section)\n";
5304 } else
5305 memcpy(&c, r, sizeof(struct category64_t));
5306 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5307 swapStruct(c);
5308
5309 outs() << " name ";
5310 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name)__builtin_offsetof(struct category64_t, name), S,
5311 info, n_value, c.name);
5312 if (n_value != 0) {
5313 if (info->verbose && sym_name != nullptr)
5314 outs() << sym_name;
5315 else
5316 outs() << format("0x%" PRIx64"l" "x", n_value);
5317 if (c.name != 0)
5318 outs() << " + " << format("0x%" PRIx64"l" "x", c.name);
5319 } else
5320 outs() << format("0x%" PRIx64"l" "x", c.name);
5321 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
5322 if (name != nullptr)
5323 outs() << format(" %.*s", left, name);
5324 outs() << "\n";
5325
5326 outs() << " cls ";
5327 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls)__builtin_offsetof(struct category64_t, cls), S, info,
5328 n_value, c.cls);
5329 if (n_value != 0) {
5330 if (info->verbose && sym_name != nullptr)
5331 outs() << sym_name;
5332 else
5333 outs() << format("0x%" PRIx64"l" "x", n_value);
5334 if (c.cls != 0)
5335 outs() << " + " << format("0x%" PRIx64"l" "x", c.cls);
5336 } else
5337 outs() << format("0x%" PRIx64"l" "x", c.cls);
5338 outs() << "\n";
5339 if (c.cls + n_value != 0)
5340 print_class64_t(c.cls + n_value, info);
5341
5342 outs() << " instanceMethods ";
5343 sym_name =
5344 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods)__builtin_offsetof(struct category64_t, instanceMethods), S,
5345 info, n_value, c.instanceMethods);
5346 if (n_value != 0) {
5347 if (info->verbose && sym_name != nullptr)
5348 outs() << sym_name;
5349 else
5350 outs() << format("0x%" PRIx64"l" "x", n_value);
5351 if (c.instanceMethods != 0)
5352 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceMethods);
5353 } else
5354 outs() << format("0x%" PRIx64"l" "x", c.instanceMethods);
5355 outs() << "\n";
5356 if (c.instanceMethods + n_value != 0)
5357 print_method_list64_t(c.instanceMethods + n_value, info, "");
5358
5359 outs() << " classMethods ";
5360 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods)__builtin_offsetof(struct category64_t, classMethods),
5361 S, info, n_value, c.classMethods);
5362 if (n_value != 0) {
5363 if (info->verbose && sym_name != nullptr)
5364 outs() << sym_name;
5365 else
5366 outs() << format("0x%" PRIx64"l" "x", n_value);
5367 if (c.classMethods != 0)
5368 outs() << " + " << format("0x%" PRIx64"l" "x", c.classMethods);
5369 } else
5370 outs() << format("0x%" PRIx64"l" "x", c.classMethods);
5371 outs() << "\n";
5372 if (c.classMethods + n_value != 0)
5373 print_method_list64_t(c.classMethods + n_value, info, "");
5374
5375 outs() << " protocols ";
5376 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols)__builtin_offsetof(struct category64_t, protocols), S,
5377 info, n_value, c.protocols);
5378 if (n_value != 0) {
5379 if (info->verbose && sym_name != nullptr)
5380 outs() << sym_name;
5381 else
5382 outs() << format("0x%" PRIx64"l" "x", n_value);
5383 if (c.protocols != 0)
5384 outs() << " + " << format("0x%" PRIx64"l" "x", c.protocols);
5385 } else
5386 outs() << format("0x%" PRIx64"l" "x", c.protocols);
5387 outs() << "\n";
5388 if (c.protocols + n_value != 0)
5389 print_protocol_list64_t(c.protocols + n_value, info);
5390
5391 outs() << "instanceProperties ";
5392 sym_name =
5393 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties)__builtin_offsetof(struct category64_t, instanceProperties),
5394 S, info, n_value, c.instanceProperties);
5395 if (n_value != 0) {
5396 if (info->verbose && sym_name != nullptr)
5397 outs() << sym_name;
5398 else
5399 outs() << format("0x%" PRIx64"l" "x", n_value);
5400 if (c.instanceProperties != 0)
5401 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceProperties);
5402 } else
5403 outs() << format("0x%" PRIx64"l" "x", c.instanceProperties);
5404 outs() << "\n";
5405 if (c.instanceProperties + n_value != 0)
5406 print_objc_property_list64(c.instanceProperties + n_value, info);
5407}
5408
5409static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
5410 struct category32_t c;
5411 const char *r;
5412 uint32_t offset, left;
5413 SectionRef S, xS;
5414 const char *name;
5415
5416 r = get_pointer_32(p, offset, left, S, info);
5417 if (r == nullptr)
5418 return;
5419 memset(&c, '\0', sizeof(struct category32_t));
5420 if (left < sizeof(struct category32_t)) {
5421 memcpy(&c, r, left);
5422 outs() << " (category_t entends past the end of the section)\n";
5423 } else
5424 memcpy(&c, r, sizeof(struct category32_t));
5425 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5426 swapStruct(c);
5427
5428 outs() << " name " << format("0x%" PRIx32"x", c.name);
5429 name = get_symbol_32(offset + offsetof(struct category32_t, name)__builtin_offsetof(struct category32_t, name), S, info,
5430 c.name);
5431 if (name)
5432 outs() << " " << name;
5433 outs() << "\n";
5434
5435 outs() << " cls " << format("0x%" PRIx32"x", c.cls) << "\n";
5436 if (c.cls != 0)
5437 print_class32_t(c.cls, info);
5438 outs() << " instanceMethods " << format("0x%" PRIx32"x", c.instanceMethods)
5439 << "\n";
5440 if (c.instanceMethods != 0)
5441 print_method_list32_t(c.instanceMethods, info, "");
5442 outs() << " classMethods " << format("0x%" PRIx32"x", c.classMethods)
5443 << "\n";
5444 if (c.classMethods != 0)
5445 print_method_list32_t(c.classMethods, info, "");
5446 outs() << " protocols " << format("0x%" PRIx32"x", c.protocols) << "\n";
5447 if (c.protocols != 0)
5448 print_protocol_list32_t(c.protocols, info);
5449 outs() << "instanceProperties " << format("0x%" PRIx32"x", c.instanceProperties)
5450 << "\n";
5451 if (c.instanceProperties != 0)
5452 print_objc_property_list32(c.instanceProperties, info);
5453}
5454
5455static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
5456 uint32_t i, left, offset, xoffset;
5457 uint64_t p, n_value;
5458 struct message_ref64 mr;
5459 const char *name, *sym_name;
5460 const char *r;
5461 SectionRef xS;
5462
5463 if (S == SectionRef())
5464 return;
5465
5466 StringRef SectName;
5467 S.getName(SectName);
5468 DataRefImpl Ref = S.getRawDataRefImpl();
5469 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5470 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5471 offset = 0;
5472 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5473 p = S.getAddress() + i;
5474 r = get_pointer_64(p, offset, left, S, info);
5475 if (r == nullptr)
5476 return;
5477 memset(&mr, '\0', sizeof(struct message_ref64));
5478 if (left < sizeof(struct message_ref64)) {
5479 memcpy(&mr, r, left);
5480 outs() << " (message_ref entends past the end of the section)\n";
5481 } else
5482 memcpy(&mr, r, sizeof(struct message_ref64));
5483 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5484 swapStruct(mr);
5485
5486 outs() << " imp ";
5487 name = get_symbol_64(offset + offsetof(struct message_ref64, imp)__builtin_offsetof(struct message_ref64, imp), S, info,
5488 n_value, mr.imp);
5489 if (n_value != 0) {
5490 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
5491 if (mr.imp != 0)
5492 outs() << "+ " << format("0x%" PRIx64"l" "x", mr.imp) << " ";
5493 } else
5494 outs() << format("0x%" PRIx64"l" "x", mr.imp) << " ";
5495 if (name != nullptr)
5496 outs() << " " << name;
5497 outs() << "\n";
5498
5499 outs() << " sel ";
5500 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel)__builtin_offsetof(struct message_ref64, sel), S,
5501 info, n_value, mr.sel);
5502 if (n_value != 0) {
5503 if (info->verbose && sym_name != nullptr)
5504 outs() << sym_name;
5505 else
5506 outs() << format("0x%" PRIx64"l" "x", n_value);
5507 if (mr.sel != 0)
5508 outs() << " + " << format("0x%" PRIx64"l" "x", mr.sel);
5509 } else
5510 outs() << format("0x%" PRIx64"l" "x", mr.sel);
5511 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
5512 if (name != nullptr)
5513 outs() << format(" %.*s", left, name);
5514 outs() << "\n";
5515
5516 offset += sizeof(struct message_ref64);
5517 }
5518}
5519
5520static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
5521 uint32_t i, left, offset, xoffset, p;
5522 struct message_ref32 mr;
5523 const char *name, *r;
5524 SectionRef xS;
5525
5526 if (S == SectionRef())
5527 return;
5528
5529 StringRef SectName;
5530 S.getName(SectName);
5531 DataRefImpl Ref = S.getRawDataRefImpl();
5532 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5533 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5534 offset = 0;
5535 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5536 p = S.getAddress() + i;
5537 r = get_pointer_32(p, offset, left, S, info);
5538 if (r == nullptr)
5539 return;
5540 memset(&mr, '\0', sizeof(struct message_ref32));
5541 if (left < sizeof(struct message_ref32)) {
5542 memcpy(&mr, r, left);
5543 outs() << " (message_ref entends past the end of the section)\n";
5544 } else
5545 memcpy(&mr, r, sizeof(struct message_ref32));
5546 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5547 swapStruct(mr);
5548
5549 outs() << " imp " << format("0x%" PRIx32"x", mr.imp);
5550 name = get_symbol_32(offset + offsetof(struct message_ref32, imp)__builtin_offsetof(struct message_ref32, imp), S, info,
5551 mr.imp);
5552 if (name != nullptr)
5553 outs() << " " << name;
5554 outs() << "\n";
5555
5556 outs() << " sel " << format("0x%" PRIx32"x", mr.sel);
5557 name = get_pointer_32(mr.sel, xoffset, left, xS, info);
5558 if (name != nullptr)
5559 outs() << " " << name;
5560 outs() << "\n";
5561
5562 offset += sizeof(struct message_ref32);
5563 }
5564}
5565
5566static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
5567 uint32_t left, offset, swift_version;
5568 uint64_t p;
5569 struct objc_image_info64 o;
5570 const char *r;
5571
5572 if (S == SectionRef())
5573 return;
5574
5575 StringRef SectName;
5576 S.getName(SectName);
5577 DataRefImpl Ref = S.getRawDataRefImpl();
5578 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5579 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5580 p = S.getAddress();
5581 r = get_pointer_64(p, offset, left, S, info);
5582 if (r == nullptr)
5583 return;
5584 memset(&o, '\0', sizeof(struct objc_image_info64));
5585 if (left < sizeof(struct objc_image_info64)) {
5586 memcpy(&o, r, left);
5587 outs() << " (objc_image_info entends past the end of the section)\n";
5588 } else
5589 memcpy(&o, r, sizeof(struct objc_image_info64));
5590 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5591 swapStruct(o);
5592 outs() << " version " << o.version << "\n";
5593 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5594 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5595 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5596 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5597 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5598 swift_version = (o.flags >> 8) & 0xff;
5599 if (swift_version != 0) {
5600 if (swift_version == 1)
5601 outs() << " Swift 1.0";
5602 else if (swift_version == 2)
5603 outs() << " Swift 1.1";
5604 else if(swift_version == 3)
5605 outs() << " Swift 2.0";
5606 else if(swift_version == 4)
5607 outs() << " Swift 3.0";
5608 else if(swift_version == 5)
5609 outs() << " Swift 4.0";
5610 else if(swift_version == 6)
5611 outs() << " Swift 4.1";
5612 else
5613 outs() << " unknown future Swift version (" << swift_version << ")";
5614 }
5615 outs() << "\n";
5616}
5617
5618static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
5619 uint32_t left, offset, swift_version, p;
5620 struct objc_image_info32 o;
5621 const char *r;
5622
5623 if (S == SectionRef())
5624 return;
5625
5626 StringRef SectName;
5627 S.getName(SectName);
5628 DataRefImpl Ref = S.getRawDataRefImpl();
5629 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5630 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5631 p = S.getAddress();
5632 r = get_pointer_32(p, offset, left, S, info);
5633 if (r == nullptr)
5634 return;
5635 memset(&o, '\0', sizeof(struct objc_image_info32));
5636 if (left < sizeof(struct objc_image_info32)) {
5637 memcpy(&o, r, left);
5638 outs() << " (objc_image_info entends past the end of the section)\n";
5639 } else
5640 memcpy(&o, r, sizeof(struct objc_image_info32));
5641 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5642 swapStruct(o);
5643 outs() << " version " << o.version << "\n";
5644 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5645 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5646 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5647 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5648 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5649 swift_version = (o.flags >> 8) & 0xff;
5650 if (swift_version != 0) {
5651 if (swift_version == 1)
5652 outs() << " Swift 1.0";
5653 else if (swift_version == 2)
5654 outs() << " Swift 1.1";
5655 else if(swift_version == 3)
5656 outs() << " Swift 2.0";
5657 else if(swift_version == 4)
5658 outs() << " Swift 3.0";
5659 else if(swift_version == 5)
5660 outs() << " Swift 4.0";
5661 else if(swift_version == 6)
5662 outs() << " Swift 4.1";
5663 else
5664 outs() << " unknown future Swift version (" << swift_version << ")";
5665 }
5666 outs() << "\n";
5667}
5668
5669static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
5670 uint32_t left, offset, p;
5671 struct imageInfo_t o;
5672 const char *r;
5673
5674 StringRef SectName;
5675 S.getName(SectName);
5676 DataRefImpl Ref = S.getRawDataRefImpl