Bug Summary

File:include/llvm/Object/ObjectFile.h
Warning:line 413, 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~svn337103/build-llvm/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-7~svn337103/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-7~svn337103/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn337103/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/lib/gcc/x86_64-linux-gnu/7.3.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~svn337103/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-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-07-15-073923-5500-1 -x c++ /build/llvm-toolchain-snapshot-7~svn337103/tools/llvm-objdump/MachODump.cpp

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