Bug Summary

File:include/llvm/Support/Error.h
Warning:line 201, column 5
Potential leak of memory pointed to by 'Payload._M_t._M_head_impl'

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-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-8/lib/clang/8.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-objdump -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn345461/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn345461/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-10-27-211344-32123-1 -x c++ /build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-objdump/MachODump.cpp -faddrsig

/build/llvm-toolchain-snapshot-8~svn345461/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 ||
10
Assuming the condition is false
11
Assuming the condition is false
12
Assuming the condition is false
13
Assuming the condition is false
14
Assuming the condition is false
26
Taking false branch
1581 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
15
Assuming the condition is false
16
Assuming the condition is false
17
Assuming the condition is false
18
Assuming the condition is false
19
Assuming the condition is false
1582 DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData ||
20
Assuming the condition is false
21
Assuming the condition is false
22
Assuming the condition is false
23
Assuming the condition is false
24
Assuming the condition is false
1583 (FilterSections.size() != 0)) {
25
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()) {
27
Assuming the condition is false
28
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 ||
29
Assuming the condition is false
30
Assuming the condition is false
31
Assuming the condition is false
33
Taking false branch
1609 UnwindInfo)
32
Assuming the condition is false
1610 if (Error Err = MachOOF->checkSymbolTable())
1611 report_error(ArchiveName, FileName, std::move(Err), ArchitectureName);
1612
1613 if (Disassemble) {
34
Assuming the condition is false
35
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)
36
Assuming the condition is false
37
Taking false branch
1621 PrintIndirectSymbols(MachOOF, !NonVerbose);
1622 if (DataInCode)
38
Assuming the condition is false
39
Taking false branch
1623 PrintDataInCodeTable(MachOOF, !NonVerbose);
1624 if (LinkOptHints)
40
Assuming the condition is false
41
Taking false branch
1625 PrintLinkOptHints(MachOOF);
1626 if (Relocations)
42
Assuming the condition is false
43
Taking false branch
1627 PrintRelocations(MachOOF, !NonVerbose);
1628 if (SectionHeaders)
44
Assuming the condition is false
45
Taking false branch
1629 PrintSectionHeaders(MachOOF);
1630 if (SectionContents)
46
Assuming the condition is false
47
Taking false branch
1631 PrintSectionContents(MachOOF);
1632 if (FilterSections.size() != 0)
48
Assuming the condition is false
49
Taking false branch
1633 DumpSectionContents(FileName, MachOOF, !NonVerbose);
1634 if (InfoPlist)
50
Assuming the condition is false
51
Taking false branch
1635 DumpInfoPlistSectionContents(FileName, MachOOF);
1636 if (DylibsUsed)
52
Assuming the condition is false
53
Taking false branch
1637 PrintDylibs(MachOOF, false);
1638 if (DylibId)
54
Assuming the condition is false
55
Taking false branch
1639 PrintDylibs(MachOOF, true);
1640 if (SymbolTable)
56
Assuming the condition is false
57
Taking false branch
1641 PrintSymbolTable(MachOOF, ArchiveName, ArchitectureName);
1642 if (UnwindInfo)
58
Assuming the condition is true
59
Taking true branch
1643 printMachOUnwindInfo(MachOOF);
60
Calling 'printMachOUnwindInfo'
1644 if (PrivateHeaders) {
1645 printMachOFileHeader(MachOOF);
1646 printMachOLoadCommands(MachOOF);
1647 }
1648 if (FirstPrivateHeader)
1649 printMachOFileHeader(MachOOF);
1650 if (ObjcMetaData)
1651 printObjcMetaData(MachOOF, !NonVerbose);
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
1940static bool ValidateArchFlags() {
1941 // Check for -arch all and verifiy the -arch flags are valid.
1942 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
1943 if (ArchFlags[i] == "all") {
1944 ArchAll = true;
1945 } else {
1946 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
1947 errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] +
1948 "'for the -arch option\n";
1949 return false;
1950 }
1951 }
1952 }
1953 return true;
1954}
1955
1956// ParseInputMachO() parses the named Mach-O file in Filename and handles the
1957// -arch flags selecting just those slices as specified by them and also parses
1958// archive files. Then for each individual Mach-O file ProcessMachO() is
1959// called to process the file based on the command line options.
1960void llvm::ParseInputMachO(StringRef Filename) {
1961 if (!ValidateArchFlags())
1
Taking false branch
1962 return;
1963
1964 // Attempt to open the binary.
1965 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
1966 if (!BinaryOrErr) {
2
Taking false branch
1967 if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
1968 report_error(Filename, std::move(E));
1969 else
1970 outs() << Filename << ": is not an object file\n";
1971 return;
1972 }
1973 Binary &Bin = *BinaryOrErr.get().getBinary();
1974
1975 if (Archive *A = dyn_cast<Archive>(&Bin)) {
3
Taking true branch
1976 outs() << "Archive : " << Filename << "\n";
1977 if (ArchiveHeaders)
4
Assuming the condition is false
5
Taking false branch
1978 printArchiveHeaders(Filename, A, !NonVerbose, ArchiveMemberOffsets);
1979
1980 Error Err = Error::success();
1981 for (auto &C : A->children(Err)) {
1982 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1983 if (!ChildOrErr) {
6
Taking false branch
1984 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
1985 report_error(Filename, C, std::move(E));
1986 continue;
1987 }
1988 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
7
Taking true branch
1989 if (!checkMachOAndArchFlags(O, Filename))
8
Taking false branch
1990 return;
1991 ProcessMachO(Filename, O, O->getFileName());
9
Calling 'ProcessMachO'
1992 }
1993 }
1994 if (Err)
1995 report_error(Filename, std::move(Err));
1996 return;
1997 }
1998 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
1999 ParseInputMachO(UB);
2000 return;
2001 }
2002 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
2003 if (!checkMachOAndArchFlags(O, Filename))
2004 return;
2005 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))
2006 ProcessMachO(Filename, MachOOF);
2007 else
2008 errs() << "llvm-objdump: '" << Filename << "': "
2009 << "Object is not a Mach-O file type.\n";
2010 return;
2011 }
2012 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-8~svn345461/tools/llvm-objdump/MachODump.cpp"
, 2012)
;
2013}
2014
2015void llvm::ParseInputMachO(MachOUniversalBinary *UB) {
2016 if (!ValidateArchFlags())
2017 return;
2018
2019 auto Filename = UB->getFileName();
2020
2021 if (UniversalHeaders)
2022 printMachOUniversalHeaders(UB, !NonVerbose);
2023
2024 // If we have a list of architecture flags specified dump only those.
2025 if (!ArchAll && ArchFlags.size() != 0) {
2026 // Look for a slice in the universal binary that matches each ArchFlag.
2027 bool ArchFound;
2028 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2029 ArchFound = false;
2030 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2031 E = UB->end_objects();
2032 I != E; ++I) {
2033 if (ArchFlags[i] == I->getArchFlagName()) {
2034 ArchFound = true;
2035 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2036 I->getAsObjectFile();
2037 std::string ArchitectureName = "";
2038 if (ArchFlags.size() > 1)
2039 ArchitectureName = I->getArchFlagName();
2040 if (ObjOrErr) {
2041 ObjectFile &O = *ObjOrErr.get();
2042 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2043 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2044 } else if (auto E = isNotObjectErrorInvalidFileType(
2045 ObjOrErr.takeError())) {
2046 report_error(Filename, StringRef(), std::move(E),
2047 ArchitectureName);
2048 continue;
2049 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2050 I->getAsArchive()) {
2051 std::unique_ptr<Archive> &A = *AOrErr;
2052 outs() << "Archive : " << Filename;
2053 if (!ArchitectureName.empty())
2054 outs() << " (architecture " << ArchitectureName << ")";
2055 outs() << "\n";
2056 if (ArchiveHeaders)
2057 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2058 ArchiveMemberOffsets, ArchitectureName);
2059 Error Err = Error::success();
2060 for (auto &C : A->children(Err)) {
2061 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2062 if (!ChildOrErr) {
2063 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2064 report_error(Filename, C, std::move(E), ArchitectureName);
2065 continue;
2066 }
2067 if (MachOObjectFile *O =
2068 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2069 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
2070 }
2071 if (Err)
2072 report_error(Filename, std::move(Err));
2073 } else {
2074 consumeError(AOrErr.takeError());
2075 error("Mach-O universal file: " + Filename + " for " +
2076 "architecture " + StringRef(I->getArchFlagName()) +
2077 " is not a Mach-O file or an archive file");
2078 }
2079 }
2080 }
2081 if (!ArchFound) {
2082 errs() << "llvm-objdump: file: " + Filename + " does not contain "
2083 << "architecture: " + ArchFlags[i] + "\n";
2084 return;
2085 }
2086 }
2087 return;
2088 }
2089 // No architecture flags were specified so if this contains a slice that
2090 // matches the host architecture dump only that.
2091 if (!ArchAll) {
2092 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2093 E = UB->end_objects();
2094 I != E; ++I) {
2095 if (MachOObjectFile::getHostArch().getArchName() ==
2096 I->getArchFlagName()) {
2097 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2098 std::string ArchiveName;
2099 ArchiveName.clear();
2100 if (ObjOrErr) {
2101 ObjectFile &O = *ObjOrErr.get();
2102 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2103 ProcessMachO(Filename, MachOOF);
2104 } else if (auto E = isNotObjectErrorInvalidFileType(
2105 ObjOrErr.takeError())) {
2106 report_error(Filename, std::move(E));
2107 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2108 I->getAsArchive()) {
2109 std::unique_ptr<Archive> &A = *AOrErr;
2110 outs() << "Archive : " << Filename << "\n";
2111 if (ArchiveHeaders)
2112 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2113 ArchiveMemberOffsets);
2114 Error Err = Error::success();
2115 for (auto &C : A->children(Err)) {
2116 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2117 if (!ChildOrErr) {
2118 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2119 report_error(Filename, C, std::move(E));
2120 continue;
2121 }
2122 if (MachOObjectFile *O =
2123 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2124 ProcessMachO(Filename, O, O->getFileName());
2125 }
2126 if (Err)
2127 report_error(Filename, std::move(Err));
2128 } else {
2129 consumeError(AOrErr.takeError());
2130 error("Mach-O universal file: " + Filename + " for architecture " +
2131 StringRef(I->getArchFlagName()) +
2132 " is not a Mach-O file or an archive file");
2133 }
2134 return;
2135 }
2136 }
2137 }
2138 // Either all architectures have been specified or none have been specified
2139 // and this does not contain the host architecture so dump all the slices.
2140 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
2141 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2142 E = UB->end_objects();
2143 I != E; ++I) {
2144 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2145 std::string ArchitectureName = "";
2146 if (moreThanOneArch)
2147 ArchitectureName = I->getArchFlagName();
2148 if (ObjOrErr) {
2149 ObjectFile &Obj = *ObjOrErr.get();
2150 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
2151 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2152 } else if (auto E = isNotObjectErrorInvalidFileType(
2153 ObjOrErr.takeError())) {
2154 report_error(StringRef(), Filename, std::move(E), ArchitectureName);
2155 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2156 I->getAsArchive()) {
2157 std::unique_ptr<Archive> &A = *AOrErr;
2158 outs() << "Archive : " << Filename;
2159 if (!ArchitectureName.empty())
2160 outs() << " (architecture " << ArchitectureName << ")";
2161 outs() << "\n";
2162 if (ArchiveHeaders)
2163 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2164 ArchiveMemberOffsets, ArchitectureName);
2165 Error Err = Error::success();
2166 for (auto &C : A->children(Err)) {
2167 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2168 if (!ChildOrErr) {
2169 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2170 report_error(Filename, C, std::move(E), ArchitectureName);
2171 continue;
2172 }
2173 if (MachOObjectFile *O =
2174 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2175 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
2176 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
2177 ArchitectureName);
2178 }
2179 }
2180 if (Err)
2181 report_error(Filename, std::move(Err));
2182 } else {
2183 consumeError(AOrErr.takeError());
2184 error("Mach-O universal file: " + Filename + " for architecture " +
2185 StringRef(I->getArchFlagName()) +
2186 " is not a Mach-O file or an archive file");
2187 }
2188 }
2189}
2190
2191// The block of info used by the Symbolizer call backs.
2192struct DisassembleInfo {
2193 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2194 std::vector<SectionRef> *Sections, bool verbose)
2195 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
2196 bool verbose;
2197 MachOObjectFile *O;
2198 SectionRef S;
2199 SymbolAddressMap *AddrMap;
2200 std::vector<SectionRef> *Sections;
2201 const char *class_name = nullptr;
2202 const char *selector_name = nullptr;
2203 std::unique_ptr<char[]> method = nullptr;
2204 char *demangled_name = nullptr;
2205 uint64_t adrp_addr = 0;
2206 uint32_t adrp_inst = 0;
2207 std::unique_ptr<SymbolAddressMap> bindtable;
2208 uint32_t depth = 0;
2209};
2210
2211// SymbolizerGetOpInfo() is the operand information call back function.
2212// This is called to get the symbolic information for operand(s) of an
2213// instruction when it is being done. This routine does this from
2214// the relocation information, symbol table, etc. That block of information
2215// is a pointer to the struct DisassembleInfo that was passed when the
2216// disassembler context was created and passed to back to here when
2217// called back by the disassembler for instruction operands that could have
2218// relocation information. The address of the instruction containing operand is
2219// at the Pc parameter. The immediate value the operand has is passed in
2220// op_info->Value and is at Offset past the start of the instruction and has a
2221// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2222// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2223// names and addends of the symbolic expression to add for the operand. The
2224// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2225// information is returned then this function returns 1 else it returns 0.
2226static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2227 uint64_t Size, int TagType, void *TagBuf) {
2228 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2229 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
2230 uint64_t value = op_info->Value;
2231
2232 // Make sure all fields returned are zero if we don't set them.
2233 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
2234 op_info->Value = value;
2235
2236 // If the TagType is not the value 1 which it code knows about or if no
2237 // verbose symbolic information is wanted then just return 0, indicating no
2238 // information is being returned.
2239 if (TagType != 1 || !info->verbose)
2240 return 0;
2241
2242 unsigned int Arch = info->O->getArch();
2243 if (Arch == Triple::x86) {
2244 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2245 return 0;
2246 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2247 // TODO:
2248 // Search the external relocation entries of a fully linked image
2249 // (if any) for an entry that matches this segment offset.
2250 // uint32_t seg_offset = (Pc + Offset);
2251 return 0;
2252 }
2253 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2254 // for an entry for this section offset.
2255 uint32_t sect_addr = info->S.getAddress();
2256 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2257 bool reloc_found = false;
2258 DataRefImpl Rel;
2259 MachO::any_relocation_info RE;
2260 bool isExtern = false;
2261 SymbolRef Symbol;
2262 bool r_scattered = false;
2263 uint32_t r_value, pair_r_value, r_type;
2264 for (const RelocationRef &Reloc : info->S.relocations()) {
2265 uint64_t RelocOffset = Reloc.getOffset();
2266 if (RelocOffset == sect_offset) {
2267 Rel = Reloc.getRawDataRefImpl();
2268 RE = info->O->getRelocation(Rel);
2269 r_type = info->O->getAnyRelocationType(RE);
2270 r_scattered = info->O->isRelocationScattered(RE);
2271 if (r_scattered) {
2272 r_value = info->O->getScatteredRelocationValue(RE);
2273 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2274 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2275 DataRefImpl RelNext = Rel;
2276 info->O->moveRelocationNext(RelNext);
2277 MachO::any_relocation_info RENext;
2278 RENext = info->O->getRelocation(RelNext);
2279 if (info->O->isRelocationScattered(RENext))
2280 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2281 else
2282 return 0;
2283 }
2284 } else {
2285 isExtern = info->O->getPlainRelocationExternal(RE);
2286 if (isExtern) {
2287 symbol_iterator RelocSym = Reloc.getSymbol();
2288 Symbol = *RelocSym;
2289 }
2290 }
2291 reloc_found = true;
2292 break;
2293 }
2294 }
2295 if (reloc_found && isExtern) {
2296 Expected<StringRef> SymName = Symbol.getName();
2297 if (!SymName)
2298 report_error(info->O->getFileName(), SymName.takeError());
2299 const char *name = SymName->data();
2300 op_info->AddSymbol.Present = 1;
2301 op_info->AddSymbol.Name = name;
2302 // For i386 extern relocation entries the value in the instruction is
2303 // the offset from the symbol, and value is already set in op_info->Value.
2304 return 1;
2305 }
2306 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2307 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
2308 const char *add = GuessSymbolName(r_value, info->AddrMap);
2309 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2310 uint32_t offset = value - (r_value - pair_r_value);
2311 op_info->AddSymbol.Present = 1;
2312 if (add != nullptr)
2313 op_info->AddSymbol.Name = add;
2314 else
2315 op_info->AddSymbol.Value = r_value;
2316 op_info->SubtractSymbol.Present = 1;
2317 if (sub != nullptr)
2318 op_info->SubtractSymbol.Name = sub;
2319 else
2320 op_info->SubtractSymbol.Value = pair_r_value;
2321 op_info->Value = offset;
2322 return 1;
2323 }
2324 return 0;
2325 }
2326 if (Arch == Triple::x86_64) {
2327 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2328 return 0;
2329 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2330 // relocation entries of a linked image (if any) for an entry that matches
2331 // this segment offset.
2332 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2333 uint64_t seg_offset = Pc + Offset;
2334 bool reloc_found = false;
2335 DataRefImpl Rel;
2336 MachO::any_relocation_info RE;
2337 bool isExtern = false;
2338 SymbolRef Symbol;
2339 for (const RelocationRef &Reloc : info->O->external_relocations()) {
2340 uint64_t RelocOffset = Reloc.getOffset();
2341 if (RelocOffset == seg_offset) {
2342 Rel = Reloc.getRawDataRefImpl();
2343 RE = info->O->getRelocation(Rel);
2344 // external relocation entries should always be external.
2345 isExtern = info->O->getPlainRelocationExternal(RE);
2346 if (isExtern) {
2347 symbol_iterator RelocSym = Reloc.getSymbol();
2348 Symbol = *RelocSym;
2349 }
2350 reloc_found = true;
2351 break;
2352 }
2353 }
2354 if (reloc_found && isExtern) {
2355 // The Value passed in will be adjusted by the Pc if the instruction
2356 // adds the Pc. But for x86_64 external relocation entries the Value
2357 // is the offset from the external symbol.
2358 if (info->O->getAnyRelocationPCRel(RE))
2359 op_info->Value -= Pc + Offset + Size;
2360 Expected<StringRef> SymName = Symbol.getName();
2361 if (!SymName)
2362 report_error(info->O->getFileName(), SymName.takeError());
2363 const char *name = SymName->data();
2364 op_info->AddSymbol.Present = 1;
2365 op_info->AddSymbol.Name = name;
2366 return 1;
2367 }
2368 return 0;
2369 }
2370 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2371 // for an entry for this section offset.
2372 uint64_t sect_addr = info->S.getAddress();
2373 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2374 bool reloc_found = false;
2375 DataRefImpl Rel;
2376 MachO::any_relocation_info RE;
2377 bool isExtern = false;
2378 SymbolRef Symbol;
2379 for (const RelocationRef &Reloc : info->S.relocations()) {
2380 uint64_t RelocOffset = Reloc.getOffset();
2381 if (RelocOffset == sect_offset) {
2382 Rel = Reloc.getRawDataRefImpl();
2383 RE = info->O->getRelocation(Rel);
2384 // NOTE: Scattered relocations don't exist on x86_64.
2385 isExtern = info->O->getPlainRelocationExternal(RE);
2386 if (isExtern) {
2387 symbol_iterator RelocSym = Reloc.getSymbol();
2388 Symbol = *RelocSym;
2389 }
2390 reloc_found = true;
2391 break;
2392 }
2393 }
2394 if (reloc_found && isExtern) {
2395 // The Value passed in will be adjusted by the Pc if the instruction
2396 // adds the Pc. But for x86_64 external relocation entries the Value
2397 // is the offset from the external symbol.
2398 if (info->O->getAnyRelocationPCRel(RE))
2399 op_info->Value -= Pc + Offset + Size;
2400 Expected<StringRef> SymName = Symbol.getName();
2401 if (!SymName)
2402 report_error(info->O->getFileName(), SymName.takeError());
2403 const char *name = SymName->data();
2404 unsigned Type = info->O->getAnyRelocationType(RE);
2405 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2406 DataRefImpl RelNext = Rel;
2407 info->O->moveRelocationNext(RelNext);
2408 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2409 unsigned TypeNext = info->O->getAnyRelocationType(RENext);
2410 bool isExternNext = info->O->getPlainRelocationExternal(RENext);
2411 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
2412 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
2413 op_info->SubtractSymbol.Present = 1;
2414 op_info->SubtractSymbol.Name = name;
2415 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
2416 Symbol = *RelocSymNext;
2417 Expected<StringRef> SymNameNext = Symbol.getName();
2418 if (!SymNameNext)
2419 report_error(info->O->getFileName(), SymNameNext.takeError());
2420 name = SymNameNext->data();
2421 }
2422 }
2423 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
2424 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
2425 op_info->AddSymbol.Present = 1;
2426 op_info->AddSymbol.Name = name;
2427 return 1;
2428 }
2429 return 0;
2430 }
2431 if (Arch == Triple::arm) {
2432 if (Offset != 0 || (Size != 4 && Size != 2))
2433 return 0;
2434 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2435 // TODO:
2436 // Search the external relocation entries of a fully linked image
2437 // (if any) for an entry that matches this segment offset.
2438 // uint32_t seg_offset = (Pc + Offset);
2439 return 0;
2440 }
2441 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2442 // for an entry for this section offset.
2443 uint32_t sect_addr = info->S.getAddress();
2444 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2445 DataRefImpl Rel;
2446 MachO::any_relocation_info RE;
2447 bool isExtern = false;
2448 SymbolRef Symbol;
2449 bool r_scattered = false;
2450 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
2451 auto Reloc =
2452 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2453 uint64_t RelocOffset = Reloc.getOffset();
2454 return RelocOffset == sect_offset;
2455 });
2456
2457 if (Reloc == info->S.relocations().end())
2458 return 0;
2459
2460 Rel = Reloc->getRawDataRefImpl();
2461 RE = info->O->getRelocation(Rel);
2462 r_length = info->O->getAnyRelocationLength(RE);
2463 r_scattered = info->O->isRelocationScattered(RE);
2464 if (r_scattered) {
2465 r_value = info->O->getScatteredRelocationValue(RE);
2466 r_type = info->O->getScatteredRelocationType(RE);
2467 } else {
2468 r_type = info->O->getAnyRelocationType(RE);
2469 isExtern = info->O->getPlainRelocationExternal(RE);
2470 if (isExtern) {
2471 symbol_iterator RelocSym = Reloc->getSymbol();
2472 Symbol = *RelocSym;
2473 }
2474 }
2475 if (r_type == MachO::ARM_RELOC_HALF ||
2476 r_type == MachO::ARM_RELOC_SECTDIFF ||
2477 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
2478 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2479 DataRefImpl RelNext = Rel;
2480 info->O->moveRelocationNext(RelNext);
2481 MachO::any_relocation_info RENext;
2482 RENext = info->O->getRelocation(RelNext);
2483 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
2484 if (info->O->isRelocationScattered(RENext))
2485 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2486 }
2487
2488 if (isExtern) {
2489 Expected<StringRef> SymName = Symbol.getName();
2490 if (!SymName)
2491 report_error(info->O->getFileName(), SymName.takeError());
2492 const char *name = SymName->data();
2493 op_info->AddSymbol.Present = 1;
2494 op_info->AddSymbol.Name = name;
2495 switch (r_type) {
2496 case MachO::ARM_RELOC_HALF:
2497 if ((r_length & 0x1) == 1) {
2498 op_info->Value = value << 16 | other_half;
2499 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2500 } else {
2501 op_info->Value = other_half << 16 | value;
2502 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2503 }
2504 break;
2505 default:
2506 break;
2507 }
2508 return 1;
2509 }
2510 // If we have a branch that is not an external relocation entry then
2511 // return 0 so the code in tryAddingSymbolicOperand() can use the
2512 // SymbolLookUp call back with the branch target address to look up the
2513 // symbol and possibility add an annotation for a symbol stub.
2514 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
2515 r_type == MachO::ARM_THUMB_RELOC_BR22))
2516 return 0;
2517
2518 uint32_t offset = 0;
2519 if (r_type == MachO::ARM_RELOC_HALF ||
2520 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2521 if ((r_length & 0x1) == 1)
2522 value = value << 16 | other_half;
2523 else
2524 value = other_half << 16 | value;
2525 }
2526 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
2527 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
2528 offset = value - r_value;
2529 value = r_value;
2530 }
2531
2532 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2533 if ((r_length & 0x1) == 1)
2534 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2535 else
2536 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2537 const char *add = GuessSymbolName(r_value, info->AddrMap);
2538 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2539 int32_t offset = value - (r_value - pair_r_value);
2540 op_info->AddSymbol.Present = 1;
2541 if (add != nullptr)
2542 op_info->AddSymbol.Name = add;
2543 else
2544 op_info->AddSymbol.Value = r_value;
2545 op_info->SubtractSymbol.Present = 1;
2546 if (sub != nullptr)
2547 op_info->SubtractSymbol.Name = sub;
2548 else
2549 op_info->SubtractSymbol.Value = pair_r_value;
2550 op_info->Value = offset;
2551 return 1;
2552 }
2553
2554 op_info->AddSymbol.Present = 1;
2555 op_info->Value = offset;
2556 if (r_type == MachO::ARM_RELOC_HALF) {
2557 if ((r_length & 0x1) == 1)
2558 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2559 else
2560 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2561 }
2562 const char *add = GuessSymbolName(value, info->AddrMap);
2563 if (add != nullptr) {
2564 op_info->AddSymbol.Name = add;
2565 return 1;
2566 }
2567 op_info->AddSymbol.Value = value;
2568 return 1;
2569 }
2570 if (Arch == Triple::aarch64) {
2571 if (Offset != 0 || Size != 4)
2572 return 0;
2573 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2574 // TODO:
2575 // Search the external relocation entries of a fully linked image
2576 // (if any) for an entry that matches this segment offset.
2577 // uint64_t seg_offset = (Pc + Offset);
2578 return 0;
2579 }
2580 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2581 // for an entry for this section offset.
2582 uint64_t sect_addr = info->S.getAddress();
2583 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2584 auto Reloc =
2585 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2586 uint64_t RelocOffset = Reloc.getOffset();
2587 return RelocOffset == sect_offset;
2588 });
2589
2590 if (Reloc == info->S.relocations().end())
2591 return 0;
2592
2593 DataRefImpl Rel = Reloc->getRawDataRefImpl();
2594 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
2595 uint32_t r_type = info->O->getAnyRelocationType(RE);
2596 if (r_type == MachO::ARM64_RELOC_ADDEND) {
2597 DataRefImpl RelNext = Rel;
2598 info->O->moveRelocationNext(RelNext);
2599 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2600 if (value == 0) {
2601 value = info->O->getPlainRelocationSymbolNum(RENext);
2602 op_info->Value = value;
2603 }
2604 }
2605 // NOTE: Scattered relocations don't exist on arm64.
2606 if (!info->O->getPlainRelocationExternal(RE))
2607 return 0;
2608 Expected<StringRef> SymName = Reloc->getSymbol()->getName();
2609 if (!SymName)
2610 report_error(info->O->getFileName(), SymName.takeError());
2611 const char *name = SymName->data();
2612 op_info->AddSymbol.Present = 1;
2613 op_info->AddSymbol.Name = name;
2614
2615 switch (r_type) {
2616 case MachO::ARM64_RELOC_PAGE21:
2617 /* @page */
2618 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE1;
2619 break;
2620 case MachO::ARM64_RELOC_PAGEOFF12:
2621 /* @pageoff */
2622 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF2;
2623 break;
2624 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
2625 /* @gotpage */
2626 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE3;
2627 break;
2628 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
2629 /* @gotpageoff */
2630 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF4;
2631 break;
2632 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
2633 /* @tvlppage is not implemented in llvm-mc */
2634 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP5;
2635 break;
2636 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
2637 /* @tvlppageoff is not implemented in llvm-mc */
2638 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF6;
2639 break;
2640 default:
2641 case MachO::ARM64_RELOC_BRANCH26:
2642 op_info->VariantKind = LLVMDisassembler_VariantKind_None0;
2643 break;
2644 }
2645 return 1;
2646 }
2647 return 0;
2648}
2649
2650// GuessCstringPointer is passed the address of what might be a pointer to a
2651// literal string in a cstring section. If that address is in a cstring section
2652// it returns a pointer to that string. Else it returns nullptr.
2653static const char *GuessCstringPointer(uint64_t ReferenceValue,
2654 struct DisassembleInfo *info) {
2655 for (const auto &Load : info->O->load_commands()) {
2656 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2657 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2658 for (unsigned J = 0; J < Seg.nsects; ++J) {
2659 MachO::section_64 Sec = info->O->getSection64(Load, J);
2660 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2661 if (section_type == MachO::S_CSTRING_LITERALS &&
2662 ReferenceValue >= Sec.addr &&
2663 ReferenceValue < Sec.addr + Sec.size) {
2664 uint64_t sect_offset = ReferenceValue - Sec.addr;
2665 uint64_t object_offset = Sec.offset + sect_offset;
2666 StringRef MachOContents = info->O->getData();
2667 uint64_t object_size = MachOContents.size();
2668 const char *object_addr = (const char *)MachOContents.data();
2669 if (object_offset < object_size) {
2670 const char *name = object_addr + object_offset;
2671 return name;
2672 } else {
2673 return nullptr;
2674 }
2675 }
2676 }
2677 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2678 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2679 for (unsigned J = 0; J < Seg.nsects; ++J) {
2680 MachO::section Sec = info->O->getSection(Load, J);
2681 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2682 if (section_type == MachO::S_CSTRING_LITERALS &&
2683 ReferenceValue >= Sec.addr &&
2684 ReferenceValue < Sec.addr + Sec.size) {
2685 uint64_t sect_offset = ReferenceValue - Sec.addr;
2686 uint64_t object_offset = Sec.offset + sect_offset;
2687 StringRef MachOContents = info->O->getData();
2688 uint64_t object_size = MachOContents.size();
2689 const char *object_addr = (const char *)MachOContents.data();
2690 if (object_offset < object_size) {
2691 const char *name = object_addr + object_offset;
2692 return name;
2693 } else {
2694 return nullptr;
2695 }
2696 }
2697 }
2698 }
2699 }
2700 return nullptr;
2701}
2702
2703// GuessIndirectSymbol returns the name of the indirect symbol for the
2704// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
2705// an address of a symbol stub or a lazy or non-lazy pointer to associate the
2706// symbol name being referenced by the stub or pointer.
2707static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
2708 struct DisassembleInfo *info) {
2709 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
2710 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
2711 for (const auto &Load : info->O->load_commands()) {
2712 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2713 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2714 for (unsigned J = 0; J < Seg.nsects; ++J) {
2715 MachO::section_64 Sec = info->O->getSection64(Load, J);
2716 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2717 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2718 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2719 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2720 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2721 section_type == MachO::S_SYMBOL_STUBS) &&
2722 ReferenceValue >= Sec.addr &&
2723 ReferenceValue < Sec.addr + Sec.size) {
2724 uint32_t stride;
2725 if (section_type == MachO::S_SYMBOL_STUBS)
2726 stride = Sec.reserved2;
2727 else
2728 stride = 8;
2729 if (stride == 0)
2730 return nullptr;
2731 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2732 if (index < Dysymtab.nindirectsyms) {
2733 uint32_t indirect_symbol =
2734 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2735 if (indirect_symbol < Symtab.nsyms) {
2736 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2737 SymbolRef Symbol = *Sym;
2738 Expected<StringRef> SymName = Symbol.getName();
2739 if (!SymName)
2740 report_error(info->O->getFileName(), SymName.takeError());
2741 const char *name = SymName->data();
2742 return name;
2743 }
2744 }
2745 }
2746 }
2747 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2748 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2749 for (unsigned J = 0; J < Seg.nsects; ++J) {
2750 MachO::section Sec = info->O->getSection(Load, J);
2751 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2752 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2753 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2754 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2755 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2756 section_type == MachO::S_SYMBOL_STUBS) &&
2757 ReferenceValue >= Sec.addr &&
2758 ReferenceValue < Sec.addr + Sec.size) {
2759 uint32_t stride;
2760 if (section_type == MachO::S_SYMBOL_STUBS)
2761 stride = Sec.reserved2;
2762 else
2763 stride = 4;
2764 if (stride == 0)
2765 return nullptr;
2766 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2767 if (index < Dysymtab.nindirectsyms) {
2768 uint32_t indirect_symbol =
2769 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2770 if (indirect_symbol < Symtab.nsyms) {
2771 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2772 SymbolRef Symbol = *Sym;
2773 Expected<StringRef> SymName = Symbol.getName();
2774 if (!SymName)
2775 report_error(info->O->getFileName(), SymName.takeError());
2776 const char *name = SymName->data();
2777 return name;
2778 }
2779 }
2780 }
2781 }
2782 }
2783 }
2784 return nullptr;
2785}
2786
2787// method_reference() is called passing it the ReferenceName that might be
2788// a reference it to an Objective-C method call. If so then it allocates and
2789// assembles a method call string with the values last seen and saved in
2790// the DisassembleInfo's class_name and selector_name fields. This is saved
2791// into the method field of the info and any previous string is free'ed.
2792// Then the class_name field in the info is set to nullptr. The method call
2793// string is set into ReferenceName and ReferenceType is set to
2794// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
2795// then both ReferenceType and ReferenceName are left unchanged.
2796static void method_reference(struct DisassembleInfo *info,
2797 uint64_t *ReferenceType,
2798 const char **ReferenceName) {
2799 unsigned int Arch = info->O->getArch();
2800 if (*ReferenceName != nullptr) {
2801 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
2802 if (info->selector_name != nullptr) {
2803 if (info->class_name != nullptr) {
2804 info->method = llvm::make_unique<char[]>(
2805 5 + strlen(info->class_name) + strlen(info->selector_name));
2806 char *method = info->method.get();
2807 if (method != nullptr) {
2808 strcpy(method, "+[");
2809 strcat(method, info->class_name);
2810 strcat(method, " ");
2811 strcat(method, info->selector_name);
2812 strcat(method, "]");
2813 *ReferenceName = method;
2814 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2815 }
2816 } else {
2817 info->method =
2818 llvm::make_unique<char[]>(9 + strlen(info->selector_name));
2819 char *method = info->method.get();
2820 if (method != nullptr) {
2821 if (Arch == Triple::x86_64)
2822 strcpy(method, "-[%rdi ");
2823 else if (Arch == Triple::aarch64)
2824 strcpy(method, "-[x0 ");
2825 else
2826 strcpy(method, "-[r? ");
2827 strcat(method, info->selector_name);
2828 strcat(method, "]");
2829 *ReferenceName = method;
2830 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2831 }
2832 }
2833 info->class_name = nullptr;
2834 }
2835 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
2836 if (info->selector_name != nullptr) {
2837 info->method =
2838 llvm::make_unique<char[]>(17 + strlen(info->selector_name));
2839 char *method = info->method.get();
2840 if (method != nullptr) {
2841 if (Arch == Triple::x86_64)
2842 strcpy(method, "-[[%rdi super] ");
2843 else if (Arch == Triple::aarch64)
2844 strcpy(method, "-[[x0 super] ");
2845 else
2846 strcpy(method, "-[[r? super] ");
2847 strcat(method, info->selector_name);
2848 strcat(method, "]");
2849 *ReferenceName = method;
2850 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2851 }
2852 info->class_name = nullptr;
2853 }
2854 }
2855 }
2856}
2857
2858// GuessPointerPointer() is passed the address of what might be a pointer to
2859// a reference to an Objective-C class, selector, message ref or cfstring.
2860// If so the value of the pointer is returned and one of the booleans are set
2861// to true. If not zero is returned and all the booleans are set to false.
2862static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
2863 struct DisassembleInfo *info,
2864 bool &classref, bool &selref, bool &msgref,
2865 bool &cfstring) {
2866 classref = false;
2867 selref = false;
2868 msgref = false;
2869 cfstring = false;
2870 for (const auto &Load : info->O->load_commands()) {
2871 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2872 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2873 for (unsigned J = 0; J < Seg.nsects; ++J) {
2874 MachO::section_64 Sec = info->O->getSection64(Load, J);
2875 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
2876 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2877 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
2878 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
2879 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
2880 ReferenceValue >= Sec.addr &&
2881 ReferenceValue < Sec.addr + Sec.size) {
2882 uint64_t sect_offset = ReferenceValue - Sec.addr;
2883 uint64_t object_offset = Sec.offset + sect_offset;
2884 StringRef MachOContents = info->O->getData();
2885 uint64_t object_size = MachOContents.size();
2886 const char *object_addr = (const char *)MachOContents.data();
2887 if (object_offset < object_size) {
2888 uint64_t pointer_value;
2889 memcpy(&pointer_value, object_addr + object_offset,
2890 sizeof(uint64_t));
2891 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2892 sys::swapByteOrder(pointer_value);
2893 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
2894 selref = true;
2895 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2896 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
2897 classref = true;
2898 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
2899 ReferenceValue + 8 < Sec.addr + Sec.size) {
2900 msgref = true;
2901 memcpy(&pointer_value, object_addr + object_offset + 8,
2902 sizeof(uint64_t));
2903 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2904 sys::swapByteOrder(pointer_value);
2905 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
2906 cfstring = true;
2907 return pointer_value;
2908 } else {
2909 return 0;
2910 }
2911 }
2912 }
2913 }
2914 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
2915 }
2916 return 0;
2917}
2918
2919// get_pointer_64 returns a pointer to the bytes in the object file at the
2920// Address from a section in the Mach-O file. And indirectly returns the
2921// offset into the section, number of bytes left in the section past the offset
2922// and which section is was being referenced. If the Address is not in a
2923// section nullptr is returned.
2924static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
2925 uint32_t &left, SectionRef &S,
2926 DisassembleInfo *info,
2927 bool objc_only = false) {
2928 offset = 0;
2929 left = 0;
2930 S = SectionRef();
2931 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
2932 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
2933 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
2934 if (SectSize == 0)
2935 continue;
2936 if (objc_only) {
2937 StringRef SectName;
2938 ((*(info->Sections))[SectIdx]).getName(SectName);
2939 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
2940 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
2941 if (SegName != "__OBJC" && SectName != "__cstring")
2942 continue;
2943 }
2944 if (Address >= SectAddress && Address < SectAddress + SectSize) {
2945 S = (*(info->Sections))[SectIdx];
2946 offset = Address - SectAddress;
2947 left = SectSize - offset;
2948 StringRef SectContents;
2949 ((*(info->Sections))[SectIdx]).getContents(SectContents);
2950 return SectContents.data() + offset;
2951 }
2952 }
2953 return nullptr;
2954}
2955
2956static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
2957 uint32_t &left, SectionRef &S,
2958 DisassembleInfo *info,
2959 bool objc_only = false) {
2960 return get_pointer_64(Address, offset, left, S, info, objc_only);
2961}
2962
2963// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
2964// the symbol indirectly through n_value. Based on the relocation information
2965// for the specified section offset in the specified section reference.
2966// If no relocation information is found and a non-zero ReferenceValue for the
2967// symbol is passed, look up that address in the info's AddrMap.
2968static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
2969 DisassembleInfo *info, uint64_t &n_value,
2970 uint64_t ReferenceValue = 0) {
2971 n_value = 0;
2972 if (!info->verbose)
2973 return nullptr;
2974
2975 // See if there is an external relocation entry at the sect_offset.
2976 bool reloc_found = false;
2977 DataRefImpl Rel;
2978 MachO::any_relocation_info RE;
2979 bool isExtern = false;
2980 SymbolRef Symbol;
2981 for (const RelocationRef &Reloc : S.relocations()) {
2982 uint64_t RelocOffset = Reloc.getOffset();
2983 if (RelocOffset == sect_offset) {
2984 Rel = Reloc.getRawDataRefImpl();
2985 RE = info->O->getRelocation(Rel);
2986 if (info->O->isRelocationScattered(RE))
2987 continue;
2988 isExtern = info->O->getPlainRelocationExternal(RE);
2989 if (isExtern) {
2990 symbol_iterator RelocSym = Reloc.getSymbol();
2991 Symbol = *RelocSym;
2992 }
2993 reloc_found = true;
2994 break;
2995 }
2996 }
2997 // If there is an external relocation entry for a symbol in this section
2998 // at this section_offset then use that symbol's value for the n_value
2999 // and return its name.
3000 const char *SymbolName = nullptr;
3001 if (reloc_found && isExtern) {
3002 n_value = Symbol.getValue();
3003 Expected<StringRef> NameOrError = Symbol.getName();
3004 if (!NameOrError)
3005 report_error(info->O->getFileName(), NameOrError.takeError());
3006 StringRef Name = *NameOrError;
3007 if (!Name.empty()) {
3008 SymbolName = Name.data();
3009 return SymbolName;
3010 }
3011 }
3012
3013 // TODO: For fully linked images, look through the external relocation
3014 // entries off the dynamic symtab command. For these the r_offset is from the
3015 // start of the first writeable segment in the Mach-O file. So the offset
3016 // to this section from that segment is passed to this routine by the caller,
3017 // as the database_offset. Which is the difference of the section's starting
3018 // address and the first writable segment.
3019 //
3020 // NOTE: need add passing the database_offset to this routine.
3021
3022 // We did not find an external relocation entry so look up the ReferenceValue
3023 // as an address of a symbol and if found return that symbol's name.
3024 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
3025
3026 return SymbolName;
3027}
3028
3029static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3030 DisassembleInfo *info,
3031 uint32_t ReferenceValue) {
3032 uint64_t n_value64;
3033 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
3034}
3035
3036// These are structs in the Objective-C meta data and read to produce the
3037// comments for disassembly. While these are part of the ABI they are no
3038// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
3039// .
3040
3041// The cfstring object in a 64-bit Mach-O file.
3042struct cfstring64_t {
3043 uint64_t isa; // class64_t * (64-bit pointer)
3044 uint64_t flags; // flag bits
3045 uint64_t characters; // char * (64-bit pointer)
3046 uint64_t length; // number of non-NULL characters in above
3047};
3048
3049// The class object in a 64-bit Mach-O file.
3050struct class64_t {
3051 uint64_t isa; // class64_t * (64-bit pointer)
3052 uint64_t superclass; // class64_t * (64-bit pointer)
3053 uint64_t cache; // Cache (64-bit pointer)
3054 uint64_t vtable; // IMP * (64-bit pointer)
3055 uint64_t data; // class_ro64_t * (64-bit pointer)
3056};
3057
3058struct class32_t {
3059 uint32_t isa; /* class32_t * (32-bit pointer) */
3060 uint32_t superclass; /* class32_t * (32-bit pointer) */
3061 uint32_t cache; /* Cache (32-bit pointer) */
3062 uint32_t vtable; /* IMP * (32-bit pointer) */
3063 uint32_t data; /* class_ro32_t * (32-bit pointer) */
3064};
3065
3066struct class_ro64_t {
3067 uint32_t flags;
3068 uint32_t instanceStart;
3069 uint32_t instanceSize;
3070 uint32_t reserved;
3071 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3072 uint64_t name; // const char * (64-bit pointer)
3073 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3074 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3075 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3076 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3077 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3078};
3079
3080struct class_ro32_t {
3081 uint32_t flags;
3082 uint32_t instanceStart;
3083 uint32_t instanceSize;
3084 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3085 uint32_t name; /* const char * (32-bit pointer) */
3086 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3087 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3088 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3089 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3090 uint32_t baseProperties; /* const struct objc_property_list *
3091 (32-bit pointer) */
3092};
3093
3094/* Values for class_ro{64,32}_t->flags */
3095#define RO_META(1 << 0) (1 << 0)
3096#define RO_ROOT(1 << 1) (1 << 1)
3097#define RO_HAS_CXX_STRUCTORS(1 << 2) (1 << 2)
3098
3099struct method_list64_t {
3100 uint32_t entsize;
3101 uint32_t count;
3102 /* struct method64_t first; These structures follow inline */
3103};
3104
3105struct method_list32_t {
3106 uint32_t entsize;
3107 uint32_t count;
3108 /* struct method32_t first; These structures follow inline */
3109};
3110
3111struct method64_t {
3112 uint64_t name; /* SEL (64-bit pointer) */
3113 uint64_t types; /* const char * (64-bit pointer) */
3114 uint64_t imp; /* IMP (64-bit pointer) */
3115};
3116
3117struct method32_t {
3118 uint32_t name; /* SEL (32-bit pointer) */
3119 uint32_t types; /* const char * (32-bit pointer) */
3120 uint32_t imp; /* IMP (32-bit pointer) */
3121};
3122
3123struct protocol_list64_t {
3124 uint64_t count; /* uintptr_t (a 64-bit value) */
3125 /* struct protocol64_t * list[0]; These pointers follow inline */
3126};
3127
3128struct protocol_list32_t {
3129 uint32_t count; /* uintptr_t (a 32-bit value) */
3130 /* struct protocol32_t * list[0]; These pointers follow inline */
3131};
3132
3133struct protocol64_t {
3134 uint64_t isa; /* id * (64-bit pointer) */
3135 uint64_t name; /* const char * (64-bit pointer) */
3136 uint64_t protocols; /* struct protocol_list64_t *
3137 (64-bit pointer) */
3138 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3139 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3140 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3141 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3142 uint64_t instanceProperties; /* struct objc_property_list *
3143 (64-bit pointer) */
3144};
3145
3146struct protocol32_t {
3147 uint32_t isa; /* id * (32-bit pointer) */
3148 uint32_t name; /* const char * (32-bit pointer) */
3149 uint32_t protocols; /* struct protocol_list_t *
3150 (32-bit pointer) */
3151 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3152 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3153 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3154 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3155 uint32_t instanceProperties; /* struct objc_property_list *
3156 (32-bit pointer) */
3157};
3158
3159struct ivar_list64_t {
3160 uint32_t entsize;
3161 uint32_t count;
3162 /* struct ivar64_t first; These structures follow inline */
3163};
3164
3165struct ivar_list32_t {
3166 uint32_t entsize;
3167 uint32_t count;
3168 /* struct ivar32_t first; These structures follow inline */
3169};
3170
3171struct ivar64_t {
3172 uint64_t offset; /* uintptr_t * (64-bit pointer) */
3173 uint64_t name; /* const char * (64-bit pointer) */
3174 uint64_t type; /* const char * (64-bit pointer) */
3175 uint32_t alignment;
3176 uint32_t size;
3177};
3178
3179struct ivar32_t {
3180 uint32_t offset; /* uintptr_t * (32-bit pointer) */
3181 uint32_t name; /* const char * (32-bit pointer) */
3182 uint32_t type; /* const char * (32-bit pointer) */
3183 uint32_t alignment;
3184 uint32_t size;
3185};
3186
3187struct objc_property_list64 {
3188 uint32_t entsize;
3189 uint32_t count;
3190 /* struct objc_property64 first; These structures follow inline */
3191};
3192
3193struct objc_property_list32 {
3194 uint32_t entsize;
3195 uint32_t count;
3196 /* struct objc_property32 first; These structures follow inline */
3197};
3198
3199struct objc_property64 {
3200 uint64_t name; /* const char * (64-bit pointer) */
3201 uint64_t attributes; /* const char * (64-bit pointer) */
3202};
3203
3204struct objc_property32 {
3205 uint32_t name; /* const char * (32-bit pointer) */
3206 uint32_t attributes; /* const char * (32-bit pointer) */
3207};
3208
3209struct category64_t {
3210 uint64_t name; /* const char * (64-bit pointer) */
3211 uint64_t cls; /* struct class_t * (64-bit pointer) */
3212 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3213 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3214 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3215 uint64_t instanceProperties; /* struct objc_property_list *
3216 (64-bit pointer) */
3217};
3218
3219struct category32_t {
3220 uint32_t name; /* const char * (32-bit pointer) */
3221 uint32_t cls; /* struct class_t * (32-bit pointer) */
3222 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3223 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3224 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3225 uint32_t instanceProperties; /* struct objc_property_list *
3226 (32-bit pointer) */
3227};
3228
3229struct objc_image_info64 {
3230 uint32_t version;
3231 uint32_t flags;
3232};
3233struct objc_image_info32 {
3234 uint32_t version;
3235 uint32_t flags;
3236};
3237struct imageInfo_t {
3238 uint32_t version;
3239 uint32_t flags;
3240};
3241/* masks for objc_image_info.flags */
3242#define OBJC_IMAGE_IS_REPLACEMENT(1 << 0) (1 << 0)
3243#define OBJC_IMAGE_SUPPORTS_GC(1 << 1) (1 << 1)
3244#define OBJC_IMAGE_IS_SIMULATED(1 << 5) (1 << 5)
3245#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES(1 << 6) (1 << 6)
3246
3247struct message_ref64 {
3248 uint64_t imp; /* IMP (64-bit pointer) */
3249 uint64_t sel; /* SEL (64-bit pointer) */
3250};
3251
3252struct message_ref32 {
3253 uint32_t imp; /* IMP (32-bit pointer) */
3254 uint32_t sel; /* SEL (32-bit pointer) */
3255};
3256
3257// Objective-C 1 (32-bit only) meta data structs.
3258
3259struct objc_module_t {
3260 uint32_t version;
3261 uint32_t size;
3262 uint32_t name; /* char * (32-bit pointer) */
3263 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3264};
3265
3266struct objc_symtab_t {
3267 uint32_t sel_ref_cnt;
3268 uint32_t refs; /* SEL * (32-bit pointer) */
3269 uint16_t cls_def_cnt;
3270 uint16_t cat_def_cnt;
3271 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3272};
3273
3274struct objc_class_t {
3275 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3276 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3277 uint32_t name; /* const char * (32-bit pointer) */
3278 int32_t version;
3279 int32_t info;
3280 int32_t instance_size;
3281 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3282 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3283 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3284 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3285};
3286
3287#define CLS_GETINFO(cls, infomask)((cls)->info & (infomask)) ((cls)->info & (infomask))
3288// class is not a metaclass
3289#define CLS_CLASS0x1 0x1
3290// class is a metaclass
3291#define CLS_META0x2 0x2
3292
3293struct objc_category_t {
3294 uint32_t category_name; /* char * (32-bit pointer) */
3295 uint32_t class_name; /* char * (32-bit pointer) */
3296 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3297 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3298 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3299};
3300
3301struct objc_ivar_t {
3302 uint32_t ivar_name; /* char * (32-bit pointer) */
3303 uint32_t ivar_type; /* char * (32-bit pointer) */
3304 int32_t ivar_offset;
3305};
3306
3307struct objc_ivar_list_t {
3308 int32_t ivar_count;
3309 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
3310};
3311
3312struct objc_method_list_t {
3313 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3314 int32_t method_count;
3315 // struct objc_method_t method_list[1]; /* variable length structure */
3316};
3317
3318struct objc_method_t {
3319 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3320 uint32_t method_types; /* char * (32-bit pointer) */
3321 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3322 (32-bit pointer) */
3323};
3324
3325struct objc_protocol_list_t {
3326 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3327 int32_t count;
3328 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3329 // (32-bit pointer) */
3330};
3331
3332struct objc_protocol_t {
3333 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3334 uint32_t protocol_name; /* char * (32-bit pointer) */
3335 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3336 uint32_t instance_methods; /* struct objc_method_description_list *
3337 (32-bit pointer) */
3338 uint32_t class_methods; /* struct objc_method_description_list *
3339 (32-bit pointer) */
3340};
3341
3342struct objc_method_description_list_t {
3343 int32_t count;
3344 // struct objc_method_description_t list[1];
3345};
3346
3347struct objc_method_description_t {
3348 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3349 uint32_t types; /* char * (32-bit pointer) */
3350};
3351
3352inline void swapStruct(struct cfstring64_t &cfs) {
3353 sys::swapByteOrder(cfs.isa);
3354 sys::swapByteOrder(cfs.flags);
3355 sys::swapByteOrder(cfs.characters);
3356 sys::swapByteOrder(cfs.length);
3357}
3358
3359inline void swapStruct(struct class64_t &c) {
3360 sys::swapByteOrder(c.isa);
3361 sys::swapByteOrder(c.superclass);
3362 sys::swapByteOrder(c.cache);
3363 sys::swapByteOrder(c.vtable);
3364 sys::swapByteOrder(c.data);
3365}
3366
3367inline void swapStruct(struct class32_t &c) {
3368 sys::swapByteOrder(c.isa);
3369 sys::swapByteOrder(c.superclass);
3370 sys::swapByteOrder(c.cache);
3371 sys::swapByteOrder(c.vtable);
3372 sys::swapByteOrder(c.data);
3373}
3374
3375inline void swapStruct(struct class_ro64_t &cro) {
3376 sys::swapByteOrder(cro.flags);
3377 sys::swapByteOrder(cro.instanceStart);
3378 sys::swapByteOrder(cro.instanceSize);
3379 sys::swapByteOrder(cro.reserved);
3380 sys::swapByteOrder(cro.ivarLayout);
3381 sys::swapByteOrder(cro.name);
3382 sys::swapByteOrder(cro.baseMethods);
3383 sys::swapByteOrder(cro.baseProtocols);
3384 sys::swapByteOrder(cro.ivars);
3385 sys::swapByteOrder(cro.weakIvarLayout);
3386 sys::swapByteOrder(cro.baseProperties);
3387}
3388
3389inline void swapStruct(struct class_ro32_t &cro) {
3390 sys::swapByteOrder(cro.flags);
3391 sys::swapByteOrder(cro.instanceStart);
3392 sys::swapByteOrder(cro.instanceSize);
3393 sys::swapByteOrder(cro.ivarLayout);
3394 sys::swapByteOrder(cro.name);
3395 sys::swapByteOrder(cro.baseMethods);
3396 sys::swapByteOrder(cro.baseProtocols);
3397 sys::swapByteOrder(cro.ivars);
3398 sys::swapByteOrder(cro.weakIvarLayout);
3399 sys::swapByteOrder(cro.baseProperties);
3400}
3401
3402inline void swapStruct(struct method_list64_t &ml) {
3403 sys::swapByteOrder(ml.entsize);
3404 sys::swapByteOrder(ml.count);
3405}
3406
3407inline void swapStruct(struct method_list32_t &ml) {
3408 sys::swapByteOrder(ml.entsize);
3409 sys::swapByteOrder(ml.count);
3410}
3411
3412inline void swapStruct(struct method64_t &m) {
3413 sys::swapByteOrder(m.name);
3414 sys::swapByteOrder(m.types);
3415 sys::swapByteOrder(m.imp);
3416}
3417
3418inline void swapStruct(struct method32_t &m) {
3419 sys::swapByteOrder(m.name);
3420 sys::swapByteOrder(m.types);
3421 sys::swapByteOrder(m.imp);
3422}
3423
3424inline void swapStruct(struct protocol_list64_t &pl) {
3425 sys::swapByteOrder(pl.count);
3426}
3427
3428inline void swapStruct(struct protocol_list32_t &pl) {
3429 sys::swapByteOrder(pl.count);
3430}
3431
3432inline void swapStruct(struct protocol64_t &p) {
3433 sys::swapByteOrder(p.isa);
3434 sys::swapByteOrder(p.name);
3435 sys::swapByteOrder(p.protocols);
3436 sys::swapByteOrder(p.instanceMethods);
3437 sys::swapByteOrder(p.classMethods);
3438 sys::swapByteOrder(p.optionalInstanceMethods);
3439 sys::swapByteOrder(p.optionalClassMethods);
3440 sys::swapByteOrder(p.instanceProperties);
3441}
3442
3443inline void swapStruct(struct protocol32_t &p) {
3444 sys::swapByteOrder(p.isa);
3445 sys::swapByteOrder(p.name);
3446 sys::swapByteOrder(p.protocols);
3447 sys::swapByteOrder(p.instanceMethods);
3448 sys::swapByteOrder(p.classMethods);
3449 sys::swapByteOrder(p.optionalInstanceMethods);
3450 sys::swapByteOrder(p.optionalClassMethods);
3451 sys::swapByteOrder(p.instanceProperties);
3452}
3453
3454inline void swapStruct(struct ivar_list64_t &il) {
3455 sys::swapByteOrder(il.entsize);
3456 sys::swapByteOrder(il.count);
3457}
3458
3459inline void swapStruct(struct ivar_list32_t &il) {
3460 sys::swapByteOrder(il.entsize);
3461 sys::swapByteOrder(il.count);
3462}
3463
3464inline void swapStruct(struct ivar64_t &i) {
3465 sys::swapByteOrder(i.offset);
3466 sys::swapByteOrder(i.name);
3467 sys::swapByteOrder(i.type);
3468 sys::swapByteOrder(i.alignment);
3469 sys::swapByteOrder(i.size);
3470}
3471
3472inline void swapStruct(struct ivar32_t &i) {
3473 sys::swapByteOrder(i.offset);
3474 sys::swapByteOrder(i.name);
3475 sys::swapByteOrder(i.type);
3476 sys::swapByteOrder(i.alignment);
3477 sys::swapByteOrder(i.size);
3478}
3479
3480inline void swapStruct(struct objc_property_list64 &pl) {
3481 sys::swapByteOrder(pl.entsize);
3482 sys::swapByteOrder(pl.count);
3483}
3484
3485inline void swapStruct(struct objc_property_list32 &pl) {
3486 sys::swapByteOrder(pl.entsize);
3487 sys::swapByteOrder(pl.count);
3488}
3489
3490inline void swapStruct(struct objc_property64 &op) {
3491 sys::swapByteOrder(op.name);
3492 sys::swapByteOrder(op.attributes);
3493}
3494
3495inline void swapStruct(struct objc_property32 &op) {
3496 sys::swapByteOrder(op.name);
3497 sys::swapByteOrder(op.attributes);
3498}
3499
3500inline void swapStruct(struct category64_t &c) {
3501 sys::swapByteOrder(c.name);
3502 sys::swapByteOrder(c.cls);
3503 sys::swapByteOrder(c.instanceMethods);
3504 sys::swapByteOrder(c.classMethods);
3505 sys::swapByteOrder(c.protocols);
3506 sys::swapByteOrder(c.instanceProperties);
3507}
3508
3509inline void swapStruct(struct category32_t &c) {
3510 sys::swapByteOrder(c.name);
3511 sys::swapByteOrder(c.cls);
3512 sys::swapByteOrder(c.instanceMethods);
3513 sys::swapByteOrder(c.classMethods);
3514 sys::swapByteOrder(c.protocols);
3515 sys::swapByteOrder(c.instanceProperties);
3516}
3517
3518inline void swapStruct(struct objc_image_info64 &o) {
3519 sys::swapByteOrder(o.version);
3520 sys::swapByteOrder(o.flags);
3521}
3522
3523inline void swapStruct(struct objc_image_info32 &o) {
3524 sys::swapByteOrder(o.version);
3525 sys::swapByteOrder(o.flags);
3526}
3527
3528inline void swapStruct(struct imageInfo_t &o) {
3529 sys::swapByteOrder(o.version);
3530 sys::swapByteOrder(o.flags);
3531}
3532
3533inline void swapStruct(struct message_ref64 &mr) {
3534 sys::swapByteOrder(mr.imp);
3535 sys::swapByteOrder(mr.sel);
3536}
3537
3538inline void swapStruct(struct message_ref32 &mr) {
3539 sys::swapByteOrder(mr.imp);
3540 sys::swapByteOrder(mr.sel);
3541}
3542
3543inline void swapStruct(struct objc_module_t &module) {
3544 sys::swapByteOrder(module.version);
3545 sys::swapByteOrder(module.size);
3546 sys::swapByteOrder(module.name);
3547 sys::swapByteOrder(module.symtab);
3548}
3549
3550inline void swapStruct(struct objc_symtab_t &symtab) {
3551 sys::swapByteOrder(symtab.sel_ref_cnt);
3552 sys::swapByteOrder(symtab.refs);
3553 sys::swapByteOrder(symtab.cls_def_cnt);
3554 sys::swapByteOrder(symtab.cat_def_cnt);
3555}
3556
3557inline void swapStruct(struct objc_class_t &objc_class) {
3558 sys::swapByteOrder(objc_class.isa);
3559 sys::swapByteOrder(objc_class.super_class);
3560 sys::swapByteOrder(objc_class.name);
3561 sys::swapByteOrder(objc_class.version);
3562 sys::swapByteOrder(objc_class.info);
3563 sys::swapByteOrder(objc_class.instance_size);
3564 sys::swapByteOrder(objc_class.ivars);
3565 sys::swapByteOrder(objc_class.methodLists);
3566 sys::swapByteOrder(objc_class.cache);
3567 sys::swapByteOrder(objc_class.protocols);
3568}
3569
3570inline void swapStruct(struct objc_category_t &objc_category) {
3571 sys::swapByteOrder(objc_category.category_name);
3572 sys::swapByteOrder(objc_category.class_name);
3573 sys::swapByteOrder(objc_category.instance_methods);
3574 sys::swapByteOrder(objc_category.class_methods);
3575 sys::swapByteOrder(objc_category.protocols);
3576}
3577
3578inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
3579 sys::swapByteOrder(objc_ivar_list.ivar_count);
3580}
3581
3582inline void swapStruct(struct objc_ivar_t &objc_ivar) {
3583 sys::swapByteOrder(objc_ivar.ivar_name);
3584 sys::swapByteOrder(objc_ivar.ivar_type);
3585 sys::swapByteOrder(objc_ivar.ivar_offset);
3586}
3587
3588inline void swapStruct(struct objc_method_list_t &method_list) {
3589 sys::swapByteOrder(method_list.obsolete);
3590 sys::swapByteOrder(method_list.method_count);
3591}
3592
3593inline void swapStruct(struct objc_method_t &method) {
3594 sys::swapByteOrder(method.method_name);
3595 sys::swapByteOrder(method.method_types);
3596 sys::swapByteOrder(method.method_imp);
3597}
3598
3599inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
3600 sys::swapByteOrder(protocol_list.next);
3601 sys::swapByteOrder(protocol_list.count);
3602}
3603
3604inline void swapStruct(struct objc_protocol_t &protocol) {
3605 sys::swapByteOrder(protocol.isa);
3606 sys::swapByteOrder(protocol.protocol_name);
3607 sys::swapByteOrder(protocol.protocol_list);
3608 sys::swapByteOrder(protocol.instance_methods);
3609 sys::swapByteOrder(protocol.class_methods);
3610}
3611
3612inline void swapStruct(struct objc_method_description_list_t &mdl) {
3613 sys::swapByteOrder(mdl.count);
3614}
3615
3616inline void swapStruct(struct objc_method_description_t &md) {
3617 sys::swapByteOrder(md.name);
3618 sys::swapByteOrder(md.types);
3619}
3620
3621static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
3622 struct DisassembleInfo *info);
3623
3624// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
3625// to an Objective-C class and returns the class name. It is also passed the
3626// address of the pointer, so when the pointer is zero as it can be in an .o
3627// file, that is used to look for an external relocation entry with a symbol
3628// name.
3629static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
3630 uint64_t ReferenceValue,
3631 struct DisassembleInfo *info) {
3632 const char *r;
3633 uint32_t offset, left;
3634 SectionRef S;
3635
3636 // The pointer_value can be 0 in an object file and have a relocation
3637 // entry for the class symbol at the ReferenceValue (the address of the
3638 // pointer).
3639 if (pointer_value == 0) {
3640 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3641 if (r == nullptr || left < sizeof(uint64_t))
3642 return nullptr;
3643 uint64_t n_value;
3644 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3645 if (symbol_name == nullptr)
3646 return nullptr;
3647 const char *class_name = strrchr(symbol_name, '$');
3648 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
3649 return class_name + 2;
3650 else
3651 return nullptr;
3652 }
3653
3654 // The case were the pointer_value is non-zero and points to a class defined
3655 // in this Mach-O file.
3656 r = get_pointer_64(pointer_value, offset, left, S, info);
3657 if (r == nullptr || left < sizeof(struct class64_t))
3658 return nullptr;
3659 struct class64_t c;
3660 memcpy(&c, r, sizeof(struct class64_t));
3661 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3662 swapStruct(c);
3663 if (c.data == 0)
3664 return nullptr;
3665 r = get_pointer_64(c.data, offset, left, S, info);
3666 if (r == nullptr || left < sizeof(struct class_ro64_t))
3667 return nullptr;
3668 struct class_ro64_t cro;
3669 memcpy(&cro, r, sizeof(struct class_ro64_t));
3670 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3671 swapStruct(cro);
3672 if (cro.name == 0)
3673 return nullptr;
3674 const char *name = get_pointer_64(cro.name, offset, left, S, info);
3675 return name;
3676}
3677
3678// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
3679// pointer to a cfstring and returns its name or nullptr.
3680static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
3681 struct DisassembleInfo *info) {
3682 const char *r, *name;
3683 uint32_t offset, left;
3684 SectionRef S;
3685 struct cfstring64_t cfs;
3686 uint64_t cfs_characters;
3687
3688 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3689 if (r == nullptr || left < sizeof(struct cfstring64_t))
3690 return nullptr;
3691 memcpy(&cfs, r, sizeof(struct cfstring64_t));
3692 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3693 swapStruct(cfs);
3694 if (cfs.characters == 0) {
3695 uint64_t n_value;
3696 const char *symbol_name = get_symbol_64(
3697 offset + offsetof(struct cfstring64_t, characters)__builtin_offsetof(struct cfstring64_t, characters), S, info, n_value);
3698 if (symbol_name == nullptr)
3699 return nullptr;
3700 cfs_characters = n_value;
3701 } else
3702 cfs_characters = cfs.characters;
3703 name = get_pointer_64(cfs_characters, offset, left, S, info);
3704
3705 return name;
3706}
3707
3708// get_objc2_64bit_selref() is used for disassembly and is passed a the address
3709// of a pointer to an Objective-C selector reference when the pointer value is
3710// zero as in a .o file and is likely to have a external relocation entry with
3711// who's symbol's n_value is the real pointer to the selector name. If that is
3712// the case the real pointer to the selector name is returned else 0 is
3713// returned
3714static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
3715 struct DisassembleInfo *info) {
3716 uint32_t offset, left;
3717 SectionRef S;
3718
3719 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
3720 if (r == nullptr || left < sizeof(uint64_t))
3721 return 0;
3722 uint64_t n_value;
3723 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3724 if (symbol_name == nullptr)
3725 return 0;
3726 return n_value;
3727}
3728
3729static const SectionRef get_section(MachOObjectFile *O, const char *segname,
3730 const char *sectname) {
3731 for (const SectionRef &Section : O->sections()) {
3732 StringRef SectName;
3733 Section.getName(SectName);
3734 DataRefImpl Ref = Section.getRawDataRefImpl();
3735 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3736 if (SegName == segname && SectName == sectname)
3737 return Section;
3738 }
3739 return SectionRef();
3740}
3741
3742static void
3743walk_pointer_list_64(const char *listname, const SectionRef S,
3744 MachOObjectFile *O, struct DisassembleInfo *info,
3745 void (*func)(uint64_t, struct DisassembleInfo *info)) {
3746 if (S == SectionRef())
3747 return;
3748
3749 StringRef SectName;
3750 S.getName(SectName);
3751 DataRefImpl Ref = S.getRawDataRefImpl();
3752 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3753 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3754
3755 StringRef BytesStr;
3756 S.getContents(BytesStr);
3757 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3758
3759 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
3760 uint32_t left = S.getSize() - i;
3761 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
3762 uint64_t p = 0;
3763 memcpy(&p, Contents + i, size);
3764 if (i + sizeof(uint64_t) > S.getSize())
3765 outs() << listname << " list pointer extends past end of (" << SegName
3766 << "," << SectName << ") section\n";
3767 outs() << format("%016" PRIx64"l" "x", S.getAddress() + i) << " ";
3768
3769 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3770 sys::swapByteOrder(p);
3771
3772 uint64_t n_value = 0;
3773 const char *name = get_symbol_64(i, S, info, n_value, p);
3774 if (name == nullptr)
3775 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
3776
3777 if (n_value != 0) {
3778 outs() << format("0x%" PRIx64"l" "x", n_value);
3779 if (p != 0)
3780 outs() << " + " << format("0x%" PRIx64"l" "x", p);
3781 } else
3782 outs() << format("0x%" PRIx64"l" "x", p);
3783 if (name != nullptr)
3784 outs() << " " << name;
3785 outs() << "\n";
3786
3787 p += n_value;
3788 if (func)
3789 func(p, info);
3790 }
3791}
3792
3793static void
3794walk_pointer_list_32(const char *listname, const SectionRef S,
3795 MachOObjectFile *O, struct DisassembleInfo *info,
3796 void (*func)(uint32_t, struct DisassembleInfo *info)) {
3797 if (S == SectionRef())
3798 return;
3799
3800 StringRef SectName;
3801 S.getName(SectName);
3802 DataRefImpl Ref = S.getRawDataRefImpl();
3803 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3804 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3805
3806 StringRef BytesStr;
3807 S.getContents(BytesStr);
3808 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3809
3810 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
3811 uint32_t left = S.getSize() - i;
3812 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
3813 uint32_t p = 0;
3814 memcpy(&p, Contents + i, size);
3815 if (i + sizeof(uint32_t) > S.getSize())
3816 outs() << listname << " list pointer extends past end of (" << SegName
3817 << "," << SectName << ") section\n";
3818 uint32_t Address = S.getAddress() + i;
3819 outs() << format("%08" PRIx32"x", Address) << " ";
3820
3821 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3822 sys::swapByteOrder(p);
3823 outs() << format("0x%" PRIx32"x", p);
3824
3825 const char *name = get_symbol_32(i, S, info, p);
3826 if (name != nullptr)
3827 outs() << " " << name;
3828 outs() << "\n";
3829
3830 if (func)
3831 func(p, info);
3832 }
3833}
3834
3835static void print_layout_map(const char *layout_map, uint32_t left) {
3836 if (layout_map == nullptr)
3837 return;
3838 outs() << " layout map: ";
3839 do {
3840 outs() << format("0x%02" PRIx32"x", (*layout_map) & 0xff) << " ";
3841 left--;
3842 layout_map++;
3843 } while (*layout_map != '\0' && left != 0);
3844 outs() << "\n";
3845}
3846
3847static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
3848 uint32_t offset, left;
3849 SectionRef S;
3850 const char *layout_map;
3851
3852 if (p == 0)
3853 return;
3854 layout_map = get_pointer_64(p, offset, left, S, info);
3855 print_layout_map(layout_map, left);
3856}
3857
3858static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
3859 uint32_t offset, left;
3860 SectionRef S;
3861 const char *layout_map;
3862
3863 if (p == 0)
3864 return;
3865 layout_map = get_pointer_32(p, offset, left, S, info);
3866 print_layout_map(layout_map, left);
3867}
3868
3869static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
3870 const char *indent) {
3871 struct method_list64_t ml;
3872 struct method64_t m;
3873 const char *r;
3874 uint32_t offset, xoffset, left, i;
3875 SectionRef S, xS;
3876 const char *name, *sym_name;
3877 uint64_t n_value;
3878
3879 r = get_pointer_64(p, offset, left, S, info);
3880 if (r == nullptr)
3881 return;
3882 memset(&ml, '\0', sizeof(struct method_list64_t));
3883 if (left < sizeof(struct method_list64_t)) {
3884 memcpy(&ml, r, left);
3885 outs() << " (method_list_t entends past the end of the section)\n";
3886 } else
3887 memcpy(&ml, r, sizeof(struct method_list64_t));
3888 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3889 swapStruct(ml);
3890 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3891 outs() << indent << "\t\t count " << ml.count << "\n";
3892
3893 p += sizeof(struct method_list64_t);
3894 offset += sizeof(struct method_list64_t);
3895 for (i = 0; i < ml.count; i++) {
3896 r = get_pointer_64(p, offset, left, S, info);
3897 if (r == nullptr)
3898 return;
3899 memset(&m, '\0', sizeof(struct method64_t));
3900 if (left < sizeof(struct method64_t)) {
3901 memcpy(&m, r, left);
3902 outs() << indent << " (method_t extends past the end of the section)\n";
3903 } else
3904 memcpy(&m, r, sizeof(struct method64_t));
3905 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3906 swapStruct(m);
3907
3908 outs() << indent << "\t\t name ";
3909 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name)__builtin_offsetof(struct method64_t, name), S,
3910 info, n_value, m.name);
3911 if (n_value != 0) {
3912 if (info->verbose && sym_name != nullptr)
3913 outs() << sym_name;
3914 else
3915 outs() << format("0x%" PRIx64"l" "x", n_value);
3916 if (m.name != 0)
3917 outs() << " + " << format("0x%" PRIx64"l" "x", m.name);
3918 } else
3919 outs() << format("0x%" PRIx64"l" "x", m.name);
3920 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
3921 if (name != nullptr)
3922 outs() << format(" %.*s", left, name);
3923 outs() << "\n";
3924
3925 outs() << indent << "\t\t types ";
3926 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types)__builtin_offsetof(struct method64_t, types), S,
3927 info, n_value, m.types);
3928 if (n_value != 0) {
3929 if (info->verbose && sym_name != nullptr)
3930 outs() << sym_name;
3931 else
3932 outs() << format("0x%" PRIx64"l" "x", n_value);
3933 if (m.types != 0)
3934 outs() << " + " << format("0x%" PRIx64"l" "x", m.types);
3935 } else
3936 outs() << format("0x%" PRIx64"l" "x", m.types);
3937 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
3938 if (name != nullptr)
3939 outs() << format(" %.*s", left, name);
3940 outs() << "\n";
3941
3942 outs() << indent << "\t\t imp ";
3943 name = get_symbol_64(offset + offsetof(struct method64_t, imp)__builtin_offsetof(struct method64_t, imp), S, info,
3944 n_value, m.imp);
3945 if (info->verbose && name == nullptr) {
3946 if (n_value != 0) {
3947 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
3948 if (m.imp != 0)
3949 outs() << "+ " << format("0x%" PRIx64"l" "x", m.imp) << " ";
3950 } else
3951 outs() << format("0x%" PRIx64"l" "x", m.imp) << " ";
3952 }
3953 if (name != nullptr)
3954 outs() << name;
3955 outs() << "\n";
3956
3957 p += sizeof(struct method64_t);
3958 offset += sizeof(struct method64_t);
3959 }
3960}
3961
3962static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
3963 const char *indent) {
3964 struct method_list32_t ml;
3965 struct method32_t m;
3966 const char *r, *name;
3967 uint32_t offset, xoffset, left, i;
3968 SectionRef S, xS;
3969
3970 r = get_pointer_32(p, offset, left, S, info);
3971 if (r == nullptr)
3972 return;
3973 memset(&ml, '\0', sizeof(struct method_list32_t));
3974 if (left < sizeof(struct method_list32_t)) {
3975 memcpy(&ml, r, left);
3976 outs() << " (method_list_t entends past the end of the section)\n";
3977 } else
3978 memcpy(&ml, r, sizeof(struct method_list32_t));
3979 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3980 swapStruct(ml);
3981 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3982 outs() << indent << "\t\t count " << ml.count << "\n";
3983
3984 p += sizeof(struct method_list32_t);
3985 offset += sizeof(struct method_list32_t);
3986 for (i = 0; i < ml.count; i++) {
3987 r = get_pointer_32(p, offset, left, S, info);
3988 if (r == nullptr)
3989 return;
3990 memset(&m, '\0', sizeof(struct method32_t));
3991 if (left < sizeof(struct method32_t)) {
3992 memcpy(&ml, r, left);
3993 outs() << indent << " (method_t entends past the end of the section)\n";
3994 } else
3995 memcpy(&m, r, sizeof(struct method32_t));
3996 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3997 swapStruct(m);
3998
3999 outs() << indent << "\t\t name " << format("0x%" PRIx32"x", m.name);
4000 name = get_pointer_32(m.name, xoffset, left, xS, info);
4001 if (name != nullptr)
4002 outs() << format(" %.*s", left, name);
4003 outs() << "\n";
4004
4005 outs() << indent << "\t\t types " << format("0x%" PRIx32"x", m.types);
4006 name = get_pointer_32(m.types, xoffset, left, xS, info);
4007 if (name != nullptr)
4008 outs() << format(" %.*s", left, name);
4009 outs() << "\n";
4010
4011 outs() << indent << "\t\t imp " << format("0x%" PRIx32"x", m.imp);
4012 name = get_symbol_32(offset + offsetof(struct method32_t, imp)__builtin_offsetof(struct method32_t, imp), S, info,
4013 m.imp);
4014 if (name != nullptr)
4015 outs() << " " << name;
4016 outs() << "\n";
4017
4018 p += sizeof(struct method32_t);
4019 offset += sizeof(struct method32_t);
4020 }
4021}
4022
4023static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4024 uint32_t offset, left, xleft;
4025 SectionRef S;
4026 struct objc_method_list_t method_list;
4027 struct objc_method_t method;
4028 const char *r, *methods, *name, *SymbolName;
4029 int32_t i;
4030
4031 r = get_pointer_32(p, offset, left, S, info, true);
4032 if (r == nullptr)
4033 return true;
4034
4035 outs() << "\n";
4036 if (left > sizeof(struct objc_method_list_t)) {
4037 memcpy(&method_list, r, sizeof(struct objc_method_list_t));
4038 } else {
4039 outs() << "\t\t objc_method_list extends past end of the section\n";
4040 memset(&method_list, '\0', sizeof(struct objc_method_list_t));
4041 memcpy(&method_list, r, left);
4042 }
4043 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4044 swapStruct(method_list);
4045
4046 outs() << "\t\t obsolete "
4047 << format("0x%08" PRIx32"x", method_list.obsolete) << "\n";
4048 outs() << "\t\t method_count " << method_list.method_count << "\n";
4049
4050 methods = r + sizeof(struct objc_method_list_t);
4051 for (i = 0; i < method_list.method_count; i++) {
4052 if ((i + 1) * sizeof(struct objc_method_t) > left) {
4053 outs() << "\t\t remaining method's extend past the of the section\n";
4054 break;
4055 }
4056 memcpy(&method, methods + i * sizeof(struct objc_method_t),
4057 sizeof(struct objc_method_t));
4058 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4059 swapStruct(method);
4060
4061 outs() << "\t\t method_name "
4062 << format("0x%08" PRIx32"x", method.method_name);
4063 if (info->verbose) {
4064 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
4065 if (name != nullptr)
4066 outs() << format(" %.*s", xleft, name);
4067 else
4068 outs() << " (not in an __OBJC section)";
4069 }
4070 outs() << "\n";
4071
4072 outs() << "\t\t method_types "
4073 << format("0x%08" PRIx32"x", method.method_types);
4074 if (info->verbose) {
4075 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
4076 if (name != nullptr)
4077 outs() << format(" %.*s", xleft, name);
4078 else
4079 outs() << " (not in an __OBJC section)";
4080 }
4081 outs() << "\n";
4082
4083 outs() << "\t\t method_imp "
4084 << format("0x%08" PRIx32"x", method.method_imp) << " ";
4085 if (info->verbose) {
4086 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
4087 if (SymbolName != nullptr)
4088 outs() << SymbolName;
4089 }
4090 outs() << "\n";
4091 }
4092 return false;
4093}
4094
4095static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4096 struct protocol_list64_t pl;
4097 uint64_t q, n_value;
4098 struct protocol64_t pc;
4099 const char *r;
4100 uint32_t offset, xoffset, left, i;
4101 SectionRef S, xS;
4102 const char *name, *sym_name;
4103
4104 r = get_pointer_64(p, offset, left, S, info);
4105 if (r == nullptr)
4106 return;
4107 memset(&pl, '\0', sizeof(struct protocol_list64_t));
4108 if (left < sizeof(struct protocol_list64_t)) {
4109 memcpy(&pl, r, left);
4110 outs() << " (protocol_list_t entends past the end of the section)\n";
4111 } else
4112 memcpy(&pl, r, sizeof(struct protocol_list64_t));
4113 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4114 swapStruct(pl);
4115 outs() << " count " << pl.count << "\n";
4116
4117 p += sizeof(struct protocol_list64_t);
4118 offset += sizeof(struct protocol_list64_t);
4119 for (i = 0; i < pl.count; i++) {
4120 r = get_pointer_64(p, offset, left, S, info);
4121 if (r == nullptr)
4122 return;
4123 q = 0;
4124 if (left < sizeof(uint64_t)) {
4125 memcpy(&q, r, left);
4126 outs() << " (protocol_t * entends past the end of the section)\n";
4127 } else
4128 memcpy(&q, r, sizeof(uint64_t));
4129 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4130 sys::swapByteOrder(q);
4131
4132 outs() << "\t\t list[" << i << "] ";
4133 sym_name = get_symbol_64(offset, S, info, n_value, q);
4134 if (n_value != 0) {
4135 if (info->verbose && sym_name != nullptr)
4136 outs() << sym_name;
4137 else
4138 outs() << format("0x%" PRIx64"l" "x", n_value);
4139 if (q != 0)
4140 outs() << " + " << format("0x%" PRIx64"l" "x", q);
4141 } else
4142 outs() << format("0x%" PRIx64"l" "x", q);
4143 outs() << " (struct protocol_t *)\n";
4144
4145 r = get_pointer_64(q + n_value, offset, left, S, info);
4146 if (r == nullptr)
4147 return;
4148 memset(&pc, '\0', sizeof(struct protocol64_t));
4149 if (left < sizeof(struct protocol64_t)) {
4150 memcpy(&pc, r, left);
4151 outs() << " (protocol_t entends past the end of the section)\n";
4152 } else
4153 memcpy(&pc, r, sizeof(struct protocol64_t));
4154 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4155 swapStruct(pc);
4156
4157 outs() << "\t\t\t isa " << format("0x%" PRIx64"l" "x", pc.isa) << "\n";
4158
4159 outs() << "\t\t\t name ";
4160 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name)__builtin_offsetof(struct protocol64_t, name), S,
4161 info, n_value, pc.name);
4162 if (n_value != 0) {
4163 if (info->verbose && sym_name != nullptr)
4164 outs() << sym_name;
4165 else
4166 outs() << format("0x%" PRIx64"l" "x", n_value);
4167 if (pc.name != 0)
4168 outs() << " + " << format("0x%" PRIx64"l" "x", pc.name);
4169 } else
4170 outs() << format("0x%" PRIx64"l" "x", pc.name);
4171 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
4172 if (name != nullptr)
4173 outs() << format(" %.*s", left, name);
4174 outs() << "\n";
4175
4176 outs() << "\t\t\tprotocols " << format("0x%" PRIx64"l" "x", pc.protocols) << "\n";
4177
4178 outs() << "\t\t instanceMethods ";
4179 sym_name =
4180 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods)__builtin_offsetof(struct protocol64_t, instanceMethods),
4181 S, info, n_value, pc.instanceMethods);
4182 if (n_value != 0) {
4183 if (info->verbose && sym_name != nullptr)
4184 outs() << sym_name;
4185 else
4186 outs() << format("0x%" PRIx64"l" "x", n_value);
4187 if (pc.instanceMethods != 0)
4188 outs() << " + " << format("0x%" PRIx64"l" "x", pc.instanceMethods);
4189 } else
4190 outs() << format("0x%" PRIx64"l" "x", pc.instanceMethods);
4191 outs() << " (struct method_list_t *)\n";
4192 if (pc.instanceMethods + n_value != 0)
4193 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
4194
4195 outs() << "\t\t classMethods ";
4196 sym_name =
4197 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods)__builtin_offsetof(struct protocol64_t, classMethods), S,
4198 info, n_value, pc.classMethods);
4199 if (n_value != 0) {
4200 if (info->verbose && sym_name != nullptr)
4201 outs() << sym_name;
4202 else
4203 outs() << format("0x%" PRIx64"l" "x", n_value);
4204 if (pc.classMethods != 0)
4205 outs() << " + " << format("0x%" PRIx64"l" "x", pc.classMethods);
4206 } else
4207 outs() << format("0x%" PRIx64"l" "x", pc.classMethods);
4208 outs() << " (struct method_list_t *)\n";
4209 if (pc.classMethods + n_value != 0)
4210 print_method_list64_t(pc.classMethods + n_value, info, "\t");
4211
4212 outs() << "\t optionalInstanceMethods "
4213 << format("0x%" PRIx64"l" "x", pc.optionalInstanceMethods) << "\n";
4214 outs() << "\t optionalClassMethods "
4215 << format("0x%" PRIx64"l" "x", pc.optionalClassMethods) << "\n";
4216 outs() << "\t instanceProperties "
4217 << format("0x%" PRIx64"l" "x", pc.instanceProperties) << "\n";
4218
4219 p += sizeof(uint64_t);
4220 offset += sizeof(uint64_t);
4221 }
4222}
4223
4224static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4225 struct protocol_list32_t pl;
4226 uint32_t q;
4227 struct protocol32_t pc;
4228 const char *r;
4229 uint32_t offset, xoffset, left, i;
4230 SectionRef S, xS;
4231 const char *name;
4232
4233 r = get_pointer_32(p, offset, left, S, info);
4234 if (r == nullptr)
4235 return;
4236 memset(&pl, '\0', sizeof(struct protocol_list32_t));
4237 if (left < sizeof(struct protocol_list32_t)) {
4238 memcpy(&pl, r, left);
4239 outs() << " (protocol_list_t entends past the end of the section)\n";
4240 } else
4241 memcpy(&pl, r, sizeof(struct protocol_list32_t));
4242 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4243 swapStruct(pl);
4244 outs() << " count " << pl.count << "\n";
4245
4246 p += sizeof(struct protocol_list32_t);
4247 offset += sizeof(struct protocol_list32_t);
4248 for (i = 0; i < pl.count; i++) {
4249 r = get_pointer_32(p, offset, left, S, info);
4250 if (r == nullptr)
4251 return;
4252 q = 0;
4253 if (left < sizeof(uint32_t)) {
4254 memcpy(&q, r, left);
4255 outs() << " (protocol_t * entends past the end of the section)\n";
4256 } else
4257 memcpy(&q, r, sizeof(uint32_t));
4258 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4259 sys::swapByteOrder(q);
4260 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32"x", q)
4261 << " (struct protocol_t *)\n";
4262 r = get_pointer_32(q, offset, left, S, info);
4263 if (r == nullptr)
4264 return;
4265 memset(&pc, '\0', sizeof(struct protocol32_t));
4266 if (left < sizeof(struct protocol32_t)) {
4267 memcpy(&pc, r, left);
4268 outs() << " (protocol_t entends past the end of the section)\n";
4269 } else
4270 memcpy(&pc, r, sizeof(struct protocol32_t));
4271 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4272 swapStruct(pc);
4273 outs() << "\t\t\t isa " << format("0x%" PRIx32"x", pc.isa) << "\n";
4274 outs() << "\t\t\t name " << format("0x%" PRIx32"x", pc.name);
4275 name = get_pointer_32(pc.name, xoffset, left, xS, info);
4276 if (name != nullptr)
4277 outs() << format(" %.*s", left, name);
4278 outs() << "\n";
4279 outs() << "\t\t\tprotocols " << format("0x%" PRIx32"x", pc.protocols) << "\n";
4280 outs() << "\t\t instanceMethods "
4281 << format("0x%" PRIx32"x", pc.instanceMethods)
4282 << " (struct method_list_t *)\n";
4283 if (pc.instanceMethods != 0)
4284 print_method_list32_t(pc.instanceMethods, info, "\t");
4285 outs() << "\t\t classMethods " << format("0x%" PRIx32"x", pc.classMethods)
4286 << " (struct method_list_t *)\n";
4287 if (pc.classMethods != 0)
4288 print_method_list32_t(pc.classMethods, info, "\t");
4289 outs() << "\t optionalInstanceMethods "
4290 << format("0x%" PRIx32"x", pc.optionalInstanceMethods) << "\n";
4291 outs() << "\t optionalClassMethods "
4292 << format("0x%" PRIx32"x", pc.optionalClassMethods) << "\n";
4293 outs() << "\t instanceProperties "
4294 << format("0x%" PRIx32"x", pc.instanceProperties) << "\n";
4295 p += sizeof(uint32_t);
4296 offset += sizeof(uint32_t);
4297 }
4298}
4299
4300static void print_indent(uint32_t indent) {
4301 for (uint32_t i = 0; i < indent;) {
4302 if (indent - i >= 8) {
4303 outs() << "\t";
4304 i += 8;
4305 } else {
4306 for (uint32_t j = i; j < indent; j++)
4307 outs() << " ";
4308 return;
4309 }
4310 }
4311}
4312
4313static bool print_method_description_list(uint32_t p, uint32_t indent,
4314 struct DisassembleInfo *info) {
4315 uint32_t offset, left, xleft;
4316 SectionRef S;
4317 struct objc_method_description_list_t mdl;
4318 struct objc_method_description_t md;
4319 const char *r, *list, *name;
4320 int32_t i;
4321
4322 r = get_pointer_32(p, offset, left, S, info, true);
4323 if (r == nullptr)
4324 return true;
4325
4326 outs() << "\n";
4327 if (left > sizeof(struct objc_method_description_list_t)) {
4328 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
4329 } else {
4330 print_indent(indent);
4331 outs() << " objc_method_description_list extends past end of the section\n";
4332 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
4333 memcpy(&mdl, r, left);
4334 }
4335 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4336 swapStruct(mdl);
4337
4338 print_indent(indent);
4339 outs() << " count " << mdl.count << "\n";
4340
4341 list = r + sizeof(struct objc_method_description_list_t);
4342 for (i = 0; i < mdl.count; i++) {
4343 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
4344 print_indent(indent);
4345 outs() << " remaining list entries extend past the of the section\n";
4346 break;
4347 }
4348 print_indent(indent);
4349 outs() << " list[" << i << "]\n";
4350 memcpy(&md, list + i * sizeof(struct objc_method_description_t),
4351 sizeof(struct objc_method_description_t));
4352 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4353 swapStruct(md);
4354
4355 print_indent(indent);
4356 outs() << " name " << format("0x%08" PRIx32"x", md.name);
4357 if (info->verbose) {
4358 name = get_pointer_32(md.name, offset, xleft, S, info, true);
4359 if (name != nullptr)
4360 outs() << format(" %.*s", xleft, name);
4361 else
4362 outs() << " (not in an __OBJC section)";
4363 }
4364 outs() << "\n";
4365
4366 print_indent(indent);
4367 outs() << " types " << format("0x%08" PRIx32"x", md.types);
4368 if (info->verbose) {
4369 name = get_pointer_32(md.types, offset, xleft, S, info, true);
4370 if (name != nullptr)
4371 outs() << format(" %.*s", xleft, name);
4372 else
4373 outs() << " (not in an __OBJC section)";
4374 }
4375 outs() << "\n";
4376 }
4377 return false;
4378}
4379
4380static bool print_protocol_list(uint32_t p, uint32_t indent,
4381 struct DisassembleInfo *info);
4382
4383static bool print_protocol(uint32_t p, uint32_t indent,
4384 struct DisassembleInfo *info) {
4385 uint32_t offset, left;
4386 SectionRef S;
4387 struct objc_protocol_t protocol;
4388 const char *r, *name;
4389
4390 r = get_pointer_32(p, offset, left, S, info, true);
4391 if (r == nullptr)
4392 return true;
4393
4394 outs() << "\n";
4395 if (left >= sizeof(struct objc_protocol_t)) {
4396 memcpy(&protocol, r, sizeof(struct objc_protocol_t));
4397 } else {
4398 print_indent(indent);
4399 outs() << " Protocol extends past end of the section\n";
4400 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
4401 memcpy(&protocol, r, left);
4402 }
4403 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4404 swapStruct(protocol);
4405
4406 print_indent(indent);
4407 outs() << " isa " << format("0x%08" PRIx32"x", protocol.isa)
4408 << "\n";
4409
4410 print_indent(indent);
4411 outs() << " protocol_name "
4412 << format("0x%08" PRIx32"x", protocol.protocol_name);
4413 if (info->verbose) {
4414 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
4415 if (name != nullptr)
4416 outs() << format(" %.*s", left, name);
4417 else
4418 outs() << " (not in an __OBJC section)";
4419 }
4420 outs() << "\n";
4421
4422 print_indent(indent);
4423 outs() << " protocol_list "
4424 << format("0x%08" PRIx32"x", protocol.protocol_list);
4425 if (print_protocol_list(protocol.protocol_list, indent + 4, info))
4426 outs() << " (not in an __OBJC section)\n";
4427
4428 print_indent(indent);
4429 outs() << " instance_methods "
4430 << format("0x%08" PRIx32"x", protocol.instance_methods);
4431 if (print_method_description_list(protocol.instance_methods, indent, info))
4432 outs() << " (not in an __OBJC section)\n";
4433
4434 print_indent(indent);
4435 outs() << " class_methods "
4436 << format("0x%08" PRIx32"x", protocol.class_methods);
4437 if (print_method_description_list(protocol.class_methods, indent, info))
4438 outs() << " (not in an __OBJC section)\n";
4439
4440 return false;
4441}
4442
4443static bool print_protocol_list(uint32_t p, uint32_t indent,
4444 struct DisassembleInfo *info) {
4445 uint32_t offset, left, l;
4446 SectionRef S;
4447 struct objc_protocol_list_t protocol_list;
4448 const char *r, *list;
4449 int32_t i;
4450
4451 r = get_pointer_32(p, offset, left, S, info, true);
4452 if (r == nullptr)
4453 return true;
4454
4455 outs() << "\n";
4456 if (left > sizeof(struct objc_protocol_list_t)) {
4457 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
4458 } else {
4459 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
4460 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
4461 memcpy(&protocol_list, r, left);
4462 }
4463 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4464 swapStruct(protocol_list);
4465
4466 print_indent(indent);
4467 outs() << " next " << format("0x%08" PRIx32"x", protocol_list.next)
4468 << "\n";
4469 print_indent(indent);
4470 outs() << " count " << protocol_list.count << "\n";
4471
4472 list = r + sizeof(struct objc_protocol_list_t);
4473 for (i = 0; i < protocol_list.count; i++) {
4474 if ((i + 1) * sizeof(uint32_t) > left) {
4475 outs() << "\t\t remaining list entries extend past the of the section\n";
4476 break;
4477 }
4478 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
4479 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4480 sys::swapByteOrder(l);
4481
4482 print_indent(indent);
4483 outs() << " list[" << i << "] " << format("0x%08" PRIx32"x", l);
4484 if (print_protocol(l, indent, info))
4485 outs() << "(not in an __OBJC section)\n";
4486 }
4487 return false;
4488}
4489
4490static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
4491 struct ivar_list64_t il;
4492 struct ivar64_t i;
4493 const char *r;
4494 uint32_t offset, xoffset, left, j;
4495 SectionRef S, xS;
4496 const char *name, *sym_name, *ivar_offset_p;
4497 uint64_t ivar_offset, n_value;
4498
4499 r = get_pointer_64(p, offset, left, S, info);
4500 if (r == nullptr)
4501 return;
4502 memset(&il, '\0', sizeof(struct ivar_list64_t));
4503 if (left < sizeof(struct ivar_list64_t)) {
4504 memcpy(&il, r, left);
4505 outs() << " (ivar_list_t entends past the end of the section)\n";
4506 } else
4507 memcpy(&il, r, sizeof(struct ivar_list64_t));
4508 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4509 swapStruct(il);
4510 outs() << " entsize " << il.entsize << "\n";
4511 outs() << " count " << il.count << "\n";
4512
4513 p += sizeof(struct ivar_list64_t);
4514 offset += sizeof(struct ivar_list64_t);
4515 for (j = 0; j < il.count; j++) {
4516 r = get_pointer_64(p, offset, left, S, info);
4517 if (r == nullptr)
4518 return;
4519 memset(&i, '\0', sizeof(struct ivar64_t));
4520 if (left < sizeof(struct ivar64_t)) {
4521 memcpy(&i, r, left);
4522 outs() << " (ivar_t entends past the end of the section)\n";
4523 } else
4524 memcpy(&i, r, sizeof(struct ivar64_t));
4525 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4526 swapStruct(i);
4527
4528 outs() << "\t\t\t offset ";
4529 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset)__builtin_offsetof(struct ivar64_t, offset), S,
4530 info, n_value, i.offset);
4531 if (n_value != 0) {
4532 if (info->verbose && sym_name != nullptr)
4533 outs() << sym_name;
4534 else
4535 outs() << format("0x%" PRIx64"l" "x", n_value);
4536 if (i.offset != 0)
4537 outs() << " + " << format("0x%" PRIx64"l" "x", i.offset);
4538 } else
4539 outs() << format("0x%" PRIx64"l" "x", i.offset);
4540 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
4541 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4542 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4543 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4544 sys::swapByteOrder(ivar_offset);
4545 outs() << " " << ivar_offset << "\n";
4546 } else
4547 outs() << "\n";
4548
4549 outs() << "\t\t\t name ";
4550 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name)__builtin_offsetof(struct ivar64_t, name), S, info,
4551 n_value, i.name);
4552 if (n_value != 0) {
4553 if (info->verbose && sym_name != nullptr)
4554 outs() << sym_name;
4555 else
4556 outs() << format("0x%" PRIx64"l" "x", n_value);
4557 if (i.name != 0)
4558 outs() << " + " << format("0x%" PRIx64"l" "x", i.name);
4559 } else
4560 outs() << format("0x%" PRIx64"l" "x", i.name);
4561 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
4562 if (name != nullptr)
4563 outs() << format(" %.*s", left, name);
4564 outs() << "\n";
4565
4566 outs() << "\t\t\t type ";
4567 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type)__builtin_offsetof(struct ivar64_t, type), S, info,
4568 n_value, i.name);
4569 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
4570 if (n_value != 0) {
4571 if (info->verbose && sym_name != nullptr)
4572 outs() << sym_name;
4573 else
4574 outs() << format("0x%" PRIx64"l" "x", n_value);
4575 if (i.type != 0)
4576 outs() << " + " << format("0x%" PRIx64"l" "x", i.type);
4577 } else
4578 outs() << format("0x%" PRIx64"l" "x", i.type);
4579 if (name != nullptr)
4580 outs() << format(" %.*s", left, name);
4581 outs() << "\n";
4582
4583 outs() << "\t\t\talignment " << i.alignment << "\n";
4584 outs() << "\t\t\t size " << i.size << "\n";
4585
4586 p += sizeof(struct ivar64_t);
4587 offset += sizeof(struct ivar64_t);
4588 }
4589}
4590
4591static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
4592 struct ivar_list32_t il;
4593 struct ivar32_t i;
4594 const char *r;
4595 uint32_t offset, xoffset, left, j;
4596 SectionRef S, xS;
4597 const char *name, *ivar_offset_p;
4598 uint32_t ivar_offset;
4599
4600 r = get_pointer_32(p, offset, left, S, info);
4601 if (r == nullptr)
4602 return;
4603 memset(&il, '\0', sizeof(struct ivar_list32_t));
4604 if (left < sizeof(struct ivar_list32_t)) {
4605 memcpy(&il, r, left);
4606 outs() << " (ivar_list_t entends past the end of the section)\n";
4607 } else
4608 memcpy(&il, r, sizeof(struct ivar_list32_t));
4609 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4610 swapStruct(il);
4611 outs() << " entsize " << il.entsize << "\n";
4612 outs() << " count " << il.count << "\n";
4613
4614 p += sizeof(struct ivar_list32_t);
4615 offset += sizeof(struct ivar_list32_t);
4616 for (j = 0; j < il.count; j++) {
4617 r = get_pointer_32(p, offset, left, S, info);
4618 if (r == nullptr)
4619 return;
4620 memset(&i, '\0', sizeof(struct ivar32_t));
4621 if (left < sizeof(struct ivar32_t)) {
4622 memcpy(&i, r, left);
4623 outs() << " (ivar_t entends past the end of the section)\n";
4624 } else
4625 memcpy(&i, r, sizeof(struct ivar32_t));
4626 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4627 swapStruct(i);
4628
4629 outs() << "\t\t\t offset " << format("0x%" PRIx32"x", i.offset);
4630 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
4631 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4632 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4633 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4634 sys::swapByteOrder(ivar_offset);
4635 outs() << " " << ivar_offset << "\n";
4636 } else
4637 outs() << "\n";
4638
4639 outs() << "\t\t\t name " << format("0x%" PRIx32"x", i.name);
4640 name = get_pointer_32(i.name, xoffset, left, xS, info);
4641 if (name != nullptr)
4642 outs() << format(" %.*s", left, name);
4643 outs() << "\n";
4644
4645 outs() << "\t\t\t type " << format("0x%" PRIx32"x", i.type);
4646 name = get_pointer_32(i.type, xoffset, left, xS, info);
4647 if (name != nullptr)
4648 outs() << format(" %.*s", left, name);
4649 outs() << "\n";
4650
4651 outs() << "\t\t\talignment " << i.alignment << "\n";
4652 outs() << "\t\t\t size " << i.size << "\n";
4653
4654 p += sizeof(struct ivar32_t);
4655 offset += sizeof(struct ivar32_t);
4656 }
4657}
4658
4659static void print_objc_property_list64(uint64_t p,
4660 struct DisassembleInfo *info) {
4661 struct objc_property_list64 opl;
4662 struct objc_property64 op;
4663 const char *r;
4664 uint32_t offset, xoffset, left, j;
4665 SectionRef S, xS;
4666 const char *name, *sym_name;
4667 uint64_t n_value;
4668
4669 r = get_pointer_64(p, offset, left, S, info);
4670 if (r == nullptr)
4671 return;
4672 memset(&opl, '\0', sizeof(struct objc_property_list64));
4673 if (left < sizeof(struct objc_property_list64)) {
4674 memcpy(&opl, r, left);
4675 outs() << " (objc_property_list entends past the end of the section)\n";
4676 } else
4677 memcpy(&opl, r, sizeof(struct objc_property_list64));
4678 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4679 swapStruct(opl);
4680 outs() << " entsize " << opl.entsize << "\n";
4681 outs() << " count " << opl.count << "\n";
4682
4683 p += sizeof(struct objc_property_list64);
4684 offset += sizeof(struct objc_property_list64);
4685 for (j = 0; j < opl.count; j++) {
4686 r = get_pointer_64(p, offset, left, S, info);
4687 if (r == nullptr)
4688 return;
4689 memset(&op, '\0', sizeof(struct objc_property64));
4690 if (left < sizeof(struct objc_property64)) {
4691 memcpy(&op, r, left);
4692 outs() << " (objc_property entends past the end of the section)\n";
4693 } else
4694 memcpy(&op, r, sizeof(struct objc_property64));
4695 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4696 swapStruct(op);
4697
4698 outs() << "\t\t\t name ";
4699 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name)__builtin_offsetof(struct objc_property64, name), S,
4700 info, n_value, op.name);
4701 if (n_value != 0) {
4702 if (info->verbose && sym_name != nullptr)
4703 outs() << sym_name;
4704 else
4705 outs() << format("0x%" PRIx64"l" "x", n_value);
4706 if (op.name != 0)
4707 outs() << " + " << format("0x%" PRIx64"l" "x", op.name);
4708 } else
4709 outs() << format("0x%" PRIx64"l" "x", op.name);
4710 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
4711 if (name != nullptr)
4712 outs() << format(" %.*s", left, name);
4713 outs() << "\n";
4714
4715 outs() << "\t\t\tattributes ";
4716 sym_name =
4717 get_symbol_64(offset + offsetof(struct objc_property64, attributes)__builtin_offsetof(struct objc_property64, attributes), S,
4718 info, n_value, op.attributes);
4719 if (n_value != 0) {
4720 if (info->verbose && sym_name != nullptr)
4721 outs() << sym_name;
4722 else
4723 outs() << format("0x%" PRIx64"l" "x", n_value);
4724 if (op.attributes != 0)
4725 outs() << " + " << format("0x%" PRIx64"l" "x", op.attributes);
4726 } else
4727 outs() << format("0x%" PRIx64"l" "x", op.attributes);
4728 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
4729 if (name != nullptr)
4730 outs() << format(" %.*s", left, name);
4731 outs() << "\n";
4732
4733 p += sizeof(struct objc_property64);
4734 offset += sizeof(struct objc_property64);
4735 }
4736}
4737
4738static void print_objc_property_list32(uint32_t p,
4739 struct DisassembleInfo *info) {
4740 struct objc_property_list32 opl;
4741 struct objc_property32 op;
4742 const char *r;
4743 uint32_t offset, xoffset, left, j;
4744 SectionRef S, xS;
4745 const char *name;
4746
4747 r = get_pointer_32(p, offset, left, S, info);
4748 if (r == nullptr)
4749 return;
4750 memset(&opl, '\0', sizeof(struct objc_property_list32));
4751 if (left < sizeof(struct objc_property_list32)) {
4752 memcpy(&opl, r, left);
4753 outs() << " (objc_property_list entends past the end of the section)\n";
4754 } else
4755 memcpy(&opl, r, sizeof(struct objc_property_list32));
4756 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4757 swapStruct(opl);
4758 outs() << " entsize " << opl.entsize << "\n";
4759 outs() << " count " << opl.count << "\n";
4760
4761 p += sizeof(struct objc_property_list32);
4762 offset += sizeof(struct objc_property_list32);
4763 for (j = 0; j < opl.count; j++) {
4764 r = get_pointer_32(p, offset, left, S, info);
4765 if (r == nullptr)
4766 return;
4767 memset(&op, '\0', sizeof(struct objc_property32));
4768 if (left < sizeof(struct objc_property32)) {
4769 memcpy(&op, r, left);
4770 outs() << " (objc_property entends past the end of the section)\n";
4771 } else
4772 memcpy(&op, r, sizeof(struct objc_property32));
4773 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4774 swapStruct(op);
4775
4776 outs() << "\t\t\t name " << format("0x%" PRIx32"x", op.name);
4777 name = get_pointer_32(op.name, xoffset, left, xS, info);
4778 if (name != nullptr)
4779 outs() << format(" %.*s", left, name);
4780 outs() << "\n";
4781
4782 outs() << "\t\t\tattributes " << format("0x%" PRIx32"x", op.attributes);
4783 name = get_pointer_32(op.attributes, xoffset, left, xS, info);
4784 if (name != nullptr)
4785 outs() << format(" %.*s", left, name);
4786 outs() << "\n";
4787
4788 p += sizeof(struct objc_property32);
4789 offset += sizeof(struct objc_property32);
4790 }
4791}
4792
4793static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
4794 bool &is_meta_class) {
4795 struct class_ro64_t cro;
4796 const char *r;
4797 uint32_t offset, xoffset, left;
4798 SectionRef S, xS;
4799 const char *name, *sym_name;
4800 uint64_t n_value;
4801
4802 r = get_pointer_64(p, offset, left, S, info);
4803 if (r == nullptr || left < sizeof(struct class_ro64_t))
4804 return false;
4805 memcpy(&cro, r, sizeof(struct class_ro64_t));
4806 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4807 swapStruct(cro);
4808 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4809 if (cro.flags & RO_META(1 << 0))
4810 outs() << " RO_META";
4811 if (cro.flags & RO_ROOT(1 << 1))
4812 outs() << " RO_ROOT";
4813 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4814 outs() << " RO_HAS_CXX_STRUCTORS";
4815 outs() << "\n";
4816 outs() << " instanceStart " << cro.instanceStart << "\n";
4817 outs() << " instanceSize " << cro.instanceSize << "\n";
4818 outs() << " reserved " << format("0x%" PRIx32"x", cro.reserved)
4819 << "\n";
4820 outs() << " ivarLayout " << format("0x%" PRIx64"l" "x", cro.ivarLayout)
4821 << "\n";
4822 print_layout_map64(cro.ivarLayout, info);
4823
4824 outs() << " name ";
4825 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name)__builtin_offsetof(struct class_ro64_t, name), S,
4826 info, n_value, cro.name);
4827 if (n_value != 0) {
4828 if (info->verbose && sym_name != nullptr)
4829 outs() << sym_name;
4830 else
4831 outs() << format("0x%" PRIx64"l" "x", n_value);
4832 if (cro.name != 0)
4833 outs() << " + " << format("0x%" PRIx64"l" "x", cro.name);
4834 } else
4835 outs() << format("0x%" PRIx64"l" "x", cro.name);
4836 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
4837 if (name != nullptr)
4838 outs() << format(" %.*s", left, name);
4839 outs() << "\n";
4840
4841 outs() << " baseMethods ";
4842 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods)__builtin_offsetof(struct class_ro64_t, baseMethods),
4843 S, info, n_value, cro.baseMethods);
4844 if (n_value != 0) {
4845 if (info->verbose && sym_name != nullptr)
4846 outs() << sym_name;
4847 else
4848 outs() << format("0x%" PRIx64"l" "x", n_value);
4849 if (cro.baseMethods != 0)
4850 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseMethods);
4851 } else
4852 outs() << format("0x%" PRIx64"l" "x", cro.baseMethods);
4853 outs() << " (struct method_list_t *)\n";
4854 if (cro.baseMethods + n_value != 0)
4855 print_method_list64_t(cro.baseMethods + n_value, info, "");
4856
4857 outs() << " baseProtocols ";
4858 sym_name =
4859 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols)__builtin_offsetof(struct class_ro64_t, baseProtocols), S,
4860 info, n_value, cro.baseProtocols);
4861 if (n_value != 0) {
4862 if (info->verbose && sym_name != nullptr)
4863 outs() << sym_name;
4864 else
4865 outs() << format("0x%" PRIx64"l" "x", n_value);
4866 if (cro.baseProtocols != 0)
4867 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4868 } else
4869 outs() << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4870 outs() << "\n";
4871 if (cro.baseProtocols + n_value != 0)
4872 print_protocol_list64_t(cro.baseProtocols + n_value, info);
4873
4874 outs() << " ivars ";
4875 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars)__builtin_offsetof(struct class_ro64_t, ivars), S,
4876 info, n_value, cro.ivars);
4877 if (n_value != 0) {
4878 if (info->verbose && sym_name != nullptr)
4879 outs() << sym_name;
4880 else
4881 outs() << format("0x%" PRIx64"l" "x", n_value);
4882 if (cro.ivars != 0)
4883 outs() << " + " << format("0x%" PRIx64"l" "x", cro.ivars);
4884 } else
4885 outs() << format("0x%" PRIx64"l" "x", cro.ivars);
4886 outs() << "\n";
4887 if (cro.ivars + n_value != 0)
4888 print_ivar_list64_t(cro.ivars + n_value, info);
4889
4890 outs() << " weakIvarLayout ";
4891 sym_name =
4892 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout)__builtin_offsetof(struct class_ro64_t, weakIvarLayout), S,
4893 info, n_value, cro.weakIvarLayout);
4894 if (n_value != 0) {
4895 if (info->verbose && sym_name != nullptr)
4896 outs() << sym_name;
4897 else
4898 outs() << format("0x%" PRIx64"l" "x", n_value);
4899 if (cro.weakIvarLayout != 0)
4900 outs() << " + " << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4901 } else
4902 outs() << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4903 outs() << "\n";
4904 print_layout_map64(cro.weakIvarLayout + n_value, info);
4905
4906 outs() << " baseProperties ";
4907 sym_name =
4908 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties)__builtin_offsetof(struct class_ro64_t, baseProperties), S,
4909 info, n_value, cro.baseProperties);
4910 if (n_value != 0) {
4911 if (info->verbose && sym_name != nullptr)
4912 outs() << sym_name;
4913 else
4914 outs() << format("0x%" PRIx64"l" "x", n_value);
4915 if (cro.baseProperties != 0)
4916 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProperties);
4917 } else
4918 outs() << format("0x%" PRIx64"l" "x", cro.baseProperties);
4919 outs() << "\n";
4920 if (cro.baseProperties + n_value != 0)
4921 print_objc_property_list64(cro.baseProperties + n_value, info);
4922
4923 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4924 return true;
4925}
4926
4927static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
4928 bool &is_meta_class) {
4929 struct class_ro32_t cro;
4930 const char *r;
4931 uint32_t offset, xoffset, left;
4932 SectionRef S, xS;
4933 const char *name;
4934
4935 r = get_pointer_32(p, offset, left, S, info);
4936 if (r == nullptr)
4937 return false;
4938 memset(&cro, '\0', sizeof(struct class_ro32_t));
4939 if (left < sizeof(struct class_ro32_t)) {
4940 memcpy(&cro, r, left);
4941 outs() << " (class_ro_t entends past the end of the section)\n";
4942 } else
4943 memcpy(&cro, r, sizeof(struct class_ro32_t));
4944 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4945 swapStruct(cro);
4946 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4947 if (cro.flags & RO_META(1 << 0))
4948 outs() << " RO_META";
4949 if (cro.flags & RO_ROOT(1 << 1))
4950 outs() << " RO_ROOT";
4951 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4952 outs() << " RO_HAS_CXX_STRUCTORS";
4953 outs() << "\n";
4954 outs() << " instanceStart " << cro.instanceStart << "\n";
4955 outs() << " instanceSize " << cro.instanceSize << "\n";
4956 outs() << " ivarLayout " << format("0x%" PRIx32"x", cro.ivarLayout)
4957 << "\n";
4958 print_layout_map32(cro.ivarLayout, info);
4959
4960 outs() << " name " << format("0x%" PRIx32"x", cro.name);
4961 name = get_pointer_32(cro.name, xoffset, left, xS, info);
4962 if (name != nullptr)
4963 outs() << format(" %.*s", left, name);
4964 outs() << "\n";
4965
4966 outs() << " baseMethods "
4967 << format("0x%" PRIx32"x", cro.baseMethods)
4968 << " (struct method_list_t *)\n";
4969 if (cro.baseMethods != 0)
4970 print_method_list32_t(cro.baseMethods, info, "");
4971
4972 outs() << " baseProtocols "
4973 << format("0x%" PRIx32"x", cro.baseProtocols) << "\n";
4974 if (cro.baseProtocols != 0)
4975 print_protocol_list32_t(cro.baseProtocols, info);
4976 outs() << " ivars " << format("0x%" PRIx32"x", cro.ivars)
4977 << "\n";
4978 if (cro.ivars != 0)
4979 print_ivar_list32_t(cro.ivars, info);
4980 outs() << " weakIvarLayout "
4981 << format("0x%" PRIx32"x", cro.weakIvarLayout) << "\n";
4982 print_layout_map32(cro.weakIvarLayout, info);
4983 outs() << " baseProperties "
4984 << format("0x%" PRIx32"x", cro.baseProperties) << "\n";
4985 if (cro.baseProperties != 0)
4986 print_objc_property_list32(cro.baseProperties, info);
4987 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4988 return true;
4989}
4990
4991static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
4992 struct class64_t c;
4993 const char *r;
4994 uint32_t offset, left;
4995 SectionRef S;
4996 const char *name;
4997 uint64_t isa_n_value, n_value;
4998
4999 r = get_pointer_64(p, offset, left, S, info);
5000 if (r == nullptr || left < sizeof(struct class64_t))
5001 return;
5002 memcpy(&c, r, sizeof(struct class64_t));
5003 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5004 swapStruct(c);
5005
5006 outs() << " isa " << format("0x%" PRIx64"l" "x", c.isa);
5007 name = get_symbol_64(offset + offsetof(struct class64_t, isa)__builtin_offsetof(struct class64_t, isa), S, info,
5008 isa_n_value, c.isa);
5009 if (name != nullptr)
5010 outs() << " " << name;
5011 outs() << "\n";
5012
5013 outs() << " superclass " << format("0x%" PRIx64"l" "x", c.superclass);
5014 name = get_symbol_64(offset + offsetof(struct class64_t, superclass)__builtin_offsetof(struct class64_t, superclass), S, info,
5015 n_value, c.superclass);
5016 if (name != nullptr)
5017 outs() << " " << name;
5018 else {
5019 name = get_dyld_bind_info_symbolname(S.getAddress() +
5020 offset + offsetof(struct class64_t, superclass)__builtin_offsetof(struct class64_t, superclass), info);
5021 if (name != nullptr)
5022 outs() << " " << name;
5023 }
5024 outs() << "\n";
5025
5026 outs() << " cache " << format("0x%" PRIx64"l" "x", c.cache);
5027 name = get_symbol_64(offset + offsetof(struct class64_t, cache)__builtin_offsetof(struct class64_t, cache), S, info,
5028 n_value, c.cache);
5029 if (name != nullptr)
5030 outs() << " " << name;
5031 outs() << "\n";
5032
5033 outs() << " vtable " << format("0x%" PRIx64"l" "x", c.vtable);
5034 name = get_symbol_64(offset + offsetof(struct class64_t, vtable)__builtin_offsetof(struct class64_t, vtable), S, info,
5035 n_value, c.vtable);
5036 if (name != nullptr)
5037 outs() << " " << name;
5038 outs() << "\n";
5039
5040 name = get_symbol_64(offset + offsetof(struct class64_t, data)__builtin_offsetof(struct class64_t, data), S, info,
5041 n_value, c.data);
5042 outs() << " data ";
5043 if (n_value != 0) {
5044 if (info->verbose && name != nullptr)
5045 outs() << name;
5046 else
5047 outs() << format("0x%" PRIx64"l" "x", n_value);
5048 if (c.data != 0)
5049 outs() << " + " << format("0x%" PRIx64"l" "x", c.data);
5050 } else
5051 outs() << format("0x%" PRIx64"l" "x", c.data);
5052 outs() << " (struct class_ro_t *)";
5053
5054 // This is a Swift class if some of the low bits of the pointer are set.
5055 if ((c.data + n_value) & 0x7)
5056 outs() << " Swift class";
5057 outs() << "\n";
5058 bool is_meta_class;
5059 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
5060 return;
5061
5062 if (!is_meta_class &&
5063 c.isa + isa_n_value != p &&
5064 c.isa + isa_n_value != 0 &&
5065 info->depth < 100) {
5066 info->depth++;
5067 outs() << "Meta Class\n";
5068 print_class64_t(c.isa + isa_n_value, info);
5069 }
5070}
5071
5072static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5073 struct class32_t c;
5074 const char *r;
5075 uint32_t offset, left;
5076 SectionRef S;
5077 const char *name;
5078
5079 r = get_pointer_32(p, offset, left, S, info);
5080 if (r == nullptr)
5081 return;
5082 memset(&c, '\0', sizeof(struct class32_t));
5083 if (left < sizeof(struct class32_t)) {
5084 memcpy(&c, r, left);
5085 outs() << " (class_t entends past the end of the section)\n";
5086 } else
5087 memcpy(&c, r, sizeof(struct class32_t));
5088 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5089 swapStruct(c);
5090
5091 outs() << " isa " << format("0x%" PRIx32"x", c.isa);
5092 name =
5093 get_symbol_32(offset + offsetof(struct class32_t, isa)__builtin_offsetof(struct class32_t, isa), S, info, c.isa);
5094 if (name != nullptr)
5095 outs() << " " << name;
5096 outs() << "\n";
5097
5098 outs() << " superclass " << format("0x%" PRIx32"x", c.superclass);
5099 name = get_symbol_32(offset + offsetof(struct class32_t, superclass)__builtin_offsetof(struct class32_t, superclass), S, info,
5100 c.superclass);
5101 if (name != nullptr)
5102 outs() << " " << name;
5103 outs() << "\n";
5104
5105 outs() << " cache " << format("0x%" PRIx32"x", c.cache);
5106 name = get_symbol_32(offset + offsetof(struct class32_t, cache)__builtin_offsetof(struct class32_t, cache), S, info,
5107 c.cache);
5108 if (name != nullptr)
5109 outs() << " " << name;
5110 outs() << "\n";
5111
5112 outs() << " vtable " << format("0x%" PRIx32"x", c.vtable);
5113 name = get_symbol_32(offset + offsetof(struct class32_t, vtable)__builtin_offsetof(struct class32_t, vtable), S, info,
5114 c.vtable);
5115 if (name != nullptr)
5116 outs() << " " << name;
5117 outs() << "\n";
5118
5119 name =
5120 get_symbol_32(offset + offsetof(struct class32_t, data)__builtin_offsetof(struct class32_t, data), S, info, c.data);
5121 outs() << " data " << format("0x%" PRIx32"x", c.data)
5122 << " (struct class_ro_t *)";
5123
5124 // This is a Swift class if some of the low bits of the pointer are set.
5125 if (c.data & 0x3)
5126 outs() << " Swift class";
5127 outs() << "\n";
5128 bool is_meta_class;
5129 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
5130 return;
5131
5132 if (!is_meta_class) {
5133 outs() << "Meta Class\n";
5134 print_class32_t(c.isa, info);
5135 }
5136}
5137
5138static void print_objc_class_t(struct objc_class_t *objc_class,
5139 struct DisassembleInfo *info) {
5140 uint32_t offset, left, xleft;
5141 const char *name, *p, *ivar_list;
5142 SectionRef S;
5143 int32_t i;
5144 struct objc_ivar_list_t objc_ivar_list;
5145 struct objc_ivar_t ivar;
5146
5147 outs() << "\t\t isa " << format("0x%08" PRIx32"x", objc_class->isa);
5148 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2))) {
5149 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
5150 if (name != nullptr)
5151 outs() << format(" %.*s", left, name);
5152 else
5153 outs() << " (not in an __OBJC section)";
5154 }
5155 outs() << "\n";
5156
5157 outs() << "\t super_class "
5158 << format("0x%08" PRIx32"x", objc_class->super_class);
5159 if (info->verbose) {
5160 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
5161 if (name != nullptr)
5162 outs() << format(" %.*s", left, name);
5163 else
5164 outs() << " (not in an __OBJC section)";
5165 }
5166 outs() << "\n";
5167
5168 outs() << "\t\t name " << format("0x%08" PRIx32"x", objc_class->name);
5169 if (info->verbose) {
5170 name = get_pointer_32(objc_class->name, offset, left, S, info, true);
5171 if (name != nullptr)
5172 outs() << format(" %.*s", left, name);
5173 else
5174 outs() << " (not in an __OBJC section)";
5175 }
5176 outs() << "\n";
5177
5178 outs() << "\t\t version " << format("0x%08" PRIx32"x", objc_class->version)
5179 << "\n";
5180
5181 outs() << "\t\t info " << format("0x%08" PRIx32"x", objc_class->info);
5182 if (info->verbose) {
5183 if (CLS_GETINFO(objc_class, CLS_CLASS)((objc_class)->info & (0x1)))
5184 outs() << " CLS_CLASS";
5185 else if (CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2)))
5186 outs() << " CLS_META";
5187 }
5188 outs() << "\n";
5189
5190 outs() << "\t instance_size "
5191 << format("0x%08" PRIx32"x", objc_class->instance_size) << "\n";
5192
5193 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
5194 outs() << "\t\t ivars " << format("0x%08" PRIx32"x", objc_class->ivars);
5195 if (p != nullptr) {
5196 if (left > sizeof(struct objc_ivar_list_t)) {
5197 outs() << "\n";
5198 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
5199 } else {
5200 outs() << " (entends past the end of the section)\n";
5201 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
5202 memcpy(&objc_ivar_list, p, left);
5203 }
5204 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5205 swapStruct(objc_ivar_list);
5206 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5207 ivar_list = p + sizeof(struct objc_ivar_list_t);
5208 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5209 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5210 outs() << "\t\t remaining ivar's extend past the of the section\n";
5211 break;
5212 }
5213 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
5214 sizeof(struct objc_ivar_t));
5215 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5216 swapStruct(ivar);
5217
5218 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32"x", ivar.ivar_name);
5219 if (info->verbose) {
5220 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
5221 if (name != nullptr)
5222 outs() << format(" %.*s", xleft, name);
5223 else
5224 outs() << " (not in an __OBJC section)";
5225 }
5226 outs() << "\n";
5227
5228 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32"x", ivar.ivar_type);
5229 if (info->verbose) {
5230 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
5231 if (name != nullptr)
5232 outs() << format(" %.*s", xleft, name);
5233 else
5234 outs() << " (not in an __OBJC section)";
5235 }
5236 outs() << "\n";
5237
5238 outs() << "\t\t ivar_offset "
5239 << format("0x%08" PRIx32"x", ivar.ivar_offset) << "\n";
5240 }
5241 } else {
5242 outs() << " (not in an __OBJC section)\n";
5243 }
5244
5245 outs() << "\t\t methods " << format("0x%08" PRIx32"x", objc_class->methodLists);
5246 if (print_method_list(objc_class->methodLists, info))
5247 outs() << " (not in an __OBJC section)\n";
5248
5249 outs() << "\t\t cache " << format("0x%08" PRIx32"x", objc_class->cache)
5250 << "\n";
5251
5252 outs() << "\t\tprotocols " << format("0x%08" PRIx32"x", objc_class->protocols);
5253 if (print_protocol_list(objc_class->protocols, 16, info))
5254 outs() << " (not in an __OBJC section)\n";
5255}
5256
5257static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5258 struct DisassembleInfo *info) {
5259 uint32_t offset, left;
5260 const char *name;
5261 SectionRef S;
5262
5263 outs() << "\t category name "
5264 << format("0x%08" PRIx32"x", objc_category->category_name);
5265 if (info->verbose) {
5266 name = get_pointer_32(objc_category->category_name, offset, left, S, info,
5267 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\t class name "
5276 << format("0x%08" PRIx32"x", objc_category->class_name);
5277 if (info->verbose) {
5278 name =
5279 get_pointer_32(objc_category->class_name, offset, left, S, info, true);
5280 if (name != nullptr)
5281 outs() << format(" %.*s", left, name);
5282 else
5283 outs() << " (not in an __OBJC section)";
5284 }
5285 outs() << "\n";
5286
5287 outs() << "\t instance methods "
5288 << format("0x%08" PRIx32"x", objc_category->instance_methods);
5289 if (print_method_list(objc_category->instance_methods, info))
5290 outs() << " (not in an __OBJC section)\n";
5291
5292 outs() << "\t class methods "
5293 << format("0x%08" PRIx32"x", objc_category->class_methods);
5294 if (print_method_list(objc_category->class_methods, info))
5295 outs() << " (not in an __OBJC section)\n";
5296}
5297
5298static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
5299 struct category64_t c;
5300 const char *r;
5301 uint32_t offset, xoffset, left;
5302 SectionRef S, xS;
5303 const char *name, *sym_name;
5304 uint64_t n_value;
5305
5306 r = get_pointer_64(p, offset, left, S, info);
5307 if (r == nullptr)
5308 return;
5309 memset(&c, '\0', sizeof(struct category64_t));
5310 if (left < sizeof(struct category64_t)) {
5311 memcpy(&c, r, left);
5312 outs() << " (category_t entends past the end of the section)\n";
5313 } else
5314 memcpy(&c, r, sizeof(struct category64_t));
5315 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5316 swapStruct(c);
5317
5318 outs() << " name ";
5319 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name)__builtin_offsetof(struct category64_t, name), S,
5320 info, n_value, c.name);
5321 if (n_value != 0) {
5322 if (info->verbose && sym_name != nullptr)
5323 outs() << sym_name;
5324 else
5325 outs() << format("0x%" PRIx64"l" "x", n_value);
5326 if (c.name != 0)
5327 outs() << " + " << format("0x%" PRIx64"l" "x", c.name);
5328 } else
5329 outs() << format("0x%" PRIx64"l" "x", c.name);
5330 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
5331 if (name != nullptr)
5332 outs() << format(" %.*s", left, name);
5333 outs() << "\n";
5334
5335 outs() << " cls ";
5336 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls)__builtin_offsetof(struct category64_t, cls), S, info,
5337 n_value, c.cls);
5338 if (n_value != 0) {
5339 if (info->verbose && sym_name != nullptr)
5340 outs() << sym_name;
5341 else
5342 outs() << format("0x%" PRIx64"l" "x", n_value);
5343 if (c.cls != 0)
5344 outs() << " + " << format("0x%" PRIx64"l" "x", c.cls);
5345 } else
5346 outs() << format("0x%" PRIx64"l" "x", c.cls);
5347 outs() << "\n";
5348 if (c.cls + n_value != 0)
5349 print_class64_t(c.cls + n_value, info);
5350
5351 outs() << " instanceMethods ";
5352 sym_name =
5353 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods)__builtin_offsetof(struct category64_t, instanceMethods), S,
5354 info, n_value, c.instanceMethods);
5355 if (n_value != 0) {
5356 if (info->verbose && sym_name != nullptr)
5357 outs() << sym_name;
5358 else
5359 outs() << format("0x%" PRIx64"l" "x", n_value);
5360 if (c.instanceMethods != 0)
5361 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceMethods);
5362 } else
5363 outs() << format("0x%" PRIx64"l" "x", c.instanceMethods);
5364 outs() << "\n";
5365 if (c.instanceMethods + n_value != 0)
5366 print_method_list64_t(c.instanceMethods + n_value, info, "");
5367
5368 outs() << " classMethods ";
5369 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods)__builtin_offsetof(struct category64_t, classMethods),
5370 S, info, n_value, c.classMethods);
5371 if (n_value != 0) {
5372 if (info->verbose && sym_name != nullptr)
5373 outs() << sym_name;
5374 else
5375 outs() << format("0x%" PRIx64"l" "x", n_value);
5376 if (c.classMethods != 0)
5377 outs() << " + " << format("0x%" PRIx64"l" "x", c.classMethods);
5378 } else
5379 outs() << format("0x%" PRIx64"l" "x", c.classMethods);
5380 outs() << "\n";
5381 if (c.classMethods + n_value != 0)
5382 print_method_list64_t(c.classMethods + n_value, info, "");
5383
5384 outs() << " protocols ";
5385 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols)__builtin_offsetof(struct category64_t, protocols), S,
5386 info, n_value, c.protocols);
5387 if (n_value != 0) {
5388 if (info->verbose && sym_name != nullptr)
5389 outs() << sym_name;
5390 else
5391 outs() << format("0x%" PRIx64"l" "x", n_value);
5392 if (c.protocols != 0)
5393 outs() << " + " << format("0x%" PRIx64"l" "x", c.protocols);
5394 } else
5395 outs() << format("0x%" PRIx64"l" "x", c.protocols);
5396 outs() << "\n";
5397 if (c.protocols + n_value != 0)
5398 print_protocol_list64_t(c.protocols + n_value, info);
5399
5400 outs() << "instanceProperties ";
5401 sym_name =
5402 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties)__builtin_offsetof(struct category64_t, instanceProperties),
5403 S, info, n_value, c.instanceProperties);
5404 if (n_value != 0) {
5405 if (info->verbose && sym_name != nullptr)
5406 outs() << sym_name;
5407 else
5408 outs() << format("0x%" PRIx64"l" "x", n_value);
5409 if (c.instanceProperties != 0)
5410 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceProperties);
5411 } else
5412 outs() << format("0x%" PRIx64"l" "x", c.instanceProperties);
5413 outs() << "\n";
5414 if (c.instanceProperties + n_value != 0)
5415 print_objc_property_list64(c.instanceProperties + n_value, info);
5416}
5417
5418static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
5419 struct category32_t c;
5420 const char *r;
5421 uint32_t offset, left;
5422 SectionRef S, xS;
5423 const char *name;
5424
5425 r = get_pointer_32(p, offset, left, S, info);
5426 if (r == nullptr)
5427 return;
5428 memset(&c, '\0', sizeof(struct category32_t));
5429 if (left < sizeof(struct category32_t)) {
5430 memcpy(&c, r, left);
5431 outs() << " (category_t entends past the end of the section)\n";
5432 } else
5433 memcpy(&c, r, sizeof(struct category32_t));
5434 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5435 swapStruct(c);
5436
5437 outs() << " name " << format("0x%" PRIx32"x", c.name);
5438 name = get_symbol_32(offset + offsetof(struct category32_t, name)__builtin_offsetof(struct category32_t, name), S, info,
5439 c.name);
5440 if (name)
5441 outs() << " " << name;
5442 outs() << "\n";
5443
5444 outs() << " cls " << format("0x%" PRIx32"x", c.cls) << "\n";
5445 if (c.cls != 0)
5446 print_class32_t(c.cls, info);
5447 outs() << " instanceMethods " << format("0x%" PRIx32"x", c.instanceMethods)
5448 << "\n";
5449 if (c.instanceMethods != 0)
5450 print_method_list32_t(c.instanceMethods, info, "");
5451 outs() << " classMethods " << format("0x%" PRIx32"x", c.classMethods)
5452 << "\n";
5453 if (c.classMethods != 0)
5454 print_method_list32_t(c.classMethods, info, "");
5455 outs() << " protocols " << format("0x%" PRIx32"x", c.protocols) << "\n";
5456 if (c.protocols != 0)
5457 print_protocol_list32_t(c.protocols, info);
5458 outs() << "instanceProperties " << format("0x%" PRIx32"x", c.instanceProperties)
5459 << "\n";
5460 if (c.instanceProperties != 0)
5461 print_objc_property_list32(c.instanceProperties, info);
5462}
5463
5464static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
5465 uint32_t i, left, offset, xoffset;
5466 uint64_t p, n_value;
5467 struct message_ref64 mr;
5468 const char *name, *sym_name;
5469 const char *r;
5470 SectionRef xS;
5471
5472 if (S == SectionRef())
5473 return;
5474
5475 StringRef SectName;
5476 S.getName(SectName);
5477 DataRefImpl Ref = S.getRawDataRefImpl();
5478 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5479 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5480 offset = 0;
5481 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5482 p = S.getAddress() + i;
5483 r = get_pointer_64(p, offset, left, S, info);
5484 if (r == nullptr)
5485 return;
5486 memset(&mr, '\0', sizeof(struct message_ref64));
5487 if (left < sizeof(struct message_ref64)) {
5488 memcpy(&mr, r, left);
5489 outs() << " (message_ref entends past the end of the section)\n";
5490 } else
5491 memcpy(&mr, r, sizeof(struct message_ref64));
5492 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5493 swapStruct(mr);
5494
5495 outs() << " imp ";
5496 name = get_symbol_64(offset + offsetof(struct message_ref64, imp)__builtin_offsetof(struct message_ref64, imp), S, info,
5497 n_value, mr.imp);
5498 if (n_value != 0) {
5499 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
5500 if (mr.imp != 0)
5501 outs() << "+ " << format("0x%" PRIx64"l" "x", mr.imp) << " ";
5502 } else
5503 outs() << format("0x%" PRIx64"l" "x", mr.imp) << " ";
5504 if (name != nullptr)
5505 outs() << " " << name;
5506 outs() << "\n";
5507
5508 outs() << " sel ";
5509 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel)__builtin_offsetof(struct message_ref64, sel), S,
5510 info, n_value, mr.sel);
5511 if (n_value != 0) {
5512 if (info->verbose && sym_name != nullptr)
5513 outs() << sym_name;
5514 else
5515 outs() << format("0x%" PRIx64"l" "x", n_value);
5516 if (mr.sel != 0)
5517 outs() << " + " << format("0x%" PRIx64"l" "x", mr.sel);
5518 } else
5519 outs() << format("0x%" PRIx64"l" "x", mr.sel);
5520 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
5521 if (name != nullptr)
5522 outs() << format(" %.*s", left, name);
5523 outs() << "\n";
5524
5525 offset += sizeof(struct message_ref64);
5526 }
5527}
5528
5529static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
5530 uint32_t i, left, offset, xoffset, p;
5531 struct message_ref32 mr;
5532 const char *name, *r;
5533 SectionRef xS;
5534
5535 if (S == SectionRef())
5536 return;
5537
5538 StringRef SectName;
5539 S.getName(SectName);
5540 DataRefImpl Ref = S.getRawDataRefImpl();
5541 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5542 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5543 offset = 0;
5544 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5545 p = S.getAddress() + i;
5546 r = get_pointer_32(p, offset, left, S, info);
5547 if (r == nullptr)
5548 return;
5549 memset(&mr, '\0', sizeof(struct message_ref32));
5550 if (left < sizeof(struct message_ref32)) {
5551 memcpy(&mr, r, left);
5552 outs() << " (message_ref entends past the end of the section)\n";
5553 } else
5554 memcpy(&mr, r, sizeof(struct message_ref32));
5555 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5556 swapStruct(mr);
5557
5558 outs() << " imp " << format("0x%" PRIx32"x", mr.imp);
5559 name = get_symbol_32(offset + offsetof(struct message_ref32, imp)__builtin_offsetof(struct message_ref32, imp), S, info,
5560 mr.imp);
5561 if (name != nullptr)
5562 outs() << " " << name;
5563 outs() << "\n";
5564
5565 outs() << " sel " << format("0x%" PRIx32"x", mr.sel);
5566 name = get_pointer_32(mr.sel, xoffset, left, xS, info);
5567 if (name != nullptr)
5568 outs() << " " << name;
5569 outs() << "\n";
5570
5571 offset += sizeof(struct message_ref32);
5572 }
5573}
5574
5575static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
5576 uint32_t left, offset, swift_version;
5577 uint64_t p;
5578 struct objc_image_info64 o;
5579 const char *r;
5580
5581 if (S == SectionRef())
5582 return;
5583
5584 StringRef SectName;
5585 S.getName(SectName);
5586 DataRefImpl Ref = S.getRawDataRefImpl();
5587 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5588 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5589 p = S.getAddress();
5590 r = get_pointer_64(p, offset, left, S, info);
5591 if (r == nullptr)
5592 return;
5593 memset(&o, '\0', sizeof(struct objc_image_info64));
5594 if (left < sizeof(struct objc_image_info64)) {
5595 memcpy(&o, r, left);
5596 outs() << " (objc_image_info entends past the end of the section)\n";
5597 } else
5598 memcpy(&o, r, sizeof(struct objc_image_info64));
5599 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5600 swapStruct(o);
5601 outs() << " version " << o.version << "\n";
5602 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5603 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5604 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5605 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5606 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5607 if (o.flags & OBJC_IMAGE_IS_SIMULATED(1 << 5))
5608 outs() << " OBJC_IMAGE_IS_SIMULATED";
5609 if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES(1 << 6))
5610 outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";
5611 swift_version = (o.flags >> 8) & 0xff;
5612 if (swift_version != 0) {
5613 if (swift_version == 1)
5614 outs() << " Swift 1.0";
5615 else if (swift_version == 2)
5616 outs() << " Swift 1.1";
5617 else if(swift_version == 3)
5618 outs() << " Swift 2.0";
5619 else if(swift_version == 4)
5620 outs() << " Swift 3.0";
5621 else if(swift_version == 5)
5622 outs() << " Swift 4.0";
5623 else if(swift_version == 6)
5624 outs() << " Swift 4.1";
5625 else
5626 outs() << " unknown future Swift version (" << swift_version << ")";
5627 }
5628 outs() << "\n";
5629}
5630
5631static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
5632 uint32_t left, offset, swift_version, p;
5633 struct objc_image_info32 o;
5634 const char *r;
5635
5636 if (S == SectionRef())
5637 return;
5638
5639 StringRef SectName;
5640 S.getName(SectName);
5641 DataRefImpl Ref = S.getRawDataRefImpl();
5642 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5643 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5644 p = S.getAddress();
5645 r = get_pointer_32(p, offset, left, S, info);
5646 if (r == nullptr)
5647 return;
5648 memset(&o, '\0', sizeof(struct objc_image_info32));
5649 if (left < sizeof(struct objc_image_info32)) {
5650 memcpy(&o, r, left);
5651 outs() << " (objc_image_info entends past the end of the section)\n";
5652 } else
5653 memcpy(&o, r, sizeof(struct objc_image_info32));
5654 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5655 swapStruct(o);
5656 outs() << " version " << o.version << "\n";
5657 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5658 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5659 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5660 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5661 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5662 swift_version = (o.flags >> 8) & 0xff;
5663 if (swift_version != 0) {
5664 if (swift_version == 1)
5665 outs() << " Swift 1.0";
5666 else if (swift_version == 2)
5667 outs() << " Swift 1.1";
5668 else if(swift_version == 3)
5669 outs() << " Swift 2.0";
5670 else if(swift_version == 4)
5671 outs() << " Swift 3.0";
5672 else if(swift_version == 5)
5673 outs() << " Swift 4.0";
5674 else if(swift_version == 6)
5675 outs() << " Swift 4.1";
5676 else
5677 outs() << " unknown future Swift version (" << swift_version << ")";
5678 }
5679 outs() << "\n";
5680}
5681
5682static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
5683 uint32_t left, offset, p;
5684 struct imageInfo_t o;
5685 const char *r;
5686
5687 StringRef SectName;
5688 S.getName(SectName);
5689 DataRefImpl Ref = S.getRawDataRefImpl();
5690 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5691 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5692 p = S.getAddress();
5693 r = get_pointer_32(p, offset, left, S, info);
5694 if (r == nullptr)
5695 return;
5696 memset(&o, '\0', sizeof(struct imageInfo_t));
5697 if (left < sizeof(struct imageInfo_t)) {
5698 memcpy(&o, r, left);
5699 outs() << " (imageInfo entends past the end of the section)\n";
5700 } else
5701 memcpy(&o, r, sizeof(struct imageInfo_t));
5702 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5703 swapStruct(o);
5704 outs() << " version " << o.version << "\n";
5705 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5706 if (o.flags & 0x1)
5707 outs() << " F&C";
5708 if (o.flags & 0x2)
5709 outs() << " GC";
5710 if (o.flags & 0x4)
5711 outs() << " GC-only";
5712 else
5713 outs() << " RR";
5714 outs() << "\n";
5715}
5716
5717static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
5718 SymbolAddressMap AddrMap;
5719 if (verbose)
5720 CreateSymbolAddressMap(O, &AddrMap);
5721
5722 std::vector<SectionRef> Sections;
5723 for (const SectionRef &Section : O->sections()) {
5724 StringRef SectName;
5725 Section.getName(SectName);
5726 Sections.push_back(Section);
5727 }
5728
5729 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
5730
5731 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
5732 if (CL == SectionRef())
5733 CL = get_section(O, "__DATA", "__objc_classlist");
5734 if (CL == SectionRef())
5735 CL = get_section(O, "__DATA_CONST", "__objc_classlist");
5736 if (CL == SectionRef())
5737 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
5738 info.S = CL;
5739 walk_pointer_list_64("class", CL, O, &info, print_class64_t);
5740
5741 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
5742 if (CR == SectionRef())