Bug Summary

File:tools/llvm-objdump/MachODump.cpp
Location:line 1990, column 25
Description:Function call argument is an uninitialized value

Annotated Source Code

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/Object/MachO.h"
15#include "llvm-objdump.h"
16#include "llvm-c/Disassembler.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/Triple.h"
20#include "llvm/Config/config.h"
21#include "llvm/DebugInfo/DIContext.h"
22#include "llvm/DebugInfo/DWARF/DWARFContext.h"
23#include "llvm/MC/MCAsmInfo.h"
24#include "llvm/MC/MCContext.h"
25#include "llvm/MC/MCDisassembler/MCDisassembler.h"
26#include "llvm/MC/MCInst.h"
27#include "llvm/MC/MCInstPrinter.h"
28#include "llvm/MC/MCInstrDesc.h"
29#include "llvm/MC/MCInstrInfo.h"
30#include "llvm/MC/MCRegisterInfo.h"
31#include "llvm/MC/MCSubtargetInfo.h"
32#include "llvm/Object/MachOUniversal.h"
33#include "llvm/Support/Casting.h"
34#include "llvm/Support/CommandLine.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/Endian.h"
37#include "llvm/Support/Format.h"
38#include "llvm/Support/FormattedStream.h"
39#include "llvm/Support/GraphWriter.h"
40#include "llvm/Support/LEB128.h"
41#include "llvm/Support/MachO.h"
42#include "llvm/Support/MemoryBuffer.h"
43#include "llvm/Support/TargetRegistry.h"
44#include "llvm/Support/TargetSelect.h"
45#include "llvm/Support/raw_ostream.h"
46#include <algorithm>
47#include <cstring>
48#include <system_error>
49
50#if HAVE_CXXABI_H1
51#include <cxxabi.h>
52#endif
53
54using namespace llvm;
55using namespace object;
56
57static cl::opt<bool>
58 UseDbg("g",
59 cl::desc("Print line information from debug info if available"));
60
61static cl::opt<std::string> DSYMFile("dsym",
62 cl::desc("Use .dSYM file for debug info"));
63
64static cl::opt<bool> FullLeadingAddr("full-leading-addr",
65 cl::desc("Print full leading address"));
66
67static cl::opt<bool> NoLeadingAddr("no-leading-addr",
68 cl::desc("Print no leading address"));
69
70cl::opt<bool> llvm::UniversalHeaders("universal-headers",
71 cl::desc("Print Mach-O universal headers "
72 "(requires -macho)"));
73
74cl::opt<bool>
75 llvm::ArchiveHeaders("archive-headers",
76 cl::desc("Print archive headers for Mach-O archives "
77 "(requires -macho)"));
78
79cl::opt<bool>
80 ArchiveMemberOffsets("archive-member-offsets",
81 cl::desc("Print the offset to each archive member for "
82 "Mach-O archives (requires -macho and "
83 "-archive-headers)"));
84
85cl::opt<bool>
86 llvm::IndirectSymbols("indirect-symbols",
87 cl::desc("Print indirect symbol table for Mach-O "
88 "objects (requires -macho)"));
89
90cl::opt<bool>
91 llvm::DataInCode("data-in-code",
92 cl::desc("Print the data in code table for Mach-O objects "
93 "(requires -macho)"));
94
95cl::opt<bool>
96 llvm::LinkOptHints("link-opt-hints",
97 cl::desc("Print the linker optimization hints for "
98 "Mach-O objects (requires -macho)"));
99
100cl::opt<bool>
101 llvm::InfoPlist("info-plist",
102 cl::desc("Print the info plist section as strings for "
103 "Mach-O objects (requires -macho)"));
104
105cl::opt<bool>
106 llvm::DylibsUsed("dylibs-used",
107 cl::desc("Print the shared libraries used for linked "
108 "Mach-O files (requires -macho)"));
109
110cl::opt<bool>
111 llvm::DylibId("dylib-id",
112 cl::desc("Print the shared library's id for the dylib Mach-O "
113 "file (requires -macho)"));
114
115cl::opt<bool>
116 llvm::NonVerbose("non-verbose",
117 cl::desc("Print the info for Mach-O objects in "
118 "non-verbose or numeric form (requires -macho)"));
119
120cl::opt<bool>
121 llvm::ObjcMetaData("objc-meta-data",
122 cl::desc("Print the Objective-C runtime meta data for "
123 "Mach-O files (requires -macho)"));
124
125cl::opt<std::string> llvm::DisSymName(
126 "dis-symname",
127 cl::desc("disassemble just this symbol's instructions (requires -macho"));
128
129static cl::opt<bool> NoSymbolicOperands(
130 "no-symbolic-operands",
131 cl::desc("do not symbolic operands when disassembling (requires -macho)"));
132
133static cl::list<std::string>
134 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
135 cl::ZeroOrMore);
136
137bool ArchAll = false;
138
139static std::string ThumbTripleName;
140
141static const Target *GetTarget(const MachOObjectFile *MachOObj,
142 const char **McpuDefault,
143 const Target **ThumbTarget) {
144 // Figure out the target triple.
145 if (TripleName.empty()) {
146 llvm::Triple TT("unknown-unknown-unknown");
147 llvm::Triple ThumbTriple = Triple();
148 TT = MachOObj->getArch(McpuDefault, &ThumbTriple);
149 TripleName = TT.str();
150 ThumbTripleName = ThumbTriple.str();
151 }
152
153 // Get the target specific parser.
154 std::string Error;
155 const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
156 if (TheTarget && ThumbTripleName.empty())
157 return TheTarget;
158
159 *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
160 if (*ThumbTarget)
161 return TheTarget;
162
163 errs() << "llvm-objdump: error: unable to get target for '";
164 if (!TheTarget)
165 errs() << TripleName;
166 else
167 errs() << ThumbTripleName;
168 errs() << "', see --version and --triple.\n";
169 return nullptr;
170}
171
172struct SymbolSorter {
173 bool operator()(const SymbolRef &A, const SymbolRef &B) {
174 ErrorOr<SymbolRef::Type> ATypeOrErr = A.getType();
175 if (std::error_code EC = ATypeOrErr.getError())
176 report_fatal_error(EC.message());
177 SymbolRef::Type AType = *ATypeOrErr;
178 ErrorOr<SymbolRef::Type> BTypeOrErr = B.getType();
179 if (std::error_code EC = BTypeOrErr.getError())
180 report_fatal_error(EC.message());
181 SymbolRef::Type BType = *BTypeOrErr;
182 uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue();
183 uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue();
184 return AAddr < BAddr;
185 }
186};
187
188// Types for the storted data in code table that is built before disassembly
189// and the predicate function to sort them.
190typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
191typedef std::vector<DiceTableEntry> DiceTable;
192typedef DiceTable::iterator dice_table_iterator;
193
194// This is used to search for a data in code table entry for the PC being
195// disassembled. The j parameter has the PC in j.first. A single data in code
196// table entry can cover many bytes for each of its Kind's. So if the offset,
197// aka the i.first value, of the data in code table entry plus its Length
198// covers the PC being searched for this will return true. If not it will
199// return false.
200static bool compareDiceTableEntries(const DiceTableEntry &i,
201 const DiceTableEntry &j) {
202 uint16_t Length;
203 i.second.getLength(Length);
204
205 return j.first >= i.first && j.first < i.first + Length;
206}
207
208static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
209 unsigned short Kind) {
210 uint32_t Value, Size = 1;
211
212 switch (Kind) {
213 default:
214 case MachO::DICE_KIND_DATA:
215 if (Length >= 4) {
216 if (!NoShowRawInsn)
217 dumpBytes(makeArrayRef(bytes, 4), outs());
218 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
219 outs() << "\t.long " << Value;
220 Size = 4;
221 } else if (Length >= 2) {
222 if (!NoShowRawInsn)
223 dumpBytes(makeArrayRef(bytes, 2), outs());
224 Value = bytes[1] << 8 | bytes[0];
225 outs() << "\t.short " << Value;
226 Size = 2;
227 } else {
228 if (!NoShowRawInsn)
229 dumpBytes(makeArrayRef(bytes, 2), outs());
230 Value = bytes[0];
231 outs() << "\t.byte " << Value;
232 Size = 1;
233 }
234 if (Kind == MachO::DICE_KIND_DATA)
235 outs() << "\t@ KIND_DATA\n";
236 else
237 outs() << "\t@ data in code kind = " << Kind << "\n";
238 break;
239 case MachO::DICE_KIND_JUMP_TABLE8:
240 if (!NoShowRawInsn)
241 dumpBytes(makeArrayRef(bytes, 1), outs());
242 Value = bytes[0];
243 outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
244 Size = 1;
245 break;
246 case MachO::DICE_KIND_JUMP_TABLE16:
247 if (!NoShowRawInsn)
248 dumpBytes(makeArrayRef(bytes, 2), outs());
249 Value = bytes[1] << 8 | bytes[0];
250 outs() << "\t.short " << format("%5u", Value & 0xffff)
251 << "\t@ KIND_JUMP_TABLE16\n";
252 Size = 2;
253 break;
254 case MachO::DICE_KIND_JUMP_TABLE32:
255 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
256 if (!NoShowRawInsn)
257 dumpBytes(makeArrayRef(bytes, 4), outs());
258 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
259 outs() << "\t.long " << Value;
260 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
261 outs() << "\t@ KIND_JUMP_TABLE32\n";
262 else
263 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
264 Size = 4;
265 break;
266 }
267 return Size;
268}
269
270static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
271 std::vector<SectionRef> &Sections,
272 std::vector<SymbolRef> &Symbols,
273 SmallVectorImpl<uint64_t> &FoundFns,
274 uint64_t &BaseSegmentAddress) {
275 for (const SymbolRef &Symbol : MachOObj->symbols()) {
276 ErrorOr<StringRef> SymName = Symbol.getName();
277 if (std::error_code EC = SymName.getError())
278 report_fatal_error(EC.message());
279 if (!SymName->startswith("ltmp"))
280 Symbols.push_back(Symbol);
281 }
282
283 for (const SectionRef &Section : MachOObj->sections()) {
284 StringRef SectName;
285 Section.getName(SectName);
286 Sections.push_back(Section);
287 }
288
289 bool BaseSegmentAddressSet = false;
290 for (const auto &Command : MachOObj->load_commands()) {
291 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
292 // We found a function starts segment, parse the addresses for later
293 // consumption.
294 MachO::linkedit_data_command LLC =
295 MachOObj->getLinkeditDataLoadCommand(Command);
296
297 MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
298 } else if (Command.C.cmd == MachO::LC_SEGMENT) {
299 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
300 StringRef SegName = SLC.segname;
301 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
302 BaseSegmentAddressSet = true;
303 BaseSegmentAddress = SLC.vmaddr;
304 }
305 }
306 }
307}
308
309static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
310 uint32_t n, uint32_t count,
311 uint32_t stride, uint64_t addr) {
312 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
313 uint32_t nindirectsyms = Dysymtab.nindirectsyms;
314 if (n > nindirectsyms)
315 outs() << " (entries start past the end of the indirect symbol "
316 "table) (reserved1 field greater than the table size)";
317 else if (n + count > nindirectsyms)
318 outs() << " (entries extends past the end of the indirect symbol "
319 "table)";
320 outs() << "\n";
321 uint32_t cputype = O->getHeader().cputype;
322 if (cputype & MachO::CPU_ARCH_ABI64)
323 outs() << "address index";
324 else
325 outs() << "address index";
326 if (verbose)
327 outs() << " name\n";
328 else
329 outs() << "\n";
330 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
331 if (cputype & MachO::CPU_ARCH_ABI64)
332 outs() << format("0x%016" PRIx64"l" "x", addr + j * stride) << " ";
333 else
334 outs() << format("0x%08" PRIx32"x", addr + j * stride) << " ";
335 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
336 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
337 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
338 outs() << "LOCAL\n";
339 continue;
340 }
341 if (indirect_symbol ==
342 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
343 outs() << "LOCAL ABSOLUTE\n";
344 continue;
345 }
346 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
347 outs() << "ABSOLUTE\n";
348 continue;
349 }
350 outs() << format("%5u ", indirect_symbol);
351 if (verbose) {
352 MachO::symtab_command Symtab = O->getSymtabLoadCommand();
353 if (indirect_symbol < Symtab.nsyms) {
354 symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
355 SymbolRef Symbol = *Sym;
356 ErrorOr<StringRef> SymName = Symbol.getName();
357 if (std::error_code EC = SymName.getError())
358 report_fatal_error(EC.message());
359 outs() << *SymName;
360 } else {
361 outs() << "?";
362 }
363 }
364 outs() << "\n";
365 }
366}
367
368static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
369 for (const auto &Load : O->load_commands()) {
370 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
371 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
372 for (unsigned J = 0; J < Seg.nsects; ++J) {
373 MachO::section_64 Sec = O->getSection64(Load, J);
374 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
375 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
376 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
377 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
378 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
379 section_type == MachO::S_SYMBOL_STUBS) {
380 uint32_t stride;
381 if (section_type == MachO::S_SYMBOL_STUBS)
382 stride = Sec.reserved2;
383 else
384 stride = 8;
385 if (stride == 0) {
386 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
387 << Sec.sectname << ") "
388 << "(size of stubs in reserved2 field is zero)\n";
389 continue;
390 }
391 uint32_t count = Sec.size / stride;
392 outs() << "Indirect symbols for (" << Sec.segname << ","
393 << Sec.sectname << ") " << count << " entries";
394 uint32_t n = Sec.reserved1;
395 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
396 }
397 }
398 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
399 MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
400 for (unsigned J = 0; J < Seg.nsects; ++J) {
401 MachO::section Sec = O->getSection(Load, J);
402 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
403 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
404 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
405 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
406 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
407 section_type == MachO::S_SYMBOL_STUBS) {
408 uint32_t stride;
409 if (section_type == MachO::S_SYMBOL_STUBS)
410 stride = Sec.reserved2;
411 else
412 stride = 4;
413 if (stride == 0) {
414 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
415 << Sec.sectname << ") "
416 << "(size of stubs in reserved2 field is zero)\n";
417 continue;
418 }
419 uint32_t count = Sec.size / stride;
420 outs() << "Indirect symbols for (" << Sec.segname << ","
421 << Sec.sectname << ") " << count << " entries";
422 uint32_t n = Sec.reserved1;
423 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
424 }
425 }
426 }
427 }
428}
429
430static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
431 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
432 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
433 outs() << "Data in code table (" << nentries << " entries)\n";
434 outs() << "offset length kind\n";
435 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
436 ++DI) {
437 uint32_t Offset;
438 DI->getOffset(Offset);
439 outs() << format("0x%08" PRIx32"x", Offset) << " ";
440 uint16_t Length;
441 DI->getLength(Length);
442 outs() << format("%6u", Length) << " ";
443 uint16_t Kind;
444 DI->getKind(Kind);
445 if (verbose) {
446 switch (Kind) {
447 case MachO::DICE_KIND_DATA:
448 outs() << "DATA";
449 break;
450 case MachO::DICE_KIND_JUMP_TABLE8:
451 outs() << "JUMP_TABLE8";
452 break;
453 case MachO::DICE_KIND_JUMP_TABLE16:
454 outs() << "JUMP_TABLE16";
455 break;
456 case MachO::DICE_KIND_JUMP_TABLE32:
457 outs() << "JUMP_TABLE32";
458 break;
459 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
460 outs() << "ABS_JUMP_TABLE32";
461 break;
462 default:
463 outs() << format("0x%04" PRIx32"x", Kind);
464 break;
465 }
466 } else
467 outs() << format("0x%04" PRIx32"x", Kind);
468 outs() << "\n";
469 }
470}
471
472static void PrintLinkOptHints(MachOObjectFile *O) {
473 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
474 const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
475 uint32_t nloh = LohLC.datasize;
476 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
477 for (uint32_t i = 0; i < nloh;) {
478 unsigned n;
479 uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
480 i += n;
481 outs() << " identifier " << identifier << " ";
482 if (i >= nloh)
483 return;
484 switch (identifier) {
485 case 1:
486 outs() << "AdrpAdrp\n";
487 break;
488 case 2:
489 outs() << "AdrpLdr\n";
490 break;
491 case 3:
492 outs() << "AdrpAddLdr\n";
493 break;
494 case 4:
495 outs() << "AdrpLdrGotLdr\n";
496 break;
497 case 5:
498 outs() << "AdrpAddStr\n";
499 break;
500 case 6:
501 outs() << "AdrpLdrGotStr\n";
502 break;
503 case 7:
504 outs() << "AdrpAdd\n";
505 break;
506 case 8:
507 outs() << "AdrpLdrGot\n";
508 break;
509 default:
510 outs() << "Unknown identifier value\n";
511 break;
512 }
513 uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
514 i += n;
515 outs() << " narguments " << narguments << "\n";
516 if (i >= nloh)
517 return;
518
519 for (uint32_t j = 0; j < narguments; j++) {
520 uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
521 i += n;
522 outs() << "\tvalue " << format("0x%" PRIx64"l" "x", value) << "\n";
523 if (i >= nloh)
524 return;
525 }
526 }
527}
528
529static void PrintDylibs(MachOObjectFile *O, bool JustId) {
530 unsigned Index = 0;
531 for (const auto &Load : O->load_commands()) {
532 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
533 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
534 Load.C.cmd == MachO::LC_LOAD_DYLIB ||
535 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
536 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
537 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
538 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
539 MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
540 if (dl.dylib.name < dl.cmdsize) {
541 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
542 if (JustId)
543 outs() << p << "\n";
544 else {
545 outs() << "\t" << p;
546 outs() << " (compatibility version "
547 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
548 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
549 << (dl.dylib.compatibility_version & 0xff) << ",";
550 outs() << " current version "
551 << ((dl.dylib.current_version >> 16) & 0xffff) << "."
552 << ((dl.dylib.current_version >> 8) & 0xff) << "."
553 << (dl.dylib.current_version & 0xff) << ")\n";
554 }
555 } else {
556 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
557 if (Load.C.cmd == MachO::LC_ID_DYLIB)
558 outs() << "LC_ID_DYLIB ";
559 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
560 outs() << "LC_LOAD_DYLIB ";
561 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
562 outs() << "LC_LOAD_WEAK_DYLIB ";
563 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
564 outs() << "LC_LAZY_LOAD_DYLIB ";
565 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
566 outs() << "LC_REEXPORT_DYLIB ";
567 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
568 outs() << "LC_LOAD_UPWARD_DYLIB ";
569 else
570 outs() << "LC_??? ";
571 outs() << "command " << Index++ << "\n";
572 }
573 }
574 }
575}
576
577typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
578
579static void CreateSymbolAddressMap(MachOObjectFile *O,
580 SymbolAddressMap *AddrMap) {
581 // Create a map of symbol addresses to symbol names.
582 for (const SymbolRef &Symbol : O->symbols()) {
583 ErrorOr<SymbolRef::Type> STOrErr = Symbol.getType();
584 if (std::error_code EC = STOrErr.getError())
585 report_fatal_error(EC.message());
586 SymbolRef::Type ST = *STOrErr;
587 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
588 ST == SymbolRef::ST_Other) {
589 uint64_t Address = Symbol.getValue();
590 ErrorOr<StringRef> SymNameOrErr = Symbol.getName();
591 if (std::error_code EC = SymNameOrErr.getError())
592 report_fatal_error(EC.message());
593 StringRef SymName = *SymNameOrErr;
594 if (!SymName.startswith(".objc"))
595 (*AddrMap)[Address] = SymName;
596 }
597 }
598}
599
600// GuessSymbolName is passed the address of what might be a symbol and a
601// pointer to the SymbolAddressMap. It returns the name of a symbol
602// with that address or nullptr if no symbol is found with that address.
603static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
604 const char *SymbolName = nullptr;
605 // A DenseMap can't lookup up some values.
606 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
607 StringRef name = AddrMap->lookup(value);
608 if (!name.empty())
609 SymbolName = name.data();
610 }
611 return SymbolName;
612}
613
614static void DumpCstringChar(const char c) {
615 char p[2];
616 p[0] = c;
617 p[1] = '\0';
618 outs().write_escaped(p);
619}
620
621static void DumpCstringSection(MachOObjectFile *O, const char *sect,
622 uint32_t sect_size, uint64_t sect_addr,
623 bool print_addresses) {
624 for (uint32_t i = 0; i < sect_size; i++) {
625 if (print_addresses) {
626 if (O->is64Bit())
627 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
628 else
629 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
630 }
631 for (; i < sect_size && sect[i] != '\0'; i++)
632 DumpCstringChar(sect[i]);
633 if (i < sect_size && sect[i] == '\0')
634 outs() << "\n";
635 }
636}
637
638static void DumpLiteral4(uint32_t l, float f) {
639 outs() << format("0x%08" PRIx32"x", l);
640 if ((l & 0x7f800000) != 0x7f800000)
641 outs() << format(" (%.16e)\n", f);
642 else {
643 if (l == 0x7f800000)
644 outs() << " (+Infinity)\n";
645 else if (l == 0xff800000)
646 outs() << " (-Infinity)\n";
647 else if ((l & 0x00400000) == 0x00400000)
648 outs() << " (non-signaling Not-a-Number)\n";
649 else
650 outs() << " (signaling Not-a-Number)\n";
651 }
652}
653
654static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
655 uint32_t sect_size, uint64_t sect_addr,
656 bool print_addresses) {
657 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
658 if (print_addresses) {
659 if (O->is64Bit())
660 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
661 else
662 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
663 }
664 float f;
665 memcpy(&f, sect + i, sizeof(float));
666 if (O->isLittleEndian() != sys::IsLittleEndianHost)
667 sys::swapByteOrder(f);
668 uint32_t l;
669 memcpy(&l, sect + i, sizeof(uint32_t));
670 if (O->isLittleEndian() != sys::IsLittleEndianHost)
671 sys::swapByteOrder(l);
672 DumpLiteral4(l, f);
673 }
674}
675
676static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
677 double d) {
678 outs() << format("0x%08" PRIx32"x", l0) << " " << format("0x%08" PRIx32"x", l1);
679 uint32_t Hi, Lo;
680 Hi = (O->isLittleEndian()) ? l1 : l0;
681 Lo = (O->isLittleEndian()) ? l0 : l1;
682
683 // Hi is the high word, so this is equivalent to if(isfinite(d))
684 if ((Hi & 0x7ff00000) != 0x7ff00000)
685 outs() << format(" (%.16e)\n", d);
686 else {
687 if (Hi == 0x7ff00000 && Lo == 0)
688 outs() << " (+Infinity)\n";
689 else if (Hi == 0xfff00000 && Lo == 0)
690 outs() << " (-Infinity)\n";
691 else if ((Hi & 0x00080000) == 0x00080000)
692 outs() << " (non-signaling Not-a-Number)\n";
693 else
694 outs() << " (signaling Not-a-Number)\n";
695 }
696}
697
698static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
699 uint32_t sect_size, uint64_t sect_addr,
700 bool print_addresses) {
701 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
702 if (print_addresses) {
703 if (O->is64Bit())
704 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
705 else
706 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
707 }
708 double d;
709 memcpy(&d, sect + i, sizeof(double));
710 if (O->isLittleEndian() != sys::IsLittleEndianHost)
711 sys::swapByteOrder(d);
712 uint32_t l0, l1;
713 memcpy(&l0, sect + i, sizeof(uint32_t));
714 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
715 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
716 sys::swapByteOrder(l0);
717 sys::swapByteOrder(l1);
718 }
719 DumpLiteral8(O, l0, l1, d);
720 }
721}
722
723static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
724 outs() << format("0x%08" PRIx32"x", l0) << " ";
725 outs() << format("0x%08" PRIx32"x", l1) << " ";
726 outs() << format("0x%08" PRIx32"x", l2) << " ";
727 outs() << format("0x%08" PRIx32"x", l3) << "\n";
728}
729
730static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
731 uint32_t sect_size, uint64_t sect_addr,
732 bool print_addresses) {
733 for (uint32_t i = 0; i < sect_size; i += 16) {
734 if (print_addresses) {
735 if (O->is64Bit())
736 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
737 else
738 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
739 }
740 uint32_t l0, l1, l2, l3;
741 memcpy(&l0, sect + i, sizeof(uint32_t));
742 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
743 memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
744 memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
745 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
746 sys::swapByteOrder(l0);
747 sys::swapByteOrder(l1);
748 sys::swapByteOrder(l2);
749 sys::swapByteOrder(l3);
750 }
751 DumpLiteral16(l0, l1, l2, l3);
752 }
753}
754
755static void DumpLiteralPointerSection(MachOObjectFile *O,
756 const SectionRef &Section,
757 const char *sect, uint32_t sect_size,
758 uint64_t sect_addr,
759 bool print_addresses) {
760 // Collect the literal sections in this Mach-O file.
761 std::vector<SectionRef> LiteralSections;
762 for (const SectionRef &Section : O->sections()) {
763 DataRefImpl Ref = Section.getRawDataRefImpl();
764 uint32_t section_type;
765 if (O->is64Bit()) {
766 const MachO::section_64 Sec = O->getSection64(Ref);
767 section_type = Sec.flags & MachO::SECTION_TYPE;
768 } else {
769 const MachO::section Sec = O->getSection(Ref);
770 section_type = Sec.flags & MachO::SECTION_TYPE;
771 }
772 if (section_type == MachO::S_CSTRING_LITERALS ||
773 section_type == MachO::S_4BYTE_LITERALS ||
774 section_type == MachO::S_8BYTE_LITERALS ||
775 section_type == MachO::S_16BYTE_LITERALS)
776 LiteralSections.push_back(Section);
777 }
778
779 // Set the size of the literal pointer.
780 uint32_t lp_size = O->is64Bit() ? 8 : 4;
781
782 // Collect the external relocation symbols for the literal pointers.
783 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
784 for (const RelocationRef &Reloc : Section.relocations()) {
785 DataRefImpl Rel;
786 MachO::any_relocation_info RE;
787 bool isExtern = false;
788 Rel = Reloc.getRawDataRefImpl();
789 RE = O->getRelocation(Rel);
790 isExtern = O->getPlainRelocationExternal(RE);
791 if (isExtern) {
792 uint64_t RelocOffset = Reloc.getOffset();
793 symbol_iterator RelocSym = Reloc.getSymbol();
794 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
795 }
796 }
797 array_pod_sort(Relocs.begin(), Relocs.end());
798
799 // Dump each literal pointer.
800 for (uint32_t i = 0; i < sect_size; i += lp_size) {
801 if (print_addresses) {
802 if (O->is64Bit())
803 outs() << format("%016" PRIx64"l" "x", sect_addr + i) << " ";
804 else
805 outs() << format("%08" PRIx64"l" "x", sect_addr + i) << " ";
806 }
807 uint64_t lp;
808 if (O->is64Bit()) {
809 memcpy(&lp, sect + i, sizeof(uint64_t));
810 if (O->isLittleEndian() != sys::IsLittleEndianHost)
811 sys::swapByteOrder(lp);
812 } else {
813 uint32_t li;
814 memcpy(&li, sect + i, sizeof(uint32_t));
815 if (O->isLittleEndian() != sys::IsLittleEndianHost)
816 sys::swapByteOrder(li);
817 lp = li;
818 }
819
820 // First look for an external relocation entry for this literal pointer.
821 auto Reloc = std::find_if(
822 Relocs.begin(), Relocs.end(),
823 [&](const std::pair<uint64_t, SymbolRef> &P) { return P.first == i; });
824 if (Reloc != Relocs.end()) {
825 symbol_iterator RelocSym = Reloc->second;
826 ErrorOr<StringRef> SymName = RelocSym->getName();
827 if (std::error_code EC = SymName.getError())
828 report_fatal_error(EC.message());
829 outs() << "external relocation entry for symbol:" << *SymName << "\n";
830 continue;
831 }
832
833 // For local references see what the section the literal pointer points to.
834 auto Sect = std::find_if(LiteralSections.begin(), LiteralSections.end(),
835 [&](const SectionRef &R) {
836 return lp >= R.getAddress() &&
837 lp < R.getAddress() + R.getSize();
838 });
839 if (Sect == LiteralSections.end()) {
840 outs() << format("0x%" PRIx64"l" "x", lp) << " (not in a literal section)\n";
841 continue;
842 }
843
844 uint64_t SectAddress = Sect->getAddress();
845 uint64_t SectSize = Sect->getSize();
846
847 StringRef SectName;
848 Sect->getName(SectName);
849 DataRefImpl Ref = Sect->getRawDataRefImpl();
850 StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
851 outs() << SegmentName << ":" << SectName << ":";
852
853 uint32_t section_type;
854 if (O->is64Bit()) {
855 const MachO::section_64 Sec = O->getSection64(Ref);
856 section_type = Sec.flags & MachO::SECTION_TYPE;
857 } else {
858 const MachO::section Sec = O->getSection(Ref);
859 section_type = Sec.flags & MachO::SECTION_TYPE;
860 }
861
862 StringRef BytesStr;
863 Sect->getContents(BytesStr);
864 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
865
866 switch (section_type) {
867 case MachO::S_CSTRING_LITERALS:
868 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
869 i++) {
870 DumpCstringChar(Contents[i]);
871 }
872 outs() << "\n";
873 break;
874 case MachO::S_4BYTE_LITERALS:
875 float f;
876 memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
877 uint32_t l;
878 memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
879 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
880 sys::swapByteOrder(f);
881 sys::swapByteOrder(l);
882 }
883 DumpLiteral4(l, f);
884 break;
885 case MachO::S_8BYTE_LITERALS: {
886 double d;
887 memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
888 uint32_t l0, l1;
889 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
890 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
891 sizeof(uint32_t));
892 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
893 sys::swapByteOrder(f);
894 sys::swapByteOrder(l0);
895 sys::swapByteOrder(l1);
896 }
897 DumpLiteral8(O, l0, l1, d);
898 break;
899 }
900 case MachO::S_16BYTE_LITERALS: {
901 uint32_t l0, l1, l2, l3;
902 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
903 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
904 sizeof(uint32_t));
905 memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
906 sizeof(uint32_t));
907 memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
908 sizeof(uint32_t));
909 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
910 sys::swapByteOrder(l0);
911 sys::swapByteOrder(l1);
912 sys::swapByteOrder(l2);
913 sys::swapByteOrder(l3);
914 }
915 DumpLiteral16(l0, l1, l2, l3);
916 break;
917 }
918 }
919 }
920}
921
922static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect,
923 uint32_t sect_size, uint64_t sect_addr,
924 SymbolAddressMap *AddrMap,
925 bool verbose) {
926 uint32_t stride;
927 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
928 for (uint32_t i = 0; i < sect_size; i += stride) {
929 const char *SymbolName = nullptr;
930 if (O->is64Bit()) {
931 outs() << format("0x%016" PRIx64"l" "x", sect_addr + i * stride) << " ";
932 uint64_t pointer_value;
933 memcpy(&pointer_value, sect + i, stride);
934 if (O->isLittleEndian() != sys::IsLittleEndianHost)
935 sys::swapByteOrder(pointer_value);
936 outs() << format("0x%016" PRIx64"l" "x", pointer_value);
937 if (verbose)
938 SymbolName = GuessSymbolName(pointer_value, AddrMap);
939 } else {
940 outs() << format("0x%08" PRIx64"l" "x", sect_addr + i * stride) << " ";
941 uint32_t pointer_value;
942 memcpy(&pointer_value, sect + i, stride);
943 if (O->isLittleEndian() != sys::IsLittleEndianHost)
944 sys::swapByteOrder(pointer_value);
945 outs() << format("0x%08" PRIx32"x", pointer_value);
946 if (verbose)
947 SymbolName = GuessSymbolName(pointer_value, AddrMap);
948 }
949 if (SymbolName)
950 outs() << " " << SymbolName;
951 outs() << "\n";
952 }
953}
954
955static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
956 uint32_t size, uint64_t addr) {
957 uint32_t cputype = O->getHeader().cputype;
958 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
959 uint32_t j;
960 for (uint32_t i = 0; i < size; i += j, addr += j) {
961 if (O->is64Bit())
962 outs() << format("%016" PRIx64"l" "x", addr) << "\t";
963 else
964 outs() << format("%08" PRIx64"l" "x", addr) << "\t";
965 for (j = 0; j < 16 && i + j < size; j++) {
966 uint8_t byte_word = *(sect + i + j);
967 outs() << format("%02" PRIx32"x", (uint32_t)byte_word) << " ";
968 }
969 outs() << "\n";
970 }
971 } else {
972 uint32_t j;
973 for (uint32_t i = 0; i < size; i += j, addr += j) {
974 if (O->is64Bit())
975 outs() << format("%016" PRIx64"l" "x", addr) << "\t";
976 else
977 outs() << format("%08" PRIx64"l" "x", sect) << "\t";
978 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
979 j += sizeof(int32_t)) {
980 if (i + j + sizeof(int32_t) < size) {
981 uint32_t long_word;
982 memcpy(&long_word, sect + i + j, sizeof(int32_t));
983 if (O->isLittleEndian() != sys::IsLittleEndianHost)
984 sys::swapByteOrder(long_word);
985 outs() << format("%08" PRIx32"x", long_word) << " ";
986 } else {
987 for (uint32_t k = 0; i + j + k < size; k++) {
988 uint8_t byte_word = *(sect + i + j);
989 outs() << format("%02" PRIx32"x", (uint32_t)byte_word) << " ";
990 }
991 }
992 }
993 outs() << "\n";
994 }
995 }
996}
997
998static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
999 StringRef DisSegName, StringRef DisSectName);
1000static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1001 uint32_t size, uint32_t addr);
1002
1003static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1004 bool verbose) {
1005 SymbolAddressMap AddrMap;
1006 if (verbose)
1007 CreateSymbolAddressMap(O, &AddrMap);
1008
1009 for (unsigned i = 0; i < FilterSections.size(); ++i) {
1010 StringRef DumpSection = FilterSections[i];
1011 std::pair<StringRef, StringRef> DumpSegSectName;
1012 DumpSegSectName = DumpSection.split(',');
1013 StringRef DumpSegName, DumpSectName;
1014 if (DumpSegSectName.second.size()) {
1015 DumpSegName = DumpSegSectName.first;
1016 DumpSectName = DumpSegSectName.second;
1017 } else {
1018 DumpSegName = "";
1019 DumpSectName = DumpSegSectName.first;
1020 }
1021 for (const SectionRef &Section : O->sections()) {
1022 StringRef SectName;
1023 Section.getName(SectName);
1024 DataRefImpl Ref = Section.getRawDataRefImpl();
1025 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1026 if ((DumpSegName.empty() || SegName == DumpSegName) &&
1027 (SectName == DumpSectName)) {
1028
1029 uint32_t section_flags;
1030 if (O->is64Bit()) {
1031 const MachO::section_64 Sec = O->getSection64(Ref);
1032 section_flags = Sec.flags;
1033
1034 } else {
1035 const MachO::section Sec = O->getSection(Ref);
1036 section_flags = Sec.flags;
1037 }
1038 uint32_t section_type = section_flags & MachO::SECTION_TYPE;
1039
1040 StringRef BytesStr;
1041 Section.getContents(BytesStr);
1042 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1043 uint32_t sect_size = BytesStr.size();
1044 uint64_t sect_addr = Section.getAddress();
1045
1046 outs() << "Contents of (" << SegName << "," << SectName
1047 << ") section\n";
1048
1049 if (verbose) {
1050 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1051 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1052 DisassembleMachO(Filename, O, SegName, SectName);
1053 continue;
1054 }
1055 if (SegName == "__TEXT" && SectName == "__info_plist") {
1056 outs() << sect;
1057 continue;
1058 }
1059 if (SegName == "__OBJC" && SectName == "__protocol") {
1060 DumpProtocolSection(O, sect, sect_size, sect_addr);
1061 continue;
1062 }
1063 switch (section_type) {
1064 case MachO::S_REGULAR:
1065 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1066 break;
1067 case MachO::S_ZEROFILL:
1068 outs() << "zerofill section and has no contents in the file\n";
1069 break;
1070 case MachO::S_CSTRING_LITERALS:
1071 DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1072 break;
1073 case MachO::S_4BYTE_LITERALS:
1074 DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1075 break;
1076 case MachO::S_8BYTE_LITERALS:
1077 DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1078 break;
1079 case MachO::S_16BYTE_LITERALS:
1080 DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1081 break;
1082 case MachO::S_LITERAL_POINTERS:
1083 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
1084 !NoLeadingAddr);
1085 break;
1086 case MachO::S_MOD_INIT_FUNC_POINTERS:
1087 case MachO::S_MOD_TERM_FUNC_POINTERS:
1088 DumpInitTermPointerSection(O, sect, sect_size, sect_addr, &AddrMap,
1089 verbose);
1090 break;
1091 default:
1092 outs() << "Unknown section type ("
1093 << format("0x%08" PRIx32"x", section_type) << ")\n";
1094 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1095 break;
1096 }
1097 } else {
1098 if (section_type == MachO::S_ZEROFILL)
1099 outs() << "zerofill section and has no contents in the file\n";
1100 else
1101 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1102 }
1103 }
1104 }
1105 }
1106}
1107
1108static void DumpInfoPlistSectionContents(StringRef Filename,
1109 MachOObjectFile *O) {
1110 for (const SectionRef &Section : O->sections()) {
1111 StringRef SectName;
1112 Section.getName(SectName);
1113 DataRefImpl Ref = Section.getRawDataRefImpl();
1114 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1115 if (SegName == "__TEXT" && SectName == "__info_plist") {
1116 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
1117 StringRef BytesStr;
1118 Section.getContents(BytesStr);
1119 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1120 outs() << sect;
1121 return;
1122 }
1123 }
1124}
1125
1126// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
1127// and if it is and there is a list of architecture flags is specified then
1128// check to make sure this Mach-O file is one of those architectures or all
1129// architectures were specified. If not then an error is generated and this
1130// routine returns false. Else it returns true.
1131static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
1132 if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) {
1133 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
1134 bool ArchFound = false;
1135 MachO::mach_header H;
1136 MachO::mach_header_64 H_64;
1137 Triple T;
1138 if (MachO->is64Bit()) {
1139 H_64 = MachO->MachOObjectFile::getHeader64();
1140 T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
1141 } else {
1142 H = MachO->MachOObjectFile::getHeader();
1143 T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
1144 }
1145 unsigned i;
1146 for (i = 0; i < ArchFlags.size(); ++i) {
1147 if (ArchFlags[i] == T.getArchName())
1148 ArchFound = true;
1149 break;
1150 }
1151 if (!ArchFound) {
1152 errs() << "llvm-objdump: file: " + Filename + " does not contain "
1153 << "architecture: " + ArchFlags[i] + "\n";
1154 return false;
1155 }
1156 }
1157 return true;
1158}
1159
1160static void printObjcMetaData(MachOObjectFile *O, bool verbose);
1161
1162// ProcessMachO() is passed a single opened Mach-O file, which may be an
1163// archive member and or in a slice of a universal file. It prints the
1164// the file name and header info and then processes it according to the
1165// command line options.
1166static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
1167 StringRef ArchiveMemberName = StringRef(),
1168 StringRef ArchitectureName = StringRef()) {
1169 // If we are doing some processing here on the Mach-O file print the header
1170 // info. And don't print it otherwise like in the case of printing the
1171 // UniversalHeaders or ArchiveHeaders.
1172 if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
1173 LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
1174 DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) {
1175 outs() << Filename;
1176 if (!ArchiveMemberName.empty())
1177 outs() << '(' << ArchiveMemberName << ')';
1178 if (!ArchitectureName.empty())
1179 outs() << " (architecture " << ArchitectureName << ")";
1180 outs() << ":\n";
1181 }
1182
1183 if (Disassemble)
1184 DisassembleMachO(Filename, MachOOF, "__TEXT", "__text");
1185 if (IndirectSymbols)
1186 PrintIndirectSymbols(MachOOF, !NonVerbose);
1187 if (DataInCode)
1188 PrintDataInCodeTable(MachOOF, !NonVerbose);
1189 if (LinkOptHints)
1190 PrintLinkOptHints(MachOOF);
1191 if (Relocations)
1192 PrintRelocations(MachOOF);
1193 if (SectionHeaders)
1194 PrintSectionHeaders(MachOOF);
1195 if (SectionContents)
1196 PrintSectionContents(MachOOF);
1197 if (FilterSections.size() != 0)
1198 DumpSectionContents(Filename, MachOOF, !NonVerbose);
1199 if (InfoPlist)
1200 DumpInfoPlistSectionContents(Filename, MachOOF);
1201 if (DylibsUsed)
1202 PrintDylibs(MachOOF, false);
1203 if (DylibId)
1204 PrintDylibs(MachOOF, true);
1205 if (SymbolTable)
1206 PrintSymbolTable(MachOOF);
1207 if (UnwindInfo)
1208 printMachOUnwindInfo(MachOOF);
1209 if (PrivateHeaders) {
1210 printMachOFileHeader(MachOOF);
1211 printMachOLoadCommands(MachOOF);
1212 }
1213 if (FirstPrivateHeader)
1214 printMachOFileHeader(MachOOF);
1215 if (ObjcMetaData)
1216 printObjcMetaData(MachOOF, !NonVerbose);
1217 if (ExportsTrie)
1218 printExportsTrie(MachOOF);
1219 if (Rebase)
1220 printRebaseTable(MachOOF);
1221 if (Bind)
1222 printBindTable(MachOOF);
1223 if (LazyBind)
1224 printLazyBindTable(MachOOF);
1225 if (WeakBind)
1226 printWeakBindTable(MachOOF);
1227
1228 if (DwarfDumpType != DIDT_Null) {
1229 std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*MachOOF));
1230 // Dump the complete DWARF structure.
1231 DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
1232 }
1233}
1234
1235// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
1236static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
1237 outs() << " cputype (" << cputype << ")\n";
1238 outs() << " cpusubtype (" << cpusubtype << ")\n";
1239}
1240
1241// printCPUType() helps print_fat_headers by printing the cputype and
1242// pusubtype (symbolically for the one's it knows about).
1243static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
1244 switch (cputype) {
1245 case MachO::CPU_TYPE_I386:
1246 switch (cpusubtype) {
1247 case MachO::CPU_SUBTYPE_I386_ALL:
1248 outs() << " cputype CPU_TYPE_I386\n";
1249 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
1250 break;
1251 default:
1252 printUnknownCPUType(cputype, cpusubtype);
1253 break;
1254 }
1255 break;
1256 case MachO::CPU_TYPE_X86_64:
1257 switch (cpusubtype) {
1258 case MachO::CPU_SUBTYPE_X86_64_ALL:
1259 outs() << " cputype CPU_TYPE_X86_64\n";
1260 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
1261 break;
1262 case MachO::CPU_SUBTYPE_X86_64_H:
1263 outs() << " cputype CPU_TYPE_X86_64\n";
1264 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
1265 break;
1266 default:
1267 printUnknownCPUType(cputype, cpusubtype);
1268 break;
1269 }
1270 break;
1271 case MachO::CPU_TYPE_ARM:
1272 switch (cpusubtype) {
1273 case MachO::CPU_SUBTYPE_ARM_ALL:
1274 outs() << " cputype CPU_TYPE_ARM\n";
1275 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
1276 break;
1277 case MachO::CPU_SUBTYPE_ARM_V4T:
1278 outs() << " cputype CPU_TYPE_ARM\n";
1279 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
1280 break;
1281 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
1282 outs() << " cputype CPU_TYPE_ARM\n";
1283 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
1284 break;
1285 case MachO::CPU_SUBTYPE_ARM_XSCALE:
1286 outs() << " cputype CPU_TYPE_ARM\n";
1287 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
1288 break;
1289 case MachO::CPU_SUBTYPE_ARM_V6:
1290 outs() << " cputype CPU_TYPE_ARM\n";
1291 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
1292 break;
1293 case MachO::CPU_SUBTYPE_ARM_V6M:
1294 outs() << " cputype CPU_TYPE_ARM\n";
1295 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
1296 break;
1297 case MachO::CPU_SUBTYPE_ARM_V7:
1298 outs() << " cputype CPU_TYPE_ARM\n";
1299 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
1300 break;
1301 case MachO::CPU_SUBTYPE_ARM_V7EM:
1302 outs() << " cputype CPU_TYPE_ARM\n";
1303 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
1304 break;
1305 case MachO::CPU_SUBTYPE_ARM_V7K:
1306 outs() << " cputype CPU_TYPE_ARM\n";
1307 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
1308 break;
1309 case MachO::CPU_SUBTYPE_ARM_V7M:
1310 outs() << " cputype CPU_TYPE_ARM\n";
1311 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
1312 break;
1313 case MachO::CPU_SUBTYPE_ARM_V7S:
1314 outs() << " cputype CPU_TYPE_ARM\n";
1315 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
1316 break;
1317 default:
1318 printUnknownCPUType(cputype, cpusubtype);
1319 break;
1320 }
1321 break;
1322 case MachO::CPU_TYPE_ARM64:
1323 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
1324 case MachO::CPU_SUBTYPE_ARM64_ALL:
1325 outs() << " cputype CPU_TYPE_ARM64\n";
1326 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
1327 break;
1328 default:
1329 printUnknownCPUType(cputype, cpusubtype);
1330 break;
1331 }
1332 break;
1333 default:
1334 printUnknownCPUType(cputype, cpusubtype);
1335 break;
1336 }
1337}
1338
1339static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
1340 bool verbose) {
1341 outs() << "Fat headers\n";
1342 if (verbose)
1343 outs() << "fat_magic FAT_MAGIC\n";
1344 else
1345 outs() << "fat_magic " << format("0x%" PRIx32"x", MachO::FAT_MAGIC) << "\n";
1346
1347 uint32_t nfat_arch = UB->getNumberOfObjects();
1348 StringRef Buf = UB->getData();
1349 uint64_t size = Buf.size();
1350 uint64_t big_size = sizeof(struct MachO::fat_header) +
1351 nfat_arch * sizeof(struct MachO::fat_arch);
1352 outs() << "nfat_arch " << UB->getNumberOfObjects();
1353 if (nfat_arch == 0)
1354 outs() << " (malformed, contains zero architecture types)\n";
1355 else if (big_size > size)
1356 outs() << " (malformed, architectures past end of file)\n";
1357 else
1358 outs() << "\n";
1359
1360 for (uint32_t i = 0; i < nfat_arch; ++i) {
1361 MachOUniversalBinary::ObjectForArch OFA(UB, i);
1362 uint32_t cputype = OFA.getCPUType();
1363 uint32_t cpusubtype = OFA.getCPUSubType();
1364 outs() << "architecture ";
1365 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
1366 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
1367 uint32_t other_cputype = other_OFA.getCPUType();
1368 uint32_t other_cpusubtype = other_OFA.getCPUSubType();
1369 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
1370 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
1371 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
1372 outs() << "(illegal duplicate architecture) ";
1373 break;
1374 }
1375 }
1376 if (verbose) {
1377 outs() << OFA.getArchTypeName() << "\n";
1378 printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
1379 } else {
1380 outs() << i << "\n";
1381 outs() << " cputype " << cputype << "\n";
1382 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
1383 << "\n";
1384 }
1385 if (verbose &&
1386 (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
1387 outs() << " capabilities CPU_SUBTYPE_LIB64\n";
1388 else
1389 outs() << " capabilities "
1390 << format("0x%" PRIx32"x",
1391 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
1392 outs() << " offset " << OFA.getOffset();
1393 if (OFA.getOffset() > size)
1394 outs() << " (past end of file)";
1395 if (OFA.getOffset() % (1 << OFA.getAlign()) != 0)
1396 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
1397 outs() << "\n";
1398 outs() << " size " << OFA.getSize();
1399 big_size = OFA.getOffset() + OFA.getSize();
1400 if (big_size > size)
1401 outs() << " (past end of file)";
1402 outs() << "\n";
1403 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
1404 << ")\n";
1405 }
1406}
1407
1408static void printArchiveChild(const Archive::Child &C, bool verbose,
1409 bool print_offset) {
1410 if (print_offset)
1411 outs() << C.getChildOffset() << "\t";
1412 sys::fs::perms Mode = C.getAccessMode();
1413 if (verbose) {
1414 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
1415 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
1416 outs() << "-";
1417 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
1418 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
1419 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
1420 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
1421 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
1422 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
1423 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
1424 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
1425 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
1426 } else {
1427 outs() << format("0%o ", Mode);
1428 }
1429
1430 unsigned UID = C.getUID();
1431 outs() << format("%3d/", UID);
1432 unsigned GID = C.getGID();
1433 outs() << format("%-3d ", GID);
1434 ErrorOr<uint64_t> Size = C.getRawSize();
1435 if (std::error_code EC = Size.getError())
1436 report_fatal_error(EC.message());
1437 outs() << format("%5" PRId64"l" "d", Size.get()) << " ";
1438
1439 StringRef RawLastModified = C.getRawLastModified();
1440 if (verbose) {
1441 unsigned Seconds;
1442 if (RawLastModified.getAsInteger(10, Seconds))
1443 outs() << "(date: \"%s\" contains non-decimal chars) " << RawLastModified;
1444 else {
1445 // Since cime(3) returns a 26 character string of the form:
1446 // "Sun Sep 16 01:03:52 1973\n\0"
1447 // just print 24 characters.
1448 time_t t = Seconds;
1449 outs() << format("%.24s ", ctime(&t));
1450 }
1451 } else {
1452 outs() << RawLastModified << " ";
1453 }
1454
1455 if (verbose) {
1456 ErrorOr<StringRef> NameOrErr = C.getName();
1457 if (NameOrErr.getError()) {
1458 StringRef RawName = C.getRawName();
1459 outs() << RawName << "\n";
1460 } else {
1461 StringRef Name = NameOrErr.get();
1462 outs() << Name << "\n";
1463 }
1464 } else {
1465 StringRef RawName = C.getRawName();
1466 outs() << RawName << "\n";
1467 }
1468}
1469
1470static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) {
1471 for (Archive::child_iterator I = A->child_begin(false), E = A->child_end();
1472 I != E; ++I) {
1473 if (std::error_code EC = I->getError())
1474 report_fatal_error(EC.message());
1475 const Archive::Child &C = **I;
1476 printArchiveChild(C, verbose, print_offset);
1477 }
1478}
1479
1480// ParseInputMachO() parses the named Mach-O file in Filename and handles the
1481// -arch flags selecting just those slices as specified by them and also parses
1482// archive files. Then for each individual Mach-O file ProcessMachO() is
1483// called to process the file based on the command line options.
1484void llvm::ParseInputMachO(StringRef Filename) {
1485 // Check for -arch all and verifiy the -arch flags are valid.
1486 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
1487 if (ArchFlags[i] == "all") {
1488 ArchAll = true;
1489 } else {
1490 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
1491 errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] +
1492 "'for the -arch option\n";
1493 return;
1494 }
1495 }
1496 }
1497
1498 // Attempt to open the binary.
1499 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
1500 if (!BinaryOrErr)
1501 report_error(Filename, BinaryOrErr.takeError());
1502 Binary &Bin = *BinaryOrErr.get().getBinary();
1503
1504 if (Archive *A = dyn_cast<Archive>(&Bin)) {
1505 outs() << "Archive : " << Filename << "\n";
1506 if (ArchiveHeaders)
1507 printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets);
1508 for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
1509 I != E; ++I) {
1510 if (std::error_code EC = I->getError())
1511 report_error(Filename, EC);
1512 auto &C = I->get();
1513 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1514 if (ChildOrErr.getError())
1515 continue;
1516 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
1517 if (!checkMachOAndArchFlags(O, Filename))
1518 return;
1519 ProcessMachO(Filename, O, O->getFileName());
1520 }
1521 }
1522 return;
1523 }
1524 if (UniversalHeaders) {
1525 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
1526 printMachOUniversalHeaders(UB, !NonVerbose);
1527 }
1528 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
1529 // If we have a list of architecture flags specified dump only those.
1530 if (!ArchAll && ArchFlags.size() != 0) {
1531 // Look for a slice in the universal binary that matches each ArchFlag.
1532 bool ArchFound;
1533 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
1534 ArchFound = false;
1535 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
1536 E = UB->end_objects();
1537 I != E; ++I) {
1538 if (ArchFlags[i] == I->getArchTypeName()) {
1539 ArchFound = true;
1540 ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
1541 I->getAsObjectFile();
1542 std::string ArchitectureName = "";
1543 if (ArchFlags.size() > 1)
1544 ArchitectureName = I->getArchTypeName();
1545 if (ObjOrErr) {
1546 ObjectFile &O = *ObjOrErr.get();
1547 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
1548 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
1549 } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
1550 I->getAsArchive()) {
1551 std::unique_ptr<Archive> &A = *AOrErr;
1552 outs() << "Archive : " << Filename;
1553 if (!ArchitectureName.empty())
1554 outs() << " (architecture " << ArchitectureName << ")";
1555 outs() << "\n";
1556 if (ArchiveHeaders)
1557 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1558 for (Archive::child_iterator AI = A->child_begin(),
1559 AE = A->child_end();
1560 AI != AE; ++AI) {
1561 if (std::error_code EC = AI->getError())
1562 report_error(Filename, EC);
1563 auto &C = AI->get();
1564 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1565 if (ChildOrErr.getError())
1566 continue;
1567 if (MachOObjectFile *O =
1568 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
1569 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
1570 }
1571 }
1572 }
1573 }
1574 if (!ArchFound) {
1575 errs() << "llvm-objdump: file: " + Filename + " does not contain "
1576 << "architecture: " + ArchFlags[i] + "\n";
1577 return;
1578 }
1579 }
1580 return;
1581 }
1582 // No architecture flags were specified so if this contains a slice that
1583 // matches the host architecture dump only that.
1584 if (!ArchAll) {
1585 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
1586 E = UB->end_objects();
1587 I != E; ++I) {
1588 if (MachOObjectFile::getHostArch().getArchName() ==
1589 I->getArchTypeName()) {
1590 ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
1591 std::string ArchiveName;
1592 ArchiveName.clear();
1593 if (ObjOrErr) {
1594 ObjectFile &O = *ObjOrErr.get();
1595 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
1596 ProcessMachO(Filename, MachOOF);
1597 } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
1598 I->getAsArchive()) {
1599 std::unique_ptr<Archive> &A = *AOrErr;
1600 outs() << "Archive : " << Filename << "\n";
1601 if (ArchiveHeaders)
1602 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1603 for (Archive::child_iterator AI = A->child_begin(),
1604 AE = A->child_end();
1605 AI != AE; ++AI) {
1606 if (std::error_code EC = AI->getError())
1607 report_error(Filename, EC);
1608 auto &C = AI->get();
1609 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1610 if (ChildOrErr.getError())
1611 continue;
1612 if (MachOObjectFile *O =
1613 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
1614 ProcessMachO(Filename, O, O->getFileName());
1615 }
1616 }
1617 return;
1618 }
1619 }
1620 }
1621 // Either all architectures have been specified or none have been specified
1622 // and this does not contain the host architecture so dump all the slices.
1623 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
1624 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
1625 E = UB->end_objects();
1626 I != E; ++I) {
1627 ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
1628 std::string ArchitectureName = "";
1629 if (moreThanOneArch)
1630 ArchitectureName = I->getArchTypeName();
1631 if (ObjOrErr) {
1632 ObjectFile &Obj = *ObjOrErr.get();
1633 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
1634 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
1635 } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
1636 std::unique_ptr<Archive> &A = *AOrErr;
1637 outs() << "Archive : " << Filename;
1638 if (!ArchitectureName.empty())
1639 outs() << " (architecture " << ArchitectureName << ")";
1640 outs() << "\n";
1641 if (ArchiveHeaders)
1642 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1643 for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
1644 AI != AE; ++AI) {
1645 if (std::error_code EC = AI->getError())
1646 report_error(Filename, EC);
1647 auto &C = AI->get();
1648 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
1649 if (ChildOrErr.getError())
1650 continue;
1651 if (MachOObjectFile *O =
1652 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
1653 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
1654 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
1655 ArchitectureName);
1656 }
1657 }
1658 }
1659 }
1660 return;
1661 }
1662 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
1663 if (!checkMachOAndArchFlags(O, Filename))
1664 return;
1665 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O)) {
1666 ProcessMachO(Filename, MachOOF);
1667 } else
1668 errs() << "llvm-objdump: '" << Filename << "': "
1669 << "Object is not a Mach-O file type.\n";
1670 return;
1671 }
1672 llvm_unreachable("Input object can't be invalid at this point")::llvm::llvm_unreachable_internal("Input object can't be invalid at this point"
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 1672)
;
1673}
1674
1675typedef std::pair<uint64_t, const char *> BindInfoEntry;
1676typedef std::vector<BindInfoEntry> BindTable;
1677typedef BindTable::iterator bind_table_iterator;
1678
1679// The block of info used by the Symbolizer call backs.
1680struct DisassembleInfo {
1681 bool verbose;
1682 MachOObjectFile *O;
1683 SectionRef S;
1684 SymbolAddressMap *AddrMap;
1685 std::vector<SectionRef> *Sections;
1686 const char *class_name;
1687 const char *selector_name;
1688 char *method;
1689 char *demangled_name;
1690 uint64_t adrp_addr;
1691 uint32_t adrp_inst;
1692 BindTable *bindtable;
1693 uint32_t depth;
1694};
1695
1696// SymbolizerGetOpInfo() is the operand information call back function.
1697// This is called to get the symbolic information for operand(s) of an
1698// instruction when it is being done. This routine does this from
1699// the relocation information, symbol table, etc. That block of information
1700// is a pointer to the struct DisassembleInfo that was passed when the
1701// disassembler context was created and passed to back to here when
1702// called back by the disassembler for instruction operands that could have
1703// relocation information. The address of the instruction containing operand is
1704// at the Pc parameter. The immediate value the operand has is passed in
1705// op_info->Value and is at Offset past the start of the instruction and has a
1706// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
1707// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
1708// names and addends of the symbolic expression to add for the operand. The
1709// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
1710// information is returned then this function returns 1 else it returns 0.
1711static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
1712 uint64_t Size, int TagType, void *TagBuf) {
1713 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
1714 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
1715 uint64_t value = op_info->Value;
1716
1717 // Make sure all fields returned are zero if we don't set them.
1718 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
1719 op_info->Value = value;
1720
1721 // If the TagType is not the value 1 which it code knows about or if no
1722 // verbose symbolic information is wanted then just return 0, indicating no
1723 // information is being returned.
1724 if (TagType != 1 || !info->verbose)
1
Assuming 'TagType' is equal to 1
2
Taking false branch
1725 return 0;
1726
1727 unsigned int Arch = info->O->getArch();
1728 if (Arch == Triple::x86) {
3
Assuming 'Arch' is not equal to x86
4
Taking false branch
1729 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
1730 return 0;
1731 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
1732 // TODO:
1733 // Search the external relocation entries of a fully linked image
1734 // (if any) for an entry that matches this segment offset.
1735 // uint32_t seg_offset = (Pc + Offset);
1736 return 0;
1737 }
1738 // In MH_OBJECT filetypes search the section's relocation entries (if any)
1739 // for an entry for this section offset.
1740 uint32_t sect_addr = info->S.getAddress();
1741 uint32_t sect_offset = (Pc + Offset) - sect_addr;
1742 bool reloc_found = false;
1743 DataRefImpl Rel;
1744 MachO::any_relocation_info RE;
1745 bool isExtern = false;
1746 SymbolRef Symbol;
1747 bool r_scattered = false;
1748 uint32_t r_value, pair_r_value, r_type;
1749 for (const RelocationRef &Reloc : info->S.relocations()) {
1750 uint64_t RelocOffset = Reloc.getOffset();
1751 if (RelocOffset == sect_offset) {
1752 Rel = Reloc.getRawDataRefImpl();
1753 RE = info->O->getRelocation(Rel);
1754 r_type = info->O->getAnyRelocationType(RE);
1755 r_scattered = info->O->isRelocationScattered(RE);
1756 if (r_scattered) {
1757 r_value = info->O->getScatteredRelocationValue(RE);
1758 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
1759 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
1760 DataRefImpl RelNext = Rel;
1761 info->O->moveRelocationNext(RelNext);
1762 MachO::any_relocation_info RENext;
1763 RENext = info->O->getRelocation(RelNext);
1764 if (info->O->isRelocationScattered(RENext))
1765 pair_r_value = info->O->getScatteredRelocationValue(RENext);
1766 else
1767 return 0;
1768 }
1769 } else {
1770 isExtern = info->O->getPlainRelocationExternal(RE);
1771 if (isExtern) {
1772 symbol_iterator RelocSym = Reloc.getSymbol();
1773 Symbol = *RelocSym;
1774 }
1775 }
1776 reloc_found = true;
1777 break;
1778 }
1779 }
1780 if (reloc_found && isExtern) {
1781 ErrorOr<StringRef> SymName = Symbol.getName();
1782 if (std::error_code EC = SymName.getError())
1783 report_fatal_error(EC.message());
1784 const char *name = SymName->data();
1785 op_info->AddSymbol.Present = 1;
1786 op_info->AddSymbol.Name = name;
1787 // For i386 extern relocation entries the value in the instruction is
1788 // the offset from the symbol, and value is already set in op_info->Value.
1789 return 1;
1790 }
1791 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
1792 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
1793 const char *add = GuessSymbolName(r_value, info->AddrMap);
1794 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
1795 uint32_t offset = value - (r_value - pair_r_value);
1796 op_info->AddSymbol.Present = 1;
1797 if (add != nullptr)
1798 op_info->AddSymbol.Name = add;
1799 else
1800 op_info->AddSymbol.Value = r_value;
1801 op_info->SubtractSymbol.Present = 1;
1802 if (sub != nullptr)
1803 op_info->SubtractSymbol.Name = sub;
1804 else
1805 op_info->SubtractSymbol.Value = pair_r_value;
1806 op_info->Value = offset;
1807 return 1;
1808 }
1809 return 0;
1810 }
1811 if (Arch == Triple::x86_64) {
5
Assuming 'Arch' is not equal to x86_64
6
Taking false branch
1812 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
1813 return 0;
1814 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
1815 // TODO:
1816 // Search the external relocation entries of a fully linked image
1817 // (if any) for an entry that matches this segment offset.
1818 // uint64_t seg_offset = (Pc + Offset);
1819 return 0;
1820 }
1821 // In MH_OBJECT filetypes search the section's relocation entries (if any)
1822 // for an entry for this section offset.
1823 uint64_t sect_addr = info->S.getAddress();
1824 uint64_t sect_offset = (Pc + Offset) - sect_addr;
1825 bool reloc_found = false;
1826 DataRefImpl Rel;
1827 MachO::any_relocation_info RE;
1828 bool isExtern = false;
1829 SymbolRef Symbol;
1830 for (const RelocationRef &Reloc : info->S.relocations()) {
1831 uint64_t RelocOffset = Reloc.getOffset();
1832 if (RelocOffset == sect_offset) {
1833 Rel = Reloc.getRawDataRefImpl();
1834 RE = info->O->getRelocation(Rel);
1835 // NOTE: Scattered relocations don't exist on x86_64.
1836 isExtern = info->O->getPlainRelocationExternal(RE);
1837 if (isExtern) {
1838 symbol_iterator RelocSym = Reloc.getSymbol();
1839 Symbol = *RelocSym;
1840 }
1841 reloc_found = true;
1842 break;
1843 }
1844 }
1845 if (reloc_found && isExtern) {
1846 // The Value passed in will be adjusted by the Pc if the instruction
1847 // adds the Pc. But for x86_64 external relocation entries the Value
1848 // is the offset from the external symbol.
1849 if (info->O->getAnyRelocationPCRel(RE))
1850 op_info->Value -= Pc + Offset + Size;
1851 ErrorOr<StringRef> SymName = Symbol.getName();
1852 if (std::error_code EC = SymName.getError())
1853 report_fatal_error(EC.message());
1854 const char *name = SymName->data();
1855 unsigned Type = info->O->getAnyRelocationType(RE);
1856 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
1857 DataRefImpl RelNext = Rel;
1858 info->O->moveRelocationNext(RelNext);
1859 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
1860 unsigned TypeNext = info->O->getAnyRelocationType(RENext);
1861 bool isExternNext = info->O->getPlainRelocationExternal(RENext);
1862 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
1863 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
1864 op_info->SubtractSymbol.Present = 1;
1865 op_info->SubtractSymbol.Name = name;
1866 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
1867 Symbol = *RelocSymNext;
1868 ErrorOr<StringRef> SymNameNext = Symbol.getName();
1869 if (std::error_code EC = SymNameNext.getError())
1870 report_fatal_error(EC.message());
1871 name = SymNameNext->data();
1872 }
1873 }
1874 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
1875 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
1876 op_info->AddSymbol.Present = 1;
1877 op_info->AddSymbol.Name = name;
1878 return 1;
1879 }
1880 return 0;
1881 }
1882 if (Arch == Triple::arm) {
7
Assuming 'Arch' is equal to arm
8
Taking true branch
1883 if (Offset != 0 || (Size != 4 && Size != 2))
9
Assuming 'Offset' is equal to 0
10
Assuming 'Size' is equal to 4
1884 return 0;
1885 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
11
Taking false branch
1886 // TODO:
1887 // Search the external relocation entries of a fully linked image
1888 // (if any) for an entry that matches this segment offset.
1889 // uint32_t seg_offset = (Pc + Offset);
1890 return 0;
1891 }
1892 // In MH_OBJECT filetypes search the section's relocation entries (if any)
1893 // for an entry for this section offset.
1894 uint32_t sect_addr = info->S.getAddress();
1895 uint32_t sect_offset = (Pc + Offset) - sect_addr;
1896 DataRefImpl Rel;
1897 MachO::any_relocation_info RE;
1898 bool isExtern = false;
1899 SymbolRef Symbol;
1900 bool r_scattered = false;
1901 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
12
'pair_r_value' declared without an initial value
1902 auto Reloc =
1903 std::find_if(info->S.relocations().begin(), info->S.relocations().end(),
1904 [&](const RelocationRef &Reloc) {
1905 uint64_t RelocOffset = Reloc.getOffset();
1906 return RelocOffset == sect_offset;
1907 });
1908
1909 if (Reloc == info->S.relocations().end())
13
Taking false branch
1910 return 0;
1911
1912 Rel = Reloc->getRawDataRefImpl();
1913 RE = info->O->getRelocation(Rel);
1914 r_length = info->O->getAnyRelocationLength(RE);
1915 r_scattered = info->O->isRelocationScattered(RE);
1916 if (r_scattered) {
14
Assuming 'r_scattered' is not equal to 0
15
Taking true branch
1917 r_value = info->O->getScatteredRelocationValue(RE);
1918 r_type = info->O->getScatteredRelocationType(RE);
1919 } else {
1920 r_type = info->O->getAnyRelocationType(RE);
1921 isExtern = info->O->getPlainRelocationExternal(RE);
1922 if (isExtern) {
1923 symbol_iterator RelocSym = Reloc->getSymbol();
1924 Symbol = *RelocSym;
1925 }
1926 }
1927 if (r_type == MachO::ARM_RELOC_HALF ||
16
Assuming 'r_type' is not equal to ARM_RELOC_HALF
20
Taking true branch
1928 r_type == MachO::ARM_RELOC_SECTDIFF ||
17
Assuming 'r_type' is not equal to ARM_RELOC_SECTDIFF
1929 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
18
Assuming 'r_type' is not equal to ARM_RELOC_LOCAL_SECTDIFF
1930 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
19
Assuming 'r_type' is equal to ARM_RELOC_HALF_SECTDIFF
1931 DataRefImpl RelNext = Rel;
1932 info->O->moveRelocationNext(RelNext);
1933 MachO::any_relocation_info RENext;
1934 RENext = info->O->getRelocation(RelNext);
1935 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
1936 if (info->O->isRelocationScattered(RENext))
21
Taking false branch
1937 pair_r_value = info->O->getScatteredRelocationValue(RENext);
1938 }
1939
1940 if (isExtern) {
22
Taking false branch
1941 ErrorOr<StringRef> SymName = Symbol.getName();
1942 if (std::error_code EC = SymName.getError())
1943 report_fatal_error(EC.message());
1944 const char *name = SymName->data();
1945 op_info->AddSymbol.Present = 1;
1946 op_info->AddSymbol.Name = name;
1947 switch (r_type) {
1948 case MachO::ARM_RELOC_HALF:
1949 if ((r_length & 0x1) == 1) {
1950 op_info->Value = value << 16 | other_half;
1951 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
1952 } else {
1953 op_info->Value = other_half << 16 | value;
1954 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
1955 }
1956 break;
1957 default:
1958 break;
1959 }
1960 return 1;
1961 }
1962 // If we have a branch that is not an external relocation entry then
1963 // return 0 so the code in tryAddingSymbolicOperand() can use the
1964 // SymbolLookUp call back with the branch target address to look up the
1965 // symbol and possiblity add an annotation for a symbol stub.
1966 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
23
Taking false branch
1967 r_type == MachO::ARM_THUMB_RELOC_BR22))
1968 return 0;
1969
1970 uint32_t offset = 0;
1971 if (r_type == MachO::ARM_RELOC_HALF ||
24
Taking true branch
1972 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
1973 if ((r_length & 0x1) == 1)
25
Taking false branch
1974 value = value << 16 | other_half;
1975 else
1976 value = other_half << 16 | value;
1977 }
1978 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
26
Taking false branch
1979 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
1980 offset = value - r_value;
1981 value = r_value;
1982 }
1983
1984 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
27
Taking true branch
1985 if ((r_length & 0x1) == 1)
28
Taking false branch
1986 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
1987 else
1988 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
1989 const char *add = GuessSymbolName(r_value, info->AddrMap);
1990 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
29
Function call argument is an uninitialized value
1991 int32_t offset = value - (r_value - pair_r_value);
1992 op_info->AddSymbol.Present = 1;
1993 if (add != nullptr)
1994 op_info->AddSymbol.Name = add;
1995 else
1996 op_info->AddSymbol.Value = r_value;
1997 op_info->SubtractSymbol.Present = 1;
1998 if (sub != nullptr)
1999 op_info->SubtractSymbol.Name = sub;
2000 else
2001 op_info->SubtractSymbol.Value = pair_r_value;
2002 op_info->Value = offset;
2003 return 1;
2004 }
2005
2006 op_info->AddSymbol.Present = 1;
2007 op_info->Value = offset;
2008 if (r_type == MachO::ARM_RELOC_HALF) {
2009 if ((r_length & 0x1) == 1)
2010 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI161;
2011 else
2012 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO162;
2013 }
2014 const char *add = GuessSymbolName(value, info->AddrMap);
2015 if (add != nullptr) {
2016 op_info->AddSymbol.Name = add;
2017 return 1;
2018 }
2019 op_info->AddSymbol.Value = value;
2020 return 1;
2021 }
2022 if (Arch == Triple::aarch64) {
2023 if (Offset != 0 || Size != 4)
2024 return 0;
2025 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2026 // TODO:
2027 // Search the external relocation entries of a fully linked image
2028 // (if any) for an entry that matches this segment offset.
2029 // uint64_t seg_offset = (Pc + Offset);
2030 return 0;
2031 }
2032 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2033 // for an entry for this section offset.
2034 uint64_t sect_addr = info->S.getAddress();
2035 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2036 auto Reloc =
2037 std::find_if(info->S.relocations().begin(), info->S.relocations().end(),
2038 [&](const RelocationRef &Reloc) {
2039 uint64_t RelocOffset = Reloc.getOffset();
2040 return RelocOffset == sect_offset;
2041 });
2042
2043 if (Reloc == info->S.relocations().end())
2044 return 0;
2045
2046 DataRefImpl Rel = Reloc->getRawDataRefImpl();
2047 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
2048 uint32_t r_type = info->O->getAnyRelocationType(RE);
2049 if (r_type == MachO::ARM64_RELOC_ADDEND) {
2050 DataRefImpl RelNext = Rel;
2051 info->O->moveRelocationNext(RelNext);
2052 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2053 if (value == 0) {
2054 value = info->O->getPlainRelocationSymbolNum(RENext);
2055 op_info->Value = value;
2056 }
2057 }
2058 // NOTE: Scattered relocations don't exist on arm64.
2059 if (!info->O->getPlainRelocationExternal(RE))
2060 return 0;
2061 ErrorOr<StringRef> SymName = Reloc->getSymbol()->getName();
2062 if (std::error_code EC = SymName.getError())
2063 report_fatal_error(EC.message());
2064 const char *name = SymName->data();
2065 op_info->AddSymbol.Present = 1;
2066 op_info->AddSymbol.Name = name;
2067
2068 switch (r_type) {
2069 case MachO::ARM64_RELOC_PAGE21:
2070 /* @page */
2071 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE1;
2072 break;
2073 case MachO::ARM64_RELOC_PAGEOFF12:
2074 /* @pageoff */
2075 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF2;
2076 break;
2077 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
2078 /* @gotpage */
2079 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE3;
2080 break;
2081 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
2082 /* @gotpageoff */
2083 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF4;
2084 break;
2085 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
2086 /* @tvlppage is not implemented in llvm-mc */
2087 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP5;
2088 break;
2089 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
2090 /* @tvlppageoff is not implemented in llvm-mc */
2091 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF6;
2092 break;
2093 default:
2094 case MachO::ARM64_RELOC_BRANCH26:
2095 op_info->VariantKind = LLVMDisassembler_VariantKind_None0;
2096 break;
2097 }
2098 return 1;
2099 }
2100 return 0;
2101}
2102
2103// GuessCstringPointer is passed the address of what might be a pointer to a
2104// literal string in a cstring section. If that address is in a cstring section
2105// it returns a pointer to that string. Else it returns nullptr.
2106static const char *GuessCstringPointer(uint64_t ReferenceValue,
2107 struct DisassembleInfo *info) {
2108 for (const auto &Load : info->O->load_commands()) {
2109 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2110 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2111 for (unsigned J = 0; J < Seg.nsects; ++J) {
2112 MachO::section_64 Sec = info->O->getSection64(Load, J);
2113 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2114 if (section_type == MachO::S_CSTRING_LITERALS &&
2115 ReferenceValue >= Sec.addr &&
2116 ReferenceValue < Sec.addr + Sec.size) {
2117 uint64_t sect_offset = ReferenceValue - Sec.addr;
2118 uint64_t object_offset = Sec.offset + sect_offset;
2119 StringRef MachOContents = info->O->getData();
2120 uint64_t object_size = MachOContents.size();
2121 const char *object_addr = (const char *)MachOContents.data();
2122 if (object_offset < object_size) {
2123 const char *name = object_addr + object_offset;
2124 return name;
2125 } else {
2126 return nullptr;
2127 }
2128 }
2129 }
2130 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2131 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2132 for (unsigned J = 0; J < Seg.nsects; ++J) {
2133 MachO::section Sec = info->O->getSection(Load, J);
2134 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2135 if (section_type == MachO::S_CSTRING_LITERALS &&
2136 ReferenceValue >= Sec.addr &&
2137 ReferenceValue < Sec.addr + Sec.size) {
2138 uint64_t sect_offset = ReferenceValue - Sec.addr;
2139 uint64_t object_offset = Sec.offset + sect_offset;
2140 StringRef MachOContents = info->O->getData();
2141 uint64_t object_size = MachOContents.size();
2142 const char *object_addr = (const char *)MachOContents.data();
2143 if (object_offset < object_size) {
2144 const char *name = object_addr + object_offset;
2145 return name;
2146 } else {
2147 return nullptr;
2148 }
2149 }
2150 }
2151 }
2152 }
2153 return nullptr;
2154}
2155
2156// GuessIndirectSymbol returns the name of the indirect symbol for the
2157// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
2158// an address of a symbol stub or a lazy or non-lazy pointer to associate the
2159// symbol name being referenced by the stub or pointer.
2160static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
2161 struct DisassembleInfo *info) {
2162 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
2163 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
2164 for (const auto &Load : info->O->load_commands()) {
2165 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2166 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2167 for (unsigned J = 0; J < Seg.nsects; ++J) {
2168 MachO::section_64 Sec = info->O->getSection64(Load, J);
2169 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2170 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2171 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2172 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2173 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2174 section_type == MachO::S_SYMBOL_STUBS) &&
2175 ReferenceValue >= Sec.addr &&
2176 ReferenceValue < Sec.addr + Sec.size) {
2177 uint32_t stride;
2178 if (section_type == MachO::S_SYMBOL_STUBS)
2179 stride = Sec.reserved2;
2180 else
2181 stride = 8;
2182 if (stride == 0)
2183 return nullptr;
2184 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2185 if (index < Dysymtab.nindirectsyms) {
2186 uint32_t indirect_symbol =
2187 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2188 if (indirect_symbol < Symtab.nsyms) {
2189 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2190 SymbolRef Symbol = *Sym;
2191 ErrorOr<StringRef> SymName = Symbol.getName();
2192 if (std::error_code EC = SymName.getError())
2193 report_fatal_error(EC.message());
2194 const char *name = SymName->data();
2195 return name;
2196 }
2197 }
2198 }
2199 }
2200 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2201 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2202 for (unsigned J = 0; J < Seg.nsects; ++J) {
2203 MachO::section Sec = info->O->getSection(Load, J);
2204 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2205 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2206 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2207 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2208 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2209 section_type == MachO::S_SYMBOL_STUBS) &&
2210 ReferenceValue >= Sec.addr &&
2211 ReferenceValue < Sec.addr + Sec.size) {
2212 uint32_t stride;
2213 if (section_type == MachO::S_SYMBOL_STUBS)
2214 stride = Sec.reserved2;
2215 else
2216 stride = 4;
2217 if (stride == 0)
2218 return nullptr;
2219 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2220 if (index < Dysymtab.nindirectsyms) {
2221 uint32_t indirect_symbol =
2222 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
2223 if (indirect_symbol < Symtab.nsyms) {
2224 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
2225 SymbolRef Symbol = *Sym;
2226 ErrorOr<StringRef> SymName = Symbol.getName();
2227 if (std::error_code EC = SymName.getError())
2228 report_fatal_error(EC.message());
2229 const char *name = SymName->data();
2230 return name;
2231 }
2232 }
2233 }
2234 }
2235 }
2236 }
2237 return nullptr;
2238}
2239
2240// method_reference() is called passing it the ReferenceName that might be
2241// a reference it to an Objective-C method call. If so then it allocates and
2242// assembles a method call string with the values last seen and saved in
2243// the DisassembleInfo's class_name and selector_name fields. This is saved
2244// into the method field of the info and any previous string is free'ed.
2245// Then the class_name field in the info is set to nullptr. The method call
2246// string is set into ReferenceName and ReferenceType is set to
2247// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
2248// then both ReferenceType and ReferenceName are left unchanged.
2249static void method_reference(struct DisassembleInfo *info,
2250 uint64_t *ReferenceType,
2251 const char **ReferenceName) {
2252 unsigned int Arch = info->O->getArch();
2253 if (*ReferenceName != nullptr) {
2254 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
2255 if (info->selector_name != nullptr) {
2256 if (info->method != nullptr)
2257 free(info->method);
2258 if (info->class_name != nullptr) {
2259 info->method = (char *)malloc(5 + strlen(info->class_name) +
2260 strlen(info->selector_name));
2261 if (info->method != nullptr) {
2262 strcpy(info->method, "+[");
2263 strcat(info->method, info->class_name);
2264 strcat(info->method, " ");
2265 strcat(info->method, info->selector_name);
2266 strcat(info->method, "]");
2267 *ReferenceName = info->method;
2268 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2269 }
2270 } else {
2271 info->method = (char *)malloc(9 + strlen(info->selector_name));
2272 if (info->method != nullptr) {
2273 if (Arch == Triple::x86_64)
2274 strcpy(info->method, "-[%rdi ");
2275 else if (Arch == Triple::aarch64)
2276 strcpy(info->method, "-[x0 ");
2277 else
2278 strcpy(info->method, "-[r? ");
2279 strcat(info->method, info->selector_name);
2280 strcat(info->method, "]");
2281 *ReferenceName = info->method;
2282 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2283 }
2284 }
2285 info->class_name = nullptr;
2286 }
2287 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
2288 if (info->selector_name != nullptr) {
2289 if (info->method != nullptr)
2290 free(info->method);
2291 info->method = (char *)malloc(17 + strlen(info->selector_name));
2292 if (info->method != nullptr) {
2293 if (Arch == Triple::x86_64)
2294 strcpy(info->method, "-[[%rdi super] ");
2295 else if (Arch == Triple::aarch64)
2296 strcpy(info->method, "-[[x0 super] ");
2297 else
2298 strcpy(info->method, "-[[r? super] ");
2299 strcat(info->method, info->selector_name);
2300 strcat(info->method, "]");
2301 *ReferenceName = info->method;
2302 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message5;
2303 }
2304 info->class_name = nullptr;
2305 }
2306 }
2307 }
2308}
2309
2310// GuessPointerPointer() is passed the address of what might be a pointer to
2311// a reference to an Objective-C class, selector, message ref or cfstring.
2312// If so the value of the pointer is returned and one of the booleans are set
2313// to true. If not zero is returned and all the booleans are set to false.
2314static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
2315 struct DisassembleInfo *info,
2316 bool &classref, bool &selref, bool &msgref,
2317 bool &cfstring) {
2318 classref = false;
2319 selref = false;
2320 msgref = false;
2321 cfstring = false;
2322 for (const auto &Load : info->O->load_commands()) {
2323 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2324 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2325 for (unsigned J = 0; J < Seg.nsects; ++J) {
2326 MachO::section_64 Sec = info->O->getSection64(Load, J);
2327 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
2328 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2329 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
2330 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
2331 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
2332 ReferenceValue >= Sec.addr &&
2333 ReferenceValue < Sec.addr + Sec.size) {
2334 uint64_t sect_offset = ReferenceValue - Sec.addr;
2335 uint64_t object_offset = Sec.offset + sect_offset;
2336 StringRef MachOContents = info->O->getData();
2337 uint64_t object_size = MachOContents.size();
2338 const char *object_addr = (const char *)MachOContents.data();
2339 if (object_offset < object_size) {
2340 uint64_t pointer_value;
2341 memcpy(&pointer_value, object_addr + object_offset,
2342 sizeof(uint64_t));
2343 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2344 sys::swapByteOrder(pointer_value);
2345 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
2346 selref = true;
2347 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
2348 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
2349 classref = true;
2350 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
2351 ReferenceValue + 8 < Sec.addr + Sec.size) {
2352 msgref = true;
2353 memcpy(&pointer_value, object_addr + object_offset + 8,
2354 sizeof(uint64_t));
2355 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
2356 sys::swapByteOrder(pointer_value);
2357 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
2358 cfstring = true;
2359 return pointer_value;
2360 } else {
2361 return 0;
2362 }
2363 }
2364 }
2365 }
2366 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
2367 }
2368 return 0;
2369}
2370
2371// get_pointer_64 returns a pointer to the bytes in the object file at the
2372// Address from a section in the Mach-O file. And indirectly returns the
2373// offset into the section, number of bytes left in the section past the offset
2374// and which section is was being referenced. If the Address is not in a
2375// section nullptr is returned.
2376static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
2377 uint32_t &left, SectionRef &S,
2378 DisassembleInfo *info,
2379 bool objc_only = false) {
2380 offset = 0;
2381 left = 0;
2382 S = SectionRef();
2383 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
2384 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
2385 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
2386 if (SectSize == 0)
2387 continue;
2388 if (objc_only) {
2389 StringRef SectName;
2390 ((*(info->Sections))[SectIdx]).getName(SectName);
2391 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
2392 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
2393 if (SegName != "__OBJC" && SectName != "__cstring")
2394 continue;
2395 }
2396 if (Address >= SectAddress && Address < SectAddress + SectSize) {
2397 S = (*(info->Sections))[SectIdx];
2398 offset = Address - SectAddress;
2399 left = SectSize - offset;
2400 StringRef SectContents;
2401 ((*(info->Sections))[SectIdx]).getContents(SectContents);
2402 return SectContents.data() + offset;
2403 }
2404 }
2405 return nullptr;
2406}
2407
2408static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
2409 uint32_t &left, SectionRef &S,
2410 DisassembleInfo *info,
2411 bool objc_only = false) {
2412 return get_pointer_64(Address, offset, left, S, info, objc_only);
2413}
2414
2415// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
2416// the symbol indirectly through n_value. Based on the relocation information
2417// for the specified section offset in the specified section reference.
2418// If no relocation information is found and a non-zero ReferenceValue for the
2419// symbol is passed, look up that address in the info's AddrMap.
2420static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
2421 DisassembleInfo *info, uint64_t &n_value,
2422 uint64_t ReferenceValue = 0) {
2423 n_value = 0;
2424 if (!info->verbose)
2425 return nullptr;
2426
2427 // See if there is an external relocation entry at the sect_offset.
2428 bool reloc_found = false;
2429 DataRefImpl Rel;
2430 MachO::any_relocation_info RE;
2431 bool isExtern = false;
2432 SymbolRef Symbol;
2433 for (const RelocationRef &Reloc : S.relocations()) {
2434 uint64_t RelocOffset = Reloc.getOffset();
2435 if (RelocOffset == sect_offset) {
2436 Rel = Reloc.getRawDataRefImpl();
2437 RE = info->O->getRelocation(Rel);
2438 if (info->O->isRelocationScattered(RE))
2439 continue;
2440 isExtern = info->O->getPlainRelocationExternal(RE);
2441 if (isExtern) {
2442 symbol_iterator RelocSym = Reloc.getSymbol();
2443 Symbol = *RelocSym;
2444 }
2445 reloc_found = true;
2446 break;
2447 }
2448 }
2449 // If there is an external relocation entry for a symbol in this section
2450 // at this section_offset then use that symbol's value for the n_value
2451 // and return its name.
2452 const char *SymbolName = nullptr;
2453 if (reloc_found && isExtern) {
2454 n_value = Symbol.getValue();
2455 ErrorOr<StringRef> NameOrError = Symbol.getName();
2456 if (std::error_code EC = NameOrError.getError())
2457 report_fatal_error(EC.message());
2458 StringRef Name = *NameOrError;
2459 if (!Name.empty()) {
2460 SymbolName = Name.data();
2461 return SymbolName;
2462 }
2463 }
2464
2465 // TODO: For fully linked images, look through the external relocation
2466 // entries off the dynamic symtab command. For these the r_offset is from the
2467 // start of the first writeable segment in the Mach-O file. So the offset
2468 // to this section from that segment is passed to this routine by the caller,
2469 // as the database_offset. Which is the difference of the section's starting
2470 // address and the first writable segment.
2471 //
2472 // NOTE: need add passing the database_offset to this routine.
2473
2474 // We did not find an external relocation entry so look up the ReferenceValue
2475 // as an address of a symbol and if found return that symbol's name.
2476 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
2477
2478 return SymbolName;
2479}
2480
2481static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
2482 DisassembleInfo *info,
2483 uint32_t ReferenceValue) {
2484 uint64_t n_value64;
2485 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
2486}
2487
2488// These are structs in the Objective-C meta data and read to produce the
2489// comments for disassembly. While these are part of the ABI they are no
2490// public defintions. So the are here not in include/llvm/Support/MachO.h .
2491
2492// The cfstring object in a 64-bit Mach-O file.
2493struct cfstring64_t {
2494 uint64_t isa; // class64_t * (64-bit pointer)
2495 uint64_t flags; // flag bits
2496 uint64_t characters; // char * (64-bit pointer)
2497 uint64_t length; // number of non-NULL characters in above
2498};
2499
2500// The class object in a 64-bit Mach-O file.
2501struct class64_t {
2502 uint64_t isa; // class64_t * (64-bit pointer)
2503 uint64_t superclass; // class64_t * (64-bit pointer)
2504 uint64_t cache; // Cache (64-bit pointer)
2505 uint64_t vtable; // IMP * (64-bit pointer)
2506 uint64_t data; // class_ro64_t * (64-bit pointer)
2507};
2508
2509struct class32_t {
2510 uint32_t isa; /* class32_t * (32-bit pointer) */
2511 uint32_t superclass; /* class32_t * (32-bit pointer) */
2512 uint32_t cache; /* Cache (32-bit pointer) */
2513 uint32_t vtable; /* IMP * (32-bit pointer) */
2514 uint32_t data; /* class_ro32_t * (32-bit pointer) */
2515};
2516
2517struct class_ro64_t {
2518 uint32_t flags;
2519 uint32_t instanceStart;
2520 uint32_t instanceSize;
2521 uint32_t reserved;
2522 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
2523 uint64_t name; // const char * (64-bit pointer)
2524 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
2525 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
2526 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
2527 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
2528 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
2529};
2530
2531struct class_ro32_t {
2532 uint32_t flags;
2533 uint32_t instanceStart;
2534 uint32_t instanceSize;
2535 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
2536 uint32_t name; /* const char * (32-bit pointer) */
2537 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
2538 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
2539 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
2540 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
2541 uint32_t baseProperties; /* const struct objc_property_list *
2542 (32-bit pointer) */
2543};
2544
2545/* Values for class_ro{64,32}_t->flags */
2546#define RO_META(1 << 0) (1 << 0)
2547#define RO_ROOT(1 << 1) (1 << 1)
2548#define RO_HAS_CXX_STRUCTORS(1 << 2) (1 << 2)
2549
2550struct method_list64_t {
2551 uint32_t entsize;
2552 uint32_t count;
2553 /* struct method64_t first; These structures follow inline */
2554};
2555
2556struct method_list32_t {
2557 uint32_t entsize;
2558 uint32_t count;
2559 /* struct method32_t first; These structures follow inline */
2560};
2561
2562struct method64_t {
2563 uint64_t name; /* SEL (64-bit pointer) */
2564 uint64_t types; /* const char * (64-bit pointer) */
2565 uint64_t imp; /* IMP (64-bit pointer) */
2566};
2567
2568struct method32_t {
2569 uint32_t name; /* SEL (32-bit pointer) */
2570 uint32_t types; /* const char * (32-bit pointer) */
2571 uint32_t imp; /* IMP (32-bit pointer) */
2572};
2573
2574struct protocol_list64_t {
2575 uint64_t count; /* uintptr_t (a 64-bit value) */
2576 /* struct protocol64_t * list[0]; These pointers follow inline */
2577};
2578
2579struct protocol_list32_t {
2580 uint32_t count; /* uintptr_t (a 32-bit value) */
2581 /* struct protocol32_t * list[0]; These pointers follow inline */
2582};
2583
2584struct protocol64_t {
2585 uint64_t isa; /* id * (64-bit pointer) */
2586 uint64_t name; /* const char * (64-bit pointer) */
2587 uint64_t protocols; /* struct protocol_list64_t *
2588 (64-bit pointer) */
2589 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
2590 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
2591 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
2592 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
2593 uint64_t instanceProperties; /* struct objc_property_list *
2594 (64-bit pointer) */
2595};
2596
2597struct protocol32_t {
2598 uint32_t isa; /* id * (32-bit pointer) */
2599 uint32_t name; /* const char * (32-bit pointer) */
2600 uint32_t protocols; /* struct protocol_list_t *
2601 (32-bit pointer) */
2602 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
2603 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
2604 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
2605 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
2606 uint32_t instanceProperties; /* struct objc_property_list *
2607 (32-bit pointer) */
2608};
2609
2610struct ivar_list64_t {
2611 uint32_t entsize;
2612 uint32_t count;
2613 /* struct ivar64_t first; These structures follow inline */
2614};
2615
2616struct ivar_list32_t {
2617 uint32_t entsize;
2618 uint32_t count;
2619 /* struct ivar32_t first; These structures follow inline */
2620};
2621
2622struct ivar64_t {
2623 uint64_t offset; /* uintptr_t * (64-bit pointer) */
2624 uint64_t name; /* const char * (64-bit pointer) */
2625 uint64_t type; /* const char * (64-bit pointer) */
2626 uint32_t alignment;
2627 uint32_t size;
2628};
2629
2630struct ivar32_t {
2631 uint32_t offset; /* uintptr_t * (32-bit pointer) */
2632 uint32_t name; /* const char * (32-bit pointer) */
2633 uint32_t type; /* const char * (32-bit pointer) */
2634 uint32_t alignment;
2635 uint32_t size;
2636};
2637
2638struct objc_property_list64 {
2639 uint32_t entsize;
2640 uint32_t count;
2641 /* struct objc_property64 first; These structures follow inline */
2642};
2643
2644struct objc_property_list32 {
2645 uint32_t entsize;
2646 uint32_t count;
2647 /* struct objc_property32 first; These structures follow inline */
2648};
2649
2650struct objc_property64 {
2651 uint64_t name; /* const char * (64-bit pointer) */
2652 uint64_t attributes; /* const char * (64-bit pointer) */
2653};
2654
2655struct objc_property32 {
2656 uint32_t name; /* const char * (32-bit pointer) */
2657 uint32_t attributes; /* const char * (32-bit pointer) */
2658};
2659
2660struct category64_t {
2661 uint64_t name; /* const char * (64-bit pointer) */
2662 uint64_t cls; /* struct class_t * (64-bit pointer) */
2663 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
2664 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
2665 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
2666 uint64_t instanceProperties; /* struct objc_property_list *
2667 (64-bit pointer) */
2668};
2669
2670struct category32_t {
2671 uint32_t name; /* const char * (32-bit pointer) */
2672 uint32_t cls; /* struct class_t * (32-bit pointer) */
2673 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
2674 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
2675 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
2676 uint32_t instanceProperties; /* struct objc_property_list *
2677 (32-bit pointer) */
2678};
2679
2680struct objc_image_info64 {
2681 uint32_t version;
2682 uint32_t flags;
2683};
2684struct objc_image_info32 {
2685 uint32_t version;
2686 uint32_t flags;
2687};
2688struct imageInfo_t {
2689 uint32_t version;
2690 uint32_t flags;
2691};
2692/* masks for objc_image_info.flags */
2693#define OBJC_IMAGE_IS_REPLACEMENT(1 << 0) (1 << 0)
2694#define OBJC_IMAGE_SUPPORTS_GC(1 << 1) (1 << 1)
2695
2696struct message_ref64 {
2697 uint64_t imp; /* IMP (64-bit pointer) */
2698 uint64_t sel; /* SEL (64-bit pointer) */
2699};
2700
2701struct message_ref32 {
2702 uint32_t imp; /* IMP (32-bit pointer) */
2703 uint32_t sel; /* SEL (32-bit pointer) */
2704};
2705
2706// Objective-C 1 (32-bit only) meta data structs.
2707
2708struct objc_module_t {
2709 uint32_t version;
2710 uint32_t size;
2711 uint32_t name; /* char * (32-bit pointer) */
2712 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
2713};
2714
2715struct objc_symtab_t {
2716 uint32_t sel_ref_cnt;
2717 uint32_t refs; /* SEL * (32-bit pointer) */
2718 uint16_t cls_def_cnt;
2719 uint16_t cat_def_cnt;
2720 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
2721};
2722
2723struct objc_class_t {
2724 uint32_t isa; /* struct objc_class * (32-bit pointer) */
2725 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
2726 uint32_t name; /* const char * (32-bit pointer) */
2727 int32_t version;
2728 int32_t info;
2729 int32_t instance_size;
2730 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
2731 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
2732 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
2733 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
2734};
2735
2736#define CLS_GETINFO(cls, infomask)((cls)->info & (infomask)) ((cls)->info & (infomask))
2737// class is not a metaclass
2738#define CLS_CLASS0x1 0x1
2739// class is a metaclass
2740#define CLS_META0x2 0x2
2741
2742struct objc_category_t {
2743 uint32_t category_name; /* char * (32-bit pointer) */
2744 uint32_t class_name; /* char * (32-bit pointer) */
2745 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
2746 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
2747 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
2748};
2749
2750struct objc_ivar_t {
2751 uint32_t ivar_name; /* char * (32-bit pointer) */
2752 uint32_t ivar_type; /* char * (32-bit pointer) */
2753 int32_t ivar_offset;
2754};
2755
2756struct objc_ivar_list_t {
2757 int32_t ivar_count;
2758 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
2759};
2760
2761struct objc_method_list_t {
2762 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
2763 int32_t method_count;
2764 // struct objc_method_t method_list[1]; /* variable length structure */
2765};
2766
2767struct objc_method_t {
2768 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
2769 uint32_t method_types; /* char * (32-bit pointer) */
2770 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
2771 (32-bit pointer) */
2772};
2773
2774struct objc_protocol_list_t {
2775 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
2776 int32_t count;
2777 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
2778 // (32-bit pointer) */
2779};
2780
2781struct objc_protocol_t {
2782 uint32_t isa; /* struct objc_class * (32-bit pointer) */
2783 uint32_t protocol_name; /* char * (32-bit pointer) */
2784 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
2785 uint32_t instance_methods; /* struct objc_method_description_list *
2786 (32-bit pointer) */
2787 uint32_t class_methods; /* struct objc_method_description_list *
2788 (32-bit pointer) */
2789};
2790
2791struct objc_method_description_list_t {
2792 int32_t count;
2793 // struct objc_method_description_t list[1];
2794};
2795
2796struct objc_method_description_t {
2797 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
2798 uint32_t types; /* char * (32-bit pointer) */
2799};
2800
2801inline void swapStruct(struct cfstring64_t &cfs) {
2802 sys::swapByteOrder(cfs.isa);
2803 sys::swapByteOrder(cfs.flags);
2804 sys::swapByteOrder(cfs.characters);
2805 sys::swapByteOrder(cfs.length);
2806}
2807
2808inline void swapStruct(struct class64_t &c) {
2809 sys::swapByteOrder(c.isa);
2810 sys::swapByteOrder(c.superclass);
2811 sys::swapByteOrder(c.cache);
2812 sys::swapByteOrder(c.vtable);
2813 sys::swapByteOrder(c.data);
2814}
2815
2816inline void swapStruct(struct class32_t &c) {
2817 sys::swapByteOrder(c.isa);
2818 sys::swapByteOrder(c.superclass);
2819 sys::swapByteOrder(c.cache);
2820 sys::swapByteOrder(c.vtable);
2821 sys::swapByteOrder(c.data);
2822}
2823
2824inline void swapStruct(struct class_ro64_t &cro) {
2825 sys::swapByteOrder(cro.flags);
2826 sys::swapByteOrder(cro.instanceStart);
2827 sys::swapByteOrder(cro.instanceSize);
2828 sys::swapByteOrder(cro.reserved);
2829 sys::swapByteOrder(cro.ivarLayout);
2830 sys::swapByteOrder(cro.name);
2831 sys::swapByteOrder(cro.baseMethods);
2832 sys::swapByteOrder(cro.baseProtocols);
2833 sys::swapByteOrder(cro.ivars);
2834 sys::swapByteOrder(cro.weakIvarLayout);
2835 sys::swapByteOrder(cro.baseProperties);
2836}
2837
2838inline void swapStruct(struct class_ro32_t &cro) {
2839 sys::swapByteOrder(cro.flags);
2840 sys::swapByteOrder(cro.instanceStart);
2841 sys::swapByteOrder(cro.instanceSize);
2842 sys::swapByteOrder(cro.ivarLayout);
2843 sys::swapByteOrder(cro.name);
2844 sys::swapByteOrder(cro.baseMethods);
2845 sys::swapByteOrder(cro.baseProtocols);
2846 sys::swapByteOrder(cro.ivars);
2847 sys::swapByteOrder(cro.weakIvarLayout);
2848 sys::swapByteOrder(cro.baseProperties);
2849}
2850
2851inline void swapStruct(struct method_list64_t &ml) {
2852 sys::swapByteOrder(ml.entsize);
2853 sys::swapByteOrder(ml.count);
2854}
2855
2856inline void swapStruct(struct method_list32_t &ml) {
2857 sys::swapByteOrder(ml.entsize);
2858 sys::swapByteOrder(ml.count);
2859}
2860
2861inline void swapStruct(struct method64_t &m) {
2862 sys::swapByteOrder(m.name);
2863 sys::swapByteOrder(m.types);
2864 sys::swapByteOrder(m.imp);
2865}
2866
2867inline void swapStruct(struct method32_t &m) {
2868 sys::swapByteOrder(m.name);
2869 sys::swapByteOrder(m.types);
2870 sys::swapByteOrder(m.imp);
2871}
2872
2873inline void swapStruct(struct protocol_list64_t &pl) {
2874 sys::swapByteOrder(pl.count);
2875}
2876
2877inline void swapStruct(struct protocol_list32_t &pl) {
2878 sys::swapByteOrder(pl.count);
2879}
2880
2881inline void swapStruct(struct protocol64_t &p) {
2882 sys::swapByteOrder(p.isa);
2883 sys::swapByteOrder(p.name);
2884 sys::swapByteOrder(p.protocols);
2885 sys::swapByteOrder(p.instanceMethods);
2886 sys::swapByteOrder(p.classMethods);
2887 sys::swapByteOrder(p.optionalInstanceMethods);
2888 sys::swapByteOrder(p.optionalClassMethods);
2889 sys::swapByteOrder(p.instanceProperties);
2890}
2891
2892inline void swapStruct(struct protocol32_t &p) {
2893 sys::swapByteOrder(p.isa);
2894 sys::swapByteOrder(p.name);
2895 sys::swapByteOrder(p.protocols);
2896 sys::swapByteOrder(p.instanceMethods);
2897 sys::swapByteOrder(p.classMethods);
2898 sys::swapByteOrder(p.optionalInstanceMethods);
2899 sys::swapByteOrder(p.optionalClassMethods);
2900 sys::swapByteOrder(p.instanceProperties);
2901}
2902
2903inline void swapStruct(struct ivar_list64_t &il) {
2904 sys::swapByteOrder(il.entsize);
2905 sys::swapByteOrder(il.count);
2906}
2907
2908inline void swapStruct(struct ivar_list32_t &il) {
2909 sys::swapByteOrder(il.entsize);
2910 sys::swapByteOrder(il.count);
2911}
2912
2913inline void swapStruct(struct ivar64_t &i) {
2914 sys::swapByteOrder(i.offset);
2915 sys::swapByteOrder(i.name);
2916 sys::swapByteOrder(i.type);
2917 sys::swapByteOrder(i.alignment);
2918 sys::swapByteOrder(i.size);
2919}
2920
2921inline void swapStruct(struct ivar32_t &i) {
2922 sys::swapByteOrder(i.offset);
2923 sys::swapByteOrder(i.name);
2924 sys::swapByteOrder(i.type);
2925 sys::swapByteOrder(i.alignment);
2926 sys::swapByteOrder(i.size);
2927}
2928
2929inline void swapStruct(struct objc_property_list64 &pl) {
2930 sys::swapByteOrder(pl.entsize);
2931 sys::swapByteOrder(pl.count);
2932}
2933
2934inline void swapStruct(struct objc_property_list32 &pl) {
2935 sys::swapByteOrder(pl.entsize);
2936 sys::swapByteOrder(pl.count);
2937}
2938
2939inline void swapStruct(struct objc_property64 &op) {
2940 sys::swapByteOrder(op.name);
2941 sys::swapByteOrder(op.attributes);
2942}
2943
2944inline void swapStruct(struct objc_property32 &op) {
2945 sys::swapByteOrder(op.name);
2946 sys::swapByteOrder(op.attributes);
2947}
2948
2949inline void swapStruct(struct category64_t &c) {
2950 sys::swapByteOrder(c.name);
2951 sys::swapByteOrder(c.cls);
2952 sys::swapByteOrder(c.instanceMethods);
2953 sys::swapByteOrder(c.classMethods);
2954 sys::swapByteOrder(c.protocols);
2955 sys::swapByteOrder(c.instanceProperties);
2956}
2957
2958inline void swapStruct(struct category32_t &c) {
2959 sys::swapByteOrder(c.name);
2960 sys::swapByteOrder(c.cls);
2961 sys::swapByteOrder(c.instanceMethods);
2962 sys::swapByteOrder(c.classMethods);
2963 sys::swapByteOrder(c.protocols);
2964 sys::swapByteOrder(c.instanceProperties);
2965}
2966
2967inline void swapStruct(struct objc_image_info64 &o) {
2968 sys::swapByteOrder(o.version);
2969 sys::swapByteOrder(o.flags);
2970}
2971
2972inline void swapStruct(struct objc_image_info32 &o) {
2973 sys::swapByteOrder(o.version);
2974 sys::swapByteOrder(o.flags);
2975}
2976
2977inline void swapStruct(struct imageInfo_t &o) {
2978 sys::swapByteOrder(o.version);
2979 sys::swapByteOrder(o.flags);
2980}
2981
2982inline void swapStruct(struct message_ref64 &mr) {
2983 sys::swapByteOrder(mr.imp);
2984 sys::swapByteOrder(mr.sel);
2985}
2986
2987inline void swapStruct(struct message_ref32 &mr) {
2988 sys::swapByteOrder(mr.imp);
2989 sys::swapByteOrder(mr.sel);
2990}
2991
2992inline void swapStruct(struct objc_module_t &module) {
2993 sys::swapByteOrder(module.version);
2994 sys::swapByteOrder(module.size);
2995 sys::swapByteOrder(module.name);
2996 sys::swapByteOrder(module.symtab);
2997}
2998
2999inline void swapStruct(struct objc_symtab_t &symtab) {
3000 sys::swapByteOrder(symtab.sel_ref_cnt);
3001 sys::swapByteOrder(symtab.refs);
3002 sys::swapByteOrder(symtab.cls_def_cnt);
3003 sys::swapByteOrder(symtab.cat_def_cnt);
3004}
3005
3006inline void swapStruct(struct objc_class_t &objc_class) {
3007 sys::swapByteOrder(objc_class.isa);
3008 sys::swapByteOrder(objc_class.super_class);
3009 sys::swapByteOrder(objc_class.name);
3010 sys::swapByteOrder(objc_class.version);
3011 sys::swapByteOrder(objc_class.info);
3012 sys::swapByteOrder(objc_class.instance_size);
3013 sys::swapByteOrder(objc_class.ivars);
3014 sys::swapByteOrder(objc_class.methodLists);
3015 sys::swapByteOrder(objc_class.cache);
3016 sys::swapByteOrder(objc_class.protocols);
3017}
3018
3019inline void swapStruct(struct objc_category_t &objc_category) {
3020 sys::swapByteOrder(objc_category.category_name);
3021 sys::swapByteOrder(objc_category.class_name);
3022 sys::swapByteOrder(objc_category.instance_methods);
3023 sys::swapByteOrder(objc_category.class_methods);
3024 sys::swapByteOrder(objc_category.protocols);
3025}
3026
3027inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
3028 sys::swapByteOrder(objc_ivar_list.ivar_count);
3029}
3030
3031inline void swapStruct(struct objc_ivar_t &objc_ivar) {
3032 sys::swapByteOrder(objc_ivar.ivar_name);
3033 sys::swapByteOrder(objc_ivar.ivar_type);
3034 sys::swapByteOrder(objc_ivar.ivar_offset);
3035}
3036
3037inline void swapStruct(struct objc_method_list_t &method_list) {
3038 sys::swapByteOrder(method_list.obsolete);
3039 sys::swapByteOrder(method_list.method_count);
3040}
3041
3042inline void swapStruct(struct objc_method_t &method) {
3043 sys::swapByteOrder(method.method_name);
3044 sys::swapByteOrder(method.method_types);
3045 sys::swapByteOrder(method.method_imp);
3046}
3047
3048inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
3049 sys::swapByteOrder(protocol_list.next);
3050 sys::swapByteOrder(protocol_list.count);
3051}
3052
3053inline void swapStruct(struct objc_protocol_t &protocol) {
3054 sys::swapByteOrder(protocol.isa);
3055 sys::swapByteOrder(protocol.protocol_name);
3056 sys::swapByteOrder(protocol.protocol_list);
3057 sys::swapByteOrder(protocol.instance_methods);
3058 sys::swapByteOrder(protocol.class_methods);
3059}
3060
3061inline void swapStruct(struct objc_method_description_list_t &mdl) {
3062 sys::swapByteOrder(mdl.count);
3063}
3064
3065inline void swapStruct(struct objc_method_description_t &md) {
3066 sys::swapByteOrder(md.name);
3067 sys::swapByteOrder(md.types);
3068}
3069
3070static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
3071 struct DisassembleInfo *info);
3072
3073// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
3074// to an Objective-C class and returns the class name. It is also passed the
3075// address of the pointer, so when the pointer is zero as it can be in an .o
3076// file, that is used to look for an external relocation entry with a symbol
3077// name.
3078static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
3079 uint64_t ReferenceValue,
3080 struct DisassembleInfo *info) {
3081 const char *r;
3082 uint32_t offset, left;
3083 SectionRef S;
3084
3085 // The pointer_value can be 0 in an object file and have a relocation
3086 // entry for the class symbol at the ReferenceValue (the address of the
3087 // pointer).
3088 if (pointer_value == 0) {
3089 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3090 if (r == nullptr || left < sizeof(uint64_t))
3091 return nullptr;
3092 uint64_t n_value;
3093 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3094 if (symbol_name == nullptr)
3095 return nullptr;
3096 const char *class_name = strrchr(symbol_name, '$');
3097 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
3098 return class_name + 2;
3099 else
3100 return nullptr;
3101 }
3102
3103 // The case were the pointer_value is non-zero and points to a class defined
3104 // in this Mach-O file.
3105 r = get_pointer_64(pointer_value, offset, left, S, info);
3106 if (r == nullptr || left < sizeof(struct class64_t))
3107 return nullptr;
3108 struct class64_t c;
3109 memcpy(&c, r, sizeof(struct class64_t));
3110 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3111 swapStruct(c);
3112 if (c.data == 0)
3113 return nullptr;
3114 r = get_pointer_64(c.data, offset, left, S, info);
3115 if (r == nullptr || left < sizeof(struct class_ro64_t))
3116 return nullptr;
3117 struct class_ro64_t cro;
3118 memcpy(&cro, r, sizeof(struct class_ro64_t));
3119 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3120 swapStruct(cro);
3121 if (cro.name == 0)
3122 return nullptr;
3123 const char *name = get_pointer_64(cro.name, offset, left, S, info);
3124 return name;
3125}
3126
3127// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
3128// pointer to a cfstring and returns its name or nullptr.
3129static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
3130 struct DisassembleInfo *info) {
3131 const char *r, *name;
3132 uint32_t offset, left;
3133 SectionRef S;
3134 struct cfstring64_t cfs;
3135 uint64_t cfs_characters;
3136
3137 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3138 if (r == nullptr || left < sizeof(struct cfstring64_t))
3139 return nullptr;
3140 memcpy(&cfs, r, sizeof(struct cfstring64_t));
3141 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3142 swapStruct(cfs);
3143 if (cfs.characters == 0) {
3144 uint64_t n_value;
3145 const char *symbol_name = get_symbol_64(
3146 offset + offsetof(struct cfstring64_t, characters)__builtin_offsetof(struct cfstring64_t, characters), S, info, n_value);
3147 if (symbol_name == nullptr)
3148 return nullptr;
3149 cfs_characters = n_value;
3150 } else
3151 cfs_characters = cfs.characters;
3152 name = get_pointer_64(cfs_characters, offset, left, S, info);
3153
3154 return name;
3155}
3156
3157// get_objc2_64bit_selref() is used for disassembly and is passed a the address
3158// of a pointer to an Objective-C selector reference when the pointer value is
3159// zero as in a .o file and is likely to have a external relocation entry with
3160// who's symbol's n_value is the real pointer to the selector name. If that is
3161// the case the real pointer to the selector name is returned else 0 is
3162// returned
3163static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
3164 struct DisassembleInfo *info) {
3165 uint32_t offset, left;
3166 SectionRef S;
3167
3168 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
3169 if (r == nullptr || left < sizeof(uint64_t))
3170 return 0;
3171 uint64_t n_value;
3172 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3173 if (symbol_name == nullptr)
3174 return 0;
3175 return n_value;
3176}
3177
3178static const SectionRef get_section(MachOObjectFile *O, const char *segname,
3179 const char *sectname) {
3180 for (const SectionRef &Section : O->sections()) {
3181 StringRef SectName;
3182 Section.getName(SectName);
3183 DataRefImpl Ref = Section.getRawDataRefImpl();
3184 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3185 if (SegName == segname && SectName == sectname)
3186 return Section;
3187 }
3188 return SectionRef();
3189}
3190
3191static void
3192walk_pointer_list_64(const char *listname, const SectionRef S,
3193 MachOObjectFile *O, struct DisassembleInfo *info,
3194 void (*func)(uint64_t, struct DisassembleInfo *info)) {
3195 if (S == SectionRef())
3196 return;
3197
3198 StringRef SectName;
3199 S.getName(SectName);
3200 DataRefImpl Ref = S.getRawDataRefImpl();
3201 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3202 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3203
3204 StringRef BytesStr;
3205 S.getContents(BytesStr);
3206 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3207
3208 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
3209 uint32_t left = S.getSize() - i;
3210 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
3211 uint64_t p = 0;
3212 memcpy(&p, Contents + i, size);
3213 if (i + sizeof(uint64_t) > S.getSize())
3214 outs() << listname << " list pointer extends past end of (" << SegName
3215 << "," << SectName << ") section\n";
3216 outs() << format("%016" PRIx64"l" "x", S.getAddress() + i) << " ";
3217
3218 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3219 sys::swapByteOrder(p);
3220
3221 uint64_t n_value = 0;
3222 const char *name = get_symbol_64(i, S, info, n_value, p);
3223 if (name == nullptr)
3224 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
3225
3226 if (n_value != 0) {
3227 outs() << format("0x%" PRIx64"l" "x", n_value);
3228 if (p != 0)
3229 outs() << " + " << format("0x%" PRIx64"l" "x", p);
3230 } else
3231 outs() << format("0x%" PRIx64"l" "x", p);
3232 if (name != nullptr)
3233 outs() << " " << name;
3234 outs() << "\n";
3235
3236 p += n_value;
3237 if (func)
3238 func(p, info);
3239 }
3240}
3241
3242static void
3243walk_pointer_list_32(const char *listname, const SectionRef S,
3244 MachOObjectFile *O, struct DisassembleInfo *info,
3245 void (*func)(uint32_t, struct DisassembleInfo *info)) {
3246 if (S == SectionRef())
3247 return;
3248
3249 StringRef SectName;
3250 S.getName(SectName);
3251 DataRefImpl Ref = S.getRawDataRefImpl();
3252 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3253 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3254
3255 StringRef BytesStr;
3256 S.getContents(BytesStr);
3257 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3258
3259 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
3260 uint32_t left = S.getSize() - i;
3261 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
3262 uint32_t p = 0;
3263 memcpy(&p, Contents + i, size);
3264 if (i + sizeof(uint32_t) > S.getSize())
3265 outs() << listname << " list pointer extends past end of (" << SegName
3266 << "," << SectName << ") section\n";
3267 uint32_t Address = S.getAddress() + i;
3268 outs() << format("%08" PRIx32"x", Address) << " ";
3269
3270 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3271 sys::swapByteOrder(p);
3272 outs() << format("0x%" PRIx32"x", p);
3273
3274 const char *name = get_symbol_32(i, S, info, p);
3275 if (name != nullptr)
3276 outs() << " " << name;
3277 outs() << "\n";
3278
3279 if (func)
3280 func(p, info);
3281 }
3282}
3283
3284static void print_layout_map(const char *layout_map, uint32_t left) {
3285 if (layout_map == nullptr)
3286 return;
3287 outs() << " layout map: ";
3288 do {
3289 outs() << format("0x%02" PRIx32"x", (*layout_map) & 0xff) << " ";
3290 left--;
3291 layout_map++;
3292 } while (*layout_map != '\0' && left != 0);
3293 outs() << "\n";
3294}
3295
3296static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
3297 uint32_t offset, left;
3298 SectionRef S;
3299 const char *layout_map;
3300
3301 if (p == 0)
3302 return;
3303 layout_map = get_pointer_64(p, offset, left, S, info);
3304 print_layout_map(layout_map, left);
3305}
3306
3307static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
3308 uint32_t offset, left;
3309 SectionRef S;
3310 const char *layout_map;
3311
3312 if (p == 0)
3313 return;
3314 layout_map = get_pointer_32(p, offset, left, S, info);
3315 print_layout_map(layout_map, left);
3316}
3317
3318static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
3319 const char *indent) {
3320 struct method_list64_t ml;
3321 struct method64_t m;
3322 const char *r;
3323 uint32_t offset, xoffset, left, i;
3324 SectionRef S, xS;
3325 const char *name, *sym_name;
3326 uint64_t n_value;
3327
3328 r = get_pointer_64(p, offset, left, S, info);
3329 if (r == nullptr)
3330 return;
3331 memset(&ml, '\0', sizeof(struct method_list64_t));
3332 if (left < sizeof(struct method_list64_t)) {
3333 memcpy(&ml, r, left);
3334 outs() << " (method_list_t entends past the end of the section)\n";
3335 } else
3336 memcpy(&ml, r, sizeof(struct method_list64_t));
3337 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3338 swapStruct(ml);
3339 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3340 outs() << indent << "\t\t count " << ml.count << "\n";
3341
3342 p += sizeof(struct method_list64_t);
3343 offset += sizeof(struct method_list64_t);
3344 for (i = 0; i < ml.count; i++) {
3345 r = get_pointer_64(p, offset, left, S, info);
3346 if (r == nullptr)
3347 return;
3348 memset(&m, '\0', sizeof(struct method64_t));
3349 if (left < sizeof(struct method64_t)) {
3350 memcpy(&m, r, left);
3351 outs() << indent << " (method_t extends past the end of the section)\n";
3352 } else
3353 memcpy(&m, r, sizeof(struct method64_t));
3354 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3355 swapStruct(m);
3356
3357 outs() << indent << "\t\t name ";
3358 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name)__builtin_offsetof(struct method64_t, name), S,
3359 info, n_value, m.name);
3360 if (n_value != 0) {
3361 if (info->verbose && sym_name != nullptr)
3362 outs() << sym_name;
3363 else
3364 outs() << format("0x%" PRIx64"l" "x", n_value);
3365 if (m.name != 0)
3366 outs() << " + " << format("0x%" PRIx64"l" "x", m.name);
3367 } else
3368 outs() << format("0x%" PRIx64"l" "x", m.name);
3369 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
3370 if (name != nullptr)
3371 outs() << format(" %.*s", left, name);
3372 outs() << "\n";
3373
3374 outs() << indent << "\t\t types ";
3375 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types)__builtin_offsetof(struct method64_t, types), S,
3376 info, n_value, m.types);
3377 if (n_value != 0) {
3378 if (info->verbose && sym_name != nullptr)
3379 outs() << sym_name;
3380 else
3381 outs() << format("0x%" PRIx64"l" "x", n_value);
3382 if (m.types != 0)
3383 outs() << " + " << format("0x%" PRIx64"l" "x", m.types);
3384 } else
3385 outs() << format("0x%" PRIx64"l" "x", m.types);
3386 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
3387 if (name != nullptr)
3388 outs() << format(" %.*s", left, name);
3389 outs() << "\n";
3390
3391 outs() << indent << "\t\t imp ";
3392 name = get_symbol_64(offset + offsetof(struct method64_t, imp)__builtin_offsetof(struct method64_t, imp), S, info,
3393 n_value, m.imp);
3394 if (info->verbose && name == nullptr) {
3395 if (n_value != 0) {
3396 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
3397 if (m.imp != 0)
3398 outs() << "+ " << format("0x%" PRIx64"l" "x", m.imp) << " ";
3399 } else
3400 outs() << format("0x%" PRIx64"l" "x", m.imp) << " ";
3401 }
3402 if (name != nullptr)
3403 outs() << name;
3404 outs() << "\n";
3405
3406 p += sizeof(struct method64_t);
3407 offset += sizeof(struct method64_t);
3408 }
3409}
3410
3411static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
3412 const char *indent) {
3413 struct method_list32_t ml;
3414 struct method32_t m;
3415 const char *r, *name;
3416 uint32_t offset, xoffset, left, i;
3417 SectionRef S, xS;
3418
3419 r = get_pointer_32(p, offset, left, S, info);
3420 if (r == nullptr)
3421 return;
3422 memset(&ml, '\0', sizeof(struct method_list32_t));
3423 if (left < sizeof(struct method_list32_t)) {
3424 memcpy(&ml, r, left);
3425 outs() << " (method_list_t entends past the end of the section)\n";
3426 } else
3427 memcpy(&ml, r, sizeof(struct method_list32_t));
3428 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3429 swapStruct(ml);
3430 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
3431 outs() << indent << "\t\t count " << ml.count << "\n";
3432
3433 p += sizeof(struct method_list32_t);
3434 offset += sizeof(struct method_list32_t);
3435 for (i = 0; i < ml.count; i++) {
3436 r = get_pointer_32(p, offset, left, S, info);
3437 if (r == nullptr)
3438 return;
3439 memset(&m, '\0', sizeof(struct method32_t));
3440 if (left < sizeof(struct method32_t)) {
3441 memcpy(&ml, r, left);
3442 outs() << indent << " (method_t entends past the end of the section)\n";
3443 } else
3444 memcpy(&m, r, sizeof(struct method32_t));
3445 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3446 swapStruct(m);
3447
3448 outs() << indent << "\t\t name " << format("0x%" PRIx32"x", m.name);
3449 name = get_pointer_32(m.name, xoffset, left, xS, info);
3450 if (name != nullptr)
3451 outs() << format(" %.*s", left, name);
3452 outs() << "\n";
3453
3454 outs() << indent << "\t\t types " << format("0x%" PRIx32"x", m.types);
3455 name = get_pointer_32(m.types, xoffset, left, xS, info);
3456 if (name != nullptr)
3457 outs() << format(" %.*s", left, name);
3458 outs() << "\n";
3459
3460 outs() << indent << "\t\t imp " << format("0x%" PRIx32"x", m.imp);
3461 name = get_symbol_32(offset + offsetof(struct method32_t, imp)__builtin_offsetof(struct method32_t, imp), S, info,
3462 m.imp);
3463 if (name != nullptr)
3464 outs() << " " << name;
3465 outs() << "\n";
3466
3467 p += sizeof(struct method32_t);
3468 offset += sizeof(struct method32_t);
3469 }
3470}
3471
3472static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
3473 uint32_t offset, left, xleft;
3474 SectionRef S;
3475 struct objc_method_list_t method_list;
3476 struct objc_method_t method;
3477 const char *r, *methods, *name, *SymbolName;
3478 int32_t i;
3479
3480 r = get_pointer_32(p, offset, left, S, info, true);
3481 if (r == nullptr)
3482 return true;
3483
3484 outs() << "\n";
3485 if (left > sizeof(struct objc_method_list_t)) {
3486 memcpy(&method_list, r, sizeof(struct objc_method_list_t));
3487 } else {
3488 outs() << "\t\t objc_method_list extends past end of the section\n";
3489 memset(&method_list, '\0', sizeof(struct objc_method_list_t));
3490 memcpy(&method_list, r, left);
3491 }
3492 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3493 swapStruct(method_list);
3494
3495 outs() << "\t\t obsolete "
3496 << format("0x%08" PRIx32"x", method_list.obsolete) << "\n";
3497 outs() << "\t\t method_count " << method_list.method_count << "\n";
3498
3499 methods = r + sizeof(struct objc_method_list_t);
3500 for (i = 0; i < method_list.method_count; i++) {
3501 if ((i + 1) * sizeof(struct objc_method_t) > left) {
3502 outs() << "\t\t remaining method's extend past the of the section\n";
3503 break;
3504 }
3505 memcpy(&method, methods + i * sizeof(struct objc_method_t),
3506 sizeof(struct objc_method_t));
3507 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3508 swapStruct(method);
3509
3510 outs() << "\t\t method_name "
3511 << format("0x%08" PRIx32"x", method.method_name);
3512 if (info->verbose) {
3513 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
3514 if (name != nullptr)
3515 outs() << format(" %.*s", xleft, name);
3516 else
3517 outs() << " (not in an __OBJC section)";
3518 }
3519 outs() << "\n";
3520
3521 outs() << "\t\t method_types "
3522 << format("0x%08" PRIx32"x", method.method_types);
3523 if (info->verbose) {
3524 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
3525 if (name != nullptr)
3526 outs() << format(" %.*s", xleft, name);
3527 else
3528 outs() << " (not in an __OBJC section)";
3529 }
3530 outs() << "\n";
3531
3532 outs() << "\t\t method_imp "
3533 << format("0x%08" PRIx32"x", method.method_imp) << " ";
3534 if (info->verbose) {
3535 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
3536 if (SymbolName != nullptr)
3537 outs() << SymbolName;
3538 }
3539 outs() << "\n";
3540 }
3541 return false;
3542}
3543
3544static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
3545 struct protocol_list64_t pl;
3546 uint64_t q, n_value;
3547 struct protocol64_t pc;
3548 const char *r;
3549 uint32_t offset, xoffset, left, i;
3550 SectionRef S, xS;
3551 const char *name, *sym_name;
3552
3553 r = get_pointer_64(p, offset, left, S, info);
3554 if (r == nullptr)
3555 return;
3556 memset(&pl, '\0', sizeof(struct protocol_list64_t));
3557 if (left < sizeof(struct protocol_list64_t)) {
3558 memcpy(&pl, r, left);
3559 outs() << " (protocol_list_t entends past the end of the section)\n";
3560 } else
3561 memcpy(&pl, r, sizeof(struct protocol_list64_t));
3562 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3563 swapStruct(pl);
3564 outs() << " count " << pl.count << "\n";
3565
3566 p += sizeof(struct protocol_list64_t);
3567 offset += sizeof(struct protocol_list64_t);
3568 for (i = 0; i < pl.count; i++) {
3569 r = get_pointer_64(p, offset, left, S, info);
3570 if (r == nullptr)
3571 return;
3572 q = 0;
3573 if (left < sizeof(uint64_t)) {
3574 memcpy(&q, r, left);
3575 outs() << " (protocol_t * entends past the end of the section)\n";
3576 } else
3577 memcpy(&q, r, sizeof(uint64_t));
3578 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3579 sys::swapByteOrder(q);
3580
3581 outs() << "\t\t list[" << i << "] ";
3582 sym_name = get_symbol_64(offset, S, info, n_value, q);
3583 if (n_value != 0) {
3584 if (info->verbose && sym_name != nullptr)
3585 outs() << sym_name;
3586 else
3587 outs() << format("0x%" PRIx64"l" "x", n_value);
3588 if (q != 0)
3589 outs() << " + " << format("0x%" PRIx64"l" "x", q);
3590 } else
3591 outs() << format("0x%" PRIx64"l" "x", q);
3592 outs() << " (struct protocol_t *)\n";
3593
3594 r = get_pointer_64(q + n_value, offset, left, S, info);
3595 if (r == nullptr)
3596 return;
3597 memset(&pc, '\0', sizeof(struct protocol64_t));
3598 if (left < sizeof(struct protocol64_t)) {
3599 memcpy(&pc, r, left);
3600 outs() << " (protocol_t entends past the end of the section)\n";
3601 } else
3602 memcpy(&pc, r, sizeof(struct protocol64_t));
3603 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3604 swapStruct(pc);
3605
3606 outs() << "\t\t\t isa " << format("0x%" PRIx64"l" "x", pc.isa) << "\n";
3607
3608 outs() << "\t\t\t name ";
3609 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name)__builtin_offsetof(struct protocol64_t, name), S,
3610 info, n_value, pc.name);
3611 if (n_value != 0) {
3612 if (info->verbose && sym_name != nullptr)
3613 outs() << sym_name;
3614 else
3615 outs() << format("0x%" PRIx64"l" "x", n_value);
3616 if (pc.name != 0)
3617 outs() << " + " << format("0x%" PRIx64"l" "x", pc.name);
3618 } else
3619 outs() << format("0x%" PRIx64"l" "x", pc.name);
3620 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
3621 if (name != nullptr)
3622 outs() << format(" %.*s", left, name);
3623 outs() << "\n";
3624
3625 outs() << "\t\t\tprotocols " << format("0x%" PRIx64"l" "x", pc.protocols) << "\n";
3626
3627 outs() << "\t\t instanceMethods ";
3628 sym_name =
3629 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods)__builtin_offsetof(struct protocol64_t, instanceMethods),
3630 S, info, n_value, pc.instanceMethods);
3631 if (n_value != 0) {
3632 if (info->verbose && sym_name != nullptr)
3633 outs() << sym_name;
3634 else
3635 outs() << format("0x%" PRIx64"l" "x", n_value);
3636 if (pc.instanceMethods != 0)
3637 outs() << " + " << format("0x%" PRIx64"l" "x", pc.instanceMethods);
3638 } else
3639 outs() << format("0x%" PRIx64"l" "x", pc.instanceMethods);
3640 outs() << " (struct method_list_t *)\n";
3641 if (pc.instanceMethods + n_value != 0)
3642 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
3643
3644 outs() << "\t\t classMethods ";
3645 sym_name =
3646 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods)__builtin_offsetof(struct protocol64_t, classMethods), S,
3647 info, n_value, pc.classMethods);
3648 if (n_value != 0) {
3649 if (info->verbose && sym_name != nullptr)
3650 outs() << sym_name;
3651 else
3652 outs() << format("0x%" PRIx64"l" "x", n_value);
3653 if (pc.classMethods != 0)
3654 outs() << " + " << format("0x%" PRIx64"l" "x", pc.classMethods);
3655 } else
3656 outs() << format("0x%" PRIx64"l" "x", pc.classMethods);
3657 outs() << " (struct method_list_t *)\n";
3658 if (pc.classMethods + n_value != 0)
3659 print_method_list64_t(pc.classMethods + n_value, info, "\t");
3660
3661 outs() << "\t optionalInstanceMethods "
3662 << format("0x%" PRIx64"l" "x", pc.optionalInstanceMethods) << "\n";
3663 outs() << "\t optionalClassMethods "
3664 << format("0x%" PRIx64"l" "x", pc.optionalClassMethods) << "\n";
3665 outs() << "\t instanceProperties "
3666 << format("0x%" PRIx64"l" "x", pc.instanceProperties) << "\n";
3667
3668 p += sizeof(uint64_t);
3669 offset += sizeof(uint64_t);
3670 }
3671}
3672
3673static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
3674 struct protocol_list32_t pl;
3675 uint32_t q;
3676 struct protocol32_t pc;
3677 const char *r;
3678 uint32_t offset, xoffset, left, i;
3679 SectionRef S, xS;
3680 const char *name;
3681
3682 r = get_pointer_32(p, offset, left, S, info);
3683 if (r == nullptr)
3684 return;
3685 memset(&pl, '\0', sizeof(struct protocol_list32_t));
3686 if (left < sizeof(struct protocol_list32_t)) {
3687 memcpy(&pl, r, left);
3688 outs() << " (protocol_list_t entends past the end of the section)\n";
3689 } else
3690 memcpy(&pl, r, sizeof(struct protocol_list32_t));
3691 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3692 swapStruct(pl);
3693 outs() << " count " << pl.count << "\n";
3694
3695 p += sizeof(struct protocol_list32_t);
3696 offset += sizeof(struct protocol_list32_t);
3697 for (i = 0; i < pl.count; i++) {
3698 r = get_pointer_32(p, offset, left, S, info);
3699 if (r == nullptr)
3700 return;
3701 q = 0;
3702 if (left < sizeof(uint32_t)) {
3703 memcpy(&q, r, left);
3704 outs() << " (protocol_t * entends past the end of the section)\n";
3705 } else
3706 memcpy(&q, r, sizeof(uint32_t));
3707 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3708 sys::swapByteOrder(q);
3709 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32"x", q)
3710 << " (struct protocol_t *)\n";
3711 r = get_pointer_32(q, offset, left, S, info);
3712 if (r == nullptr)
3713 return;
3714 memset(&pc, '\0', sizeof(struct protocol32_t));
3715 if (left < sizeof(struct protocol32_t)) {
3716 memcpy(&pc, r, left);
3717 outs() << " (protocol_t entends past the end of the section)\n";
3718 } else
3719 memcpy(&pc, r, sizeof(struct protocol32_t));
3720 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3721 swapStruct(pc);
3722 outs() << "\t\t\t isa " << format("0x%" PRIx32"x", pc.isa) << "\n";
3723 outs() << "\t\t\t name " << format("0x%" PRIx32"x", pc.name);
3724 name = get_pointer_32(pc.name, xoffset, left, xS, info);
3725 if (name != nullptr)
3726 outs() << format(" %.*s", left, name);
3727 outs() << "\n";
3728 outs() << "\t\t\tprotocols " << format("0x%" PRIx32"x", pc.protocols) << "\n";
3729 outs() << "\t\t instanceMethods "
3730 << format("0x%" PRIx32"x", pc.instanceMethods)
3731 << " (struct method_list_t *)\n";
3732 if (pc.instanceMethods != 0)
3733 print_method_list32_t(pc.instanceMethods, info, "\t");
3734 outs() << "\t\t classMethods " << format("0x%" PRIx32"x", pc.classMethods)
3735 << " (struct method_list_t *)\n";
3736 if (pc.classMethods != 0)
3737 print_method_list32_t(pc.classMethods, info, "\t");
3738 outs() << "\t optionalInstanceMethods "
3739 << format("0x%" PRIx32"x", pc.optionalInstanceMethods) << "\n";
3740 outs() << "\t optionalClassMethods "
3741 << format("0x%" PRIx32"x", pc.optionalClassMethods) << "\n";
3742 outs() << "\t instanceProperties "
3743 << format("0x%" PRIx32"x", pc.instanceProperties) << "\n";
3744 p += sizeof(uint32_t);
3745 offset += sizeof(uint32_t);
3746 }
3747}
3748
3749static void print_indent(uint32_t indent) {
3750 for (uint32_t i = 0; i < indent;) {
3751 if (indent - i >= 8) {
3752 outs() << "\t";
3753 i += 8;
3754 } else {
3755 for (uint32_t j = i; j < indent; j++)
3756 outs() << " ";
3757 return;
3758 }
3759 }
3760}
3761
3762static bool print_method_description_list(uint32_t p, uint32_t indent,
3763 struct DisassembleInfo *info) {
3764 uint32_t offset, left, xleft;
3765 SectionRef S;
3766 struct objc_method_description_list_t mdl;
3767 struct objc_method_description_t md;
3768 const char *r, *list, *name;
3769 int32_t i;
3770
3771 r = get_pointer_32(p, offset, left, S, info, true);
3772 if (r == nullptr)
3773 return true;
3774
3775 outs() << "\n";
3776 if (left > sizeof(struct objc_method_description_list_t)) {
3777 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
3778 } else {
3779 print_indent(indent);
3780 outs() << " objc_method_description_list extends past end of the section\n";
3781 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
3782 memcpy(&mdl, r, left);
3783 }
3784 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3785 swapStruct(mdl);
3786
3787 print_indent(indent);
3788 outs() << " count " << mdl.count << "\n";
3789
3790 list = r + sizeof(struct objc_method_description_list_t);
3791 for (i = 0; i < mdl.count; i++) {
3792 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
3793 print_indent(indent);
3794 outs() << " remaining list entries extend past the of the section\n";
3795 break;
3796 }
3797 print_indent(indent);
3798 outs() << " list[" << i << "]\n";
3799 memcpy(&md, list + i * sizeof(struct objc_method_description_t),
3800 sizeof(struct objc_method_description_t));
3801 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3802 swapStruct(md);
3803
3804 print_indent(indent);
3805 outs() << " name " << format("0x%08" PRIx32"x", md.name);
3806 if (info->verbose) {
3807 name = get_pointer_32(md.name, offset, xleft, S, info, true);
3808 if (name != nullptr)
3809 outs() << format(" %.*s", xleft, name);
3810 else
3811 outs() << " (not in an __OBJC section)";
3812 }
3813 outs() << "\n";
3814
3815 print_indent(indent);
3816 outs() << " types " << format("0x%08" PRIx32"x", md.types);
3817 if (info->verbose) {
3818 name = get_pointer_32(md.types, offset, xleft, S, info, true);
3819 if (name != nullptr)
3820 outs() << format(" %.*s", xleft, name);
3821 else
3822 outs() << " (not in an __OBJC section)";
3823 }
3824 outs() << "\n";
3825 }
3826 return false;
3827}
3828
3829static bool print_protocol_list(uint32_t p, uint32_t indent,
3830 struct DisassembleInfo *info);
3831
3832static bool print_protocol(uint32_t p, uint32_t indent,
3833 struct DisassembleInfo *info) {
3834 uint32_t offset, left;
3835 SectionRef S;
3836 struct objc_protocol_t protocol;
3837 const char *r, *name;
3838
3839 r = get_pointer_32(p, offset, left, S, info, true);
3840 if (r == nullptr)
3841 return true;
3842
3843 outs() << "\n";
3844 if (left >= sizeof(struct objc_protocol_t)) {
3845 memcpy(&protocol, r, sizeof(struct objc_protocol_t));
3846 } else {
3847 print_indent(indent);
3848 outs() << " Protocol extends past end of the section\n";
3849 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
3850 memcpy(&protocol, r, left);
3851 }
3852 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3853 swapStruct(protocol);
3854
3855 print_indent(indent);
3856 outs() << " isa " << format("0x%08" PRIx32"x", protocol.isa)
3857 << "\n";
3858
3859 print_indent(indent);
3860 outs() << " protocol_name "
3861 << format("0x%08" PRIx32"x", protocol.protocol_name);
3862 if (info->verbose) {
3863 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
3864 if (name != nullptr)
3865 outs() << format(" %.*s", left, name);
3866 else
3867 outs() << " (not in an __OBJC section)";
3868 }
3869 outs() << "\n";
3870
3871 print_indent(indent);
3872 outs() << " protocol_list "
3873 << format("0x%08" PRIx32"x", protocol.protocol_list);
3874 if (print_protocol_list(protocol.protocol_list, indent + 4, info))
3875 outs() << " (not in an __OBJC section)\n";
3876
3877 print_indent(indent);
3878 outs() << " instance_methods "
3879 << format("0x%08" PRIx32"x", protocol.instance_methods);
3880 if (print_method_description_list(protocol.instance_methods, indent, info))
3881 outs() << " (not in an __OBJC section)\n";
3882
3883 print_indent(indent);
3884 outs() << " class_methods "
3885 << format("0x%08" PRIx32"x", protocol.class_methods);
3886 if (print_method_description_list(protocol.class_methods, indent, info))
3887 outs() << " (not in an __OBJC section)\n";
3888
3889 return false;
3890}
3891
3892static bool print_protocol_list(uint32_t p, uint32_t indent,
3893 struct DisassembleInfo *info) {
3894 uint32_t offset, left, l;
3895 SectionRef S;
3896 struct objc_protocol_list_t protocol_list;
3897 const char *r, *list;
3898 int32_t i;
3899
3900 r = get_pointer_32(p, offset, left, S, info, true);
3901 if (r == nullptr)
3902 return true;
3903
3904 outs() << "\n";
3905 if (left > sizeof(struct objc_protocol_list_t)) {
3906 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
3907 } else {
3908 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
3909 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
3910 memcpy(&protocol_list, r, left);
3911 }
3912 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3913 swapStruct(protocol_list);
3914
3915 print_indent(indent);
3916 outs() << " next " << format("0x%08" PRIx32"x", protocol_list.next)
3917 << "\n";
3918 print_indent(indent);
3919 outs() << " count " << protocol_list.count << "\n";
3920
3921 list = r + sizeof(struct objc_protocol_list_t);
3922 for (i = 0; i < protocol_list.count; i++) {
3923 if ((i + 1) * sizeof(uint32_t) > left) {
3924 outs() << "\t\t remaining list entries extend past the of the section\n";
3925 break;
3926 }
3927 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
3928 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3929 sys::swapByteOrder(l);
3930
3931 print_indent(indent);
3932 outs() << " list[" << i << "] " << format("0x%08" PRIx32"x", l);
3933 if (print_protocol(l, indent, info))
3934 outs() << "(not in an __OBJC section)\n";
3935 }
3936 return false;
3937}
3938
3939static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
3940 struct ivar_list64_t il;
3941 struct ivar64_t i;
3942 const char *r;
3943 uint32_t offset, xoffset, left, j;
3944 SectionRef S, xS;
3945 const char *name, *sym_name, *ivar_offset_p;
3946 uint64_t ivar_offset, n_value;
3947
3948 r = get_pointer_64(p, offset, left, S, info);
3949 if (r == nullptr)
3950 return;
3951 memset(&il, '\0', sizeof(struct ivar_list64_t));
3952 if (left < sizeof(struct ivar_list64_t)) {
3953 memcpy(&il, r, left);
3954 outs() << " (ivar_list_t entends past the end of the section)\n";
3955 } else
3956 memcpy(&il, r, sizeof(struct ivar_list64_t));
3957 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3958 swapStruct(il);
3959 outs() << " entsize " << il.entsize << "\n";
3960 outs() << " count " << il.count << "\n";
3961
3962 p += sizeof(struct ivar_list64_t);
3963 offset += sizeof(struct ivar_list64_t);
3964 for (j = 0; j < il.count; j++) {
3965 r = get_pointer_64(p, offset, left, S, info);
3966 if (r == nullptr)
3967 return;
3968 memset(&i, '\0', sizeof(struct ivar64_t));
3969 if (left < sizeof(struct ivar64_t)) {
3970 memcpy(&i, r, left);
3971 outs() << " (ivar_t entends past the end of the section)\n";
3972 } else
3973 memcpy(&i, r, sizeof(struct ivar64_t));
3974 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3975 swapStruct(i);
3976
3977 outs() << "\t\t\t offset ";
3978 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset)__builtin_offsetof(struct ivar64_t, offset), S,
3979 info, n_value, i.offset);
3980 if (n_value != 0) {
3981 if (info->verbose && sym_name != nullptr)
3982 outs() << sym_name;
3983 else
3984 outs() << format("0x%" PRIx64"l" "x", n_value);
3985 if (i.offset != 0)
3986 outs() << " + " << format("0x%" PRIx64"l" "x", i.offset);
3987 } else
3988 outs() << format("0x%" PRIx64"l" "x", i.offset);
3989 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
3990 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
3991 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
3992 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3993 sys::swapByteOrder(ivar_offset);
3994 outs() << " " << ivar_offset << "\n";
3995 } else
3996 outs() << "\n";
3997
3998 outs() << "\t\t\t name ";
3999 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name)__builtin_offsetof(struct ivar64_t, name), S, info,
4000 n_value, i.name);
4001 if (n_value != 0) {
4002 if (info->verbose && sym_name != nullptr)
4003 outs() << sym_name;
4004 else
4005 outs() << format("0x%" PRIx64"l" "x", n_value);
4006 if (i.name != 0)
4007 outs() << " + " << format("0x%" PRIx64"l" "x", i.name);
4008 } else
4009 outs() << format("0x%" PRIx64"l" "x", i.name);
4010 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
4011 if (name != nullptr)
4012 outs() << format(" %.*s", left, name);
4013 outs() << "\n";
4014
4015 outs() << "\t\t\t type ";
4016 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type)__builtin_offsetof(struct ivar64_t, type), S, info,
4017 n_value, i.name);
4018 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
4019 if (n_value != 0) {
4020 if (info->verbose && sym_name != nullptr)
4021 outs() << sym_name;
4022 else
4023 outs() << format("0x%" PRIx64"l" "x", n_value);
4024 if (i.type != 0)
4025 outs() << " + " << format("0x%" PRIx64"l" "x", i.type);
4026 } else
4027 outs() << format("0x%" PRIx64"l" "x", i.type);
4028 if (name != nullptr)
4029 outs() << format(" %.*s", left, name);
4030 outs() << "\n";
4031
4032 outs() << "\t\t\talignment " << i.alignment << "\n";
4033 outs() << "\t\t\t size " << i.size << "\n";
4034
4035 p += sizeof(struct ivar64_t);
4036 offset += sizeof(struct ivar64_t);
4037 }
4038}
4039
4040static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
4041 struct ivar_list32_t il;
4042 struct ivar32_t i;
4043 const char *r;
4044 uint32_t offset, xoffset, left, j;
4045 SectionRef S, xS;
4046 const char *name, *ivar_offset_p;
4047 uint32_t ivar_offset;
4048
4049 r = get_pointer_32(p, offset, left, S, info);
4050 if (r == nullptr)
4051 return;
4052 memset(&il, '\0', sizeof(struct ivar_list32_t));
4053 if (left < sizeof(struct ivar_list32_t)) {
4054 memcpy(&il, r, left);
4055 outs() << " (ivar_list_t entends past the end of the section)\n";
4056 } else
4057 memcpy(&il, r, sizeof(struct ivar_list32_t));
4058 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4059 swapStruct(il);
4060 outs() << " entsize " << il.entsize << "\n";
4061 outs() << " count " << il.count << "\n";
4062
4063 p += sizeof(struct ivar_list32_t);
4064 offset += sizeof(struct ivar_list32_t);
4065 for (j = 0; j < il.count; j++) {
4066 r = get_pointer_32(p, offset, left, S, info);
4067 if (r == nullptr)
4068 return;
4069 memset(&i, '\0', sizeof(struct ivar32_t));
4070 if (left < sizeof(struct ivar32_t)) {
4071 memcpy(&i, r, left);
4072 outs() << " (ivar_t entends past the end of the section)\n";
4073 } else
4074 memcpy(&i, r, sizeof(struct ivar32_t));
4075 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4076 swapStruct(i);
4077
4078 outs() << "\t\t\t offset " << format("0x%" PRIx32"x", i.offset);
4079 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
4080 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4081 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4082 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4083 sys::swapByteOrder(ivar_offset);
4084 outs() << " " << ivar_offset << "\n";
4085 } else
4086 outs() << "\n";
4087
4088 outs() << "\t\t\t name " << format("0x%" PRIx32"x", i.name);
4089 name = get_pointer_32(i.name, xoffset, left, xS, info);
4090 if (name != nullptr)
4091 outs() << format(" %.*s", left, name);
4092 outs() << "\n";
4093
4094 outs() << "\t\t\t type " << format("0x%" PRIx32"x", i.type);
4095 name = get_pointer_32(i.type, xoffset, left, xS, info);
4096 if (name != nullptr)
4097 outs() << format(" %.*s", left, name);
4098 outs() << "\n";
4099
4100 outs() << "\t\t\talignment " << i.alignment << "\n";
4101 outs() << "\t\t\t size " << i.size << "\n";
4102
4103 p += sizeof(struct ivar32_t);
4104 offset += sizeof(struct ivar32_t);
4105 }
4106}
4107
4108static void print_objc_property_list64(uint64_t p,
4109 struct DisassembleInfo *info) {
4110 struct objc_property_list64 opl;
4111 struct objc_property64 op;
4112 const char *r;
4113 uint32_t offset, xoffset, left, j;
4114 SectionRef S, xS;
4115 const char *name, *sym_name;
4116 uint64_t n_value;
4117
4118 r = get_pointer_64(p, offset, left, S, info);
4119 if (r == nullptr)
4120 return;
4121 memset(&opl, '\0', sizeof(struct objc_property_list64));
4122 if (left < sizeof(struct objc_property_list64)) {
4123 memcpy(&opl, r, left);
4124 outs() << " (objc_property_list entends past the end of the section)\n";
4125 } else
4126 memcpy(&opl, r, sizeof(struct objc_property_list64));
4127 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4128 swapStruct(opl);
4129 outs() << " entsize " << opl.entsize << "\n";
4130 outs() << " count " << opl.count << "\n";
4131
4132 p += sizeof(struct objc_property_list64);
4133 offset += sizeof(struct objc_property_list64);
4134 for (j = 0; j < opl.count; j++) {
4135 r = get_pointer_64(p, offset, left, S, info);
4136 if (r == nullptr)
4137 return;
4138 memset(&op, '\0', sizeof(struct objc_property64));
4139 if (left < sizeof(struct objc_property64)) {
4140 memcpy(&op, r, left);
4141 outs() << " (objc_property entends past the end of the section)\n";
4142 } else
4143 memcpy(&op, r, sizeof(struct objc_property64));
4144 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4145 swapStruct(op);
4146
4147 outs() << "\t\t\t name ";
4148 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name)__builtin_offsetof(struct objc_property64, name), S,
4149 info, n_value, op.name);
4150 if (n_value != 0) {
4151 if (info->verbose && sym_name != nullptr)
4152 outs() << sym_name;
4153 else
4154 outs() << format("0x%" PRIx64"l" "x", n_value);
4155 if (op.name != 0)
4156 outs() << " + " << format("0x%" PRIx64"l" "x", op.name);
4157 } else
4158 outs() << format("0x%" PRIx64"l" "x", op.name);
4159 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
4160 if (name != nullptr)
4161 outs() << format(" %.*s", left, name);
4162 outs() << "\n";
4163
4164 outs() << "\t\t\tattributes ";
4165 sym_name =
4166 get_symbol_64(offset + offsetof(struct objc_property64, attributes)__builtin_offsetof(struct objc_property64, attributes), S,
4167 info, n_value, op.attributes);
4168 if (n_value != 0) {
4169 if (info->verbose && sym_name != nullptr)
4170 outs() << sym_name;
4171 else
4172 outs() << format("0x%" PRIx64"l" "x", n_value);
4173 if (op.attributes != 0)
4174 outs() << " + " << format("0x%" PRIx64"l" "x", op.attributes);
4175 } else
4176 outs() << format("0x%" PRIx64"l" "x", op.attributes);
4177 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
4178 if (name != nullptr)
4179 outs() << format(" %.*s", left, name);
4180 outs() << "\n";
4181
4182 p += sizeof(struct objc_property64);
4183 offset += sizeof(struct objc_property64);
4184 }
4185}
4186
4187static void print_objc_property_list32(uint32_t p,
4188 struct DisassembleInfo *info) {
4189 struct objc_property_list32 opl;
4190 struct objc_property32 op;
4191 const char *r;
4192 uint32_t offset, xoffset, left, j;
4193 SectionRef S, xS;
4194 const char *name;
4195
4196 r = get_pointer_32(p, offset, left, S, info);
4197 if (r == nullptr)
4198 return;
4199 memset(&opl, '\0', sizeof(struct objc_property_list32));
4200 if (left < sizeof(struct objc_property_list32)) {
4201 memcpy(&opl, r, left);
4202 outs() << " (objc_property_list entends past the end of the section)\n";
4203 } else
4204 memcpy(&opl, r, sizeof(struct objc_property_list32));
4205 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4206 swapStruct(opl);
4207 outs() << " entsize " << opl.entsize << "\n";
4208 outs() << " count " << opl.count << "\n";
4209
4210 p += sizeof(struct objc_property_list32);
4211 offset += sizeof(struct objc_property_list32);
4212 for (j = 0; j < opl.count; j++) {
4213 r = get_pointer_32(p, offset, left, S, info);
4214 if (r == nullptr)
4215 return;
4216 memset(&op, '\0', sizeof(struct objc_property32));
4217 if (left < sizeof(struct objc_property32)) {
4218 memcpy(&op, r, left);
4219 outs() << " (objc_property entends past the end of the section)\n";
4220 } else
4221 memcpy(&op, r, sizeof(struct objc_property32));
4222 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4223 swapStruct(op);
4224
4225 outs() << "\t\t\t name " << format("0x%" PRIx32"x", op.name);
4226 name = get_pointer_32(op.name, xoffset, left, xS, info);
4227 if (name != nullptr)
4228 outs() << format(" %.*s", left, name);
4229 outs() << "\n";
4230
4231 outs() << "\t\t\tattributes " << format("0x%" PRIx32"x", op.attributes);
4232 name = get_pointer_32(op.attributes, xoffset, left, xS, info);
4233 if (name != nullptr)
4234 outs() << format(" %.*s", left, name);
4235 outs() << "\n";
4236
4237 p += sizeof(struct objc_property32);
4238 offset += sizeof(struct objc_property32);
4239 }
4240}
4241
4242static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
4243 bool &is_meta_class) {
4244 struct class_ro64_t cro;
4245 const char *r;
4246 uint32_t offset, xoffset, left;
4247 SectionRef S, xS;
4248 const char *name, *sym_name;
4249 uint64_t n_value;
4250
4251 r = get_pointer_64(p, offset, left, S, info);
4252 if (r == nullptr || left < sizeof(struct class_ro64_t))
4253 return false;
4254 memset(&cro, '\0', sizeof(struct class_ro64_t));
4255 if (left < sizeof(struct class_ro64_t)) {
4256 memcpy(&cro, r, left);
4257 outs() << " (class_ro_t entends past the end of the section)\n";
4258 } else
4259 memcpy(&cro, r, sizeof(struct class_ro64_t));
4260 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4261 swapStruct(cro);
4262 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4263 if (cro.flags & RO_META(1 << 0))
4264 outs() << " RO_META";
4265 if (cro.flags & RO_ROOT(1 << 1))
4266 outs() << " RO_ROOT";
4267 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4268 outs() << " RO_HAS_CXX_STRUCTORS";
4269 outs() << "\n";
4270 outs() << " instanceStart " << cro.instanceStart << "\n";
4271 outs() << " instanceSize " << cro.instanceSize << "\n";
4272 outs() << " reserved " << format("0x%" PRIx32"x", cro.reserved)
4273 << "\n";
4274 outs() << " ivarLayout " << format("0x%" PRIx64"l" "x", cro.ivarLayout)
4275 << "\n";
4276 print_layout_map64(cro.ivarLayout, info);
4277
4278 outs() << " name ";
4279 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name)__builtin_offsetof(struct class_ro64_t, name), S,
4280 info, n_value, cro.name);
4281 if (n_value != 0) {
4282 if (info->verbose && sym_name != nullptr)
4283 outs() << sym_name;
4284 else
4285 outs() << format("0x%" PRIx64"l" "x", n_value);
4286 if (cro.name != 0)
4287 outs() << " + " << format("0x%" PRIx64"l" "x", cro.name);
4288 } else
4289 outs() << format("0x%" PRIx64"l" "x", cro.name);
4290 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
4291 if (name != nullptr)
4292 outs() << format(" %.*s", left, name);
4293 outs() << "\n";
4294
4295 outs() << " baseMethods ";
4296 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods)__builtin_offsetof(struct class_ro64_t, baseMethods),
4297 S, info, n_value, cro.baseMethods);
4298 if (n_value != 0) {
4299 if (info->verbose && sym_name != nullptr)
4300 outs() << sym_name;
4301 else
4302 outs() << format("0x%" PRIx64"l" "x", n_value);
4303 if (cro.baseMethods != 0)
4304 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseMethods);
4305 } else
4306 outs() << format("0x%" PRIx64"l" "x", cro.baseMethods);
4307 outs() << " (struct method_list_t *)\n";
4308 if (cro.baseMethods + n_value != 0)
4309 print_method_list64_t(cro.baseMethods + n_value, info, "");
4310
4311 outs() << " baseProtocols ";
4312 sym_name =
4313 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols)__builtin_offsetof(struct class_ro64_t, baseProtocols), S,
4314 info, n_value, cro.baseProtocols);
4315 if (n_value != 0) {
4316 if (info->verbose && sym_name != nullptr)
4317 outs() << sym_name;
4318 else
4319 outs() << format("0x%" PRIx64"l" "x", n_value);
4320 if (cro.baseProtocols != 0)
4321 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4322 } else
4323 outs() << format("0x%" PRIx64"l" "x", cro.baseProtocols);
4324 outs() << "\n";
4325 if (cro.baseProtocols + n_value != 0)
4326 print_protocol_list64_t(cro.baseProtocols + n_value, info);
4327
4328 outs() << " ivars ";
4329 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars)__builtin_offsetof(struct class_ro64_t, ivars), S,
4330 info, n_value, cro.ivars);
4331 if (n_value != 0) {
4332 if (info->verbose && sym_name != nullptr)
4333 outs() << sym_name;
4334 else
4335 outs() << format("0x%" PRIx64"l" "x", n_value);
4336 if (cro.ivars != 0)
4337 outs() << " + " << format("0x%" PRIx64"l" "x", cro.ivars);
4338 } else
4339 outs() << format("0x%" PRIx64"l" "x", cro.ivars);
4340 outs() << "\n";
4341 if (cro.ivars + n_value != 0)
4342 print_ivar_list64_t(cro.ivars + n_value, info);
4343
4344 outs() << " weakIvarLayout ";
4345 sym_name =
4346 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout)__builtin_offsetof(struct class_ro64_t, weakIvarLayout), S,
4347 info, n_value, cro.weakIvarLayout);
4348 if (n_value != 0) {
4349 if (info->verbose && sym_name != nullptr)
4350 outs() << sym_name;
4351 else
4352 outs() << format("0x%" PRIx64"l" "x", n_value);
4353 if (cro.weakIvarLayout != 0)
4354 outs() << " + " << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4355 } else
4356 outs() << format("0x%" PRIx64"l" "x", cro.weakIvarLayout);
4357 outs() << "\n";
4358 print_layout_map64(cro.weakIvarLayout + n_value, info);
4359
4360 outs() << " baseProperties ";
4361 sym_name =
4362 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties)__builtin_offsetof(struct class_ro64_t, baseProperties), S,
4363 info, n_value, cro.baseProperties);
4364 if (n_value != 0) {
4365 if (info->verbose && sym_name != nullptr)
4366 outs() << sym_name;
4367 else
4368 outs() << format("0x%" PRIx64"l" "x", n_value);
4369 if (cro.baseProperties != 0)
4370 outs() << " + " << format("0x%" PRIx64"l" "x", cro.baseProperties);
4371 } else
4372 outs() << format("0x%" PRIx64"l" "x", cro.baseProperties);
4373 outs() << "\n";
4374 if (cro.baseProperties + n_value != 0)
4375 print_objc_property_list64(cro.baseProperties + n_value, info);
4376
4377 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4378 return true;
4379}
4380
4381static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
4382 bool &is_meta_class) {
4383 struct class_ro32_t cro;
4384 const char *r;
4385 uint32_t offset, xoffset, left;
4386 SectionRef S, xS;
4387 const char *name;
4388
4389 r = get_pointer_32(p, offset, left, S, info);
4390 if (r == nullptr)
4391 return false;
4392 memset(&cro, '\0', sizeof(struct class_ro32_t));
4393 if (left < sizeof(struct class_ro32_t)) {
4394 memcpy(&cro, r, left);
4395 outs() << " (class_ro_t entends past the end of the section)\n";
4396 } else
4397 memcpy(&cro, r, sizeof(struct class_ro32_t));
4398 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4399 swapStruct(cro);
4400 outs() << " flags " << format("0x%" PRIx32"x", cro.flags);
4401 if (cro.flags & RO_META(1 << 0))
4402 outs() << " RO_META";
4403 if (cro.flags & RO_ROOT(1 << 1))
4404 outs() << " RO_ROOT";
4405 if (cro.flags & RO_HAS_CXX_STRUCTORS(1 << 2))
4406 outs() << " RO_HAS_CXX_STRUCTORS";
4407 outs() << "\n";
4408 outs() << " instanceStart " << cro.instanceStart << "\n";
4409 outs() << " instanceSize " << cro.instanceSize << "\n";
4410 outs() << " ivarLayout " << format("0x%" PRIx32"x", cro.ivarLayout)
4411 << "\n";
4412 print_layout_map32(cro.ivarLayout, info);
4413
4414 outs() << " name " << format("0x%" PRIx32"x", cro.name);
4415 name = get_pointer_32(cro.name, xoffset, left, xS, info);
4416 if (name != nullptr)
4417 outs() << format(" %.*s", left, name);
4418 outs() << "\n";
4419
4420 outs() << " baseMethods "
4421 << format("0x%" PRIx32"x", cro.baseMethods)
4422 << " (struct method_list_t *)\n";
4423 if (cro.baseMethods != 0)
4424 print_method_list32_t(cro.baseMethods, info, "");
4425
4426 outs() << " baseProtocols "
4427 << format("0x%" PRIx32"x", cro.baseProtocols) << "\n";
4428 if (cro.baseProtocols != 0)
4429 print_protocol_list32_t(cro.baseProtocols, info);
4430 outs() << " ivars " << format("0x%" PRIx32"x", cro.ivars)
4431 << "\n";
4432 if (cro.ivars != 0)
4433 print_ivar_list32_t(cro.ivars, info);
4434 outs() << " weakIvarLayout "
4435 << format("0x%" PRIx32"x", cro.weakIvarLayout) << "\n";
4436 print_layout_map32(cro.weakIvarLayout, info);
4437 outs() << " baseProperties "
4438 << format("0x%" PRIx32"x", cro.baseProperties) << "\n";
4439 if (cro.baseProperties != 0)
4440 print_objc_property_list32(cro.baseProperties, info);
4441 is_meta_class = (cro.flags & RO_META(1 << 0)) != 0;
4442 return true;
4443}
4444
4445static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
4446 struct class64_t c;
4447 const char *r;
4448 uint32_t offset, left;
4449 SectionRef S;
4450 const char *name;
4451 uint64_t isa_n_value, n_value;
4452
4453 r = get_pointer_64(p, offset, left, S, info);
4454 if (r == nullptr || left < sizeof(struct class64_t))
4455 return;
4456 memset(&c, '\0', sizeof(struct class64_t));
4457 if (left < sizeof(struct class64_t)) {
4458 memcpy(&c, r, left);
4459 outs() << " (class_t entends past the end of the section)\n";
4460 } else
4461 memcpy(&c, r, sizeof(struct class64_t));
4462 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4463 swapStruct(c);
4464
4465 outs() << " isa " << format("0x%" PRIx64"l" "x", c.isa);
4466 name = get_symbol_64(offset + offsetof(struct class64_t, isa)__builtin_offsetof(struct class64_t, isa), S, info,
4467 isa_n_value, c.isa);
4468 if (name != nullptr)
4469 outs() << " " << name;
4470 outs() << "\n";
4471
4472 outs() << " superclass " << format("0x%" PRIx64"l" "x", c.superclass);
4473 name = get_symbol_64(offset + offsetof(struct class64_t, superclass)__builtin_offsetof(struct class64_t, superclass), S, info,
4474 n_value, c.superclass);
4475 if (name != nullptr)
4476 outs() << " " << name;
4477 outs() << "\n";
4478
4479 outs() << " cache " << format("0x%" PRIx64"l" "x", c.cache);
4480 name = get_symbol_64(offset + offsetof(struct class64_t, cache)__builtin_offsetof(struct class64_t, cache), S, info,
4481 n_value, c.cache);
4482 if (name != nullptr)
4483 outs() << " " << name;
4484 outs() << "\n";
4485
4486 outs() << " vtable " << format("0x%" PRIx64"l" "x", c.vtable);
4487 name = get_symbol_64(offset + offsetof(struct class64_t, vtable)__builtin_offsetof(struct class64_t, vtable), S, info,
4488 n_value, c.vtable);
4489 if (name != nullptr)
4490 outs() << " " << name;
4491 outs() << "\n";
4492
4493 name = get_symbol_64(offset + offsetof(struct class64_t, data)__builtin_offsetof(struct class64_t, data), S, info,
4494 n_value, c.data);
4495 outs() << " data ";
4496 if (n_value != 0) {
4497 if (info->verbose && name != nullptr)
4498 outs() << name;
4499 else
4500 outs() << format("0x%" PRIx64"l" "x", n_value);
4501 if (c.data != 0)
4502 outs() << " + " << format("0x%" PRIx64"l" "x", c.data);
4503 } else
4504 outs() << format("0x%" PRIx64"l" "x", c.data);
4505 outs() << " (struct class_ro_t *)";
4506
4507 // This is a Swift class if some of the low bits of the pointer are set.
4508 if ((c.data + n_value) & 0x7)
4509 outs() << " Swift class";
4510 outs() << "\n";
4511 bool is_meta_class;
4512 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
4513 return;
4514
4515 if (!is_meta_class &&
4516 c.isa + isa_n_value != p &&
4517 c.isa + isa_n_value != 0 &&
4518 info->depth < 100) {
4519 info->depth++;
4520 outs() << "Meta Class\n";
4521 print_class64_t(c.isa + isa_n_value, info);
4522 }
4523}
4524
4525static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
4526 struct class32_t c;
4527 const char *r;
4528 uint32_t offset, left;
4529 SectionRef S;
4530 const char *name;
4531
4532 r = get_pointer_32(p, offset, left, S, info);
4533 if (r == nullptr)
4534 return;
4535 memset(&c, '\0', sizeof(struct class32_t));
4536 if (left < sizeof(struct class32_t)) {
4537 memcpy(&c, r, left);
4538 outs() << " (class_t entends past the end of the section)\n";
4539 } else
4540 memcpy(&c, r, sizeof(struct class32_t));
4541 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4542 swapStruct(c);
4543
4544 outs() << " isa " << format("0x%" PRIx32"x", c.isa);
4545 name =
4546 get_symbol_32(offset + offsetof(struct class32_t, isa)__builtin_offsetof(struct class32_t, isa), S, info, c.isa);
4547 if (name != nullptr)
4548 outs() << " " << name;
4549 outs() << "\n";
4550
4551 outs() << " superclass " << format("0x%" PRIx32"x", c.superclass);
4552 name = get_symbol_32(offset + offsetof(struct class32_t, superclass)__builtin_offsetof(struct class32_t, superclass), S, info,
4553 c.superclass);
4554 if (name != nullptr)
4555 outs() << " " << name;
4556 outs() << "\n";
4557
4558 outs() << " cache " << format("0x%" PRIx32"x", c.cache);
4559 name = get_symbol_32(offset + offsetof(struct class32_t, cache)__builtin_offsetof(struct class32_t, cache), S, info,
4560 c.cache);
4561 if (name != nullptr)
4562 outs() << " " << name;
4563 outs() << "\n";
4564
4565 outs() << " vtable " << format("0x%" PRIx32"x", c.vtable);
4566 name = get_symbol_32(offset + offsetof(struct class32_t, vtable)__builtin_offsetof(struct class32_t, vtable), S, info,
4567 c.vtable);
4568 if (name != nullptr)
4569 outs() << " " << name;
4570 outs() << "\n";
4571
4572 name =
4573 get_symbol_32(offset + offsetof(struct class32_t, data)__builtin_offsetof(struct class32_t, data), S, info, c.data);
4574 outs() << " data " << format("0x%" PRIx32"x", c.data)
4575 << " (struct class_ro_t *)";
4576
4577 // This is a Swift class if some of the low bits of the pointer are set.
4578 if (c.data & 0x3)
4579 outs() << " Swift class";
4580 outs() << "\n";
4581 bool is_meta_class;
4582 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
4583 return;
4584
4585 if (!is_meta_class) {
4586 outs() << "Meta Class\n";
4587 print_class32_t(c.isa, info);
4588 }
4589}
4590
4591static void print_objc_class_t(struct objc_class_t *objc_class,
4592 struct DisassembleInfo *info) {
4593 uint32_t offset, left, xleft;
4594 const char *name, *p, *ivar_list;
4595 SectionRef S;
4596 int32_t i;
4597 struct objc_ivar_list_t objc_ivar_list;
4598 struct objc_ivar_t ivar;
4599
4600 outs() << "\t\t isa " << format("0x%08" PRIx32"x", objc_class->isa);
4601 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2))) {
4602 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
4603 if (name != nullptr)
4604 outs() << format(" %.*s", left, name);
4605 else
4606 outs() << " (not in an __OBJC section)";
4607 }
4608 outs() << "\n";
4609
4610 outs() << "\t super_class "
4611 << format("0x%08" PRIx32"x", objc_class->super_class);
4612 if (info->verbose) {
4613 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
4614 if (name != nullptr)
4615 outs() << format(" %.*s", left, name);
4616 else
4617 outs() << " (not in an __OBJC section)";
4618 }
4619 outs() << "\n";
4620
4621 outs() << "\t\t name " << format("0x%08" PRIx32"x", objc_class->name);
4622 if (info->verbose) {
4623 name = get_pointer_32(objc_class->name, offset, left, S, info, true);
4624 if (name != nullptr)
4625 outs() << format(" %.*s", left, name);
4626 else
4627 outs() << " (not in an __OBJC section)";
4628 }
4629 outs() << "\n";
4630
4631 outs() << "\t\t version " << format("0x%08" PRIx32"x", objc_class->version)
4632 << "\n";
4633
4634 outs() << "\t\t info " << format("0x%08" PRIx32"x", objc_class->info);
4635 if (info->verbose) {
4636 if (CLS_GETINFO(objc_class, CLS_CLASS)((objc_class)->info & (0x1)))
4637 outs() << " CLS_CLASS";
4638 else if (CLS_GETINFO(objc_class, CLS_META)((objc_class)->info & (0x2)))
4639 outs() << " CLS_META";
4640 }
4641 outs() << "\n";
4642
4643 outs() << "\t instance_size "
4644 << format("0x%08" PRIx32"x", objc_class->instance_size) << "\n";
4645
4646 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
4647 outs() << "\t\t ivars " << format("0x%08" PRIx32"x", objc_class->ivars);
4648 if (p != nullptr) {
4649 if (left > sizeof(struct objc_ivar_list_t)) {
4650 outs() << "\n";
4651 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
4652 } else {
4653 outs() << " (entends past the end of the section)\n";
4654 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
4655 memcpy(&objc_ivar_list, p, left);
4656 }
4657 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4658 swapStruct(objc_ivar_list);
4659 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
4660 ivar_list = p + sizeof(struct objc_ivar_list_t);
4661 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
4662 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
4663 outs() << "\t\t remaining ivar's extend past the of the section\n";
4664 break;
4665 }
4666 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
4667 sizeof(struct objc_ivar_t));
4668 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4669 swapStruct(ivar);
4670
4671 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32"x", ivar.ivar_name);
4672 if (info->verbose) {
4673 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
4674 if (name != nullptr)
4675 outs() << format(" %.*s", xleft, name);
4676 else
4677 outs() << " (not in an __OBJC section)";
4678 }
4679 outs() << "\n";
4680
4681 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32"x", ivar.ivar_type);
4682 if (info->verbose) {
4683 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
4684 if (name != nullptr)
4685 outs() << format(" %.*s", xleft, name);
4686 else
4687 outs() << " (not in an __OBJC section)";
4688 }
4689 outs() << "\n";
4690
4691 outs() << "\t\t ivar_offset "
4692 << format("0x%08" PRIx32"x", ivar.ivar_offset) << "\n";
4693 }
4694 } else {
4695 outs() << " (not in an __OBJC section)\n";
4696 }
4697
4698 outs() << "\t\t methods " << format("0x%08" PRIx32"x", objc_class->methodLists);
4699 if (print_method_list(objc_class->methodLists, info))
4700 outs() << " (not in an __OBJC section)\n";
4701
4702 outs() << "\t\t cache " << format("0x%08" PRIx32"x", objc_class->cache)
4703 << "\n";
4704
4705 outs() << "\t\tprotocols " << format("0x%08" PRIx32"x", objc_class->protocols);
4706 if (print_protocol_list(objc_class->protocols, 16, info))
4707 outs() << " (not in an __OBJC section)\n";
4708}
4709
4710static void print_objc_objc_category_t(struct objc_category_t *objc_category,
4711 struct DisassembleInfo *info) {
4712 uint32_t offset, left;
4713 const char *name;
4714 SectionRef S;
4715
4716 outs() << "\t category name "
4717 << format("0x%08" PRIx32"x", objc_category->category_name);
4718 if (info->verbose) {
4719 name = get_pointer_32(objc_category->category_name, offset, left, S, info,
4720 true);
4721 if (name != nullptr)
4722 outs() << format(" %.*s", left, name);
4723 else
4724 outs() << " (not in an __OBJC section)";
4725 }
4726 outs() << "\n";
4727
4728 outs() << "\t\t class name "
4729 << format("0x%08" PRIx32"x", objc_category->class_name);
4730 if (info->verbose) {
4731 name =
4732 get_pointer_32(objc_category->class_name, offset, left, S, info, true);
4733 if (name != nullptr)
4734 outs() << format(" %.*s", left, name);
4735 else
4736 outs() << " (not in an __OBJC section)";
4737 }
4738 outs() << "\n";
4739
4740 outs() << "\t instance methods "
4741 << format("0x%08" PRIx32"x", objc_category->instance_methods);
4742 if (print_method_list(objc_category->instance_methods, info))
4743 outs() << " (not in an __OBJC section)\n";
4744
4745 outs() << "\t class methods "
4746 << format("0x%08" PRIx32"x", objc_category->class_methods);
4747 if (print_method_list(objc_category->class_methods, info))
4748 outs() << " (not in an __OBJC section)\n";
4749}
4750
4751static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
4752 struct category64_t c;
4753 const char *r;
4754 uint32_t offset, xoffset, left;
4755 SectionRef S, xS;
4756 const char *name, *sym_name;
4757 uint64_t n_value;
4758
4759 r = get_pointer_64(p, offset, left, S, info);
4760 if (r == nullptr)
4761 return;
4762 memset(&c, '\0', sizeof(struct category64_t));
4763 if (left < sizeof(struct category64_t)) {
4764 memcpy(&c, r, left);
4765 outs() << " (category_t entends past the end of the section)\n";
4766 } else
4767 memcpy(&c, r, sizeof(struct category64_t));
4768 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4769 swapStruct(c);
4770
4771 outs() << " name ";
4772 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name)__builtin_offsetof(struct category64_t, name), S,
4773 info, n_value, c.name);
4774 if (n_value != 0) {
4775 if (info->verbose && sym_name != nullptr)
4776 outs() << sym_name;
4777 else
4778 outs() << format("0x%" PRIx64"l" "x", n_value);
4779 if (c.name != 0)
4780 outs() << " + " << format("0x%" PRIx64"l" "x", c.name);
4781 } else
4782 outs() << format("0x%" PRIx64"l" "x", c.name);
4783 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
4784 if (name != nullptr)
4785 outs() << format(" %.*s", left, name);
4786 outs() << "\n";
4787
4788 outs() << " cls ";
4789 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls)__builtin_offsetof(struct category64_t, cls), S, info,
4790 n_value, c.cls);
4791 if (n_value != 0) {
4792 if (info->verbose && sym_name != nullptr)
4793 outs() << sym_name;
4794 else
4795 outs() << format("0x%" PRIx64"l" "x", n_value);
4796 if (c.cls != 0)
4797 outs() << " + " << format("0x%" PRIx64"l" "x", c.cls);
4798 } else
4799 outs() << format("0x%" PRIx64"l" "x", c.cls);
4800 outs() << "\n";
4801 if (c.cls + n_value != 0)
4802 print_class64_t(c.cls + n_value, info);
4803
4804 outs() << " instanceMethods ";
4805 sym_name =
4806 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods)__builtin_offsetof(struct category64_t, instanceMethods), S,
4807 info, n_value, c.instanceMethods);
4808 if (n_value != 0) {
4809 if (info->verbose && sym_name != nullptr)
4810 outs() << sym_name;
4811 else
4812 outs() << format("0x%" PRIx64"l" "x", n_value);
4813 if (c.instanceMethods != 0)
4814 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceMethods);
4815 } else
4816 outs() << format("0x%" PRIx64"l" "x", c.instanceMethods);
4817 outs() << "\n";
4818 if (c.instanceMethods + n_value != 0)
4819 print_method_list64_t(c.instanceMethods + n_value, info, "");
4820
4821 outs() << " classMethods ";
4822 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods)__builtin_offsetof(struct category64_t, classMethods),
4823 S, info, n_value, c.classMethods);
4824 if (n_value != 0) {
4825 if (info->verbose && sym_name != nullptr)
4826 outs() << sym_name;
4827 else
4828 outs() << format("0x%" PRIx64"l" "x", n_value);
4829 if (c.classMethods != 0)
4830 outs() << " + " << format("0x%" PRIx64"l" "x", c.classMethods);
4831 } else
4832 outs() << format("0x%" PRIx64"l" "x", c.classMethods);
4833 outs() << "\n";
4834 if (c.classMethods + n_value != 0)
4835 print_method_list64_t(c.classMethods + n_value, info, "");
4836
4837 outs() << " protocols ";
4838 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols)__builtin_offsetof(struct category64_t, protocols), S,
4839 info, n_value, c.protocols);
4840 if (n_value != 0) {
4841 if (info->verbose && sym_name != nullptr)
4842 outs() << sym_name;
4843 else
4844 outs() << format("0x%" PRIx64"l" "x", n_value);
4845 if (c.protocols != 0)
4846 outs() << " + " << format("0x%" PRIx64"l" "x", c.protocols);
4847 } else
4848 outs() << format("0x%" PRIx64"l" "x", c.protocols);
4849 outs() << "\n";
4850 if (c.protocols + n_value != 0)
4851 print_protocol_list64_t(c.protocols + n_value, info);
4852
4853 outs() << "instanceProperties ";
4854 sym_name =
4855 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties)__builtin_offsetof(struct category64_t, instanceProperties),
4856 S, info, n_value, c.instanceProperties);
4857 if (n_value != 0) {
4858 if (info->verbose && sym_name != nullptr)
4859 outs() << sym_name;
4860 else
4861 outs() << format("0x%" PRIx64"l" "x", n_value);
4862 if (c.instanceProperties != 0)
4863 outs() << " + " << format("0x%" PRIx64"l" "x", c.instanceProperties);
4864 } else
4865 outs() << format("0x%" PRIx64"l" "x", c.instanceProperties);
4866 outs() << "\n";
4867 if (c.instanceProperties + n_value != 0)
4868 print_objc_property_list64(c.instanceProperties + n_value, info);
4869}
4870
4871static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
4872 struct category32_t c;
4873 const char *r;
4874 uint32_t offset, left;
4875 SectionRef S, xS;
4876 const char *name;
4877
4878 r = get_pointer_32(p, offset, left, S, info);
4879 if (r == nullptr)
4880 return;
4881 memset(&c, '\0', sizeof(struct category32_t));
4882 if (left < sizeof(struct category32_t)) {
4883 memcpy(&c, r, left);
4884 outs() << " (category_t entends past the end of the section)\n";
4885 } else
4886 memcpy(&c, r, sizeof(struct category32_t));
4887 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4888 swapStruct(c);
4889
4890 outs() << " name " << format("0x%" PRIx32"x", c.name);
4891 name = get_symbol_32(offset + offsetof(struct category32_t, name)__builtin_offsetof(struct category32_t, name), S, info,
4892 c.name);
4893 if (name)
4894 outs() << " " << name;
4895 outs() << "\n";
4896
4897 outs() << " cls " << format("0x%" PRIx32"x", c.cls) << "\n";
4898 if (c.cls != 0)
4899 print_class32_t(c.cls, info);
4900 outs() << " instanceMethods " << format("0x%" PRIx32"x", c.instanceMethods)
4901 << "\n";
4902 if (c.instanceMethods != 0)
4903 print_method_list32_t(c.instanceMethods, info, "");
4904 outs() << " classMethods " << format("0x%" PRIx32"x", c.classMethods)
4905 << "\n";
4906 if (c.classMethods != 0)
4907 print_method_list32_t(c.classMethods, info, "");
4908 outs() << " protocols " << format("0x%" PRIx32"x", c.protocols) << "\n";
4909 if (c.protocols != 0)
4910 print_protocol_list32_t(c.protocols, info);
4911 outs() << "instanceProperties " << format("0x%" PRIx32"x", c.instanceProperties)
4912 << "\n";
4913 if (c.instanceProperties != 0)
4914 print_objc_property_list32(c.instanceProperties, info);
4915}
4916
4917static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
4918 uint32_t i, left, offset, xoffset;
4919 uint64_t p, n_value;
4920 struct message_ref64 mr;
4921 const char *name, *sym_name;
4922 const char *r;
4923 SectionRef xS;
4924
4925 if (S == SectionRef())
4926 return;
4927
4928 StringRef SectName;
4929 S.getName(SectName);
4930 DataRefImpl Ref = S.getRawDataRefImpl();
4931 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
4932 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4933 offset = 0;
4934 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
4935 p = S.getAddress() + i;
4936 r = get_pointer_64(p, offset, left, S, info);
4937 if (r == nullptr)
4938 return;
4939 memset(&mr, '\0', sizeof(struct message_ref64));
4940 if (left < sizeof(struct message_ref64)) {
4941 memcpy(&mr, r, left);
4942 outs() << " (message_ref entends past the end of the section)\n";
4943 } else
4944 memcpy(&mr, r, sizeof(struct message_ref64));
4945 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4946 swapStruct(mr);
4947
4948 outs() << " imp ";
4949 name = get_symbol_64(offset + offsetof(struct message_ref64, imp)__builtin_offsetof(struct message_ref64, imp), S, info,
4950 n_value, mr.imp);
4951 if (n_value != 0) {
4952 outs() << format("0x%" PRIx64"l" "x", n_value) << " ";
4953 if (mr.imp != 0)
4954 outs() << "+ " << format("0x%" PRIx64"l" "x", mr.imp) << " ";
4955 } else
4956 outs() << format("0x%" PRIx64"l" "x", mr.imp) << " ";
4957 if (name != nullptr)
4958 outs() << " " << name;
4959 outs() << "\n";
4960
4961 outs() << " sel ";
4962 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel)__builtin_offsetof(struct message_ref64, sel), S,
4963 info, n_value, mr.sel);
4964 if (n_value != 0) {
4965 if (info->verbose && sym_name != nullptr)
4966 outs() << sym_name;
4967 else
4968 outs() << format("0x%" PRIx64"l" "x", n_value);
4969 if (mr.sel != 0)
4970 outs() << " + " << format("0x%" PRIx64"l" "x", mr.sel);
4971 } else
4972 outs() << format("0x%" PRIx64"l" "x", mr.sel);
4973 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
4974 if (name != nullptr)
4975 outs() << format(" %.*s", left, name);
4976 outs() << "\n";
4977
4978 offset += sizeof(struct message_ref64);
4979 }
4980}
4981
4982static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
4983 uint32_t i, left, offset, xoffset, p;
4984 struct message_ref32 mr;
4985 const char *name, *r;
4986 SectionRef xS;
4987
4988 if (S == SectionRef())
4989 return;
4990
4991 StringRef SectName;
4992 S.getName(SectName);
4993 DataRefImpl Ref = S.getRawDataRefImpl();
4994 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
4995 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4996 offset = 0;
4997 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
4998 p = S.getAddress() + i;
4999 r = get_pointer_32(p, offset, left, S, info);
5000 if (r == nullptr)
5001 return;
5002 memset(&mr, '\0', sizeof(struct message_ref32));
5003 if (left < sizeof(struct message_ref32)) {
5004 memcpy(&mr, r, left);
5005 outs() << " (message_ref entends past the end of the section)\n";
5006 } else
5007 memcpy(&mr, r, sizeof(struct message_ref32));
5008 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5009 swapStruct(mr);
5010
5011 outs() << " imp " << format("0x%" PRIx32"x", mr.imp);
5012 name = get_symbol_32(offset + offsetof(struct message_ref32, imp)__builtin_offsetof(struct message_ref32, imp), S, info,
5013 mr.imp);
5014 if (name != nullptr)
5015 outs() << " " << name;
5016 outs() << "\n";
5017
5018 outs() << " sel " << format("0x%" PRIx32"x", mr.sel);
5019 name = get_pointer_32(mr.sel, xoffset, left, xS, info);
5020 if (name != nullptr)
5021 outs() << " " << name;
5022 outs() << "\n";
5023
5024 offset += sizeof(struct message_ref32);
5025 }
5026}
5027
5028static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
5029 uint32_t left, offset, swift_version;
5030 uint64_t p;
5031 struct objc_image_info64 o;
5032 const char *r;
5033
5034 if (S == SectionRef())
5035 return;
5036
5037 StringRef SectName;
5038 S.getName(SectName);
5039 DataRefImpl Ref = S.getRawDataRefImpl();
5040 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5041 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5042 p = S.getAddress();
5043 r = get_pointer_64(p, offset, left, S, info);
5044 if (r == nullptr)
5045 return;
5046 memset(&o, '\0', sizeof(struct objc_image_info64));
5047 if (left < sizeof(struct objc_image_info64)) {
5048 memcpy(&o, r, left);
5049 outs() << " (objc_image_info entends past the end of the section)\n";
5050 } else
5051 memcpy(&o, r, sizeof(struct objc_image_info64));
5052 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5053 swapStruct(o);
5054 outs() << " version " << o.version << "\n";
5055 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5056 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5057 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5058 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5059 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5060 swift_version = (o.flags >> 8) & 0xff;
5061 if (swift_version != 0) {
5062 if (swift_version == 1)
5063 outs() << " Swift 1.0";
5064 else if (swift_version == 2)
5065 outs() << " Swift 1.1";
5066 else
5067 outs() << " unknown future Swift version (" << swift_version << ")";
5068 }
5069 outs() << "\n";
5070}
5071
5072static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
5073 uint32_t left, offset, swift_version, p;
5074 struct objc_image_info32 o;
5075 const char *r;
5076
5077 StringRef SectName;
5078 S.getName(SectName);
5079 DataRefImpl Ref = S.getRawDataRefImpl();
5080 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5081 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5082 p = S.getAddress();
5083 r = get_pointer_32(p, offset, left, S, info);
5084 if (r == nullptr)
5085 return;
5086 memset(&o, '\0', sizeof(struct objc_image_info32));
5087 if (left < sizeof(struct objc_image_info32)) {
5088 memcpy(&o, r, left);
5089 outs() << " (objc_image_info entends past the end of the section)\n";
5090 } else
5091 memcpy(&o, r, sizeof(struct objc_image_info32));
5092 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5093 swapStruct(o);
5094 outs() << " version " << o.version << "\n";
5095 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5096 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT(1 << 0))
5097 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5098 if (o.flags & OBJC_IMAGE_SUPPORTS_GC(1 << 1))
5099 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5100 swift_version = (o.flags >> 8) & 0xff;
5101 if (swift_version != 0) {
5102 if (swift_version == 1)
5103 outs() << " Swift 1.0";
5104 else if (swift_version == 2)
5105 outs() << " Swift 1.1";
5106 else
5107 outs() << " unknown future Swift version (" << swift_version << ")";
5108 }
5109 outs() << "\n";
5110}
5111
5112static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
5113 uint32_t left, offset, p;
5114 struct imageInfo_t o;
5115 const char *r;
5116
5117 StringRef SectName;
5118 S.getName(SectName);
5119 DataRefImpl Ref = S.getRawDataRefImpl();
5120 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5121 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5122 p = S.getAddress();
5123 r = get_pointer_32(p, offset, left, S, info);
5124 if (r == nullptr)
5125 return;
5126 memset(&o, '\0', sizeof(struct imageInfo_t));
5127 if (left < sizeof(struct imageInfo_t)) {
5128 memcpy(&o, r, left);
5129 outs() << " (imageInfo entends past the end of the section)\n";
5130 } else
5131 memcpy(&o, r, sizeof(struct imageInfo_t));
5132 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5133 swapStruct(o);
5134 outs() << " version " << o.version << "\n";
5135 outs() << " flags " << format("0x%" PRIx32"x", o.flags);
5136 if (o.flags & 0x1)
5137 outs() << " F&C";
5138 if (o.flags & 0x2)
5139 outs() << " GC";
5140 if (o.flags & 0x4)
5141 outs() << " GC-only";
5142 else
5143 outs() << " RR";
5144 outs() << "\n";
5145}
5146
5147static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
5148 SymbolAddressMap AddrMap;
5149 if (verbose)
5150 CreateSymbolAddressMap(O, &AddrMap);
5151
5152 std::vector<SectionRef> Sections;
5153 for (const SectionRef &Section : O->sections()) {
5154 StringRef SectName;
5155 Section.getName(SectName);
5156 Sections.push_back(Section);
5157 }
5158
5159 struct DisassembleInfo info;
5160 // Set up the block of info used by the Symbolizer call backs.
5161 info.verbose = verbose;
5162 info.O = O;
5163 info.AddrMap = &AddrMap;
5164 info.Sections = &Sections;
5165 info.class_name = nullptr;
5166 info.selector_name = nullptr;
5167 info.method = nullptr;
5168 info.demangled_name = nullptr;
5169 info.bindtable = nullptr;
5170 info.adrp_addr = 0;
5171 info.adrp_inst = 0;
5172
5173 info.depth = 0;
5174 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
5175 if (CL == SectionRef())
5176 CL = get_section(O, "__DATA", "__objc_classlist");
5177 info.S = CL;
5178 walk_pointer_list_64("class", CL, O, &info, print_class64_t);
5179
5180 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
5181 if (CR == SectionRef())
5182 CR = get_section(O, "__DATA", "__objc_classrefs");
5183 info.S = CR;
5184 walk_pointer_list_64("class refs", CR, O, &info, nullptr);
5185
5186 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
5187 if (SR == SectionRef())
5188 SR = get_section(O, "__DATA", "__objc_superrefs");
5189 info.S = SR;
5190 walk_pointer_list_64("super refs", SR, O, &info, nullptr);
5191
5192 SectionRef CA = get_section(O, "__OBJC2", "__category_list");
5193 if (CA == SectionRef())
5194 CA = get_section(O, "__DATA", "__objc_catlist");
5195 info.S = CA;
5196 walk_pointer_list_64("category", CA, O, &info, print_category64_t);
5197
5198 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
5199 if (PL == SectionRef())
5200 PL = get_section(O, "__DATA", "__objc_protolist");
5201 info.S = PL;
5202 walk_pointer_list_64("protocol", PL, O, &info, nullptr);
5203
5204 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
5205 if (MR == SectionRef())
5206 MR = get_section(O, "__DATA", "__objc_msgrefs");
5207 info.S = MR;
5208 print_message_refs64(MR, &info);
5209
5210 SectionRef II = get_section(O, "__OBJC2", "__image_info");
5211 if (II == SectionRef())
5212 II = get_section(O, "__DATA", "__objc_imageinfo");
5213 info.S = II;
5214 print_image_info64(II, &info);
5215
5216 if (info.bindtable != nullptr)
5217 delete info.bindtable;
5218}
5219
5220static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
5221 SymbolAddressMap AddrMap;
5222 if (verbose)
5223 CreateSymbolAddressMap(O, &AddrMap);
5224
5225 std::vector<SectionRef> Sections;
5226 for (const SectionRef &Section : O->sections()) {
5227 StringRef SectName;
5228 Section.getName(SectName);
5229 Sections.push_back(Section);
5230 }
5231
5232 struct DisassembleInfo info;
5233 // Set up the block of info used by the Symbolizer call backs.
5234 info.verbose = verbose;
5235 info.O = O;
5236 info.AddrMap = &AddrMap;
5237 info.Sections = &Sections;
5238 info.class_name = nullptr;
5239 info.selector_name = nullptr;
5240 info.method = nullptr;
5241 info.demangled_name = nullptr;
5242 info.bindtable = nullptr;
5243 info.adrp_addr = 0;
5244 info.adrp_inst = 0;
5245
5246 const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
5247 if (CL != SectionRef()) {
5248 info.S = CL;
5249 walk_pointer_list_32("class", CL, O, &info, print_class32_t);
5250 } else {
5251 const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
5252 info.S = CL;
5253 walk_pointer_list_32("class", CL, O, &info, print_class32_t);
5254 }
5255
5256 const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
5257 if (CR != SectionRef()) {
5258 info.S = CR;
5259 walk_pointer_list_32("class refs", CR, O, &info, nullptr);
5260 } else {
5261 const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
5262 info.S = CR;
5263 walk_pointer_list_32("class refs", CR, O, &info, nullptr);
5264 }
5265
5266 const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
5267 if (SR != SectionRef()) {
5268 info.S = SR;
5269 walk_pointer_list_32("super refs", SR, O, &info, nullptr);
5270 } else {
5271 const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
5272 info.S = SR;
5273 walk_pointer_list_32("super refs", SR, O, &info, nullptr);
5274 }
5275
5276 const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
5277 if (CA != SectionRef()) {
5278 info.S = CA;
5279 walk_pointer_list_32("category", CA, O, &info, print_category32_t);
5280 } else {
5281 const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
5282 info.S = CA;
5283 walk_pointer_list_32("category", CA, O, &info, print_category32_t);
5284 }
5285
5286 const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
5287 if (PL != SectionRef()) {
5288 info.S = PL;
5289 walk_pointer_list_32("protocol", PL, O, &info, nullptr);
5290 } else {
5291 const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
5292 info.S = PL;
5293 walk_pointer_list_32("protocol", PL, O, &info, nullptr);
5294 }
5295
5296 const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
5297 if (MR != SectionRef()) {
5298 info.S = MR;
5299 print_message_refs32(MR, &info);
5300 } else {
5301 const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
5302 info.S = MR;
5303 print_message_refs32(MR, &info);
5304 }
5305
5306 const SectionRef II = get_section(O, "__OBJC2", "__image_info");
5307 if (II != SectionRef()) {
5308 info.S = II;
5309 print_image_info32(II, &info);
5310 } else {
5311 const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
5312 info.S = II;
5313 print_image_info32(II, &info);
5314 }
5315}
5316
5317static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
5318 uint32_t i, j, p, offset, xoffset, left, defs_left, def;
5319 const char *r, *name, *defs;
5320 struct objc_module_t module;
5321 SectionRef S, xS;
5322 struct objc_symtab_t symtab;
5323 struct objc_class_t objc_class;
5324 struct objc_category_t objc_category;
5325
5326 outs() << "Objective-C segment\n";
5327 S = get_section(O, "__OBJC", "__module_info");
5328 if (S == SectionRef())
5329 return false;
5330
5331 SymbolAddressMap AddrMap;
5332 if (verbose)
5333 CreateSymbolAddressMap(O, &AddrMap);
5334
5335 std::vector<SectionRef> Sections;
5336 for (const SectionRef &Section : O->sections()) {
5337 StringRef SectName;
5338 Section.getName(SectName);
5339 Sections.push_back(Section);
5340 }
5341
5342 struct DisassembleInfo info;
5343 // Set up the block of info used by the Symbolizer call backs.
5344 info.verbose = verbose;
5345 info.O = O;
5346 info.AddrMap = &AddrMap;
5347 info.Sections = &Sections;
5348 info.class_name = nullptr;
5349 info.selector_name = nullptr;
5350 info.method = nullptr;
5351 info.demangled_name = nullptr;
5352 info.bindtable = nullptr;
5353 info.adrp_addr = 0;
5354 info.adrp_inst = 0;
5355
5356 for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
5357 p = S.getAddress() + i;
5358 r = get_pointer_32(p, offset, left, S, &info, true);
5359 if (r == nullptr)
5360 return true;
5361 memset(&module, '\0', sizeof(struct objc_module_t));
5362 if (left < sizeof(struct objc_module_t)) {
5363 memcpy(&module, r, left);
5364 outs() << " (module extends past end of __module_info section)\n";
5365 } else
5366 memcpy(&module, r, sizeof(struct objc_module_t));
5367 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5368 swapStruct(module);
5369
5370 outs() << "Module " << format("0x%" PRIx32"x", p) << "\n";
5371 outs() << " version " << module.version << "\n";
5372 outs() << " size " << module.size << "\n";
5373 outs() << " name ";
5374 name = get_pointer_32(module.name, xoffset, left, xS, &info, true);
5375 if (name != nullptr)
5376 outs() << format("%.*s", left, name);
5377 else
5378 outs() << format("0x%08" PRIx32"x", module.name)
5379 << "(not in an __OBJC section)";
5380 outs() << "\n";
5381
5382 r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);
5383 if (module.symtab == 0 || r == nullptr) {
5384 outs() << " symtab " << format("0x%08" PRIx32"x", module.symtab)
5385 << " (not in an __OBJC section)\n";
5386 continue;
5387 }
5388 outs() << " symtab " << format("0x%08" PRIx32"x", module.symtab) << "\n";
5389 memset(&symtab, '\0', sizeof(struct objc_symtab_t));
5390 defs_left = 0;
5391 defs = nullptr;
5392 if (left < sizeof(struct objc_symtab_t)) {
5393 memcpy(&symtab, r, left);
5394 outs() << "\tsymtab extends past end of an __OBJC section)\n";
5395 } else {
5396 memcpy(&symtab, r, sizeof(struct objc_symtab_t));
5397 if (left > sizeof(struct objc_symtab_t)) {
5398 defs_left = left - sizeof(struct objc_symtab_t);
5399 defs = r + sizeof(struct objc_symtab_t);
5400 }
5401 }
5402 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5403 swapStruct(symtab);
5404
5405 outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
5406 r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);
5407 outs() << "\trefs " << format("0x%08" PRIx32"x", symtab.refs);
5408 if (r == nullptr)
5409 outs() << " (not in an __OBJC section)";
5410 outs() << "\n";
5411 outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
5412 outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
5413 if (symtab.cls_def_cnt > 0)
5414 outs() << "\tClass Definitions\n";
5415 for (j = 0; j < symtab.cls_def_cnt; j++) {
5416 if ((j + 1) * sizeof(uint32_t) > defs_left) {
5417 outs() << "\t(remaining class defs entries entends past the end of the "
5418 << "section)\n";
5419 break;
5420 }
5421 memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));
5422 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5423 sys::swapByteOrder(def);
5424
5425 r = get_pointer_32(def, xoffset, left, xS, &info, true);
5426 outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32"x", def);
5427 if (r != nullptr) {
5428 if (left > sizeof(struct objc_class_t)) {
5429 outs() << "\n";
5430 memcpy(&objc_class, r, sizeof(struct objc_class_t));
5431 } else {
5432 outs() << " (entends past the end of the section)\n";
5433 memset(&objc_class, '\0', sizeof(struct objc_class_t));
5434 memcpy(&objc_class, r, left);
5435 }
5436 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5437 swapStruct(objc_class);
5438 print_objc_class_t(&objc_class, &info);
5439 } else {
5440 outs() << "(not in an __OBJC section)\n";
5441 }
5442
5443 if (CLS_GETINFO(&objc_class, CLS_CLASS)((&objc_class)->info & (0x1))) {
5444 outs() << "\tMeta Class";
5445 r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);
5446 if (r != nullptr) {
5447 if (left > sizeof(struct objc_class_t)) {
5448 outs() << "\n";
5449 memcpy(&objc_class, r, sizeof(struct objc_class_t));
5450 } else {
5451 outs() << " (entends past the end of the section)\n";
5452 memset(&objc_class, '\0', sizeof(struct objc_class_t));
5453 memcpy(&objc_class, r, left);
5454 }
5455 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5456 swapStruct(objc_class);
5457 print_objc_class_t(&objc_class, &info);
5458 } else {
5459 outs() << "(not in an __OBJC section)\n";
5460 }
5461 }
5462 }
5463 if (symtab.cat_def_cnt > 0)
5464 outs() << "\tCategory Definitions\n";
5465 for (j = 0; j < symtab.cat_def_cnt; j++) {
5466 if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
5467 outs() << "\t(remaining category defs entries entends past the end of "
5468 << "the section)\n";
5469 break;
5470 }
5471 memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
5472 sizeof(uint32_t));
5473 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5474 sys::swapByteOrder(def);
5475
5476 r = get_pointer_32(def, xoffset, left, xS, &info, true);
5477 outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
5478 << format("0x%08" PRIx32"x", def);
5479 if (r != nullptr) {
5480 if (left > sizeof(struct objc_category_t)) {
5481 outs() << "\n";
5482 memcpy(&objc_category, r, sizeof(struct objc_category_t));
5483 } else {
5484 outs() << " (entends past the end of the section)\n";
5485 memset(&objc_category, '\0', sizeof(struct objc_category_t));
5486 memcpy(&objc_category, r, left);
5487 }
5488 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5489 swapStruct(objc_category);
5490 print_objc_objc_category_t(&objc_category, &info);
5491 } else {
5492 outs() << "(not in an __OBJC section)\n";
5493 }
5494 }
5495 }
5496 const SectionRef II = get_section(O, "__OBJC", "__image_info");
5497 if (II != SectionRef())
5498 print_image_info(II, &info);
5499
5500 return true;
5501}
5502
5503static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
5504 uint32_t size, uint32_t addr) {
5505 SymbolAddressMap AddrMap;
5506 CreateSymbolAddressMap(O, &AddrMap);
5507
5508 std::vector<SectionRef> Sections;
5509 for (const SectionRef &Section : O->sections()) {
5510 StringRef SectName;
5511 Section.getName(SectName);
5512 Sections.push_back(Section);
5513 }
5514
5515 struct DisassembleInfo info;
5516 // Set up the block of info used by the Symbolizer call backs.
5517 info.verbose = true;
5518 info.O = O;
5519 info.AddrMap = &AddrMap;
5520 info.Sections = &Sections;
5521 info.class_name = nullptr;
5522 info.selector_name = nullptr;
5523 info.method = nullptr;
5524 info.demangled_name = nullptr;
5525 info.bindtable = nullptr;
5526 info.adrp_addr = 0;
5527 info.adrp_inst = 0;
5528
5529 const char *p;
5530 struct objc_protocol_t protocol;
5531 uint32_t left, paddr;
5532 for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
5533 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
5534 left = size - (p - sect);
5535 if (left < sizeof(struct objc_protocol_t)) {
5536 outs() << "Protocol extends past end of __protocol section\n";
5537 memcpy(&protocol, p, left);
5538 } else
5539 memcpy(&protocol, p, sizeof(struct objc_protocol_t));
5540 if (O->isLittleEndian() != sys::IsLittleEndianHost)
5541 swapStruct(protocol);
5542 paddr = addr + (p - sect);
5543 outs() << "Protocol " << format("0x%" PRIx32"x", paddr);
5544 if (print_protocol(paddr, 0, &info))
5545 outs() << "(not in an __OBJC section)\n";
5546 }
5547}
5548
5549static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
5550 if (O->is64Bit())
5551 printObjc2_64bit_MetaData(O, verbose);
5552 else {
5553 MachO::mach_header H;
5554 H = O->getHeader();
5555 if (H.cputype == MachO::CPU_TYPE_ARM)
5556 printObjc2_32bit_MetaData(O, verbose);
5557 else {
5558 // This is the 32-bit non-arm cputype case. Which is normally
5559 // the first Objective-C ABI. But it may be the case of a
5560 // binary for the iOS simulator which is the second Objective-C
5561 // ABI. In that case printObjc1_32bit_MetaData() will determine that
5562 // and return false.
5563 if (!printObjc1_32bit_MetaData(O, verbose))
5564 printObjc2_32bit_MetaData(O, verbose);
5565 }
5566 }
5567}
5568
5569// GuessLiteralPointer returns a string which for the item in the Mach-O file
5570// for the address passed in as ReferenceValue for printing as a comment with
5571// the instruction and also returns the corresponding type of that item
5572// indirectly through ReferenceType.
5573//
5574// If ReferenceValue is an address of literal cstring then a pointer to the
5575// cstring is returned and ReferenceType is set to
5576// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
5577//
5578// If ReferenceValue is an address of an Objective-C CFString, Selector ref or
5579// Class ref that name is returned and the ReferenceType is set accordingly.
5580//
5581// Lastly, literals which are Symbol address in a literal pool are looked for
5582// and if found the symbol name is returned and ReferenceType is set to
5583// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
5584//
5585// If there is no item in the Mach-O file for the address passed in as
5586// ReferenceValue nullptr is returned and ReferenceType is unchanged.
5587static const char *GuessLiteralPointer(uint64_t ReferenceValue,
5588 uint64_t ReferencePC,
5589 uint64_t *ReferenceType,
5590 struct DisassembleInfo *info) {
5591 // First see if there is an external relocation entry at the ReferencePC.
5592 if (info->O->getHeader().filetype == MachO::MH_OBJECT) {
5593 uint64_t sect_addr = info->S.getAddress();
5594 uint64_t sect_offset = ReferencePC - sect_addr;
5595 bool reloc_found = false;
5596 DataRefImpl Rel;
5597 MachO::any_relocation_info RE;
5598 bool isExtern = false;
5599 SymbolRef Symbol;
5600 for (const RelocationRef &Reloc : info->S.relocations()) {
5601 uint64_t RelocOffset = Reloc.getOffset();
5602 if (RelocOffset == sect_offset) {
5603 Rel = Reloc.getRawDataRefImpl();
5604 RE = info->O->getRelocation(Rel);
5605 if (info->O->isRelocationScattered(RE))
5606 continue;
5607 isExtern = info->O->getPlainRelocationExternal(RE);
5608 if (isExtern) {
5609 symbol_iterator RelocSym = Reloc.getSymbol();
5610 Symbol = *RelocSym;
5611 }
5612 reloc_found = true;
5613 break;
5614 }
5615 }
5616 // If there is an external relocation entry for a symbol in a section
5617 // then used that symbol's value for the value of the reference.
5618 if (reloc_found && isExtern) {
5619 if (info->O->getAnyRelocationPCRel(RE)) {
5620 unsigned Type = info->O->getAnyRelocationType(RE);
5621 if (Type == MachO::X86_64_RELOC_SIGNED) {
5622 ReferenceValue = Symbol.getValue();
5623 }
5624 }
5625 }
5626 }
5627
5628 // Look for literals such as Objective-C CFStrings refs, Selector refs,
5629 // Message refs and Class refs.
5630 bool classref, selref, msgref, cfstring;
5631 uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
5632 selref, msgref, cfstring);
5633 if (classref && pointer_value == 0) {
5634 // Note the ReferenceValue is a pointer into the __objc_classrefs section.
5635 // And the pointer_value in that section is typically zero as it will be
5636 // set by dyld as part of the "bind information".
5637 const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
5638 if (name != nullptr) {
5639 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref8;
5640 const char *class_name = strrchr(name, '$');
5641 if (class_name != nullptr && class_name[1] == '_' &&
5642 class_name[2] != '\0') {
5643 info->class_name = class_name + 2;
5644 return name;
5645 }
5646 }
5647 }
5648
5649 if (classref) {
5650 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref8;
5651 const char *name =
5652 get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
5653 if (name != nullptr)
5654 info->class_name = name;
5655 else
5656 name = "bad class ref";
5657 return name;
5658 }
5659
5660 if (cfstring) {
5661 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref4;
5662 const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
5663 return name;
5664 }
5665
5666 if (selref && pointer_value == 0)
5667 pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
5668
5669 if (pointer_value != 0)
5670 ReferenceValue = pointer_value;
5671
5672 const char *name = GuessCstringPointer(ReferenceValue, info);
5673 if (name) {
5674 if (pointer_value != 0 && selref) {
5675 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref7;
5676 info->selector_name = name;
5677 } else if (pointer_value != 0 && msgref) {
5678 info->class_name = nullptr;
5679 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref6;
5680 info->selector_name = name;
5681 } else
5682 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr3;
5683 return name;
5684 }
5685
5686 // Lastly look for an indirect symbol with this ReferenceValue which is in
5687 // a literal pool. If found return that symbol name.
5688 name = GuessIndirectSymbol(ReferenceValue, info);
5689 if (name) {
5690 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr2;
5691 return name;
5692 }
5693
5694 return nullptr;
5695}
5696
5697// SymbolizerSymbolLookUp is the symbol lookup function passed when creating
5698// the Symbolizer. It looks up the ReferenceValue using the info passed via the
5699// pointer to the struct DisassembleInfo that was passed when MCSymbolizer
5700// is created and returns the symbol name that matches the ReferenceValue or
5701// nullptr if none. The ReferenceType is passed in for the IN type of
5702// reference the instruction is making from the values in defined in the header
5703// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
5704// Out type and the ReferenceName will also be set which is added as a comment
5705// to the disassembled instruction.
5706//
5707#if HAVE_CXXABI_H1
5708// If the symbol name is a C++ mangled name then the demangled name is
5709// returned through ReferenceName and ReferenceType is set to
5710// LLVMDisassembler_ReferenceType_DeMangled_Name .
5711#endif
5712//
5713// When this is called to get a symbol name for a branch target then the
5714// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
5715// SymbolValue will be looked for in the indirect symbol table to determine if
5716// it is an address for a symbol stub. If so then the symbol name for that
5717// stub is returned indirectly through ReferenceName and then ReferenceType is
5718// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
5719//
5720// When this is called with an value loaded via a PC relative load then
5721// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
5722// SymbolValue is checked to be an address of literal pointer, symbol pointer,
5723// or an Objective-C meta data reference. If so the output ReferenceType is
5724// set to correspond to that as well as setting the ReferenceName.
5725static const char *SymbolizerSymbolLookUp(void *DisInfo,
5726 uint64_t ReferenceValue,
5727 uint64_t *ReferenceType,
5728 uint64_t ReferencePC,
5729 const char **ReferenceName) {
5730 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
5731 // If no verbose symbolic information is wanted then just return nullptr.
5732 if (!info->verbose) {
5733 *ReferenceName = nullptr;
5734 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5735 return nullptr;
5736 }
5737
5738 const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
5739
5740 if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch1) {
5741 *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
5742 if (*ReferenceName != nullptr) {
5743 method_reference(info, ReferenceType, ReferenceName);
5744 if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message5)
5745 *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub1;
5746 } else
5747#if HAVE_CXXABI_H1
5748 if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
5749 if (info->demangled_name != nullptr)
5750 free(info->demangled_name);
5751 int status;
5752 info->demangled_name =
5753 abi::__cxa_demangle(SymbolName + 1, nullptr, nullptr, &status);
5754 if (info->demangled_name != nullptr) {
5755 *ReferenceName = info->demangled_name;
5756 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name9;
5757 } else
5758 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5759 } else
5760#endif
5761 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5762 } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load2) {
5763 *ReferenceName =
5764 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
5765 if (*ReferenceName)
5766 method_reference(info, ReferenceType, ReferenceName);
5767 else
5768 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5769 // If this is arm64 and the reference is an adrp instruction save the
5770 // instruction, passed in ReferenceValue and the address of the instruction
5771 // for use later if we see and add immediate instruction.
5772 } else if (info->O->getArch() == Triple::aarch64 &&
5773 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP0x100000001) {
5774 info->adrp_inst = ReferenceValue;
5775 info->adrp_addr = ReferencePC;
5776 SymbolName = nullptr;
5777 *ReferenceName = nullptr;
5778 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5779 // If this is arm64 and reference is an add immediate instruction and we
5780 // have
5781 // seen an adrp instruction just before it and the adrp's Xd register
5782 // matches
5783 // this add's Xn register reconstruct the value being referenced and look to
5784 // see if it is a literal pointer. Note the add immediate instruction is
5785 // passed in ReferenceValue.
5786 } else if (info->O->getArch() == Triple::aarch64 &&
5787 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri0x100000002 &&
5788 ReferencePC - 4 == info->adrp_addr &&
5789 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
5790 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
5791 uint32_t addxri_inst;
5792 uint64_t adrp_imm, addxri_imm;
5793
5794 adrp_imm =
5795 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
5796 if (info->adrp_inst & 0x0200000)
5797 adrp_imm |= 0xfffffffffc000000LL;
5798
5799 addxri_inst = ReferenceValue;
5800 addxri_imm = (addxri_inst >> 10) & 0xfff;
5801 if (((addxri_inst >> 22) & 0x3) == 1)
5802 addxri_imm <<= 12;
5803
5804 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
5805 (adrp_imm << 12) + addxri_imm;
5806
5807 *ReferenceName =
5808 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
5809 if (*ReferenceName == nullptr)
5810 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5811 // If this is arm64 and the reference is a load register instruction and we
5812 // have seen an adrp instruction just before it and the adrp's Xd register
5813 // matches this add's Xn register reconstruct the value being referenced and
5814 // look to see if it is a literal pointer. Note the load register
5815 // instruction is passed in ReferenceValue.
5816 } else if (info->O->getArch() == Triple::aarch64 &&
5817 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui0x100000003 &&
5818 ReferencePC - 4 == info->adrp_addr &&
5819 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
5820 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
5821 uint32_t ldrxui_inst;
5822 uint64_t adrp_imm, ldrxui_imm;
5823
5824 adrp_imm =
5825 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
5826 if (info->adrp_inst & 0x0200000)
5827 adrp_imm |= 0xfffffffffc000000LL;
5828
5829 ldrxui_inst = ReferenceValue;
5830 ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
5831
5832 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
5833 (adrp_imm << 12) + (ldrxui_imm << 3);
5834
5835 *ReferenceName =
5836 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
5837 if (*ReferenceName == nullptr)
5838 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5839 }
5840 // If this arm64 and is an load register (PC-relative) instruction the
5841 // ReferenceValue is the PC plus the immediate value.
5842 else if (info->O->getArch() == Triple::aarch64 &&
5843 (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl0x100000004 ||
5844 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR0x100000005)) {
5845 *ReferenceName =
5846 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
5847 if (*ReferenceName == nullptr)
5848 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5849 }
5850#if HAVE_CXXABI_H1
5851 else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
5852 if (info->demangled_name != nullptr)
5853 free(info->demangled_name);
5854 int status;
5855 info->demangled_name =
5856 abi::__cxa_demangle(SymbolName + 1, nullptr, nullptr, &status);
5857 if (info->demangled_name != nullptr) {
5858 *ReferenceName = info->demangled_name;
5859 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name9;
5860 }
5861 }
5862#endif
5863 else {
5864 *ReferenceName = nullptr;
5865 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None0;
5866 }
5867
5868 return SymbolName;
5869}
5870
5871/// \brief Emits the comments that are stored in the CommentStream.
5872/// Each comment in the CommentStream must end with a newline.
5873static void emitComments(raw_svector_ostream &CommentStream,
5874 SmallString<128> &CommentsToEmit,
5875 formatted_raw_ostream &FormattedOS,
5876 const MCAsmInfo &MAI) {
5877 // Flush the stream before taking its content.
5878 StringRef Comments = CommentsToEmit.str();
5879 // Get the default information for printing a comment.
5880 const char *CommentBegin = MAI.getCommentString();
5881 unsigned CommentColumn = MAI.getCommentColumn();
5882 bool IsFirst = true;
5883 while (!Comments.empty()) {
5884 if (!IsFirst)
5885 FormattedOS << '\n';
5886 // Emit a line of comments.
5887 FormattedOS.PadToColumn(CommentColumn);
5888 size_t Position = Comments.find('\n');
5889 FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
5890 // Move after the newline character.
5891 Comments = Comments.substr(Position + 1);
5892 IsFirst = false;
5893 }
5894 FormattedOS.flush();
5895
5896 // Tell the comment stream that the vector changed underneath it.
5897 CommentsToEmit.clear();
5898}
5899
5900static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
5901 StringRef DisSegName, StringRef DisSectName) {
5902 const char *McpuDefault = nullptr;
5903 const Target *ThumbTarget = nullptr;
5904 const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
5905 if (!TheTarget) {
5906 // GetTarget prints out stuff.
5907 return;
5908 }
5909 if (MCPU.empty() && McpuDefault)
5910 MCPU = McpuDefault;
5911
5912 std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
5913 std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
5914 if (ThumbTarget)
5915 ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());
5916
5917 // Package up features to be passed to target/subtarget
5918 std::string FeaturesStr;
5919 if (MAttrs.size()) {
5920 SubtargetFeatures Features;
5921 for (unsigned i = 0; i != MAttrs.size(); ++i)
5922 Features.AddFeature(MAttrs[i]);
5923 FeaturesStr = Features.getString();
5924 }
5925
5926 // Set up disassembler.
5927 std::unique_ptr<const MCRegisterInfo> MRI(
5928 TheTarget->createMCRegInfo(TripleName));
5929 std::unique_ptr<const MCAsmInfo> AsmInfo(
5930 TheTarget->createMCAsmInfo(*MRI, TripleName));
5931 std::unique_ptr<const MCSubtargetInfo> STI(
5932 TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
5933 MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr);
5934 std::unique_ptr<MCDisassembler> DisAsm(
5935 TheTarget->createMCDisassembler(*STI, Ctx));
5936 std::unique_ptr<MCSymbolizer> Symbolizer;
5937 struct DisassembleInfo SymbolizerInfo;
5938 std::unique_ptr<MCRelocationInfo> RelInfo(
5939 TheTarget->createMCRelocationInfo(TripleName, Ctx));
5940 if (RelInfo) {
5941 Symbolizer.reset(TheTarget->createMCSymbolizer(
5942 TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
5943 &SymbolizerInfo, &Ctx, std::move(RelInfo)));
5944 DisAsm->setSymbolizer(std::move(Symbolizer));
5945 }
5946 int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
5947 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
5948 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));
5949 // Set the display preference for hex vs. decimal immediates.
5950 IP->setPrintImmHex(PrintImmHex);
5951 // Comment stream and backing vector.
5952 SmallString<128> CommentsToEmit;
5953 raw_svector_ostream CommentStream(CommentsToEmit);
5954 // FIXME: Setting the CommentStream in the InstPrinter is problematic in that
5955 // if it is done then arm64 comments for string literals don't get printed
5956 // and some constant get printed instead and not setting it causes intel
5957 // (32-bit and 64-bit) comments printed with different spacing before the
5958 // comment causing different diffs with the 'C' disassembler library API.
5959 // IP->setCommentStream(CommentStream);
5960
5961 if (!AsmInfo || !STI || !DisAsm || !IP) {
5962 errs() << "error: couldn't initialize disassembler for target "
5963 << TripleName << '\n';
5964 return;
5965 }
5966
5967 // Set up thumb disassembler.
5968 std::unique_ptr<const MCRegisterInfo> ThumbMRI;
5969 std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
5970 std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
5971 std::unique_ptr<MCDisassembler> ThumbDisAsm;
5972 std::unique_ptr<MCInstPrinter> ThumbIP;
5973 std::unique_ptr<MCContext> ThumbCtx;
5974 std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
5975 struct DisassembleInfo ThumbSymbolizerInfo;
5976 std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
5977 if (ThumbTarget) {
5978 ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
5979 ThumbAsmInfo.reset(
5980 ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName));
5981 ThumbSTI.reset(
5982 ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MCPU, FeaturesStr));
5983 ThumbCtx.reset(new MCContext(ThumbAsmInfo.get(), ThumbMRI.get(), nullptr));
5984 ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
5985 MCContext *PtrThumbCtx = ThumbCtx.get();
5986 ThumbRelInfo.reset(
5987 ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));
5988 if (ThumbRelInfo) {
5989 ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
5990 ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
5991 &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
5992 ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
5993 }
5994 int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
5995 ThumbIP.reset(ThumbTarget->createMCInstPrinter(
5996 Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,
5997 *ThumbInstrInfo, *ThumbMRI));
5998 // Set the display preference for hex vs. decimal immediates.
5999 ThumbIP->setPrintImmHex(PrintImmHex);
6000 }
6001
6002 if (ThumbTarget && (!ThumbAsmInfo || !ThumbSTI || !ThumbDisAsm || !ThumbIP)) {
6003 errs() << "error: couldn't initialize disassembler for target "
6004 << ThumbTripleName << '\n';
6005 return;
6006 }
6007
6008 MachO::mach_header Header = MachOOF->getHeader();
6009
6010 // FIXME: Using the -cfg command line option, this code used to be able to
6011 // annotate relocations with the referenced symbol's name, and if this was
6012 // inside a __[cf]string section, the data it points to. This is now replaced
6013 // by the upcoming MCSymbolizer, which needs the appropriate setup done above.
6014 std::vector<SectionRef> Sections;
6015 std::vector<SymbolRef> Symbols;
6016 SmallVector<uint64_t, 8> FoundFns;
6017 uint64_t BaseSegmentAddress;
6018
6019 getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,
6020 BaseSegmentAddress);
6021
6022 // Sort the symbols by address, just in case they didn't come in that way.
6023 std::sort(Symbols.begin(), Symbols.end(), SymbolSorter());
6024
6025 // Build a data in code table that is sorted on by the address of each entry.
6026 uint64_t BaseAddress = 0;
6027 if (Header.filetype == MachO::MH_OBJECT)
6028 BaseAddress = Sections[0].getAddress();
6029 else
6030 BaseAddress = BaseSegmentAddress;
6031 DiceTable Dices;
6032 for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
6033 DI != DE; ++DI) {
6034 uint32_t Offset;
6035 DI->getOffset(Offset);
6036 Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
6037 }
6038 array_pod_sort(Dices.begin(), Dices.end());
6039
6040#ifndef NDEBUG
6041 raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
6042#else
6043 raw_ostream &DebugOut = nulls();
6044#endif
6045
6046 std::unique_ptr<DIContext> diContext;
6047 ObjectFile *DbgObj = MachOOF;
6048 // Try to find debug info and set up the DIContext for it.
6049 if (UseDbg) {
6050 // A separate DSym file path was specified, parse it as a macho file,
6051 // get the sections and supply it to the section name parsing machinery.
6052 if (!DSYMFile.empty()) {
6053 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
6054 MemoryBuffer::getFileOrSTDIN(DSYMFile);
6055 if (std::error_code EC = BufOrErr.getError()) {
6056 errs() << "llvm-objdump: " << Filename << ": " << EC.message() << '\n';
6057 return;
6058 }
6059 DbgObj =
6060 ObjectFile::createMachOObjectFile(BufOrErr.get()->getMemBufferRef())
6061 .get()
6062 .release();
6063 }
6064
6065 // Setup the DIContext
6066 diContext.reset(new DWARFContextInMemory(*DbgObj));
6067 }
6068
6069 if (FilterSections.size() == 0)
6070 outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
6071
6072 for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
6073 StringRef SectName;
6074 if (Sections[SectIdx].getName(SectName) || SectName != DisSectName)
6075 continue;
6076
6077 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
6078
6079 StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
6080 if (SegmentName != DisSegName)
6081 continue;
6082
6083 StringRef BytesStr;
6084 Sections[SectIdx].getContents(BytesStr);
6085 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
6086 BytesStr.size());
6087 uint64_t SectAddress = Sections[SectIdx].getAddress();
6088
6089 bool symbolTableWorked = false;
6090
6091 // Create a map of symbol addresses to symbol names for use by
6092 // the SymbolizerSymbolLookUp() routine.
6093 SymbolAddressMap AddrMap;
6094 bool DisSymNameFound = false;
6095 for (const SymbolRef &Symbol : MachOOF->symbols()) {
6096 ErrorOr<SymbolRef::Type> STOrErr = Symbol.getType();
6097 if (std::error_code EC = STOrErr.getError())
6098 report_fatal_error(EC.message());
6099 SymbolRef::Type ST = *STOrErr;
6100 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
6101 ST == SymbolRef::ST_Other) {
6102 uint64_t Address = Symbol.getValue();
6103 ErrorOr<StringRef> SymNameOrErr = Symbol.getName();
6104 if (std::error_code EC = SymNameOrErr.getError())
6105 report_fatal_error(EC.message());
6106 StringRef SymName = *SymNameOrErr;
6107 AddrMap[Address] = SymName;
6108 if (!DisSymName.empty() && DisSymName == SymName)
6109 DisSymNameFound = true;
6110 }
6111 }
6112 if (!DisSymName.empty() && !DisSymNameFound) {
6113 outs() << "Can't find -dis-symname: " << DisSymName << "\n";
6114 return;
6115 }
6116 // Set up the block of info used by the Symbolizer call backs.
6117 SymbolizerInfo.verbose = !NoSymbolicOperands;
6118 SymbolizerInfo.O = MachOOF;
6119 SymbolizerInfo.S = Sections[SectIdx];
6120 SymbolizerInfo.AddrMap = &AddrMap;
6121 SymbolizerInfo.Sections = &Sections;
6122 SymbolizerInfo.class_name = nullptr;
6123 SymbolizerInfo.selector_name = nullptr;
6124 SymbolizerInfo.method = nullptr;
6125 SymbolizerInfo.demangled_name = nullptr;
6126 SymbolizerInfo.bindtable = nullptr;
6127 SymbolizerInfo.adrp_addr = 0;
6128 SymbolizerInfo.adrp_inst = 0;
6129 // Same for the ThumbSymbolizer
6130 ThumbSymbolizerInfo.verbose = !NoSymbolicOperands;
6131 ThumbSymbolizerInfo.O = MachOOF;
6132 ThumbSymbolizerInfo.S = Sections[SectIdx];
6133 ThumbSymbolizerInfo.AddrMap = &AddrMap;
6134 ThumbSymbolizerInfo.Sections = &Sections;
6135 ThumbSymbolizerInfo.class_name = nullptr;
6136 ThumbSymbolizerInfo.selector_name = nullptr;
6137 ThumbSymbolizerInfo.method = nullptr;
6138 ThumbSymbolizerInfo.demangled_name = nullptr;
6139 ThumbSymbolizerInfo.bindtable = nullptr;
6140 ThumbSymbolizerInfo.adrp_addr = 0;
6141 ThumbSymbolizerInfo.adrp_inst = 0;
6142
6143 // Disassemble symbol by symbol.
6144 for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
6145 ErrorOr<StringRef> SymNameOrErr = Symbols[SymIdx].getName();
6146 if (std::error_code EC = SymNameOrErr.getError())
6147 report_fatal_error(EC.message());
6148 StringRef SymName = *SymNameOrErr;
6149
6150 ErrorOr<SymbolRef::Type> STOrErr = Symbols[SymIdx].getType();
6151 if (std::error_code EC = STOrErr.getError())
6152 report_fatal_error(EC.message());
6153 SymbolRef::Type ST = *STOrErr;
6154 if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
6155 continue;
6156
6157 // Make sure the symbol is defined in this section.
6158 bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);
6159 if (!containsSym)
6160 continue;
6161
6162 // If we are only disassembling one symbol see if this is that symbol.
6163 if (!DisSymName.empty() && DisSymName != SymName)
6164 continue;
6165
6166 // Start at the address of the symbol relative to the section's address.
6167 uint64_t Start = Symbols[SymIdx].getValue();
6168 uint64_t SectionAddress = Sections[SectIdx].getAddress();
6169 Start -= SectionAddress;
6170
6171 // Stop disassembling either at the beginning of the next symbol or at
6172 // the end of the section.
6173 bool containsNextSym = false;
6174 uint64_t NextSym = 0;
6175 uint64_t NextSymIdx = SymIdx + 1;
6176 while (Symbols.size() > NextSymIdx) {
6177 ErrorOr<SymbolRef::Type> STOrErr = Symbols[NextSymIdx].getType();
6178 if (std::error_code EC = STOrErr.getError())
6179 report_fatal_error(EC.message());
6180 SymbolRef::Type NextSymType = *STOrErr;
6181 if (NextSymType == SymbolRef::ST_Function) {
6182 containsNextSym =
6183 Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
6184 NextSym = Symbols[NextSymIdx].getValue();
6185 NextSym -= SectionAddress;
6186 break;
6187 }
6188 ++NextSymIdx;
6189 }
6190
6191 uint64_t SectSize = Sections[SectIdx].getSize();
6192 uint64_t End = containsNextSym ? NextSym : SectSize;
6193 uint64_t Size;
6194
6195 symbolTableWorked = true;
6196
6197 DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
6198 bool isThumb =
6199 (MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget;
6200
6201 outs() << SymName << ":\n";
6202 DILineInfo lastLine;
6203 for (uint64_t Index = Start; Index < End; Index += Size) {
6204 MCInst Inst;
6205
6206 uint64_t PC = SectAddress + Index;
6207 if (!NoLeadingAddr) {
6208 if (FullLeadingAddr) {
6209 if (MachOOF->is64Bit())
6210 outs() << format("%016" PRIx64"l" "x", PC);
6211 else
6212 outs() << format("%08" PRIx64"l" "x", PC);
6213 } else {
6214 outs() << format("%8" PRIx64"l" "x" ":", PC);
6215 }
6216 }
6217 if (!NoShowRawInsn)
6218 outs() << "\t";
6219
6220 // Check the data in code table here to see if this is data not an
6221 // instruction to be disassembled.
6222 DiceTable Dice;
6223 Dice.push_back(std::make_pair(PC, DiceRef()));
6224 dice_table_iterator DTI =
6225 std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),
6226 compareDiceTableEntries);
6227 if (DTI != Dices.end()) {
6228 uint16_t Length;
6229 DTI->second.getLength(Length);
6230 uint16_t Kind;
6231 DTI->second.getKind(Kind);
6232 Size = DumpDataInCode(Bytes.data() + Index, Length, Kind);
6233 if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
6234 (PC == (DTI->first + Length - 1)) && (Length & 1))
6235 Size++;
6236 continue;
6237 }
6238
6239 SmallVector<char, 64> AnnotationsBytes;
6240 raw_svector_ostream Annotations(AnnotationsBytes);
6241
6242 bool gotInst;
6243 if (isThumb)
6244 gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
6245 PC, DebugOut, Annotations);
6246 else
6247 gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,
6248 DebugOut, Annotations);
6249 if (gotInst) {
6250 if (!NoShowRawInsn) {
6251 dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs());
6252 }
6253 formatted_raw_ostream FormattedOS(outs());
6254 StringRef AnnotationsStr = Annotations.str();
6255 if (isThumb)
6256 ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI);
6257 else
6258 IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI);
6259 emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
6260
6261 // Print debug info.
6262 if (diContext) {
6263 DILineInfo dli = diContext->getLineInfoForAddress(PC);
6264 // Print valid line info if it changed.
6265 if (dli != lastLine && dli.Line != 0)
6266 outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
6267 << dli.Column;
6268 lastLine = dli;
6269 }
6270 outs() << "\n";
6271 } else {
6272 unsigned int Arch = MachOOF->getArch();
6273 if (Arch == Triple::x86_64 || Arch == Triple::x86) {
6274 outs() << format("\t.byte 0x%02x #bad opcode\n",
6275 *(Bytes.data() + Index) & 0xff);
6276 Size = 1; // skip exactly one illegible byte and move on.
6277 } else if (Arch == Triple::aarch64) {
6278 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
6279 (*(Bytes.data() + Index + 1) & 0xff) << 8 |
6280 (*(Bytes.data() + Index + 2) & 0xff) << 16 |
6281 (*(Bytes.data() + Index + 3) & 0xff) << 24;
6282 outs() << format("\t.long\t0x%08x\n", opcode);
6283 Size = 4;
6284 } else {
6285 errs() << "llvm-objdump: warning: invalid instruction encoding\n";
6286 if (Size == 0)
6287 Size = 1; // skip illegible bytes
6288 }
6289 }
6290 }
6291 }
6292 if (!symbolTableWorked) {
6293 // Reading the symbol table didn't work, disassemble the whole section.
6294 uint64_t SectAddress = Sections[SectIdx].getAddress();
6295 uint64_t SectSize = Sections[SectIdx].getSize();
6296 uint64_t InstSize;
6297 for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
6298 MCInst Inst;
6299
6300 uint64_t PC = SectAddress + Index;
6301 if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
6302 DebugOut, nulls())) {
6303 if (!NoLeadingAddr) {
6304 if (FullLeadingAddr) {
6305 if (MachOOF->is64Bit())
6306 outs() << format("%016" PRIx64"l" "x", PC);
6307 else
6308 outs() << format("%08" PRIx64"l" "x", PC);
6309 } else {
6310 outs() << format("%8" PRIx64"l" "x" ":", PC);
6311 }
6312 }
6313 if (!NoShowRawInsn) {
6314 outs() << "\t";
6315 dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
6316 }
6317 IP->printInst(&Inst, outs(), "", *STI);
6318 outs() << "\n";
6319 } else {
6320 unsigned int Arch = MachOOF->getArch();
6321 if (Arch == Triple::x86_64 || Arch == Triple::x86) {
6322 outs() << format("\t.byte 0x%02x #bad opcode\n",
6323 *(Bytes.data() + Index) & 0xff);
6324 InstSize = 1; // skip exactly one illegible byte and move on.
6325 } else {
6326 errs() << "llvm-objdump: warning: invalid instruction encoding\n";
6327 if (InstSize == 0)
6328 InstSize = 1; // skip illegible bytes
6329 }
6330 }
6331 }
6332 }
6333 // The TripleName's need to be reset if we are called again for a different
6334 // archtecture.
6335 TripleName = "";
6336 ThumbTripleName = "";
6337
6338 if (SymbolizerInfo.method != nullptr)
6339 free(SymbolizerInfo.method);
6340 if (SymbolizerInfo.demangled_name != nullptr)
6341 free(SymbolizerInfo.demangled_name);
6342 if (SymbolizerInfo.bindtable != nullptr)
6343 delete SymbolizerInfo.bindtable;
6344 if (ThumbSymbolizerInfo.method != nullptr)
6345 free(ThumbSymbolizerInfo.method);
6346 if (ThumbSymbolizerInfo.demangled_name != nullptr)
6347 free(ThumbSymbolizerInfo.demangled_name);
6348 if (ThumbSymbolizerInfo.bindtable != nullptr)
6349 delete ThumbSymbolizerInfo.bindtable;
6350 }
6351}
6352
6353//===----------------------------------------------------------------------===//
6354// __compact_unwind section dumping
6355//===----------------------------------------------------------------------===//
6356
6357namespace {
6358
6359template <typename T> static uint64_t readNext(const char *&Buf) {
6360 using llvm::support::little;
6361 using llvm::support::unaligned;
6362
6363 uint64_t Val = support::endian::read<T, little, unaligned>(Buf);
6364 Buf += sizeof(T);
6365 return Val;
6366}
6367
6368struct CompactUnwindEntry {
6369 uint32_t OffsetInSection;
6370
6371 uint64_t FunctionAddr;
6372 uint32_t Length;
6373 uint32_t CompactEncoding;
6374 uint64_t PersonalityAddr;
6375 uint64_t LSDAAddr;
6376
6377 RelocationRef FunctionReloc;
6378 RelocationRef PersonalityReloc;
6379 RelocationRef LSDAReloc;
6380
6381 CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
6382 : OffsetInSection(Offset) {
6383 if (Is64)
6384 read<uint64_t>(Contents.data() + Offset);
6385 else
6386 read<uint32_t>(Contents.data() + Offset);
6387 }
6388
6389private:
6390 template <typename UIntPtr> void read(const char *Buf) {
6391 FunctionAddr = readNext<UIntPtr>(Buf);
6392 Length = readNext<uint32_t>(Buf);
6393 CompactEncoding = readNext<uint32_t>(Buf);
6394 PersonalityAddr = readNext<UIntPtr>(Buf);
6395 LSDAAddr = readNext<UIntPtr>(Buf);
6396 }
6397};
6398}
6399
6400/// Given a relocation from __compact_unwind, consisting of the RelocationRef
6401/// and data being relocated, determine the best base Name and Addend to use for
6402/// display purposes.
6403///
6404/// 1. An Extern relocation will directly reference a symbol (and the data is
6405/// then already an addend), so use that.
6406/// 2. Otherwise the data is an offset in the object file's layout; try to find
6407// a symbol before it in the same section, and use the offset from there.
6408/// 3. Finally, if all that fails, fall back to an offset from the start of the
6409/// referenced section.
6410static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
6411 std::map<uint64_t, SymbolRef> &Symbols,
6412 const RelocationRef &Reloc, uint64_t Addr,
6413 StringRef &Name, uint64_t &Addend) {
6414 if (Reloc.getSymbol() != Obj->symbol_end()) {
6415 ErrorOr<StringRef> NameOrErr = Reloc.getSymbol()->getName();
6416 if (std::error_code EC = NameOrErr.getError())
6417 report_fatal_error(EC.message());
6418 Name = *NameOrErr;
6419 Addend = Addr;
6420 return;
6421 }
6422
6423 auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
6424 SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
6425
6426 uint64_t SectionAddr = RelocSection.getAddress();
6427
6428 auto Sym = Symbols.upper_bound(Addr);
6429 if (Sym == Symbols.begin()) {
6430 // The first symbol in the object is after this reference, the best we can
6431 // do is section-relative notation.
6432 RelocSection.getName(Name);
6433 Addend = Addr - SectionAddr;
6434 return;
6435 }
6436
6437 // Go back one so that SymbolAddress <= Addr.
6438 --Sym;
6439
6440 section_iterator SymSection = *Sym->second.getSection();
6441 if (RelocSection == *SymSection) {
6442 // There's a valid symbol in the same section before this reference.
6443 ErrorOr<StringRef> NameOrErr = Sym->second.getName();
6444 if (std::error_code EC = NameOrErr.getError())
6445 report_fatal_error(EC.message());
6446 Name = *NameOrErr;
6447 Addend = Addr - Sym->first;
6448 return;
6449 }
6450
6451 // There is a symbol before this reference, but it's in a different
6452 // section. Probably not helpful to mention it, so use the section name.
6453 RelocSection.getName(Name);
6454 Addend = Addr - SectionAddr;
6455}
6456
6457static void printUnwindRelocDest(const MachOObjectFile *Obj,
6458 std::map<uint64_t, SymbolRef> &Symbols,
6459 const RelocationRef &Reloc, uint64_t Addr) {
6460 StringRef Name;
6461 uint64_t Addend;
6462
6463 if (!Reloc.getObject())
6464 return;
6465
6466 findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
6467
6468 outs() << Name;
6469 if (Addend)
6470 outs() << " + " << format("0x%" PRIx64"l" "x", Addend);
6471}
6472
6473static void
6474printMachOCompactUnwindSection(const MachOObjectFile *Obj,
6475 std::map<uint64_t, SymbolRef> &Symbols,
6476 const SectionRef &CompactUnwind) {
6477
6478 assert(Obj->isLittleEndian() &&((Obj->isLittleEndian() && "There should not be a big-endian .o with __compact_unwind"
) ? static_cast<void> (0) : __assert_fail ("Obj->isLittleEndian() && \"There should not be a big-endian .o with __compact_unwind\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6479, __PRETTY_FUNCTION__))
6479 "There should not be a big-endian .o with __compact_unwind")((Obj->isLittleEndian() && "There should not be a big-endian .o with __compact_unwind"
) ? static_cast<void> (0) : __assert_fail ("Obj->isLittleEndian() && \"There should not be a big-endian .o with __compact_unwind\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6479, __PRETTY_FUNCTION__))
;
6480
6481 bool Is64 = Obj->is64Bit();
6482 uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
6483 uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
6484
6485 StringRef Contents;
6486 CompactUnwind.getContents(Contents);
6487
6488 SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
6489
6490 // First populate the initial raw offsets, encodings and so on from the entry.
6491 for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
6492 CompactUnwindEntry Entry(Contents.data(), Offset, Is64);
6493 CompactUnwinds.push_back(Entry);
6494 }
6495
6496 // Next we need to look at the relocations to find out what objects are
6497 // actually being referred to.
6498 for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
6499 uint64_t RelocAddress = Reloc.getOffset();
6500
6501 uint32_t EntryIdx = RelocAddress / EntrySize;
6502 uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
6503 CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
6504
6505 if (OffsetInEntry == 0)
6506 Entry.FunctionReloc = Reloc;
6507 else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
6508 Entry.PersonalityReloc = Reloc;
6509 else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
6510 Entry.LSDAReloc = Reloc;
6511 else
6512 llvm_unreachable("Unexpected relocation in __compact_unwind section")::llvm::llvm_unreachable_internal("Unexpected relocation in __compact_unwind section"
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6512)
;
6513 }
6514
6515 // Finally, we're ready to print the data we've gathered.
6516 outs() << "Contents of __compact_unwind section:\n";
6517 for (auto &Entry : CompactUnwinds) {
6518 outs() << " Entry at offset "
6519 << format("0x%" PRIx32"x", Entry.OffsetInSection) << ":\n";
6520
6521 // 1. Start of the region this entry applies to.
6522 outs() << " start: " << format("0x%" PRIx64"l" "x",
6523 Entry.FunctionAddr) << ' ';
6524 printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);
6525 outs() << '\n';
6526
6527 // 2. Length of the region this entry applies to.
6528 outs() << " length: " << format("0x%" PRIx32"x", Entry.Length)
6529 << '\n';
6530 // 3. The 32-bit compact encoding.
6531 outs() << " compact encoding: "
6532 << format("0x%08" PRIx32"x", Entry.CompactEncoding) << '\n';
6533
6534 // 4. The personality function, if present.
6535 if (Entry.PersonalityReloc.getObject()) {
6536 outs() << " personality function: "
6537 << format("0x%" PRIx64"l" "x", Entry.PersonalityAddr) << ' ';
6538 printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
6539 Entry.PersonalityAddr);
6540 outs() << '\n';
6541 }
6542
6543 // 5. This entry's language-specific data area.
6544 if (Entry.LSDAReloc.getObject()) {
6545 outs() << " LSDA: " << format("0x%" PRIx64"l" "x",
6546 Entry.LSDAAddr) << ' ';
6547 printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
6548 outs() << '\n';
6549 }
6550 }
6551}
6552
6553//===----------------------------------------------------------------------===//
6554// __unwind_info section dumping
6555//===----------------------------------------------------------------------===//
6556
6557static void printRegularSecondLevelUnwindPage(const char *PageStart) {
6558 const char *Pos = PageStart;
6559 uint32_t Kind = readNext<uint32_t>(Pos);
6560 (void)Kind;
6561 assert(Kind == 2 && "kind for a regular 2nd level index should be 2")((Kind == 2 && "kind for a regular 2nd level index should be 2"
) ? static_cast<void> (0) : __assert_fail ("Kind == 2 && \"kind for a regular 2nd level index should be 2\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6561, __PRETTY_FUNCTION__))
;
6562
6563 uint16_t EntriesStart = readNext<uint16_t>(Pos);
6564 uint16_t NumEntries = readNext<uint16_t>(Pos);
6565
6566 Pos = PageStart + EntriesStart;
6567 for (unsigned i = 0; i < NumEntries; ++i) {
6568 uint32_t FunctionOffset = readNext<uint32_t>(Pos);
6569 uint32_t Encoding = readNext<uint32_t>(Pos);
6570
6571 outs() << " [" << i << "]: "
6572 << "function offset=" << format("0x%08" PRIx32"x", FunctionOffset)
6573 << ", "
6574 << "encoding=" << format("0x%08" PRIx32"x", Encoding) << '\n';
6575 }
6576}
6577
6578static void printCompressedSecondLevelUnwindPage(
6579 const char *PageStart, uint32_t FunctionBase,
6580 const SmallVectorImpl<uint32_t> &CommonEncodings) {
6581 const char *Pos = PageStart;
6582 uint32_t Kind = readNext<uint32_t>(Pos);
6583 (void)Kind;
6584 assert(Kind == 3 && "kind for a compressed 2nd level index should be 3")((Kind == 3 && "kind for a compressed 2nd level index should be 3"
) ? static_cast<void> (0) : __assert_fail ("Kind == 3 && \"kind for a compressed 2nd level index should be 3\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6584, __PRETTY_FUNCTION__))
;
6585
6586 uint16_t EntriesStart = readNext<uint16_t>(Pos);
6587 uint16_t NumEntries = readNext<uint16_t>(Pos);
6588
6589 uint16_t EncodingsStart = readNext<uint16_t>(Pos);
6590 readNext<uint16_t>(Pos);
6591 const auto *PageEncodings = reinterpret_cast<const support::ulittle32_t *>(
6592 PageStart + EncodingsStart);
6593
6594 Pos = PageStart + EntriesStart;
6595 for (unsigned i = 0; i < NumEntries; ++i) {
6596 uint32_t Entry = readNext<uint32_t>(Pos);
6597 uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
6598 uint32_t EncodingIdx = Entry >> 24;
6599
6600 uint32_t Encoding;
6601 if (EncodingIdx < CommonEncodings.size())
6602 Encoding = CommonEncodings[EncodingIdx];
6603 else
6604 Encoding = PageEncodings[EncodingIdx - CommonEncodings.size()];
6605
6606 outs() << " [" << i << "]: "
6607 << "function offset=" << format("0x%08" PRIx32"x", FunctionOffset)
6608 << ", "
6609 << "encoding[" << EncodingIdx
6610 << "]=" << format("0x%08" PRIx32"x", Encoding) << '\n';
6611 }
6612}
6613
6614static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
6615 std::map<uint64_t, SymbolRef> &Symbols,
6616 const SectionRef &UnwindInfo) {
6617
6618 assert(Obj->isLittleEndian() &&((Obj->isLittleEndian() && "There should not be a big-endian .o with __unwind_info"
) ? static_cast<void> (0) : __assert_fail ("Obj->isLittleEndian() && \"There should not be a big-endian .o with __unwind_info\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6619, __PRETTY_FUNCTION__))
6619 "There should not be a big-endian .o with __unwind_info")((Obj->isLittleEndian() && "There should not be a big-endian .o with __unwind_info"
) ? static_cast<void> (0) : __assert_fail ("Obj->isLittleEndian() && \"There should not be a big-endian .o with __unwind_info\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6619, __PRETTY_FUNCTION__))
;
6620
6621 outs() << "Contents of __unwind_info section:\n";
6622
6623 StringRef Contents;
6624 UnwindInfo.getContents(Contents);
6625 const char *Pos = Contents.data();
6626
6627 //===----------------------------------
6628 // Section header
6629 //===----------------------------------
6630
6631 uint32_t Version = readNext<uint32_t>(Pos);
6632 outs() << " Version: "
6633 << format("0x%" PRIx32"x", Version) << '\n';
6634 assert(Version == 1 && "only understand version 1")((Version == 1 && "only understand version 1") ? static_cast
<void> (0) : __assert_fail ("Version == 1 && \"only understand version 1\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6634, __PRETTY_FUNCTION__))
;
6635
6636 uint32_t CommonEncodingsStart = readNext<uint32_t>(Pos);
6637 outs() << " Common encodings array section offset: "
6638 << format("0x%" PRIx32"x", CommonEncodingsStart) << '\n';
6639 uint32_t NumCommonEncodings = readNext<uint32_t>(Pos);
6640 outs() << " Number of common encodings in array: "
6641 << format("0x%" PRIx32"x", NumCommonEncodings) << '\n';
6642
6643 uint32_t PersonalitiesStart = readNext<uint32_t>(Pos);
6644 outs() << " Personality function array section offset: "
6645 << format("0x%" PRIx32"x", PersonalitiesStart) << '\n';
6646 uint32_t NumPersonalities = readNext<uint32_t>(Pos);
6647 outs() << " Number of personality functions in array: "
6648 << format("0x%" PRIx32"x", NumPersonalities) << '\n';
6649
6650 uint32_t IndicesStart = readNext<uint32_t>(Pos);
6651 outs() << " Index array section offset: "
6652 << format("0x%" PRIx32"x", IndicesStart) << '\n';
6653 uint32_t NumIndices = readNext<uint32_t>(Pos);
6654 outs() << " Number of indices in array: "
6655 << format("0x%" PRIx32"x", NumIndices) << '\n';
6656
6657 //===----------------------------------
6658 // A shared list of common encodings
6659 //===----------------------------------
6660
6661 // These occupy indices in the range [0, N] whenever an encoding is referenced
6662 // from a compressed 2nd level index table. In practice the linker only
6663 // creates ~128 of these, so that indices are available to embed encodings in
6664 // the 2nd level index.
6665
6666 SmallVector<uint32_t, 64> CommonEncodings;
6667 outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
6668 Pos = Contents.data() + CommonEncodingsStart;
6669 for (unsigned i = 0; i < NumCommonEncodings; ++i) {
6670 uint32_t Encoding = readNext<uint32_t>(Pos);
6671 CommonEncodings.push_back(Encoding);
6672
6673 outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32"x", Encoding)
6674 << '\n';
6675 }
6676
6677 //===----------------------------------
6678 // Personality functions used in this executable
6679 //===----------------------------------
6680
6681 // There should be only a handful of these (one per source language,
6682 // roughly). Particularly since they only get 2 bits in the compact encoding.
6683
6684 outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
6685 Pos = Contents.data() + PersonalitiesStart;
6686 for (unsigned i = 0; i < NumPersonalities; ++i) {
6687 uint32_t PersonalityFn = readNext<uint32_t>(Pos);
6688 outs() << " personality[" << i + 1
6689 << "]: " << format("0x%08" PRIx32"x", PersonalityFn) << '\n';
6690 }
6691
6692 //===----------------------------------
6693 // The level 1 index entries
6694 //===----------------------------------
6695
6696 // These specify an approximate place to start searching for the more detailed
6697 // information, sorted by PC.
6698
6699 struct IndexEntry {
6700 uint32_t FunctionOffset;
6701 uint32_t SecondLevelPageStart;
6702 uint32_t LSDAStart;
6703 };
6704
6705 SmallVector<IndexEntry, 4> IndexEntries;
6706
6707 outs() << " Top level indices: (count = " << NumIndices << ")\n";
6708 Pos = Contents.data() + IndicesStart;
6709 for (unsigned i = 0; i < NumIndices; ++i) {
6710 IndexEntry Entry;
6711
6712 Entry.FunctionOffset = readNext<uint32_t>(Pos);
6713 Entry.SecondLevelPageStart = readNext<uint32_t>(Pos);
6714 Entry.LSDAStart = readNext<uint32_t>(Pos);
6715 IndexEntries.push_back(Entry);
6716
6717 outs() << " [" << i << "]: "
6718 << "function offset=" << format("0x%08" PRIx32"x", Entry.FunctionOffset)
6719 << ", "
6720 << "2nd level page offset="
6721 << format("0x%08" PRIx32"x", Entry.SecondLevelPageStart) << ", "
6722 << "LSDA offset=" << format("0x%08" PRIx32"x", Entry.LSDAStart) << '\n';
6723 }
6724
6725 //===----------------------------------
6726 // Next come the LSDA tables
6727 //===----------------------------------
6728
6729 // The LSDA layout is rather implicit: it's a contiguous array of entries from
6730 // the first top-level index's LSDAOffset to the last (sentinel).
6731
6732 outs() << " LSDA descriptors:\n";
6733 Pos = Contents.data() + IndexEntries[0].LSDAStart;
6734 int NumLSDAs = (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) /
6735 (2 * sizeof(uint32_t));
6736 for (int i = 0; i < NumLSDAs; ++i) {
6737 uint32_t FunctionOffset = readNext<uint32_t>(Pos);
6738 uint32_t LSDAOffset = readNext<uint32_t>(Pos);
6739 outs() << " [" << i << "]: "
6740 << "function offset=" << format("0x%08" PRIx32"x", FunctionOffset)
6741 << ", "
6742 << "LSDA offset=" << format("0x%08" PRIx32"x", LSDAOffset) << '\n';
6743 }
6744
6745 //===----------------------------------
6746 // Finally, the 2nd level indices
6747 //===----------------------------------
6748
6749 // Generally these are 4K in size, and have 2 possible forms:
6750 // + Regular stores up to 511 entries with disparate encodings
6751 // + Compressed stores up to 1021 entries if few enough compact encoding
6752 // values are used.
6753 outs() << " Second level indices:\n";
6754 for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
6755 // The final sentinel top-level index has no associated 2nd level page
6756 if (IndexEntries[i].SecondLevelPageStart == 0)
6757 break;
6758
6759 outs() << " Second level index[" << i << "]: "
6760 << "offset in section="
6761 << format("0x%08" PRIx32"x", IndexEntries[i].SecondLevelPageStart)
6762 << ", "
6763 << "base function offset="
6764 << format("0x%08" PRIx32"x", IndexEntries[i].FunctionOffset) << '\n';
6765
6766 Pos = Contents.data() + IndexEntries[i].SecondLevelPageStart;
6767 uint32_t Kind = *reinterpret_cast<const support::ulittle32_t *>(Pos);
6768 if (Kind == 2)
6769 printRegularSecondLevelUnwindPage(Pos);
6770 else if (Kind == 3)
6771 printCompressedSecondLevelUnwindPage(Pos, IndexEntries[i].FunctionOffset,
6772 CommonEncodings);
6773 else
6774 llvm_unreachable("Do not know how to print this kind of 2nd level page")::llvm::llvm_unreachable_internal("Do not know how to print this kind of 2nd level page"
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 6774)
;
6775 }
6776}
6777
6778void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
6779 std::map<uint64_t, SymbolRef> Symbols;
6780 for (const SymbolRef &SymRef : Obj->symbols()) {
6781 // Discard any undefined or absolute symbols. They're not going to take part
6782 // in the convenience lookup for unwind info and just take up resources.
6783 section_iterator Section = *SymRef.getSection();
6784 if (Section == Obj->section_end())
6785 continue;
6786
6787 uint64_t Addr = SymRef.getValue();
6788 Symbols.insert(std::make_pair(Addr, SymRef));
6789 }
6790
6791 for (const SectionRef &Section : Obj->sections()) {
6792 StringRef SectName;
6793 Section.getName(SectName);
6794 if (SectName == "__compact_unwind")
6795 printMachOCompactUnwindSection(Obj, Symbols, Section);
6796 else if (SectName == "__unwind_info")
6797 printMachOUnwindInfoSection(Obj, Symbols, Section);
6798 }
6799}
6800
6801static void PrintMachHeader(uint32_t magic, uint32_t cputype,
6802 uint32_t cpusubtype, uint32_t filetype,
6803 uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
6804 bool verbose) {
6805 outs() << "Mach header\n";
6806 outs() << " magic cputype cpusubtype caps filetype ncmds "
6807 "sizeofcmds flags\n";
6808 if (verbose) {
6809 if (magic == MachO::MH_MAGIC)
6810 outs() << " MH_MAGIC";
6811 else if (magic == MachO::MH_MAGIC_64)
6812 outs() << "MH_MAGIC_64";
6813 else
6814 outs() << format(" 0x%08" PRIx32"x", magic);
6815 switch (cputype) {
6816 case MachO::CPU_TYPE_I386:
6817 outs() << " I386";
6818 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6819 case MachO::CPU_SUBTYPE_I386_ALL:
6820 outs() << " ALL";
6821 break;
6822 default:
6823 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6824 break;
6825 }
6826 break;
6827 case MachO::CPU_TYPE_X86_64:
6828 outs() << " X86_64";
6829 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6830 case MachO::CPU_SUBTYPE_X86_64_ALL:
6831 outs() << " ALL";
6832 break;
6833 case MachO::CPU_SUBTYPE_X86_64_H:
6834 outs() << " Haswell";
6835 break;
6836 default:
6837 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6838 break;
6839 }
6840 break;
6841 case MachO::CPU_TYPE_ARM:
6842 outs() << " ARM";
6843 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6844 case MachO::CPU_SUBTYPE_ARM_ALL:
6845 outs() << " ALL";
6846 break;
6847 case MachO::CPU_SUBTYPE_ARM_V4T:
6848 outs() << " V4T";
6849 break;
6850 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
6851 outs() << " V5TEJ";
6852 break;
6853 case MachO::CPU_SUBTYPE_ARM_XSCALE:
6854 outs() << " XSCALE";
6855 break;
6856 case MachO::CPU_SUBTYPE_ARM_V6:
6857 outs() << " V6";
6858 break;
6859 case MachO::CPU_SUBTYPE_ARM_V6M:
6860 outs() << " V6M";
6861 break;
6862 case MachO::CPU_SUBTYPE_ARM_V7:
6863 outs() << " V7";
6864 break;
6865 case MachO::CPU_SUBTYPE_ARM_V7EM:
6866 outs() << " V7EM";
6867 break;
6868 case MachO::CPU_SUBTYPE_ARM_V7K:
6869 outs() << " V7K";
6870 break;
6871 case MachO::CPU_SUBTYPE_ARM_V7M:
6872 outs() << " V7M";
6873 break;
6874 case MachO::CPU_SUBTYPE_ARM_V7S:
6875 outs() << " V7S";
6876 break;
6877 default:
6878 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6879 break;
6880 }
6881 break;
6882 case MachO::CPU_TYPE_ARM64:
6883 outs() << " ARM64";
6884 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6885 case MachO::CPU_SUBTYPE_ARM64_ALL:
6886 outs() << " ALL";
6887 break;
6888 default:
6889 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6890 break;
6891 }
6892 break;
6893 case MachO::CPU_TYPE_POWERPC:
6894 outs() << " PPC";
6895 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6896 case MachO::CPU_SUBTYPE_POWERPC_ALL:
6897 outs() << " ALL";
6898 break;
6899 default:
6900 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6901 break;
6902 }
6903 break;
6904 case MachO::CPU_TYPE_POWERPC64:
6905 outs() << " PPC64";
6906 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
6907 case MachO::CPU_SUBTYPE_POWERPC_ALL:
6908 outs() << " ALL";
6909 break;
6910 default:
6911 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6912 break;
6913 }
6914 break;
6915 default:
6916 outs() << format(" %7d", cputype);
6917 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
6918 break;
6919 }
6920 if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {
6921 outs() << " LIB64";
6922 } else {
6923 outs() << format(" 0x%02" PRIx32"x",
6924 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
6925 }
6926 switch (filetype) {
6927 case MachO::MH_OBJECT:
6928 outs() << " OBJECT";
6929 break;
6930 case MachO::MH_EXECUTE:
6931 outs() << " EXECUTE";
6932 break;
6933 case MachO::MH_FVMLIB:
6934 outs() << " FVMLIB";
6935 break;
6936 case MachO::MH_CORE:
6937 outs() << " CORE";
6938 break;
6939 case MachO::MH_PRELOAD:
6940 outs() << " PRELOAD";
6941 break;
6942 case MachO::MH_DYLIB:
6943 outs() << " DYLIB";
6944 break;
6945 case MachO::MH_DYLIB_STUB:
6946 outs() << " DYLIB_STUB";
6947 break;
6948 case MachO::MH_DYLINKER:
6949 outs() << " DYLINKER";
6950 break;
6951 case MachO::MH_BUNDLE:
6952 outs() << " BUNDLE";
6953 break;
6954 case MachO::MH_DSYM:
6955 outs() << " DSYM";
6956 break;
6957 case MachO::MH_KEXT_BUNDLE:
6958 outs() << " KEXTBUNDLE";
6959 break;
6960 default:
6961 outs() << format(" %10u", filetype);
6962 break;
6963 }
6964 outs() << format(" %5u", ncmds);
6965 outs() << format(" %10u", sizeofcmds);
6966 uint32_t f = flags;
6967 if (f & MachO::MH_NOUNDEFS) {
6968 outs() << " NOUNDEFS";
6969 f &= ~MachO::MH_NOUNDEFS;
6970 }
6971 if (f & MachO::MH_INCRLINK) {
6972 outs() << " INCRLINK";
6973 f &= ~MachO::MH_INCRLINK;
6974 }
6975 if (f & MachO::MH_DYLDLINK) {
6976 outs() << " DYLDLINK";
6977 f &= ~MachO::MH_DYLDLINK;
6978 }
6979 if (f & MachO::MH_BINDATLOAD) {
6980 outs() << " BINDATLOAD";
6981 f &= ~MachO::MH_BINDATLOAD;
6982 }
6983 if (f & MachO::MH_PREBOUND) {
6984 outs() << " PREBOUND";
6985 f &= ~MachO::MH_PREBOUND;
6986 }
6987 if (f & MachO::MH_SPLIT_SEGS) {
6988 outs() << " SPLIT_SEGS";
6989 f &= ~MachO::MH_SPLIT_SEGS;
6990 }
6991 if (f & MachO::MH_LAZY_INIT) {
6992 outs() << " LAZY_INIT";
6993 f &= ~MachO::MH_LAZY_INIT;
6994 }
6995 if (f & MachO::MH_TWOLEVEL) {
6996 outs() << " TWOLEVEL";
6997 f &= ~MachO::MH_TWOLEVEL;
6998 }
6999 if (f & MachO::MH_FORCE_FLAT) {
7000 outs() << " FORCE_FLAT";
7001 f &= ~MachO::MH_FORCE_FLAT;
7002 }
7003 if (f & MachO::MH_NOMULTIDEFS) {
7004 outs() << " NOMULTIDEFS";
7005 f &= ~MachO::MH_NOMULTIDEFS;
7006 }
7007 if (f & MachO::MH_NOFIXPREBINDING) {
7008 outs() << " NOFIXPREBINDING";
7009 f &= ~MachO::MH_NOFIXPREBINDING;
7010 }
7011 if (f & MachO::MH_PREBINDABLE) {
7012 outs() << " PREBINDABLE";
7013 f &= ~MachO::MH_PREBINDABLE;
7014 }
7015 if (f & MachO::MH_ALLMODSBOUND) {
7016 outs() << " ALLMODSBOUND";
7017 f &= ~MachO::MH_ALLMODSBOUND;
7018 }
7019 if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
7020 outs() << " SUBSECTIONS_VIA_SYMBOLS";
7021 f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
7022 }
7023 if (f & MachO::MH_CANONICAL) {
7024 outs() << " CANONICAL";
7025 f &= ~MachO::MH_CANONICAL;
7026 }
7027 if (f & MachO::MH_WEAK_DEFINES) {
7028 outs() << " WEAK_DEFINES";
7029 f &= ~MachO::MH_WEAK_DEFINES;
7030 }
7031 if (f & MachO::MH_BINDS_TO_WEAK) {
7032 outs() << " BINDS_TO_WEAK";
7033 f &= ~MachO::MH_BINDS_TO_WEAK;
7034 }
7035 if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
7036 outs() << " ALLOW_STACK_EXECUTION";
7037 f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
7038 }
7039 if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
7040 outs() << " DEAD_STRIPPABLE_DYLIB";
7041 f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
7042 }
7043 if (f & MachO::MH_PIE) {
7044 outs() << " PIE";
7045 f &= ~MachO::MH_PIE;
7046 }
7047 if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
7048 outs() << " NO_REEXPORTED_DYLIBS";
7049 f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
7050 }
7051 if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
7052 outs() << " MH_HAS_TLV_DESCRIPTORS";
7053 f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
7054 }
7055 if (f & MachO::MH_NO_HEAP_EXECUTION) {
7056 outs() << " MH_NO_HEAP_EXECUTION";
7057 f &= ~MachO::MH_NO_HEAP_EXECUTION;
7058 }
7059 if (f & MachO::MH_APP_EXTENSION_SAFE) {
7060 outs() << " APP_EXTENSION_SAFE";
7061 f &= ~MachO::MH_APP_EXTENSION_SAFE;
7062 }
7063 if (f != 0 || flags == 0)
7064 outs() << format(" 0x%08" PRIx32"x", f);
7065 } else {
7066 outs() << format(" 0x%08" PRIx32"x", magic);
7067 outs() << format(" %7d", cputype);
7068 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
7069 outs() << format(" 0x%02" PRIx32"x",
7070 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
7071 outs() << format(" %10u", filetype);
7072 outs() << format(" %5u", ncmds);
7073 outs() << format(" %10u", sizeofcmds);
7074 outs() << format(" 0x%08" PRIx32"x", flags);
7075 }
7076 outs() << "\n";
7077}
7078
7079static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
7080 StringRef SegName, uint64_t vmaddr,
7081 uint64_t vmsize, uint64_t fileoff,
7082 uint64_t filesize, uint32_t maxprot,
7083 uint32_t initprot, uint32_t nsects,
7084 uint32_t flags, uint32_t object_size,
7085 bool verbose) {
7086 uint64_t expected_cmdsize;
7087 if (cmd == MachO::LC_SEGMENT) {
7088 outs() << " cmd LC_SEGMENT\n";
7089 expected_cmdsize = nsects;
7090 expected_cmdsize *= sizeof(struct MachO::section);
7091 expected_cmdsize += sizeof(struct MachO::segment_command);
7092 } else {
7093 outs() << " cmd LC_SEGMENT_64\n";
7094 expected_cmdsize = nsects;
7095 expected_cmdsize *= sizeof(struct MachO::section_64);
7096 expected_cmdsize += sizeof(struct MachO::segment_command_64);
7097 }
7098 outs() << " cmdsize " << cmdsize;
7099 if (cmdsize != expected_cmdsize)
7100 outs() << " Inconsistent size\n";
7101 else
7102 outs() << "\n";
7103 outs() << " segname " << SegName << "\n";
7104 if (cmd == MachO::LC_SEGMENT_64) {
7105 outs() << " vmaddr " << format("0x%016" PRIx64"l" "x", vmaddr) << "\n";
7106 outs() << " vmsize " << format("0x%016" PRIx64"l" "x", vmsize) << "\n";
7107 } else {
7108 outs() << " vmaddr " << format("0x%08" PRIx64"l" "x", vmaddr) << "\n";
7109 outs() << " vmsize " << format("0x%08" PRIx64"l" "x", vmsize) << "\n";
7110 }
7111 outs() << " fileoff " << fileoff;
7112 if (fileoff > object_size)
7113 outs() << " (past end of file)\n";
7114 else
7115 outs() << "\n";
7116 outs() << " filesize " << filesize;
7117 if (fileoff + filesize > object_size)
7118 outs() << " (past end of file)\n";
7119 else
7120 outs() << "\n";
7121 if (verbose) {
7122 if ((maxprot &
7123 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
7124 MachO::VM_PROT_EXECUTE)) != 0)
7125 outs() << " maxprot ?" << format("0x%08" PRIx32"x", maxprot) << "\n";
7126 else {
7127 outs() << " maxprot ";
7128 outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");
7129 outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");
7130 outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
7131 }
7132 if ((initprot &
7133 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
7134 MachO::VM_PROT_EXECUTE)) != 0)
7135 outs() << " initprot ?" << format("0x%08" PRIx32"x", initprot) << "\n";
7136 else {
7137 outs() << " initprot ";
7138 outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");
7139 outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");
7140 outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
7141 }
7142 } else {
7143 outs() << " maxprot " << format("0x%08" PRIx32"x", maxprot) << "\n";
7144 outs() << " initprot " << format("0x%08" PRIx32"x", initprot) << "\n";
7145 }
7146 outs() << " nsects " << nsects << "\n";
7147 if (verbose) {
7148 outs() << " flags";
7149 if (flags == 0)
7150 outs() << " (none)\n";
7151 else {
7152 if (flags & MachO::SG_HIGHVM) {
7153 outs() << " HIGHVM";
7154 flags &= ~MachO::SG_HIGHVM;
7155 }
7156 if (flags & MachO::SG_FVMLIB) {
7157 outs() << " FVMLIB";
7158 flags &= ~MachO::SG_FVMLIB;
7159 }
7160 if (flags & MachO::SG_NORELOC) {
7161 outs() << " NORELOC";
7162 flags &= ~MachO::SG_NORELOC;
7163 }
7164 if (flags & MachO::SG_PROTECTED_VERSION_1) {
7165 outs() << " PROTECTED_VERSION_1";
7166 flags &= ~MachO::SG_PROTECTED_VERSION_1;
7167 }
7168 if (flags)
7169 outs() << format(" 0x%08" PRIx32"x", flags) << " (unknown flags)\n";
7170 else
7171 outs() << "\n";
7172 }
7173 } else {
7174 outs() << " flags " << format("0x%" PRIx32"x", flags) << "\n";
7175 }
7176}
7177
7178static void PrintSection(const char *sectname, const char *segname,
7179 uint64_t addr, uint64_t size, uint32_t offset,
7180 uint32_t align, uint32_t reloff, uint32_t nreloc,
7181 uint32_t flags, uint32_t reserved1, uint32_t reserved2,
7182 uint32_t cmd, const char *sg_segname,
7183 uint32_t filetype, uint32_t object_size,
7184 bool verbose) {
7185 outs() << "Section\n";
7186 outs() << " sectname " << format("%.16s\n", sectname);
7187 outs() << " segname " << format("%.16s", segname);
7188 if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)
7189 outs() << " (does not match segment)\n";
7190 else
7191 outs() << "\n";
7192 if (cmd == MachO::LC_SEGMENT_64) {
7193 outs() << " addr " << format("0x%016" PRIx64"l" "x", addr) << "\n";
7194 outs() << " size " << format("0x%016" PRIx64"l" "x", size);
7195 } else {
7196 outs() << " addr " << format("0x%08" PRIx64"l" "x", addr) << "\n";
7197 outs() << " size " << format("0x%08" PRIx64"l" "x", size);
7198 }
7199 if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
7200 outs() << " (past end of file)\n";
7201 else
7202 outs() << "\n";
7203 outs() << " offset " << offset;
7204 if (offset > object_size)
7205 outs() << " (past end of file)\n";
7206 else
7207 outs() << "\n";
7208 uint32_t align_shifted = 1 << align;
7209 outs() << " align 2^" << align << " (" << align_shifted << ")\n";
7210 outs() << " reloff " << reloff;
7211 if (reloff > object_size)
7212 outs() << " (past end of file)\n";
7213 else
7214 outs() << "\n";
7215 outs() << " nreloc " << nreloc;
7216 if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
7217 outs() << " (past end of file)\n";
7218 else
7219 outs() << "\n";
7220 uint32_t section_type = flags & MachO::SECTION_TYPE;
7221 if (verbose) {
7222 outs() << " type";
7223 if (section_type == MachO::S_REGULAR)
7224 outs() << " S_REGULAR\n";
7225 else if (section_type == MachO::S_ZEROFILL)
7226 outs() << " S_ZEROFILL\n";
7227 else if (section_type == MachO::S_CSTRING_LITERALS)
7228 outs() << " S_CSTRING_LITERALS\n";
7229 else if (section_type == MachO::S_4BYTE_LITERALS)
7230 outs() << " S_4BYTE_LITERALS\n";
7231 else if (section_type == MachO::S_8BYTE_LITERALS)
7232 outs() << " S_8BYTE_LITERALS\n";
7233 else if (section_type == MachO::S_16BYTE_LITERALS)
7234 outs() << " S_16BYTE_LITERALS\n";
7235 else if (section_type == MachO::S_LITERAL_POINTERS)
7236 outs() << " S_LITERAL_POINTERS\n";
7237 else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
7238 outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
7239 else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
7240 outs() << " S_LAZY_SYMBOL_POINTERS\n";
7241 else if (section_type == MachO::S_SYMBOL_STUBS)
7242 outs() << " S_SYMBOL_STUBS\n";
7243 else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
7244 outs() << " S_MOD_INIT_FUNC_POINTERS\n";
7245 else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
7246 outs() << " S_MOD_TERM_FUNC_POINTERS\n";
7247 else if (section_type == MachO::S_COALESCED)
7248 outs() << " S_COALESCED\n";
7249 else if (section_type == MachO::S_INTERPOSING)
7250 outs() << " S_INTERPOSING\n";
7251 else if (section_type == MachO::S_DTRACE_DOF)
7252 outs() << " S_DTRACE_DOF\n";
7253 else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
7254 outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
7255 else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
7256 outs() << " S_THREAD_LOCAL_REGULAR\n";
7257 else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
7258 outs() << " S_THREAD_LOCAL_ZEROFILL\n";
7259 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
7260 outs() << " S_THREAD_LOCAL_VARIABLES\n";
7261 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
7262 outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
7263 else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
7264 outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
7265 else
7266 outs() << format("0x%08" PRIx32"x", section_type) << "\n";
7267 outs() << "attributes";
7268 uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
7269 if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
7270 outs() << " PURE_INSTRUCTIONS";
7271 if (section_attributes & MachO::S_ATTR_NO_TOC)
7272 outs() << " NO_TOC";
7273 if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
7274 outs() << " STRIP_STATIC_SYMS";
7275 if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
7276 outs() << " NO_DEAD_STRIP";
7277 if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
7278 outs() << " LIVE_SUPPORT";
7279 if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
7280 outs() << " SELF_MODIFYING_CODE";
7281 if (section_attributes & MachO::S_ATTR_DEBUG)
7282 outs() << " DEBUG";
7283 if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
7284 outs() << " SOME_INSTRUCTIONS";
7285 if (section_attributes & MachO::S_ATTR_EXT_RELOC)
7286 outs() << " EXT_RELOC";
7287 if (section_attributes & MachO::S_ATTR_LOC_RELOC)
7288 outs() << " LOC_RELOC";
7289 if (section_attributes == 0)
7290 outs() << " (none)";
7291 outs() << "\n";
7292 } else
7293 outs() << " flags " << format("0x%08" PRIx32"x", flags) << "\n";
7294 outs() << " reserved1 " << reserved1;
7295 if (section_type == MachO::S_SYMBOL_STUBS ||
7296 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
7297 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
7298 section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
7299 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
7300 outs() << " (index into indirect symbol table)\n";
7301 else
7302 outs() << "\n";
7303 outs() << " reserved2 " << reserved2;
7304 if (section_type == MachO::S_SYMBOL_STUBS)
7305 outs() << " (size of stubs)\n";
7306 else
7307 outs() << "\n";
7308}
7309
7310static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
7311 uint32_t object_size) {
7312 outs() << " cmd LC_SYMTAB\n";
7313 outs() << " cmdsize " << st.cmdsize;
7314 if (st.cmdsize != sizeof(struct MachO::symtab_command))
7315 outs() << " Incorrect size\n";
7316 else
7317 outs() << "\n";
7318 outs() << " symoff " << st.symoff;
7319 if (st.symoff > object_size)
7320 outs() << " (past end of file)\n";
7321 else
7322 outs() << "\n";
7323 outs() << " nsyms " << st.nsyms;
7324 uint64_t big_size;
7325 if (Is64Bit) {
7326 big_size = st.nsyms;
7327 big_size *= sizeof(struct MachO::nlist_64);
7328 big_size += st.symoff;
7329 if (big_size > object_size)
7330 outs() << " (past end of file)\n";
7331 else
7332 outs() << "\n";
7333 } else {
7334 big_size = st.nsyms;
7335 big_size *= sizeof(struct MachO::nlist);
7336 big_size += st.symoff;
7337 if (big_size > object_size)
7338 outs() << " (past end of file)\n";
7339 else
7340 outs() << "\n";
7341 }
7342 outs() << " stroff " << st.stroff;
7343 if (st.stroff > object_size)
7344 outs() << " (past end of file)\n";
7345 else
7346 outs() << "\n";
7347 outs() << " strsize " << st.strsize;
7348 big_size = st.stroff;
7349 big_size += st.strsize;
7350 if (big_size > object_size)
7351 outs() << " (past end of file)\n";
7352 else
7353 outs() << "\n";
7354}
7355
7356static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
7357 uint32_t nsyms, uint32_t object_size,
7358 bool Is64Bit) {
7359 outs() << " cmd LC_DYSYMTAB\n";
7360 outs() << " cmdsize " << dyst.cmdsize;
7361 if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
7362 outs() << " Incorrect size\n";
7363 else
7364 outs() << "\n";
7365 outs() << " ilocalsym " << dyst.ilocalsym;
7366 if (dyst.ilocalsym > nsyms)
7367 outs() << " (greater than the number of symbols)\n";
7368 else
7369 outs() << "\n";
7370 outs() << " nlocalsym " << dyst.nlocalsym;
7371 uint64_t big_size;
7372 big_size = dyst.ilocalsym;
7373 big_size += dyst.nlocalsym;
7374 if (big_size > nsyms)
7375 outs() << " (past the end of the symbol table)\n";
7376 else
7377 outs() << "\n";
7378 outs() << " iextdefsym " << dyst.iextdefsym;
7379 if (dyst.iextdefsym > nsyms)
7380 outs() << " (greater than the number of symbols)\n";
7381 else
7382 outs() << "\n";
7383 outs() << " nextdefsym " << dyst.nextdefsym;
7384 big_size = dyst.iextdefsym;
7385 big_size += dyst.nextdefsym;
7386 if (big_size > nsyms)
7387 outs() << " (past the end of the symbol table)\n";
7388 else
7389 outs() << "\n";
7390 outs() << " iundefsym " << dyst.iundefsym;
7391 if (dyst.iundefsym > nsyms)
7392 outs() << " (greater than the number of symbols)\n";
7393 else
7394 outs() << "\n";
7395 outs() << " nundefsym " << dyst.nundefsym;
7396 big_size = dyst.iundefsym;
7397 big_size += dyst.nundefsym;
7398 if (big_size > nsyms)
7399 outs() << " (past the end of the symbol table)\n";
7400 else
7401 outs() << "\n";
7402 outs() << " tocoff " << dyst.tocoff;
7403 if (dyst.tocoff > object_size)
7404 outs() << " (past end of file)\n";
7405 else
7406 outs() << "\n";
7407 outs() << " ntoc " << dyst.ntoc;
7408 big_size = dyst.ntoc;
7409 big_size *= sizeof(struct MachO::dylib_table_of_contents);
7410 big_size += dyst.tocoff;
7411 if (big_size > object_size)
7412 outs() << " (past end of file)\n";
7413 else
7414 outs() << "\n";
7415 outs() << " modtaboff " << dyst.modtaboff;
7416 if (dyst.modtaboff > object_size)
7417 outs() << " (past end of file)\n";
7418 else
7419 outs() << "\n";
7420 outs() << " nmodtab " << dyst.nmodtab;
7421 uint64_t modtabend;
7422 if (Is64Bit) {
7423 modtabend = dyst.nmodtab;
7424 modtabend *= sizeof(struct MachO::dylib_module_64);
7425 modtabend += dyst.modtaboff;
7426 } else {
7427 modtabend = dyst.nmodtab;
7428 modtabend *= sizeof(struct MachO::dylib_module);
7429 modtabend += dyst.modtaboff;
7430 }
7431 if (modtabend > object_size)
7432 outs() << " (past end of file)\n";
7433 else
7434 outs() << "\n";
7435 outs() << " extrefsymoff " << dyst.extrefsymoff;
7436 if (dyst.extrefsymoff > object_size)
7437 outs() << " (past end of file)\n";
7438 else
7439 outs() << "\n";
7440 outs() << " nextrefsyms " << dyst.nextrefsyms;
7441 big_size = dyst.nextrefsyms;
7442 big_size *= sizeof(struct MachO::dylib_reference);
7443 big_size += dyst.extrefsymoff;
7444 if (big_size > object_size)
7445 outs() << " (past end of file)\n";
7446 else
7447 outs() << "\n";
7448 outs() << " indirectsymoff " << dyst.indirectsymoff;
7449 if (dyst.indirectsymoff > object_size)
7450 outs() << " (past end of file)\n";
7451 else
7452 outs() << "\n";
7453 outs() << " nindirectsyms " << dyst.nindirectsyms;
7454 big_size = dyst.nindirectsyms;
7455 big_size *= sizeof(uint32_t);
7456 big_size += dyst.indirectsymoff;
7457 if (big_size > object_size)
7458 outs() << " (past end of file)\n";
7459 else
7460 outs() << "\n";
7461 outs() << " extreloff " << dyst.extreloff;
7462 if (dyst.extreloff > object_size)
7463 outs() << " (past end of file)\n";
7464 else
7465 outs() << "\n";
7466 outs() << " nextrel " << dyst.nextrel;
7467 big_size = dyst.nextrel;
7468 big_size *= sizeof(struct MachO::relocation_info);
7469 big_size += dyst.extreloff;
7470 if (big_size > object_size)
7471 outs() << " (past end of file)\n";
7472 else
7473 outs() << "\n";
7474 outs() << " locreloff " << dyst.locreloff;
7475 if (dyst.locreloff > object_size)
7476 outs() << " (past end of file)\n";
7477 else
7478 outs() << "\n";
7479 outs() << " nlocrel " << dyst.nlocrel;
7480 big_size = dyst.nlocrel;
7481 big_size *= sizeof(struct MachO::relocation_info);
7482 big_size += dyst.locreloff;
7483 if (big_size > object_size)
7484 outs() << " (past end of file)\n";
7485 else
7486 outs() << "\n";
7487}
7488
7489static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
7490 uint32_t object_size) {
7491 if (dc.cmd == MachO::LC_DYLD_INFO)
7492 outs() << " cmd LC_DYLD_INFO\n";
7493 else
7494 outs() << " cmd LC_DYLD_INFO_ONLY\n";
7495 outs() << " cmdsize " << dc.cmdsize;
7496 if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
7497 outs() << " Incorrect size\n";
7498 else
7499 outs() << "\n";
7500 outs() << " rebase_off " << dc.rebase_off;
7501 if (dc.rebase_off > object_size)
7502 outs() << " (past end of file)\n";
7503 else
7504 outs() << "\n";
7505 outs() << " rebase_size " << dc.rebase_size;
7506 uint64_t big_size;
7507 big_size = dc.rebase_off;
7508 big_size += dc.rebase_size;
7509 if (big_size > object_size)
7510 outs() << " (past end of file)\n";
7511 else
7512 outs() << "\n";
7513 outs() << " bind_off " << dc.bind_off;
7514 if (dc.bind_off > object_size)
7515 outs() << " (past end of file)\n";
7516 else
7517 outs() << "\n";
7518 outs() << " bind_size " << dc.bind_size;
7519 big_size = dc.bind_off;
7520 big_size += dc.bind_size;
7521 if (big_size > object_size)
7522 outs() << " (past end of file)\n";
7523 else
7524 outs() << "\n";
7525 outs() << " weak_bind_off " << dc.weak_bind_off;
7526 if (dc.weak_bind_off > object_size)
7527 outs() << " (past end of file)\n";
7528 else
7529 outs() << "\n";
7530 outs() << " weak_bind_size " << dc.weak_bind_size;
7531 big_size = dc.weak_bind_off;
7532 big_size += dc.weak_bind_size;
7533 if (big_size > object_size)
7534 outs() << " (past end of file)\n";
7535 else
7536 outs() << "\n";
7537 outs() << " lazy_bind_off " << dc.lazy_bind_off;
7538 if (dc.lazy_bind_off > object_size)
7539 outs() << " (past end of file)\n";
7540 else
7541 outs() << "\n";
7542 outs() << " lazy_bind_size " << dc.lazy_bind_size;
7543 big_size = dc.lazy_bind_off;
7544 big_size += dc.lazy_bind_size;
7545 if (big_size > object_size)
7546 outs() << " (past end of file)\n";
7547 else
7548 outs() << "\n";
7549 outs() << " export_off " << dc.export_off;
7550 if (dc.export_off > object_size)
7551 outs() << " (past end of file)\n";
7552 else
7553 outs() << "\n";
7554 outs() << " export_size " << dc.export_size;
7555 big_size = dc.export_off;
7556 big_size += dc.export_size;
7557 if (big_size > object_size)
7558 outs() << " (past end of file)\n";
7559 else
7560 outs() << "\n";
7561}
7562
7563static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
7564 const char *Ptr) {
7565 if (dyld.cmd == MachO::LC_ID_DYLINKER)
7566 outs() << " cmd LC_ID_DYLINKER\n";
7567 else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
7568 outs() << " cmd LC_LOAD_DYLINKER\n";
7569 else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
7570 outs() << " cmd LC_DYLD_ENVIRONMENT\n";
7571 else
7572 outs() << " cmd ?(" << dyld.cmd << ")\n";
7573 outs() << " cmdsize " << dyld.cmdsize;
7574 if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
7575 outs() << " Incorrect size\n";
7576 else
7577 outs() << "\n";
7578 if (dyld.name >= dyld.cmdsize)
7579 outs() << " name ?(bad offset " << dyld.name << ")\n";
7580 else {
7581 const char *P = (const char *)(Ptr) + dyld.name;
7582 outs() << " name " << P << " (offset " << dyld.name << ")\n";
7583 }
7584}
7585
7586static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
7587 outs() << " cmd LC_UUID\n";
7588 outs() << " cmdsize " << uuid.cmdsize;
7589 if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
7590 outs() << " Incorrect size\n";
7591 else
7592 outs() << "\n";
7593 outs() << " uuid ";
7594 for (int i = 0; i < 16; ++i) {
7595 outs() << format("%02" PRIX32"X", uuid.uuid[i]);
7596 if (i == 3 || i == 5 || i == 7 || i == 9)
7597 outs() << "-";
7598 }
7599 outs() << "\n";
7600}
7601
7602static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
7603 outs() << " cmd LC_RPATH\n";
7604 outs() << " cmdsize " << rpath.cmdsize;
7605 if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
7606 outs() << " Incorrect size\n";
7607 else
7608 outs() << "\n";
7609 if (rpath.path >= rpath.cmdsize)
7610 outs() << " path ?(bad offset " << rpath.path << ")\n";
7611 else {
7612 const char *P = (const char *)(Ptr) + rpath.path;
7613 outs() << " path " << P << " (offset " << rpath.path << ")\n";
7614 }
7615}
7616
7617static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
7618 StringRef LoadCmdName;
7619 switch (vd.cmd) {
7620 case MachO::LC_VERSION_MIN_MACOSX:
7621 LoadCmdName = "LC_VERSION_MIN_MACOSX";
7622 break;
7623 case MachO::LC_VERSION_MIN_IPHONEOS:
7624 LoadCmdName = "LC_VERSION_MIN_IPHONEOS";
7625 break;
7626 case MachO::LC_VERSION_MIN_TVOS:
7627 LoadCmdName = "LC_VERSION_MIN_TVOS";
7628 break;
7629 case MachO::LC_VERSION_MIN_WATCHOS:
7630 LoadCmdName = "LC_VERSION_MIN_WATCHOS";
7631 break;
7632 default:
7633 llvm_unreachable("Unknown version min load command")::llvm::llvm_unreachable_internal("Unknown version min load command"
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 7633)
;
7634 }
7635
7636 outs() << " cmd " << LoadCmdName << '\n';
7637 outs() << " cmdsize " << vd.cmdsize;
7638 if (vd.cmdsize != sizeof(struct MachO::version_min_command))
7639 outs() << " Incorrect size\n";
7640 else
7641 outs() << "\n";
7642 outs() << " version "
7643 << MachOObjectFile::getVersionMinMajor(vd, false) << "."
7644 << MachOObjectFile::getVersionMinMinor(vd, false);
7645 uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);
7646 if (Update != 0)
7647 outs() << "." << Update;
7648 outs() << "\n";
7649 if (vd.sdk == 0)
7650 outs() << " sdk n/a";
7651 else {
7652 outs() << " sdk "
7653 << MachOObjectFile::getVersionMinMajor(vd, true) << "."
7654 << MachOObjectFile::getVersionMinMinor(vd, true);
7655 }
7656 Update = MachOObjectFile::getVersionMinUpdate(vd, true);
7657 if (Update != 0)
7658 outs() << "." << Update;
7659 outs() << "\n";
7660}
7661
7662static void PrintSourceVersionCommand(MachO::source_version_command sd) {
7663 outs() << " cmd LC_SOURCE_VERSION\n";
7664 outs() << " cmdsize " << sd.cmdsize;
7665 if (sd.cmdsize != sizeof(struct MachO::source_version_command))
7666 outs() << " Incorrect size\n";
7667 else
7668 outs() << "\n";
7669 uint64_t a = (sd.version >> 40) & 0xffffff;
7670 uint64_t b = (sd.version >> 30) & 0x3ff;
7671 uint64_t c = (sd.version >> 20) & 0x3ff;
7672 uint64_t d = (sd.version >> 10) & 0x3ff;
7673 uint64_t e = sd.version & 0x3ff;
7674 outs() << " version " << a << "." << b;
7675 if (e != 0)
7676 outs() << "." << c << "." << d << "." << e;
7677 else if (d != 0)
7678 outs() << "." << c << "." << d;
7679 else if (c != 0)
7680 outs() << "." << c;
7681 outs() << "\n";
7682}
7683
7684static void PrintEntryPointCommand(MachO::entry_point_command ep) {
7685 outs() << " cmd LC_MAIN\n";
7686 outs() << " cmdsize " << ep.cmdsize;
7687 if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
7688 outs() << " Incorrect size\n";
7689 else
7690 outs() << "\n";
7691 outs() << " entryoff " << ep.entryoff << "\n";
7692 outs() << " stacksize " << ep.stacksize << "\n";
7693}
7694
7695static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
7696 uint32_t object_size) {
7697 outs() << " cmd LC_ENCRYPTION_INFO\n";
7698 outs() << " cmdsize " << ec.cmdsize;
7699 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
7700 outs() << " Incorrect size\n";
7701 else
7702 outs() << "\n";
7703 outs() << " cryptoff " << ec.cryptoff;
7704 if (ec.cryptoff > object_size)
7705 outs() << " (past end of file)\n";
7706 else
7707 outs() << "\n";
7708 outs() << " cryptsize " << ec.cryptsize;
7709 if (ec.cryptsize > object_size)
7710 outs() << " (past end of file)\n";
7711 else
7712 outs() << "\n";
7713 outs() << " cryptid " << ec.cryptid << "\n";
7714}
7715
7716static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
7717 uint32_t object_size) {
7718 outs() << " cmd LC_ENCRYPTION_INFO_64\n";
7719 outs() << " cmdsize " << ec.cmdsize;
7720 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
7721 outs() << " Incorrect size\n";
7722 else
7723 outs() << "\n";
7724 outs() << " cryptoff " << ec.cryptoff;
7725 if (ec.cryptoff > object_size)
7726 outs() << " (past end of file)\n";
7727 else
7728 outs() << "\n";
7729 outs() << " cryptsize " << ec.cryptsize;
7730 if (ec.cryptsize > object_size)
7731 outs() << " (past end of file)\n";
7732 else
7733 outs() << "\n";
7734 outs() << " cryptid " << ec.cryptid << "\n";
7735 outs() << " pad " << ec.pad << "\n";
7736}
7737
7738static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
7739 const char *Ptr) {
7740 outs() << " cmd LC_LINKER_OPTION\n";
7741 outs() << " cmdsize " << lo.cmdsize;
7742 if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
7743 outs() << " Incorrect size\n";
7744 else
7745 outs() << "\n";
7746 outs() << " count " << lo.count << "\n";
7747 const char *string = Ptr + sizeof(struct MachO::linker_option_command);
7748 uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
7749 uint32_t i = 0;
7750 while (left > 0) {
7751 while (*string == '\0' && left > 0) {
7752 string++;
7753 left--;
7754 }
7755 if (left > 0) {
7756 i++;
7757 outs() << " string #" << i << " " << format("%.*s\n", left, string);
7758 uint32_t NullPos = StringRef(string, left).find('\0');
7759 uint32_t len = std::min(NullPos, left) + 1;
7760 string += len;
7761 left -= len;
7762 }
7763 }
7764 if (lo.count != i)
7765 outs() << " count " << lo.count << " does not match number of strings "
7766 << i << "\n";
7767}
7768
7769static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
7770 const char *Ptr) {
7771 outs() << " cmd LC_SUB_FRAMEWORK\n";
7772 outs() << " cmdsize " << sub.cmdsize;
7773 if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
7774 outs() << " Incorrect size\n";
7775 else
7776 outs() << "\n";
7777 if (sub.umbrella < sub.cmdsize) {
7778 const char *P = Ptr + sub.umbrella;
7779 outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
7780 } else {
7781 outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
7782 }
7783}
7784
7785static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
7786 const char *Ptr) {
7787 outs() << " cmd LC_SUB_UMBRELLA\n";
7788 outs() << " cmdsize " << sub.cmdsize;
7789 if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
7790 outs() << " Incorrect size\n";
7791 else
7792 outs() << "\n";
7793 if (sub.sub_umbrella < sub.cmdsize) {
7794 const char *P = Ptr + sub.sub_umbrella;
7795 outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
7796 } else {
7797 outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
7798 }
7799}
7800
7801static void PrintSubLibraryCommand(MachO::sub_library_command sub,
7802 const char *Ptr) {
7803 outs() << " cmd LC_SUB_LIBRARY\n";
7804 outs() << " cmdsize " << sub.cmdsize;
7805 if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
7806 outs() << " Incorrect size\n";
7807 else
7808 outs() << "\n";
7809 if (sub.sub_library < sub.cmdsize) {
7810 const char *P = Ptr + sub.sub_library;
7811 outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
7812 } else {
7813 outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
7814 }
7815}
7816
7817static void PrintSubClientCommand(MachO::sub_client_command sub,
7818 const char *Ptr) {
7819 outs() << " cmd LC_SUB_CLIENT\n";
7820 outs() << " cmdsize " << sub.cmdsize;
7821 if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
7822 outs() << " Incorrect size\n";
7823 else
7824 outs() << "\n";
7825 if (sub.client < sub.cmdsize) {
7826 const char *P = Ptr + sub.client;
7827 outs() << " client " << P << " (offset " << sub.client << ")\n";
7828 } else {
7829 outs() << " client ?(bad offset " << sub.client << ")\n";
7830 }
7831}
7832
7833static void PrintRoutinesCommand(MachO::routines_command r) {
7834 outs() << " cmd LC_ROUTINES\n";
7835 outs() << " cmdsize " << r.cmdsize;
7836 if (r.cmdsize != sizeof(struct MachO::routines_command))
7837 outs() << " Incorrect size\n";
7838 else
7839 outs() << "\n";
7840 outs() << " init_address " << format("0x%08" PRIx32"x", r.init_address) << "\n";
7841 outs() << " init_module " << r.init_module << "\n";
7842 outs() << " reserved1 " << r.reserved1 << "\n";
7843 outs() << " reserved2 " << r.reserved2 << "\n";
7844 outs() << " reserved3 " << r.reserved3 << "\n";
7845 outs() << " reserved4 " << r.reserved4 << "\n";
7846 outs() << " reserved5 " << r.reserved5 << "\n";
7847 outs() << " reserved6 " << r.reserved6 << "\n";
7848}
7849
7850static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
7851 outs() << " cmd LC_ROUTINES_64\n";
7852 outs() << " cmdsize " << r.cmdsize;
7853 if (r.cmdsize != sizeof(struct MachO::routines_command_64))
7854 outs() << " Incorrect size\n";
7855 else
7856 outs() << "\n";
7857 outs() << " init_address " << format("0x%016" PRIx64"l" "x", r.init_address) << "\n";
7858 outs() << " init_module " << r.init_module << "\n";
7859 outs() << " reserved1 " << r.reserved1 << "\n";
7860 outs() << " reserved2 " << r.reserved2 << "\n";
7861 outs() << " reserved3 " << r.reserved3 << "\n";
7862 outs() << " reserved4 " << r.reserved4 << "\n";
7863 outs() << " reserved5 " << r.reserved5 << "\n";
7864 outs() << " reserved6 " << r.reserved6 << "\n";
7865}
7866
7867static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
7868 outs() << " rax " << format("0x%016" PRIx64"l" "x", cpu64.rax);
7869 outs() << " rbx " << format("0x%016" PRIx64"l" "x", cpu64.rbx);
7870 outs() << " rcx " << format("0x%016" PRIx64"l" "x", cpu64.rcx) << "\n";
7871 outs() << " rdx " << format("0x%016" PRIx64"l" "x", cpu64.rdx);
7872 outs() << " rdi " << format("0x%016" PRIx64"l" "x", cpu64.rdi);
7873 outs() << " rsi " << format("0x%016" PRIx64"l" "x", cpu64.rsi) << "\n";
7874 outs() << " rbp " << format("0x%016" PRIx64"l" "x", cpu64.rbp);
7875 outs() << " rsp " << format("0x%016" PRIx64"l" "x", cpu64.rsp);
7876 outs() << " r8 " << format("0x%016" PRIx64"l" "x", cpu64.r8) << "\n";
7877 outs() << " r9 " << format("0x%016" PRIx64"l" "x", cpu64.r9);
7878 outs() << " r10 " << format("0x%016" PRIx64"l" "x", cpu64.r10);
7879 outs() << " r11 " << format("0x%016" PRIx64"l" "x", cpu64.r11) << "\n";
7880 outs() << " r12 " << format("0x%016" PRIx64"l" "x", cpu64.r12);
7881 outs() << " r13 " << format("0x%016" PRIx64"l" "x", cpu64.r13);
7882 outs() << " r14 " << format("0x%016" PRIx64"l" "x", cpu64.r14) << "\n";
7883 outs() << " r15 " << format("0x%016" PRIx64"l" "x", cpu64.r15);
7884 outs() << " rip " << format("0x%016" PRIx64"l" "x", cpu64.rip) << "\n";
7885 outs() << "rflags " << format("0x%016" PRIx64"l" "x", cpu64.rflags);
7886 outs() << " cs " << format("0x%016" PRIx64"l" "x", cpu64.cs);
7887 outs() << " fs " << format("0x%016" PRIx64"l" "x", cpu64.fs) << "\n";
7888 outs() << " gs " << format("0x%016" PRIx64"l" "x", cpu64.gs) << "\n";
7889}
7890
7891static void Print_mmst_reg(MachO::mmst_reg_t &r) {
7892 uint32_t f;
7893 outs() << "\t mmst_reg ";
7894 for (f = 0; f < 10; f++)
7895 outs() << format("%02" PRIx32"x", (r.mmst_reg[f] & 0xff)) << " ";
7896 outs() << "\n";
7897 outs() << "\t mmst_rsrv ";
7898 for (f = 0; f < 6; f++)
7899 outs() << format("%02" PRIx32"x", (r.mmst_rsrv[f] & 0xff)) << " ";
7900 outs() << "\n";
7901}
7902
7903static void Print_xmm_reg(MachO::xmm_reg_t &r) {
7904 uint32_t f;
7905 outs() << "\t xmm_reg ";
7906 for (f = 0; f < 16; f++)
7907 outs() << format("%02" PRIx32"x", (r.xmm_reg[f] & 0xff)) << " ";
7908 outs() << "\n";
7909}
7910
7911static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
7912 outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
7913 outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
7914 outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
7915 outs() << " denorm " << fpu.fpu_fcw.denorm;
7916 outs() << " zdiv " << fpu.fpu_fcw.zdiv;
7917 outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
7918 outs() << " undfl " << fpu.fpu_fcw.undfl;
7919 outs() << " precis " << fpu.fpu_fcw.precis << "\n";
7920 outs() << "\t\t pc ";
7921 if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
7922 outs() << "FP_PREC_24B ";
7923 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
7924 outs() << "FP_PREC_53B ";
7925 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
7926 outs() << "FP_PREC_64B ";
7927 else
7928 outs() << fpu.fpu_fcw.pc << " ";
7929 outs() << "rc ";
7930 if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
7931 outs() << "FP_RND_NEAR ";
7932 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
7933 outs() << "FP_RND_DOWN ";
7934 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
7935 outs() << "FP_RND_UP ";
7936 else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
7937 outs() << "FP_CHOP ";
7938 outs() << "\n";
7939 outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
7940 outs() << " denorm " << fpu.fpu_fsw.denorm;
7941 outs() << " zdiv " << fpu.fpu_fsw.zdiv;
7942 outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
7943 outs() << " undfl " << fpu.fpu_fsw.undfl;
7944 outs() << " precis " << fpu.fpu_fsw.precis;
7945 outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
7946 outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
7947 outs() << " c0 " << fpu.fpu_fsw.c0;
7948 outs() << " c1 " << fpu.fpu_fsw.c1;
7949 outs() << " c2 " << fpu.fpu_fsw.c2;
7950 outs() << " tos " << fpu.fpu_fsw.tos;
7951 outs() << " c3 " << fpu.fpu_fsw.c3;
7952 outs() << " busy " << fpu.fpu_fsw.busy << "\n";
7953 outs() << "\t fpu_ftw " << format("0x%02" PRIx32"x", fpu.fpu_ftw);
7954 outs() << " fpu_rsrv1 " << format("0x%02" PRIx32"x", fpu.fpu_rsrv1);
7955 outs() << " fpu_fop " << format("0x%04" PRIx32"x", fpu.fpu_fop);
7956 outs() << " fpu_ip " << format("0x%08" PRIx32"x", fpu.fpu_ip) << "\n";
7957 outs() << "\t fpu_cs " << format("0x%04" PRIx32"x", fpu.fpu_cs);
7958 outs() << " fpu_rsrv2 " << format("0x%04" PRIx32"x", fpu.fpu_rsrv2);
7959 outs() << " fpu_dp " << format("0x%08" PRIx32"x", fpu.fpu_dp);
7960 outs() << " fpu_ds " << format("0x%04" PRIx32"x", fpu.fpu_ds) << "\n";
7961 outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32"x", fpu.fpu_rsrv3);
7962 outs() << " fpu_mxcsr " << format("0x%08" PRIx32"x", fpu.fpu_mxcsr);
7963 outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32"x", fpu.fpu_mxcsrmask);
7964 outs() << "\n";
7965 outs() << "\t fpu_stmm0:\n";
7966 Print_mmst_reg(fpu.fpu_stmm0);
7967 outs() << "\t fpu_stmm1:\n";
7968 Print_mmst_reg(fpu.fpu_stmm1);
7969 outs() << "\t fpu_stmm2:\n";
7970 Print_mmst_reg(fpu.fpu_stmm2);
7971 outs() << "\t fpu_stmm3:\n";
7972 Print_mmst_reg(fpu.fpu_stmm3);
7973 outs() << "\t fpu_stmm4:\n";
7974 Print_mmst_reg(fpu.fpu_stmm4);
7975 outs() << "\t fpu_stmm5:\n";
7976 Print_mmst_reg(fpu.fpu_stmm5);
7977 outs() << "\t fpu_stmm6:\n";
7978 Print_mmst_reg(fpu.fpu_stmm6);
7979 outs() << "\t fpu_stmm7:\n";
7980 Print_mmst_reg(fpu.fpu_stmm7);
7981 outs() << "\t fpu_xmm0:\n";
7982 Print_xmm_reg(fpu.fpu_xmm0);
7983 outs() << "\t fpu_xmm1:\n";
7984 Print_xmm_reg(fpu.fpu_xmm1);
7985 outs() << "\t fpu_xmm2:\n";
7986 Print_xmm_reg(fpu.fpu_xmm2);
7987 outs() << "\t fpu_xmm3:\n";
7988 Print_xmm_reg(fpu.fpu_xmm3);
7989 outs() << "\t fpu_xmm4:\n";
7990 Print_xmm_reg(fpu.fpu_xmm4);
7991 outs() << "\t fpu_xmm5:\n";
7992 Print_xmm_reg(fpu.fpu_xmm5);
7993 outs() << "\t fpu_xmm6:\n";
7994 Print_xmm_reg(fpu.fpu_xmm6);
7995 outs() << "\t fpu_xmm7:\n";
7996 Print_xmm_reg(fpu.fpu_xmm7);
7997 outs() << "\t fpu_xmm8:\n";
7998 Print_xmm_reg(fpu.fpu_xmm8);
7999 outs() << "\t fpu_xmm9:\n";
8000 Print_xmm_reg(fpu.fpu_xmm9);
8001 outs() << "\t fpu_xmm10:\n";
8002 Print_xmm_reg(fpu.fpu_xmm10);
8003 outs() << "\t fpu_xmm11:\n";
8004 Print_xmm_reg(fpu.fpu_xmm11);
8005 outs() << "\t fpu_xmm12:\n";
8006 Print_xmm_reg(fpu.fpu_xmm12);
8007 outs() << "\t fpu_xmm13:\n";
8008 Print_xmm_reg(fpu.fpu_xmm13);
8009 outs() << "\t fpu_xmm14:\n";
8010 Print_xmm_reg(fpu.fpu_xmm14);
8011 outs() << "\t fpu_xmm15:\n";
8012 Print_xmm_reg(fpu.fpu_xmm15);
8013 outs() << "\t fpu_rsrv4:\n";
8014 for (uint32_t f = 0; f < 6; f++) {
8015 outs() << "\t ";
8016 for (uint32_t g = 0; g < 16; g++)
8017 outs() << format("%02" PRIx32"x", fpu.fpu_rsrv4[f * g]) << " ";
8018 outs() << "\n";
8019 }
8020 outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32"x", fpu.fpu_reserved1);
8021 outs() << "\n";
8022}
8023
8024static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
8025 outs() << "\t trapno " << format("0x%08" PRIx32"x", exc64.trapno);
8026 outs() << " err " << format("0x%08" PRIx32"x", exc64.err);
8027 outs() << " faultvaddr " << format("0x%016" PRIx64"l" "x", exc64.faultvaddr) << "\n";
8028}
8029
8030static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
8031 bool isLittleEndian, uint32_t cputype) {
8032 if (t.cmd == MachO::LC_THREAD)
8033 outs() << " cmd LC_THREAD\n";
8034 else if (t.cmd == MachO::LC_UNIXTHREAD)
8035 outs() << " cmd LC_UNIXTHREAD\n";
8036 else
8037 outs() << " cmd " << t.cmd << " (unknown)\n";
8038 outs() << " cmdsize " << t.cmdsize;
8039 if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
8040 outs() << " Incorrect size\n";
8041 else
8042 outs() << "\n";
8043
8044 const char *begin = Ptr + sizeof(struct MachO::thread_command);
8045 const char *end = Ptr + t.cmdsize;
8046 uint32_t flavor, count, left;
8047 if (cputype == MachO::CPU_TYPE_X86_64) {
8048 while (begin < end) {
8049 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
8050 memcpy((char *)&flavor, begin, sizeof(uint32_t));
8051 begin += sizeof(uint32_t);
8052 } else {
8053 flavor = 0;
8054 begin = end;
8055 }
8056 if (isLittleEndian != sys::IsLittleEndianHost)
8057 sys::swapByteOrder(flavor);
8058 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
8059 memcpy((char *)&count, begin, sizeof(uint32_t));
8060 begin += sizeof(uint32_t);
8061 } else {
8062 count = 0;
8063 begin = end;
8064 }
8065 if (isLittleEndian != sys::IsLittleEndianHost)
8066 sys::swapByteOrder(count);
8067 if (flavor == MachO::x86_THREAD_STATE64) {
8068 outs() << " flavor x86_THREAD_STATE64\n";
8069 if (count == MachO::x86_THREAD_STATE64_COUNT)
8070 outs() << " count x86_THREAD_STATE64_COUNT\n";
8071 else
8072 outs() << " count " << count
8073 << " (not x86_THREAD_STATE64_COUNT)\n";
8074 MachO::x86_thread_state64_t cpu64;
8075 left = end - begin;
8076 if (left >= sizeof(MachO::x86_thread_state64_t)) {
8077 memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));
8078 begin += sizeof(MachO::x86_thread_state64_t);
8079 } else {
8080 memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));
8081 memcpy(&cpu64, begin, left);
8082 begin += left;
8083 }
8084 if (isLittleEndian != sys::IsLittleEndianHost)
8085 swapStruct(cpu64);
8086 Print_x86_thread_state64_t(cpu64);
8087 } else if (flavor == MachO::x86_THREAD_STATE) {
8088 outs() << " flavor x86_THREAD_STATE\n";
8089 if (count == MachO::x86_THREAD_STATE_COUNT)
8090 outs() << " count x86_THREAD_STATE_COUNT\n";
8091 else
8092 outs() << " count " << count
8093 << " (not x86_THREAD_STATE_COUNT)\n";
8094 struct MachO::x86_thread_state_t ts;
8095 left = end - begin;
8096 if (left >= sizeof(MachO::x86_thread_state_t)) {
8097 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
8098 begin += sizeof(MachO::x86_thread_state_t);
8099 } else {
8100 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
8101 memcpy(&ts, begin, left);
8102 begin += left;
8103 }
8104 if (isLittleEndian != sys::IsLittleEndianHost)
8105 swapStruct(ts);
8106 if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
8107 outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
8108 if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
8109 outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
8110 else
8111 outs() << "tsh.count " << ts.tsh.count
8112 << " (not x86_THREAD_STATE64_COUNT\n";
8113 Print_x86_thread_state64_t(ts.uts.ts64);
8114 } else {
8115 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
8116 << ts.tsh.count << "\n";
8117 }
8118 } else if (flavor == MachO::x86_FLOAT_STATE) {
8119 outs() << " flavor x86_FLOAT_STATE\n";
8120 if (count == MachO::x86_FLOAT_STATE_COUNT)
8121 outs() << " count x86_FLOAT_STATE_COUNT\n";
8122 else
8123 outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
8124 struct MachO::x86_float_state_t fs;
8125 left = end - begin;
8126 if (left >= sizeof(MachO::x86_float_state_t)) {
8127 memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));
8128 begin += sizeof(MachO::x86_float_state_t);
8129 } else {
8130 memset(&fs, '\0', sizeof(MachO::x86_float_state_t));
8131 memcpy(&fs, begin, left);
8132 begin += left;
8133 }
8134 if (isLittleEndian != sys::IsLittleEndianHost)
8135 swapStruct(fs);
8136 if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
8137 outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
8138 if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
8139 outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
8140 else
8141 outs() << "fsh.count " << fs.fsh.count
8142 << " (not x86_FLOAT_STATE64_COUNT\n";
8143 Print_x86_float_state_t(fs.ufs.fs64);
8144 } else {
8145 outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
8146 << fs.fsh.count << "\n";
8147 }
8148 } else if (flavor == MachO::x86_EXCEPTION_STATE) {
8149 outs() << " flavor x86_EXCEPTION_STATE\n";
8150 if (count == MachO::x86_EXCEPTION_STATE_COUNT)
8151 outs() << " count x86_EXCEPTION_STATE_COUNT\n";
8152 else
8153 outs() << " count " << count
8154 << " (not x86_EXCEPTION_STATE_COUNT)\n";
8155 struct MachO::x86_exception_state_t es;
8156 left = end - begin;
8157 if (left >= sizeof(MachO::x86_exception_state_t)) {
8158 memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));
8159 begin += sizeof(MachO::x86_exception_state_t);
8160 } else {
8161 memset(&es, '\0', sizeof(MachO::x86_exception_state_t));
8162 memcpy(&es, begin, left);
8163 begin += left;
8164 }
8165 if (isLittleEndian != sys::IsLittleEndianHost)
8166 swapStruct(es);
8167 if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
8168 outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
8169 if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
8170 outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
8171 else
8172 outs() << "\t esh.count " << es.esh.count
8173 << " (not x86_EXCEPTION_STATE64_COUNT\n";
8174 Print_x86_exception_state_t(es.ues.es64);
8175 } else {
8176 outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
8177 << es.esh.count << "\n";
8178 }
8179 } else {
8180 outs() << " flavor " << flavor << " (unknown)\n";
8181 outs() << " count " << count << "\n";
8182 outs() << " state (unknown)\n";
8183 begin += count * sizeof(uint32_t);
8184 }
8185 }
8186 } else {
8187 while (begin < end) {
8188 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
8189 memcpy((char *)&flavor, begin, sizeof(uint32_t));
8190 begin += sizeof(uint32_t);
8191 } else {
8192 flavor = 0;
8193 begin = end;
8194 }
8195 if (isLittleEndian != sys::IsLittleEndianHost)
8196 sys::swapByteOrder(flavor);
8197 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
8198 memcpy((char *)&count, begin, sizeof(uint32_t));
8199 begin += sizeof(uint32_t);
8200 } else {
8201 count = 0;
8202 begin = end;
8203 }
8204 if (isLittleEndian != sys::IsLittleEndianHost)
8205 sys::swapByteOrder(count);
8206 outs() << " flavor " << flavor << "\n";
8207 outs() << " count " << count << "\n";
8208 outs() << " state (Unknown cputype/cpusubtype)\n";
8209 begin += count * sizeof(uint32_t);
8210 }
8211 }
8212}
8213
8214static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
8215 if (dl.cmd == MachO::LC_ID_DYLIB)
8216 outs() << " cmd LC_ID_DYLIB\n";
8217 else if (dl.cmd == MachO::LC_LOAD_DYLIB)
8218 outs() << " cmd LC_LOAD_DYLIB\n";
8219 else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
8220 outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
8221 else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
8222 outs() << " cmd LC_REEXPORT_DYLIB\n";
8223 else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
8224 outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
8225 else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
8226 outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
8227 else
8228 outs() << " cmd " << dl.cmd << " (unknown)\n";
8229 outs() << " cmdsize " << dl.cmdsize;
8230 if (dl.cmdsize < sizeof(struct MachO::dylib_command))
8231 outs() << " Incorrect size\n";
8232 else
8233 outs() << "\n";
8234 if (dl.dylib.name < dl.cmdsize) {
8235 const char *P = (const char *)(Ptr) + dl.dylib.name;
8236 outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
8237 } else {
8238 outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
8239 }
8240 outs() << " time stamp " << dl.dylib.timestamp << " ";
8241 time_t t = dl.dylib.timestamp;
8242 outs() << ctime(&t);
8243 outs() << " current version ";
8244 if (dl.dylib.current_version == 0xffffffff)
8245 outs() << "n/a\n";
8246 else
8247 outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
8248 << ((dl.dylib.current_version >> 8) & 0xff) << "."
8249 << (dl.dylib.current_version & 0xff) << "\n";
8250 outs() << "compatibility version ";
8251 if (dl.dylib.compatibility_version == 0xffffffff)
8252 outs() << "n/a\n";
8253 else
8254 outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
8255 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
8256 << (dl.dylib.compatibility_version & 0xff) << "\n";
8257}
8258
8259static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
8260 uint32_t object_size) {
8261 if (ld.cmd == MachO::LC_CODE_SIGNATURE)
8262 outs() << " cmd LC_FUNCTION_STARTS\n";
8263 else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
8264 outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
8265 else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
8266 outs() << " cmd LC_FUNCTION_STARTS\n";
8267 else if (ld.cmd == MachO::LC_DATA_IN_CODE)
8268 outs() << " cmd LC_DATA_IN_CODE\n";
8269 else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
8270 outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
8271 else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
8272 outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
8273 else
8274 outs() << " cmd " << ld.cmd << " (?)\n";
8275 outs() << " cmdsize " << ld.cmdsize;
8276 if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
8277 outs() << " Incorrect size\n";
8278 else
8279 outs() << "\n";
8280 outs() << " dataoff " << ld.dataoff;
8281 if (ld.dataoff > object_size)
8282 outs() << " (past end of file)\n";
8283 else
8284 outs() << "\n";
8285 outs() << " datasize " << ld.datasize;
8286 uint64_t big_size = ld.dataoff;
8287 big_size += ld.datasize;
8288 if (big_size > object_size)
8289 outs() << " (past end of file)\n";
8290 else
8291 outs() << "\n";
8292}
8293
8294static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
8295 uint32_t cputype, bool verbose) {
8296 StringRef Buf = Obj->getData();
8297 unsigned Index = 0;
8298 for (const auto &Command : Obj->load_commands()) {
8299 outs() << "Load command " << Index++ << "\n";
8300 if (Command.C.cmd == MachO::LC_SEGMENT) {
8301 MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
8302 const char *sg_segname = SLC.segname;
8303 PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,
8304 SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,
8305 SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
8306 verbose);
8307 for (unsigned j = 0; j < SLC.nsects; j++) {
8308 MachO::section S = Obj->getSection(Command, j);
8309 PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,
8310 S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,
8311 SLC.cmd, sg_segname, filetype, Buf.size(), verbose);
8312 }
8313 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
8314 MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);
8315 const char *sg_segname = SLC_64.segname;
8316 PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,
8317 SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,
8318 SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,
8319 SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);
8320 for (unsigned j = 0; j < SLC_64.nsects; j++) {
8321 MachO::section_64 S_64 = Obj->getSection64(Command, j);
8322 PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,
8323 S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,
8324 S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,
8325 sg_segname, filetype, Buf.size(), verbose);
8326 }
8327 } else if (Command.C.cmd == MachO::LC_SYMTAB) {
8328 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
8329 PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());
8330 } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
8331 MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
8332 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
8333 PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),
8334 Obj->is64Bit());
8335 } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
8336 Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
8337 MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);
8338 PrintDyldInfoLoadCommand(DyldInfo, Buf.size());
8339 } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
8340 Command.C.cmd == MachO::LC_ID_DYLINKER ||
8341 Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
8342 MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);
8343 PrintDyldLoadCommand(Dyld, Command.Ptr);
8344 } else if (Command.C.cmd == MachO::LC_UUID) {
8345 MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
8346 PrintUuidLoadCommand(Uuid);
8347 } else if (Command.C.cmd == MachO::LC_RPATH) {
8348 MachO::rpath_command Rpath = Obj->getRpathCommand(Command);
8349 PrintRpathLoadCommand(Rpath, Command.Ptr);
8350 } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
8351 Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||
8352 Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||
8353 Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
8354 MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
8355 PrintVersionMinLoadCommand(Vd);
8356 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
8357 MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
8358 PrintSourceVersionCommand(Sd);
8359 } else if (Command.C.cmd == MachO::LC_MAIN) {
8360 MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);
8361 PrintEntryPointCommand(Ep);
8362 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
8363 MachO::encryption_info_command Ei =
8364 Obj->getEncryptionInfoCommand(Command);
8365 PrintEncryptionInfoCommand(Ei, Buf.size());
8366 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
8367 MachO::encryption_info_command_64 Ei =
8368 Obj->getEncryptionInfoCommand64(Command);
8369 PrintEncryptionInfoCommand64(Ei, Buf.size());
8370 } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
8371 MachO::linker_option_command Lo =
8372 Obj->getLinkerOptionLoadCommand(Command);
8373 PrintLinkerOptionCommand(Lo, Command.Ptr);
8374 } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
8375 MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);
8376 PrintSubFrameworkCommand(Sf, Command.Ptr);
8377 } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
8378 MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);
8379 PrintSubUmbrellaCommand(Sf, Command.Ptr);
8380 } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
8381 MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);
8382 PrintSubLibraryCommand(Sl, Command.Ptr);
8383 } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
8384 MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);
8385 PrintSubClientCommand(Sc, Command.Ptr);
8386 } else if (Command.C.cmd == MachO::LC_ROUTINES) {
8387 MachO::routines_command Rc = Obj->getRoutinesCommand(Command);
8388 PrintRoutinesCommand(Rc);
8389 } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
8390 MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);
8391 PrintRoutinesCommand64(Rc);
8392 } else if (Command.C.cmd == MachO::LC_THREAD ||
8393 Command.C.cmd == MachO::LC_UNIXTHREAD) {
8394 MachO::thread_command Tc = Obj->getThreadCommand(Command);
8395 PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);
8396 } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
8397 Command.C.cmd == MachO::LC_ID_DYLIB ||
8398 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
8399 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
8400 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
8401 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
8402 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);
8403 PrintDylibCommand(Dl, Command.Ptr);
8404 } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
8405 Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
8406 Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
8407 Command.C.cmd == MachO::LC_DATA_IN_CODE ||
8408 Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
8409 Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
8410 MachO::linkedit_data_command Ld =
8411 Obj->getLinkeditDataLoadCommand(Command);
8412 PrintLinkEditDataCommand(Ld, Buf.size());
8413 } else {
8414 outs() << " cmd ?(" << format("0x%08" PRIx32"x", Command.C.cmd)
8415 << ")\n";
8416 outs() << " cmdsize " << Command.C.cmdsize << "\n";
8417 // TODO: get and print the raw bytes of the load command.
8418 }
8419 // TODO: print all the other kinds of load commands.
8420 }
8421}
8422
8423static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
8424 if (Obj->is64Bit()) {
8425 MachO::mach_header_64 H_64;
8426 H_64 = Obj->getHeader64();
8427 PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
8428 H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
8429 } else {
8430 MachO::mach_header H;
8431 H = Obj->getHeader();
8432 PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
8433 H.sizeofcmds, H.flags, verbose);
8434 }
8435}
8436
8437void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
8438 const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
8439 PrintMachHeader(file, !NonVerbose);
8440}
8441
8442void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
8443 const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
8444 uint32_t filetype = 0;
8445 uint32_t cputype = 0;
8446 if (file->is64Bit()) {
8447 MachO::mach_header_64 H_64;
8448 H_64 = file->getHeader64();
8449 filetype = H_64.filetype;
8450 cputype = H_64.cputype;
8451 } else {
8452 MachO::mach_header H;
8453 H = file->getHeader();
8454 filetype = H.filetype;
8455 cputype = H.cputype;
8456 }
8457 PrintLoadCommands(file, filetype, cputype, !NonVerbose);
8458}
8459
8460//===----------------------------------------------------------------------===//
8461// export trie dumping
8462//===----------------------------------------------------------------------===//
8463
8464void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
8465 for (const llvm::object::ExportEntry &Entry : Obj->exports()) {
8466 uint64_t Flags = Entry.flags();
8467 bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
8468 bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
8469 bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
8470 MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
8471 bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
8472 MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
8473 bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
8474 if (ReExport)
8475 outs() << "[re-export] ";
8476 else
8477 outs() << format("0x%08llX ",
8478 Entry.address()); // FIXME:add in base address
8479 outs() << Entry.name();
8480 if (WeakDef || ThreadLocal || Resolver || Abs) {
8481 bool NeedsComma = false;
8482 outs() << " [";
8483 if (WeakDef) {
8484 outs() << "weak_def";
8485 NeedsComma = true;
8486 }
8487 if (ThreadLocal) {
8488 if (NeedsComma)
8489 outs() << ", ";
8490 outs() << "per-thread";
8491 NeedsComma = true;
8492 }
8493 if (Abs) {
8494 if (NeedsComma)
8495 outs() << ", ";
8496 outs() << "absolute";
8497 NeedsComma = true;
8498 }
8499 if (Resolver) {
8500 if (NeedsComma)
8501 outs() << ", ";
8502 outs() << format("resolver=0x%08llX", Entry.other());
8503 NeedsComma = true;
8504 }
8505 outs() << "]";
8506 }
8507 if (ReExport) {
8508 StringRef DylibName = "unknown";
8509 int Ordinal = Entry.other() - 1;
8510 Obj->getLibraryShortNameByIndex(Ordinal, DylibName);
8511 if (Entry.otherName().empty())
8512 outs() << " (from " << DylibName << ")";
8513 else
8514 outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
8515 }
8516 outs() << "\n";
8517 }
8518}
8519
8520//===----------------------------------------------------------------------===//
8521// rebase table dumping
8522//===----------------------------------------------------------------------===//
8523
8524namespace {
8525class SegInfo {
8526public:
8527 SegInfo(const object::MachOObjectFile *Obj);
8528
8529 StringRef segmentName(uint32_t SegIndex);
8530 StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset);
8531 uint64_t address(uint32_t SegIndex, uint64_t SegOffset);
8532 bool isValidSegIndexAndOffset(uint32_t SegIndex, uint64_t SegOffset);
8533
8534private:
8535 struct SectionInfo {
8536 uint64_t Address;
8537 uint64_t Size;
8538 StringRef SectionName;
8539 StringRef SegmentName;
8540 uint64_t OffsetInSegment;
8541 uint64_t SegmentStartAddress;
8542 uint32_t SegmentIndex;
8543 };
8544 const SectionInfo &findSection(uint32_t SegIndex, uint64_t SegOffset);
8545 SmallVector<SectionInfo, 32> Sections;
8546};
8547}
8548
8549SegInfo::SegInfo(const object::MachOObjectFile *Obj) {
8550 // Build table of sections so segIndex/offset pairs can be translated.
8551 uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
8552 StringRef CurSegName;
8553 uint64_t CurSegAddress;
8554 for (const SectionRef &Section : Obj->sections()) {
8555 SectionInfo Info;
8556 error(Section.getName(Info.SectionName));
8557 Info.Address = Section.getAddress();
8558 Info.Size = Section.getSize();
8559 Info.SegmentName =
8560 Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
8561 if (!Info.SegmentName.equals(CurSegName)) {
8562 ++CurSegIndex;
8563 CurSegName = Info.SegmentName;
8564 CurSegAddress = Info.Address;
8565 }
8566 Info.SegmentIndex = CurSegIndex - 1;
8567 Info.OffsetInSegment = Info.Address - CurSegAddress;
8568 Info.SegmentStartAddress = CurSegAddress;
8569 Sections.push_back(Info);
8570 }
8571}
8572
8573StringRef SegInfo::segmentName(uint32_t SegIndex) {
8574 for (const SectionInfo &SI : Sections) {
8575 if (SI.SegmentIndex == SegIndex)
8576 return SI.SegmentName;
8577 }
8578 llvm_unreachable("invalid segIndex")::llvm::llvm_unreachable_internal("invalid segIndex", "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 8578)
;
8579}
8580
8581bool SegInfo::isValidSegIndexAndOffset(uint32_t SegIndex,
8582 uint64_t OffsetInSeg) {
8583 for (const SectionInfo &SI : Sections) {
8584 if (SI.SegmentIndex != SegIndex)
8585 continue;
8586 if (SI.OffsetInSegment > OffsetInSeg)
8587 continue;
8588 if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
8589 continue;
8590 return true;
8591 }
8592 return false;
8593}
8594
8595const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex,
8596 uint64_t OffsetInSeg) {
8597 for (const SectionInfo &SI : Sections) {
8598 if (SI.SegmentIndex != SegIndex)
8599 continue;
8600 if (SI.OffsetInSegment > OffsetInSeg)
8601 continue;
8602 if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
8603 continue;
8604 return SI;
8605 }
8606 llvm_unreachable("segIndex and offset not in any section")::llvm::llvm_unreachable_internal("segIndex and offset not in any section"
, "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn266909/tools/llvm-objdump/MachODump.cpp"
, 8606)
;
8607}
8608
8609StringRef SegInfo::sectionName(uint32_t SegIndex, uint64_t OffsetInSeg) {
8610 return findSection(SegIndex, OffsetInSeg).SectionName;
8611}
8612
8613uint64_t SegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
8614 const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
8615 return SI.SegmentStartAddress + OffsetInSeg;
8616}
8617
8618void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) {
8619 // Build table of sections so names can used in final output.
8620 SegInfo sectionTable(Obj);
8621
8622 outs() << "segment section address type\n";
8623 for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) {
8624 uint32_t SegIndex = Entry.segmentIndex();
8625 uint64_t OffsetInSeg = Entry.segmentOffset();
8626 StringRef SegmentName = sectionTable.segmentName(SegIndex);
8627 StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
8628 uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
8629
8630 // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
8631 outs() << format("%-8s %-18s 0x%08" PRIX64"l" "X" " %s\n",
8632 SegmentName.str().c_str(), SectionName.str().c_str(),
8633 Address, Entry.typeName().str().c_str());
8634 }
8635}
8636
8637static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
8638 StringRef DylibName;
8639 switch (Ordinal) {
8640 case MachO::BIND_SPECIAL_DYLIB_SELF:
8641 return "this-image";
8642 case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
8643 return "main-executable";
8644 case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
8645 return "flat-namespace";
8646 default:
8647 if (Ordinal > 0) {
8648 std::error_code EC =
8649 Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);
8650 if (EC)
8651 return "<<bad library ordinal>>";
8652 return DylibName;
8653 }
8654 }
8655 return "<<unknown special ordinal>>";
8656}
8657
8658//===----------------------------------------------------------------------===//
8659// bind table dumping
8660//===----------------------------------------------------------------------===//
8661
8662void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
8663 // Build table of sections so names can used in final output.
8664 SegInfo sectionTable(Obj);
8665
8666 outs() << "segment section address type "
8667 "addend dylib symbol\n";
8668 for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
8669 uint32_t SegIndex = Entry.segmentIndex();
8670 uint64_t OffsetInSeg = Entry.segmentOffset();
8671 StringRef SegmentName = sectionTable.segmentName(SegIndex);
8672 StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
8673 uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
8674
8675 // Table lines look like:
8676 // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
8677 StringRef Attr;
8678 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
8679 Attr = " (weak_import)";
8680 outs() << left_justify(SegmentName, 8) << " "
8681 << left_justify(SectionName, 18) << " "
8682 << format_hex(Address, 10, true) << " "
8683 << left_justify(Entry.typeName(), 8) << " "
8684 << format_decimal(Entry.addend(), 8) << " "
8685 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
8686 << Entry.symbolName() << Attr << "\n";
8687 }
8688}
8689
8690//===----------------------------------------------------------------------===//
8691// lazy bind table dumping
8692//===----------------------------------------------------------------------===//
8693
8694void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
8695 // Build table of sections so names can used in final output.
8696 SegInfo sectionTable(Obj);
8697
8698 outs() << "segment section address "
8699 "dylib symbol\n";
8700 for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) {
8701 uint32_t SegIndex = Entry.segmentIndex();
8702 uint64_t OffsetInSeg = Entry.segmentOffset();
8703 StringRef SegmentName = sectionTable.segmentName(SegIndex);
8704 StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
8705 uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
8706
8707 // Table lines look like:
8708 // __DATA __got 0x00012010 libSystem ___stack_chk_guard
8709 outs() << left_justify(SegmentName, 8) << " "
8710 << left_justify(SectionName, 18) << " "
8711 << format_hex(Address, 10, true) << " "
8712 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
8713 << Entry.symbolName() << "\n";
8714 }
8715}
8716
8717//===----------------------------------------------------------------------===//
8718// weak bind table dumping
8719//===----------------------------------------------------------------------===//
8720
8721void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
8722 // Build table of sections so names can used in final output.
8723 SegInfo sectionTable(Obj);
8724
8725 outs() << "segment section address "
8726 "type addend symbol\n";
8727 for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) {
8728 // Strong symbols don't have a location to update.
8729 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
8730 outs() << " strong "
8731 << Entry.symbolName() << "\n";
8732 continue;
8733 }
8734 uint32_t SegIndex = Entry.segmentIndex();
8735 uint64_t OffsetInSeg = Entry.segmentOffset();
8736 StringRef SegmentName = sectionTable.segmentName(SegIndex);
8737 StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
8738 uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
8739
8740 // Table lines look like:
8741 // __DATA __data 0x00001000 pointer 0 _foo
8742 outs() << left_justify(SegmentName, 8) << " "
8743 << left_justify(SectionName, 18) << " "
8744 << format_hex(Address, 10, true) << " "
8745 << left_justify(Entry.typeName(), 8) << " "
8746 << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
8747 << "\n";
8748 }
8749}
8750
8751// get_dyld_bind_info_symbolname() is used for disassembly and passed an
8752// address, ReferenceValue, in the Mach-O file and looks in the dyld bind
8753// information for that address. If the address is found its binding symbol
8754// name is returned. If not nullptr is returned.
8755static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
8756 struct DisassembleInfo *info) {
8757 if (info->bindtable == nullptr) {
8758 info->bindtable = new (BindTable);
8759 SegInfo sectionTable(info->O);
8760 for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) {
8761 uint32_t SegIndex = Entry.segmentIndex();
8762 uint64_t OffsetInSeg = Entry.segmentOffset();
8763 if (!sectionTable.isValidSegIndexAndOffset(SegIndex, OffsetInSeg))
8764 continue;
8765 uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
8766 const char *SymbolName = nullptr;
8767 StringRef name = Entry.symbolName();
8768 if (!name.empty())
8769 SymbolName = name.data();
8770 info->bindtable->push_back(std::make_pair(Address, SymbolName));
8771 }
8772 }
8773 for (bind_table_iterator BI = info->bindtable->begin(),
8774 BE = info->bindtable->end();
8775 BI != BE; ++BI) {
8776 uint64_t Address = BI->first;
8777 if (ReferenceValue == Address) {
8778 const char *SymbolName = BI->second;
8779 return SymbolName;
8780 }
8781 }
8782 return nullptr;
8783}