1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the MachO-specific dumper for llvm-objdump.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MachODump.h"
14
15#include "ObjdumpOptID.h"
16#include "SourcePrinter.h"
17#include "llvm-objdump.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/BinaryFormat/MachO.h"
21#include "llvm/Config/config.h"
22#include "llvm/DebugInfo/DIContext.h"
23#include "llvm/DebugInfo/DWARF/DWARFContext.h"
24#include "llvm/Demangle/Demangle.h"
25#include "llvm/MC/MCAsmInfo.h"
26#include "llvm/MC/MCContext.h"
27#include "llvm/MC/MCDisassembler/MCDisassembler.h"
28#include "llvm/MC/MCInst.h"
29#include "llvm/MC/MCInstPrinter.h"
30#include "llvm/MC/MCInstrDesc.h"
31#include "llvm/MC/MCInstrInfo.h"
32#include "llvm/MC/MCRegisterInfo.h"
33#include "llvm/MC/MCSubtargetInfo.h"
34#include "llvm/MC/MCTargetOptions.h"
35#include "llvm/MC/TargetRegistry.h"
36#include "llvm/Object/MachO.h"
37#include "llvm/Object/MachOUniversal.h"
38#include "llvm/Option/ArgList.h"
39#include "llvm/Support/Casting.h"
40#include "llvm/Support/Debug.h"
41#include "llvm/Support/Endian.h"
42#include "llvm/Support/Format.h"
43#include "llvm/Support/FormattedStream.h"
44#include "llvm/Support/LEB128.h"
45#include "llvm/Support/MemoryBuffer.h"
46#include "llvm/Support/WithColor.h"
47#include "llvm/Support/raw_ostream.h"
48#include "llvm/TargetParser/Triple.h"
49#include <algorithm>
50#include <cstring>
51#include <system_error>
52
53using namespace llvm;
54using namespace llvm::object;
55using namespace llvm::objdump;
56
57bool objdump::FirstPrivateHeader;
58bool objdump::ExportsTrie;
59bool objdump::Rebase;
60bool objdump::Rpaths;
61bool objdump::Bind;
62bool objdump::LazyBind;
63bool objdump::WeakBind;
64static bool UseDbg;
65static std::string DSYMFile;
66bool objdump::FullLeadingAddr;
67bool objdump::LeadingHeaders;
68bool objdump::UniversalHeaders;
69static bool ArchiveMemberOffsets;
70bool objdump::IndirectSymbols;
71bool objdump::DataInCode;
72FunctionStartsMode objdump::FunctionStartsType =
73 objdump::FunctionStartsMode::None;
74bool objdump::LinkOptHints;
75bool objdump::InfoPlist;
76bool objdump::ChainedFixups;
77bool objdump::DyldInfo;
78bool objdump::DylibsUsed;
79bool objdump::DylibId;
80bool objdump::Verbose;
81bool objdump::ObjcMetaData;
82std::string objdump::DisSymName;
83bool objdump::IsOtool;
84bool objdump::SymbolicOperands;
85static std::vector<std::string> ArchFlags;
86
87static bool ArchAll = false;
88static std::string ThumbTripleName;
89
90static StringRef ordinalName(const object::MachOObjectFile *, int);
91
92void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
93 FirstPrivateHeader = InputArgs.hasArg(Ids: OBJDUMP_private_header);
94 ExportsTrie = InputArgs.hasArg(Ids: OBJDUMP_exports_trie);
95 Rebase = InputArgs.hasArg(Ids: OBJDUMP_rebase);
96 Rpaths = InputArgs.hasArg(Ids: OBJDUMP_rpaths);
97 Bind = InputArgs.hasArg(Ids: OBJDUMP_bind);
98 LazyBind = InputArgs.hasArg(Ids: OBJDUMP_lazy_bind);
99 WeakBind = InputArgs.hasArg(Ids: OBJDUMP_weak_bind);
100 UseDbg = InputArgs.hasArg(Ids: OBJDUMP_g);
101 DSYMFile = InputArgs.getLastArgValue(Id: OBJDUMP_dsym_EQ).str();
102 FullLeadingAddr = InputArgs.hasArg(Ids: OBJDUMP_full_leading_addr);
103 LeadingHeaders = !InputArgs.hasArg(Ids: OBJDUMP_no_leading_headers);
104 UniversalHeaders = InputArgs.hasArg(Ids: OBJDUMP_universal_headers);
105 ArchiveMemberOffsets = InputArgs.hasArg(Ids: OBJDUMP_archive_member_offsets);
106 IndirectSymbols = InputArgs.hasArg(Ids: OBJDUMP_indirect_symbols);
107 DataInCode = InputArgs.hasArg(Ids: OBJDUMP_data_in_code);
108 if (const opt::Arg *A = InputArgs.getLastArg(Ids: OBJDUMP_function_starts_EQ)) {
109 FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
110 .Case(S: "addrs", Value: FunctionStartsMode::Addrs)
111 .Case(S: "names", Value: FunctionStartsMode::Names)
112 .Case(S: "both", Value: FunctionStartsMode::Both)
113 .Default(Value: FunctionStartsMode::None);
114 if (FunctionStartsType == FunctionStartsMode::None)
115 invalidArgValue(A);
116 }
117 LinkOptHints = InputArgs.hasArg(Ids: OBJDUMP_link_opt_hints);
118 InfoPlist = InputArgs.hasArg(Ids: OBJDUMP_info_plist);
119 ChainedFixups = InputArgs.hasArg(Ids: OBJDUMP_chained_fixups);
120 DyldInfo = InputArgs.hasArg(Ids: OBJDUMP_dyld_info);
121 DylibsUsed = InputArgs.hasArg(Ids: OBJDUMP_dylibs_used);
122 DylibId = InputArgs.hasArg(Ids: OBJDUMP_dylib_id);
123 Verbose = !InputArgs.hasArg(Ids: OBJDUMP_non_verbose);
124 ObjcMetaData = InputArgs.hasArg(Ids: OBJDUMP_objc_meta_data);
125 DisSymName = InputArgs.getLastArgValue(Id: OBJDUMP_dis_symname).str();
126 SymbolicOperands = !InputArgs.hasArg(Ids: OBJDUMP_no_symbolic_operands);
127 ArchFlags = InputArgs.getAllArgValues(Id: OBJDUMP_arch_EQ);
128}
129
130static const Target *GetTarget(const MachOObjectFile *MachOObj,
131 const char **McpuDefault,
132 const Target **ThumbTarget,
133 Triple &ThumbTriple) {
134 // Figure out the target triple.
135 Triple TT(TripleName);
136 if (TripleName.empty()) {
137 TT = MachOObj->getArchTriple(McpuDefault);
138 TripleName = TT.str();
139 }
140
141 if (TT.getArch() == Triple::arm) {
142 // We've inferred a 32-bit ARM target from the object file. All MachO CPUs
143 // that support ARM are also capable of Thumb mode.
144 std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(Start: 3)).str();
145 ThumbTriple = TT;
146 ThumbTriple.setArchName(ThumbName);
147 ThumbTripleName = ThumbTriple.str();
148 }
149
150 // Get the target specific parser.
151 std::string Error;
152 const Target *TheTarget = TargetRegistry::lookupTarget(TheTriple: TT, Error);
153 if (TheTarget && ThumbTripleName.empty())
154 return TheTarget;
155
156 *ThumbTarget = TargetRegistry::lookupTarget(TheTriple: ThumbTriple, Error);
157 if (*ThumbTarget)
158 return TheTarget;
159
160 WithColor::error(OS&: errs(), Prefix: "llvm-objdump") << "unable to get target for '";
161 if (!TheTarget)
162 errs() << TripleName;
163 else
164 errs() << ThumbTripleName;
165 errs() << "', see --version and --triple.\n";
166 return nullptr;
167}
168
169namespace {
170struct SymbolSorter {
171 bool operator()(const SymbolRef &A, const SymbolRef &B) {
172 Expected<SymbolRef::Type> ATypeOrErr = A.getType();
173 if (!ATypeOrErr)
174 reportError(E: ATypeOrErr.takeError(), FileName: A.getObject()->getFileName());
175 SymbolRef::Type AType = *ATypeOrErr;
176 Expected<SymbolRef::Type> BTypeOrErr = B.getType();
177 if (!BTypeOrErr)
178 reportError(E: BTypeOrErr.takeError(), FileName: B.getObject()->getFileName());
179 SymbolRef::Type BType = *BTypeOrErr;
180 uint64_t AAddr =
181 (AType != SymbolRef::ST_Function) ? 0 : cantFail(ValOrErr: A.getValue());
182 uint64_t BAddr =
183 (BType != SymbolRef::ST_Function) ? 0 : cantFail(ValOrErr: B.getValue());
184 return AAddr < BAddr;
185 }
186};
187
188class MachODumper : public Dumper {
189 const object::MachOObjectFile &Obj;
190
191public:
192 MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}
193 void printPrivateHeaders() override;
194};
195} // namespace
196
197std::unique_ptr<Dumper>
198objdump::createMachODumper(const object::MachOObjectFile &Obj) {
199 return std::make_unique<MachODumper>(args: Obj);
200}
201
202// Types for the storted data in code table that is built before disassembly
203// and the predicate function to sort them.
204typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
205typedef std::vector<DiceTableEntry> DiceTable;
206typedef DiceTable::iterator dice_table_iterator;
207
208// This is used to search for a data in code table entry for the PC being
209// disassembled. The j parameter has the PC in j.first. A single data in code
210// table entry can cover many bytes for each of its Kind's. So if the offset,
211// aka the i.first value, of the data in code table entry plus its Length
212// covers the PC being searched for this will return true. If not it will
213// return false.
214static bool compareDiceTableEntries(const DiceTableEntry &i,
215 const DiceTableEntry &j) {
216 uint16_t Length;
217 i.second.getLength(Result&: Length);
218
219 return j.first >= i.first && j.first < i.first + Length;
220}
221
222static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
223 unsigned short Kind) {
224 uint32_t Value, Size = 1;
225
226 switch (Kind) {
227 default:
228 case MachO::DICE_KIND_DATA:
229 if (Length >= 4) {
230 if (ShowRawInsn)
231 dumpBytes(Bytes: ArrayRef(bytes, 4), OS&: outs());
232 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
233 outs() << "\t.long " << Value;
234 Size = 4;
235 } else if (Length >= 2) {
236 if (ShowRawInsn)
237 dumpBytes(Bytes: ArrayRef(bytes, 2), OS&: outs());
238 Value = bytes[1] << 8 | bytes[0];
239 outs() << "\t.short " << Value;
240 Size = 2;
241 } else {
242 if (ShowRawInsn)
243 dumpBytes(Bytes: ArrayRef(bytes, 2), OS&: outs());
244 Value = bytes[0];
245 outs() << "\t.byte " << Value;
246 Size = 1;
247 }
248 if (Kind == MachO::DICE_KIND_DATA)
249 outs() << "\t@ KIND_DATA\n";
250 else
251 outs() << "\t@ data in code kind = " << Kind << "\n";
252 break;
253 case MachO::DICE_KIND_JUMP_TABLE8:
254 if (ShowRawInsn)
255 dumpBytes(Bytes: ArrayRef(bytes, 1), OS&: outs());
256 Value = bytes[0];
257 outs() << "\t.byte " << format(Fmt: "%3u", Vals: Value) << "\t@ KIND_JUMP_TABLE8\n";
258 Size = 1;
259 break;
260 case MachO::DICE_KIND_JUMP_TABLE16:
261 if (ShowRawInsn)
262 dumpBytes(Bytes: ArrayRef(bytes, 2), OS&: outs());
263 Value = bytes[1] << 8 | bytes[0];
264 outs() << "\t.short " << format(Fmt: "%5u", Vals: Value & 0xffff)
265 << "\t@ KIND_JUMP_TABLE16\n";
266 Size = 2;
267 break;
268 case MachO::DICE_KIND_JUMP_TABLE32:
269 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
270 if (ShowRawInsn)
271 dumpBytes(Bytes: ArrayRef(bytes, 4), OS&: outs());
272 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
273 outs() << "\t.long " << Value;
274 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
275 outs() << "\t@ KIND_JUMP_TABLE32\n";
276 else
277 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
278 Size = 4;
279 break;
280 }
281 return Size;
282}
283
284static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
285 std::vector<SectionRef> &Sections,
286 std::vector<SymbolRef> &Symbols,
287 SmallVectorImpl<uint64_t> &FoundFns,
288 uint64_t &BaseSegmentAddress) {
289 const StringRef FileName = MachOObj->getFileName();
290 for (const SymbolRef &Symbol : MachOObj->symbols()) {
291 StringRef SymName = unwrapOrError(EO: Symbol.getName(), Args: FileName);
292 if (!SymName.starts_with(Prefix: "ltmp"))
293 Symbols.push_back(x: Symbol);
294 }
295
296 append_range(C&: Sections, R: MachOObj->sections());
297
298 bool BaseSegmentAddressSet = false;
299 for (const auto &Command : MachOObj->load_commands()) {
300 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
301 // We found a function starts segment, parse the addresses for later
302 // consumption.
303 MachO::linkedit_data_command LLC =
304 MachOObj->getLinkeditDataLoadCommand(L: Command);
305
306 MachOObj->ReadULEB128s(Index: LLC.dataoff, Out&: FoundFns);
307 } else if (Command.C.cmd == MachO::LC_SEGMENT) {
308 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(L: Command);
309 StringRef SegName = SLC.segname;
310 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
311 BaseSegmentAddressSet = true;
312 BaseSegmentAddress = SLC.vmaddr;
313 }
314 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
315 MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(L: Command);
316 StringRef SegName = SLC.segname;
317 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
318 BaseSegmentAddressSet = true;
319 BaseSegmentAddress = SLC.vmaddr;
320 }
321 }
322 }
323}
324
325static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,
326 DiceTable &Dices, uint64_t &InstSize) {
327 // Check the data in code table here to see if this is data not an
328 // instruction to be disassembled.
329 DiceTable Dice;
330 Dice.push_back(x: std::make_pair(x&: PC, y: DiceRef()));
331 dice_table_iterator DTI =
332 std::search(first1: Dices.begin(), last1: Dices.end(), first2: Dice.begin(), last2: Dice.end(),
333 predicate: compareDiceTableEntries);
334 if (DTI != Dices.end()) {
335 uint16_t Length;
336 DTI->second.getLength(Result&: Length);
337 uint16_t Kind;
338 DTI->second.getKind(Result&: Kind);
339 InstSize = DumpDataInCode(bytes, Length, Kind);
340 if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
341 (PC == (DTI->first + Length - 1)) && (Length & 1))
342 InstSize++;
343 return true;
344 }
345 return false;
346}
347
348static void printRelocationTargetName(const MachOObjectFile *O,
349 const MachO::any_relocation_info &RE,
350 raw_string_ostream &Fmt) {
351 // Target of a scattered relocation is an address. In the interest of
352 // generating pretty output, scan through the symbol table looking for a
353 // symbol that aligns with that address. If we find one, print it.
354 // Otherwise, we just print the hex address of the target.
355 const StringRef FileName = O->getFileName();
356 if (O->isRelocationScattered(RE)) {
357 uint32_t Val = O->getPlainRelocationSymbolNum(RE);
358
359 for (const SymbolRef &Symbol : O->symbols()) {
360 uint64_t Addr = unwrapOrError(EO: Symbol.getAddress(), Args: FileName);
361 if (Addr != Val)
362 continue;
363 Fmt << unwrapOrError(EO: Symbol.getName(), Args: FileName);
364 return;
365 }
366
367 // If we couldn't find a symbol that this relocation refers to, try
368 // to find a section beginning instead.
369 for (const SectionRef &Section : ToolSectionFilter(O: *O)) {
370 uint64_t Addr = Section.getAddress();
371 if (Addr != Val)
372 continue;
373 StringRef NameOrErr = unwrapOrError(EO: Section.getName(), Args: O->getFileName());
374 Fmt << NameOrErr;
375 return;
376 }
377
378 Fmt << format(Fmt: "0x%x", Vals: Val);
379 return;
380 }
381
382 StringRef S;
383 bool isExtern = O->getPlainRelocationExternal(RE);
384 uint64_t Val = O->getPlainRelocationSymbolNum(RE);
385
386 if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&
387 Triple(O->getArchTriple()).isAArch64()) {
388 Fmt << format(Fmt: "0x%0" PRIx64, Vals: Val);
389 return;
390 }
391
392 if (O->getAnyRelocationType(RE) == MachO::RISCV_RELOC_ADDEND &&
393 O->getArch() == Triple::riscv32) {
394 Fmt << format(Fmt: "0x%0" PRIx64, Vals: Val);
395 return;
396 }
397
398 if (isExtern) {
399 symbol_iterator SI = O->symbol_begin();
400 std::advance(i&: SI, n: Val);
401 S = unwrapOrError(EO: SI->getName(), Args: FileName);
402 } else {
403 section_iterator SI = O->section_begin();
404 // Adjust for the fact that sections are 1-indexed.
405 if (Val == 0) {
406 Fmt << "0 (?,?)";
407 return;
408 }
409 uint32_t I = Val - 1;
410 while (I != 0 && SI != O->section_end()) {
411 --I;
412 std::advance(i&: SI, n: 1);
413 }
414 if (SI == O->section_end()) {
415 Fmt << Val << " (?,?)";
416 } else {
417 if (Expected<StringRef> NameOrErr = SI->getName())
418 S = *NameOrErr;
419 else
420 consumeError(Err: NameOrErr.takeError());
421 }
422 }
423
424 Fmt << S;
425}
426
427Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,
428 const RelocationRef &RelRef,
429 SmallVectorImpl<char> &Result) {
430 DataRefImpl Rel = RelRef.getRawDataRefImpl();
431 MachO::any_relocation_info RE = Obj->getRelocation(Rel);
432
433 unsigned Arch = Obj->getArch();
434
435 std::string FmtBuf;
436 raw_string_ostream Fmt(FmtBuf);
437 unsigned Type = Obj->getAnyRelocationType(RE);
438 bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
439
440 // Determine any addends that should be displayed with the relocation.
441 // These require decoding the relocation type, which is triple-specific.
442
443 // X86_64 has entirely custom relocation types.
444 if (Arch == Triple::x86_64) {
445 switch (Type) {
446 case MachO::X86_64_RELOC_GOT_LOAD:
447 case MachO::X86_64_RELOC_GOT: {
448 printRelocationTargetName(O: Obj, RE, Fmt);
449 Fmt << "@GOT";
450 if (IsPCRel)
451 Fmt << "PCREL";
452 break;
453 }
454 case MachO::X86_64_RELOC_SUBTRACTOR: {
455 DataRefImpl RelNext = Rel;
456 Obj->moveRelocationNext(Rel&: RelNext);
457 MachO::any_relocation_info RENext = Obj->getRelocation(Rel: RelNext);
458
459 // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
460 // X86_64_RELOC_UNSIGNED.
461 // NOTE: Scattered relocations don't exist on x86_64.
462 unsigned RType = Obj->getAnyRelocationType(RE: RENext);
463 if (RType != MachO::X86_64_RELOC_UNSIGNED)
464 reportError(File: Obj->getFileName(), Message: "Expected X86_64_RELOC_UNSIGNED after "
465 "X86_64_RELOC_SUBTRACTOR.");
466
467 // The X86_64_RELOC_UNSIGNED contains the minuend symbol;
468 // X86_64_RELOC_SUBTRACTOR contains the subtrahend.
469 printRelocationTargetName(O: Obj, RE: RENext, Fmt);
470 Fmt << "-";
471 printRelocationTargetName(O: Obj, RE, Fmt);
472 break;
473 }
474 case MachO::X86_64_RELOC_TLV:
475 printRelocationTargetName(O: Obj, RE, Fmt);
476 Fmt << "@TLV";
477 if (IsPCRel)
478 Fmt << "P";
479 break;
480 case MachO::X86_64_RELOC_SIGNED_1:
481 printRelocationTargetName(O: Obj, RE, Fmt);
482 Fmt << "-1";
483 break;
484 case MachO::X86_64_RELOC_SIGNED_2:
485 printRelocationTargetName(O: Obj, RE, Fmt);
486 Fmt << "-2";
487 break;
488 case MachO::X86_64_RELOC_SIGNED_4:
489 printRelocationTargetName(O: Obj, RE, Fmt);
490 Fmt << "-4";
491 break;
492 default:
493 printRelocationTargetName(O: Obj, RE, Fmt);
494 break;
495 }
496 // X86 and ARM share some relocation types in common.
497 } else if (Arch == Triple::x86 || Arch == Triple::arm ||
498 Arch == Triple::ppc) {
499 // Generic relocation types...
500 switch (Type) {
501 case MachO::GENERIC_RELOC_PAIR: // prints no info
502 return Error::success();
503 case MachO::GENERIC_RELOC_SECTDIFF: {
504 DataRefImpl RelNext = Rel;
505 Obj->moveRelocationNext(Rel&: RelNext);
506 MachO::any_relocation_info RENext = Obj->getRelocation(Rel: RelNext);
507
508 // X86 sect diff's must be followed by a relocation of type
509 // GENERIC_RELOC_PAIR.
510 unsigned RType = Obj->getAnyRelocationType(RE: RENext);
511
512 if (RType != MachO::GENERIC_RELOC_PAIR)
513 reportError(File: Obj->getFileName(), Message: "Expected GENERIC_RELOC_PAIR after "
514 "GENERIC_RELOC_SECTDIFF.");
515
516 printRelocationTargetName(O: Obj, RE, Fmt);
517 Fmt << "-";
518 printRelocationTargetName(O: Obj, RE: RENext, Fmt);
519 break;
520 }
521 }
522
523 if (Arch == Triple::x86 || Arch == Triple::ppc) {
524 switch (Type) {
525 case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
526 DataRefImpl RelNext = Rel;
527 Obj->moveRelocationNext(Rel&: RelNext);
528 MachO::any_relocation_info RENext = Obj->getRelocation(Rel: RelNext);
529
530 // X86 sect diff's must be followed by a relocation of type
531 // GENERIC_RELOC_PAIR.
532 unsigned RType = Obj->getAnyRelocationType(RE: RENext);
533 if (RType != MachO::GENERIC_RELOC_PAIR)
534 reportError(File: Obj->getFileName(), Message: "Expected GENERIC_RELOC_PAIR after "
535 "GENERIC_RELOC_LOCAL_SECTDIFF.");
536
537 printRelocationTargetName(O: Obj, RE, Fmt);
538 Fmt << "-";
539 printRelocationTargetName(O: Obj, RE: RENext, Fmt);
540 break;
541 }
542 case MachO::GENERIC_RELOC_TLV: {
543 printRelocationTargetName(O: Obj, RE, Fmt);
544 Fmt << "@TLV";
545 if (IsPCRel)
546 Fmt << "P";
547 break;
548 }
549 default:
550 printRelocationTargetName(O: Obj, RE, Fmt);
551 }
552 } else { // ARM-specific relocations
553 switch (Type) {
554 case MachO::ARM_RELOC_HALF:
555 case MachO::ARM_RELOC_HALF_SECTDIFF: {
556 // Half relocations steal a bit from the length field to encode
557 // whether this is an upper16 or a lower16 relocation.
558 bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
559
560 if (isUpper)
561 Fmt << ":upper16:(";
562 else
563 Fmt << ":lower16:(";
564 printRelocationTargetName(O: Obj, RE, Fmt);
565
566 DataRefImpl RelNext = Rel;
567 Obj->moveRelocationNext(Rel&: RelNext);
568 MachO::any_relocation_info RENext = Obj->getRelocation(Rel: RelNext);
569
570 // ARM half relocs must be followed by a relocation of type
571 // ARM_RELOC_PAIR.
572 unsigned RType = Obj->getAnyRelocationType(RE: RENext);
573 if (RType != MachO::ARM_RELOC_PAIR)
574 reportError(File: Obj->getFileName(), Message: "Expected ARM_RELOC_PAIR after "
575 "ARM_RELOC_HALF");
576
577 // NOTE: The half of the target virtual address is stashed in the
578 // address field of the secondary relocation, but we can't reverse
579 // engineer the constant offset from it without decoding the movw/movt
580 // instruction to find the other half in its immediate field.
581
582 // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
583 // symbol/section pointer of the follow-on relocation.
584 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
585 Fmt << "-";
586 printRelocationTargetName(O: Obj, RE: RENext, Fmt);
587 }
588
589 Fmt << ")";
590 break;
591 }
592 default: {
593 printRelocationTargetName(O: Obj, RE, Fmt);
594 }
595 }
596 }
597 } else
598 printRelocationTargetName(O: Obj, RE, Fmt);
599
600 Result.append(in_start: FmtBuf.begin(), in_end: FmtBuf.end());
601 return Error::success();
602}
603
604static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
605 uint32_t n, uint32_t count,
606 uint32_t stride, uint64_t addr) {
607 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
608 uint32_t nindirectsyms = Dysymtab.nindirectsyms;
609 if (n > nindirectsyms)
610 outs() << " (entries start past the end of the indirect symbol "
611 "table) (reserved1 field greater than the table size)";
612 else if (n + count > nindirectsyms)
613 outs() << " (entries extends past the end of the indirect symbol "
614 "table)";
615 outs() << "\n";
616 uint32_t cputype = O->getHeader().cputype;
617 if (cputype & MachO::CPU_ARCH_ABI64)
618 outs() << "address index";
619 else
620 outs() << "address index";
621 if (verbose)
622 outs() << " name\n";
623 else
624 outs() << "\n";
625 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
626 if (cputype & MachO::CPU_ARCH_ABI64)
627 outs() << format(Fmt: "0x%016" PRIx64, Vals: addr + j * stride) << " ";
628 else
629 outs() << format(Fmt: "0x%08" PRIx32, Vals: (uint32_t)addr + j * stride) << " ";
630 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
631 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(DLC: Dysymtab, Index: n + j);
632 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
633 outs() << "LOCAL\n";
634 continue;
635 }
636 if (indirect_symbol ==
637 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
638 outs() << "LOCAL ABSOLUTE\n";
639 continue;
640 }
641 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
642 outs() << "ABSOLUTE\n";
643 continue;
644 }
645 outs() << format(Fmt: "%5u ", Vals: indirect_symbol);
646 if (verbose) {
647 MachO::symtab_command Symtab = O->getSymtabLoadCommand();
648 if (indirect_symbol < Symtab.nsyms) {
649 symbol_iterator Sym = O->getSymbolByIndex(Index: indirect_symbol);
650 SymbolRef Symbol = *Sym;
651 outs() << unwrapOrError(EO: Symbol.getName(), Args: O->getFileName());
652 } else {
653 outs() << "?";
654 }
655 }
656 outs() << "\n";
657 }
658}
659
660static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
661 for (const auto &Load : O->load_commands()) {
662 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
663 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(L: Load);
664 for (unsigned J = 0; J < Seg.nsects; ++J) {
665 MachO::section_64 Sec = O->getSection64(L: Load, Index: J);
666 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
667 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
668 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
669 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
670 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
671 section_type == MachO::S_SYMBOL_STUBS) {
672 uint32_t stride;
673 if (section_type == MachO::S_SYMBOL_STUBS)
674 stride = Sec.reserved2;
675 else
676 stride = 8;
677 if (stride == 0) {
678 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
679 << Sec.sectname << ") "
680 << "(size of stubs in reserved2 field is zero)\n";
681 continue;
682 }
683 uint32_t count = Sec.size / stride;
684 outs() << "Indirect symbols for (" << Sec.segname << ","
685 << Sec.sectname << ") " << count << " entries";
686 uint32_t n = Sec.reserved1;
687 PrintIndirectSymbolTable(O, verbose, n, count, stride, addr: Sec.addr);
688 }
689 }
690 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
691 MachO::segment_command Seg = O->getSegmentLoadCommand(L: Load);
692 for (unsigned J = 0; J < Seg.nsects; ++J) {
693 MachO::section Sec = O->getSection(L: Load, Index: J);
694 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
695 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
696 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
697 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
698 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
699 section_type == MachO::S_SYMBOL_STUBS) {
700 uint32_t stride;
701 if (section_type == MachO::S_SYMBOL_STUBS)
702 stride = Sec.reserved2;
703 else
704 stride = 4;
705 if (stride == 0) {
706 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
707 << Sec.sectname << ") "
708 << "(size of stubs in reserved2 field is zero)\n";
709 continue;
710 }
711 uint32_t count = Sec.size / stride;
712 outs() << "Indirect symbols for (" << Sec.segname << ","
713 << Sec.sectname << ") " << count << " entries";
714 uint32_t n = Sec.reserved1;
715 PrintIndirectSymbolTable(O, verbose, n, count, stride, addr: Sec.addr);
716 }
717 }
718 }
719 }
720}
721
722static void PrintRType(const uint64_t cputype, const unsigned r_type) {
723 static char const *generic_r_types[] = {
724 "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
725 " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
726 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
727 };
728 static char const *x86_64_r_types[] = {
729 "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
730 "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
731 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
732 };
733 static char const *arm_r_types[] = {
734 "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
735 "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
736 " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
737 };
738 static char const *arm64_r_types[] = {
739 "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
740 "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
741 "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
742 };
743
744 if (r_type > 0xf){
745 outs() << format(Fmt: "%-7u", Vals: r_type) << " ";
746 return;
747 }
748 switch (cputype) {
749 case MachO::CPU_TYPE_I386:
750 outs() << generic_r_types[r_type];
751 break;
752 case MachO::CPU_TYPE_X86_64:
753 outs() << x86_64_r_types[r_type];
754 break;
755 case MachO::CPU_TYPE_ARM:
756 outs() << arm_r_types[r_type];
757 break;
758 case MachO::CPU_TYPE_ARM64:
759 case MachO::CPU_TYPE_ARM64_32:
760 outs() << arm64_r_types[r_type];
761 break;
762 default:
763 outs() << format(Fmt: "%-7u ", Vals: r_type);
764 }
765}
766
767static void PrintRLength(const uint64_t cputype, const unsigned r_type,
768 const unsigned r_length, const bool previous_arm_half){
769 if (cputype == MachO::CPU_TYPE_ARM &&
770 (r_type == MachO::ARM_RELOC_HALF ||
771 r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {
772 if ((r_length & 0x1) == 0)
773 outs() << "lo/";
774 else
775 outs() << "hi/";
776 if ((r_length & 0x1) == 0)
777 outs() << "arm ";
778 else
779 outs() << "thm ";
780 } else {
781 switch (r_length) {
782 case 0:
783 outs() << "byte ";
784 break;
785 case 1:
786 outs() << "word ";
787 break;
788 case 2:
789 outs() << "long ";
790 break;
791 case 3:
792 if (cputype == MachO::CPU_TYPE_X86_64)
793 outs() << "quad ";
794 else
795 outs() << format(Fmt: "?(%2d) ", Vals: r_length);
796 break;
797 default:
798 outs() << format(Fmt: "?(%2d) ", Vals: r_length);
799 }
800 }
801}
802
803static void PrintRelocationEntries(const MachOObjectFile *O,
804 const relocation_iterator Begin,
805 const relocation_iterator End,
806 const uint64_t cputype,
807 const bool verbose) {
808 const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
809 bool previous_arm_half = false;
810 bool previous_sectdiff = false;
811 uint32_t sectdiff_r_type = 0;
812
813 for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
814 const DataRefImpl Rel = Reloc->getRawDataRefImpl();
815 const MachO::any_relocation_info RE = O->getRelocation(Rel);
816 const unsigned r_type = O->getAnyRelocationType(RE);
817 const bool r_scattered = O->isRelocationScattered(RE);
818 const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
819 const unsigned r_length = O->getAnyRelocationLength(RE);
820 const unsigned r_address = O->getAnyRelocationAddress(RE);
821 const bool r_extern = (r_scattered ? false :
822 O->getPlainRelocationExternal(RE));
823 const uint32_t r_value = (r_scattered ?
824 O->getScatteredRelocationValue(RE) : 0);
825 const unsigned r_symbolnum = (r_scattered ? 0 :
826 O->getPlainRelocationSymbolNum(RE));
827
828 if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
829 if (verbose) {
830 // scattered: address
831 if ((cputype == MachO::CPU_TYPE_I386 &&
832 r_type == MachO::GENERIC_RELOC_PAIR) ||
833 (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))
834 outs() << " ";
835 else
836 outs() << format(Fmt: "%08x ", Vals: (unsigned int)r_address);
837
838 // scattered: pcrel
839 if (r_pcrel)
840 outs() << "True ";
841 else
842 outs() << "False ";
843
844 // scattered: length
845 PrintRLength(cputype, r_type, r_length, previous_arm_half);
846
847 // scattered: extern & type
848 outs() << "n/a ";
849 PrintRType(cputype, r_type);
850
851 // scattered: scattered & value
852 outs() << format(Fmt: "True 0x%08x", Vals: (unsigned int)r_value);
853 if (previous_sectdiff == false) {
854 if ((cputype == MachO::CPU_TYPE_ARM &&
855 r_type == MachO::ARM_RELOC_PAIR))
856 outs() << format(Fmt: " half = 0x%04x ", Vals: (unsigned int)r_address);
857 } else if (cputype == MachO::CPU_TYPE_ARM &&
858 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)
859 outs() << format(Fmt: " other_half = 0x%04x ", Vals: (unsigned int)r_address);
860 if ((cputype == MachO::CPU_TYPE_I386 &&
861 (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
862 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
863 (cputype == MachO::CPU_TYPE_ARM &&
864 (sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||
865 sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
866 sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {
867 previous_sectdiff = true;
868 sectdiff_r_type = r_type;
869 } else {
870 previous_sectdiff = false;
871 sectdiff_r_type = 0;
872 }
873 if (cputype == MachO::CPU_TYPE_ARM &&
874 (r_type == MachO::ARM_RELOC_HALF ||
875 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
876 previous_arm_half = true;
877 else
878 previous_arm_half = false;
879 outs() << "\n";
880 }
881 else {
882 // scattered: address pcrel length extern type scattered value
883 outs() << format(Fmt: "%08x %1d %-2d n/a %-7d 1 0x%08x\n",
884 Vals: (unsigned int)r_address, Vals: r_pcrel, Vals: r_length, Vals: r_type,
885 Vals: (unsigned int)r_value);
886 }
887 }
888 else {
889 if (verbose) {
890 // plain: address
891 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
892 outs() << " ";
893 else
894 outs() << format(Fmt: "%08x ", Vals: (unsigned int)r_address);
895
896 // plain: pcrel
897 if (r_pcrel)
898 outs() << "True ";
899 else
900 outs() << "False ";
901
902 // plain: length
903 PrintRLength(cputype, r_type, r_length, previous_arm_half);
904
905 if (r_extern) {
906 // plain: extern & type & scattered
907 outs() << "True ";
908 PrintRType(cputype, r_type);
909 outs() << "False ";
910
911 // plain: symbolnum/value
912 if (r_symbolnum > Symtab.nsyms)
913 outs() << format(Fmt: "?(%d)\n", Vals: r_symbolnum);
914 else {
915 SymbolRef Symbol = *O->getSymbolByIndex(Index: r_symbolnum);
916 Expected<StringRef> SymNameNext = Symbol.getName();
917 const char *name = nullptr;
918 if (SymNameNext)
919 name = SymNameNext->data();
920 if (name == nullptr)
921 outs() << format(Fmt: "?(%d)\n", Vals: r_symbolnum);
922 else
923 outs() << name << "\n";
924 }
925 }
926 else {
927 // plain: extern & type & scattered
928 outs() << "False ";
929 PrintRType(cputype, r_type);
930 outs() << "False ";
931
932 // plain: symbolnum/value
933 if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
934 outs() << format(Fmt: "other_half = 0x%04x\n", Vals: (unsigned int)r_address);
935 else if ((cputype == MachO::CPU_TYPE_ARM64 ||
936 cputype == MachO::CPU_TYPE_ARM64_32) &&
937 r_type == MachO::ARM64_RELOC_ADDEND)
938 outs() << format(Fmt: "addend = 0x%06x\n", Vals: (unsigned int)r_symbolnum);
939 else if (cputype == MachO::CPU_TYPE_RISCV &&
940 r_type == MachO::RISCV_RELOC_ADDEND)
941 outs() << format(Fmt: "addend = 0x%06x\n", Vals: (unsigned int)r_symbolnum);
942 else {
943 outs() << format(Fmt: "%d ", Vals: r_symbolnum);
944 if (r_symbolnum == MachO::R_ABS)
945 outs() << "R_ABS\n";
946 else {
947 // in this case, r_symbolnum is actually a 1-based section number
948 uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
949 if (r_symbolnum > 0 && r_symbolnum <= nsects) {
950 object::DataRefImpl DRI;
951 DRI.d.a = r_symbolnum-1;
952 StringRef SegName = O->getSectionFinalSegmentName(Sec: DRI);
953 if (Expected<StringRef> NameOrErr = O->getSectionName(Sec: DRI))
954 outs() << "(" << SegName << "," << *NameOrErr << ")\n";
955 else
956 outs() << "(?,?)\n";
957 }
958 else {
959 outs() << "(?,?)\n";
960 }
961 }
962 }
963 }
964 if (cputype == MachO::CPU_TYPE_ARM &&
965 (r_type == MachO::ARM_RELOC_HALF ||
966 r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
967 previous_arm_half = true;
968 else
969 previous_arm_half = false;
970 }
971 else {
972 // plain: address pcrel length extern type scattered symbolnum/section
973 outs() << format(Fmt: "%08x %1d %-2d %1d %-7d 0 %d\n",
974 Vals: (unsigned int)r_address, Vals: r_pcrel, Vals: r_length, Vals: r_extern,
975 Vals: r_type, Vals: r_symbolnum);
976 }
977 }
978 }
979}
980
981static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
982 const uint64_t cputype = O->getHeader().cputype;
983 const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
984 if (Dysymtab.nextrel != 0) {
985 outs() << "External relocation information " << Dysymtab.nextrel
986 << " entries";
987 outs() << "\naddress pcrel length extern type scattered "
988 "symbolnum/value\n";
989 PrintRelocationEntries(O, Begin: O->extrel_begin(), End: O->extrel_end(), cputype,
990 verbose);
991 }
992 if (Dysymtab.nlocrel != 0) {
993 outs() << format(Fmt: "Local relocation information %u entries",
994 Vals: Dysymtab.nlocrel);
995 outs() << "\naddress pcrel length extern type scattered "
996 "symbolnum/value\n";
997 PrintRelocationEntries(O, Begin: O->locrel_begin(), End: O->locrel_end(), cputype,
998 verbose);
999 }
1000 for (const auto &Load : O->load_commands()) {
1001 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
1002 const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(L: Load);
1003 for (unsigned J = 0; J < Seg.nsects; ++J) {
1004 const MachO::section_64 Sec = O->getSection64(L: Load, Index: J);
1005 if (Sec.nreloc != 0) {
1006 DataRefImpl DRI;
1007 DRI.d.a = J;
1008 const StringRef SegName = O->getSectionFinalSegmentName(Sec: DRI);
1009 if (Expected<StringRef> NameOrErr = O->getSectionName(Sec: DRI))
1010 outs() << "Relocation information (" << SegName << "," << *NameOrErr
1011 << format(Fmt: ") %u entries", Vals: Sec.nreloc);
1012 else
1013 outs() << "Relocation information (" << SegName << ",?) "
1014 << format(Fmt: "%u entries", Vals: Sec.nreloc);
1015 outs() << "\naddress pcrel length extern type scattered "
1016 "symbolnum/value\n";
1017 PrintRelocationEntries(O, Begin: O->section_rel_begin(Sec: DRI),
1018 End: O->section_rel_end(Sec: DRI), cputype, verbose);
1019 }
1020 }
1021 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
1022 const MachO::segment_command Seg = O->getSegmentLoadCommand(L: Load);
1023 for (unsigned J = 0; J < Seg.nsects; ++J) {
1024 const MachO::section Sec = O->getSection(L: Load, Index: J);
1025 if (Sec.nreloc != 0) {
1026 DataRefImpl DRI;
1027 DRI.d.a = J;
1028 const StringRef SegName = O->getSectionFinalSegmentName(Sec: DRI);
1029 if (Expected<StringRef> NameOrErr = O->getSectionName(Sec: DRI))
1030 outs() << "Relocation information (" << SegName << "," << *NameOrErr
1031 << format(Fmt: ") %u entries", Vals: Sec.nreloc);
1032 else
1033 outs() << "Relocation information (" << SegName << ",?) "
1034 << format(Fmt: "%u entries", Vals: Sec.nreloc);
1035 outs() << "\naddress pcrel length extern type scattered "
1036 "symbolnum/value\n";
1037 PrintRelocationEntries(O, Begin: O->section_rel_begin(Sec: DRI),
1038 End: O->section_rel_end(Sec: DRI), cputype, verbose);
1039 }
1040 }
1041 }
1042 }
1043}
1044
1045static void PrintFunctionStarts(MachOObjectFile *O) {
1046 uint64_t BaseSegmentAddress = 0;
1047 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1048 if (Command.C.cmd == MachO::LC_SEGMENT) {
1049 MachO::segment_command SLC = O->getSegmentLoadCommand(L: Command);
1050 if (StringRef(SLC.segname) == "__TEXT") {
1051 BaseSegmentAddress = SLC.vmaddr;
1052 break;
1053 }
1054 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1055 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(L: Command);
1056 if (StringRef(SLC.segname) == "__TEXT") {
1057 BaseSegmentAddress = SLC.vmaddr;
1058 break;
1059 }
1060 }
1061 }
1062
1063 SmallVector<uint64_t, 8> FunctionStarts;
1064 for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {
1065 if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {
1066 MachO::linkedit_data_command FunctionStartsLC =
1067 O->getLinkeditDataLoadCommand(L: LC);
1068 O->ReadULEB128s(Index: FunctionStartsLC.dataoff, Out&: FunctionStarts);
1069 break;
1070 }
1071 }
1072
1073 DenseMap<uint64_t, StringRef> SymbolNames;
1074 if (FunctionStartsType == FunctionStartsMode::Names ||
1075 FunctionStartsType == FunctionStartsMode::Both) {
1076 for (SymbolRef Sym : O->symbols()) {
1077 if (Expected<uint64_t> Addr = Sym.getAddress()) {
1078 if (Expected<StringRef> Name = Sym.getName()) {
1079 SymbolNames[*Addr] = *Name;
1080 }
1081 }
1082 }
1083 }
1084
1085 for (uint64_t S : FunctionStarts) {
1086 uint64_t Addr = BaseSegmentAddress + S;
1087 if (FunctionStartsType == FunctionStartsMode::Names) {
1088 auto It = SymbolNames.find(Val: Addr);
1089 if (It != SymbolNames.end())
1090 outs() << It->second << "\n";
1091 } else {
1092 if (O->is64Bit())
1093 outs() << format(Fmt: "%016" PRIx64, Vals: Addr);
1094 else
1095 outs() << format(Fmt: "%08" PRIx32, Vals: static_cast<uint32_t>(Addr));
1096
1097 if (FunctionStartsType == FunctionStartsMode::Both) {
1098 auto It = SymbolNames.find(Val: Addr);
1099 if (It != SymbolNames.end())
1100 outs() << " " << It->second;
1101 else
1102 outs() << " ?";
1103 }
1104 outs() << "\n";
1105 }
1106 }
1107}
1108
1109static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
1110 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
1111 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
1112 outs() << "Data in code table (" << nentries << " entries)\n";
1113 outs() << "offset length kind\n";
1114 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
1115 ++DI) {
1116 uint32_t Offset;
1117 DI->getOffset(Result&: Offset);
1118 outs() << format(Fmt: "0x%08" PRIx32, Vals: Offset) << " ";
1119 uint16_t Length;
1120 DI->getLength(Result&: Length);
1121 outs() << format(Fmt: "%6u", Vals: Length) << " ";
1122 uint16_t Kind;
1123 DI->getKind(Result&: Kind);
1124 if (verbose) {
1125 switch (Kind) {
1126 case MachO::DICE_KIND_DATA:
1127 outs() << "DATA";
1128 break;
1129 case MachO::DICE_KIND_JUMP_TABLE8:
1130 outs() << "JUMP_TABLE8";
1131 break;
1132 case MachO::DICE_KIND_JUMP_TABLE16:
1133 outs() << "JUMP_TABLE16";
1134 break;
1135 case MachO::DICE_KIND_JUMP_TABLE32:
1136 outs() << "JUMP_TABLE32";
1137 break;
1138 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
1139 outs() << "ABS_JUMP_TABLE32";
1140 break;
1141 default:
1142 outs() << format(Fmt: "0x%04" PRIx32, Vals: Kind);
1143 break;
1144 }
1145 } else
1146 outs() << format(Fmt: "0x%04" PRIx32, Vals: Kind);
1147 outs() << "\n";
1148 }
1149}
1150
1151static void PrintLinkOptHints(MachOObjectFile *O) {
1152 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
1153 const char *loh = O->getData().substr(Start: LohLC.dataoff, N: 1).data();
1154 uint32_t nloh = LohLC.datasize;
1155 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
1156 for (uint32_t i = 0; i < nloh;) {
1157 unsigned n;
1158 uint64_t identifier = decodeULEB128(p: (const uint8_t *)(loh + i), n: &n);
1159 i += n;
1160 outs() << " identifier " << identifier << " ";
1161 if (i >= nloh)
1162 return;
1163 switch (identifier) {
1164 case 1:
1165 outs() << "AdrpAdrp\n";
1166 break;
1167 case 2:
1168 outs() << "AdrpLdr\n";
1169 break;
1170 case 3:
1171 outs() << "AdrpAddLdr\n";
1172 break;
1173 case 4:
1174 outs() << "AdrpLdrGotLdr\n";
1175 break;
1176 case 5:
1177 outs() << "AdrpAddStr\n";
1178 break;
1179 case 6:
1180 outs() << "AdrpLdrGotStr\n";
1181 break;
1182 case 7:
1183 outs() << "AdrpAdd\n";
1184 break;
1185 case 8:
1186 outs() << "AdrpLdrGot\n";
1187 break;
1188 default:
1189 outs() << "Unknown identifier value\n";
1190 break;
1191 }
1192 uint64_t narguments = decodeULEB128(p: (const uint8_t *)(loh + i), n: &n);
1193 i += n;
1194 outs() << " narguments " << narguments << "\n";
1195 if (i >= nloh)
1196 return;
1197
1198 for (uint32_t j = 0; j < narguments; j++) {
1199 uint64_t value = decodeULEB128(p: (const uint8_t *)(loh + i), n: &n);
1200 i += n;
1201 outs() << "\tvalue " << format(Fmt: "0x%" PRIx64, Vals: value) << "\n";
1202 if (i >= nloh)
1203 return;
1204 }
1205 }
1206}
1207
1208static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
1209 SmallVector<std::string> Ret;
1210 for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1211 if (Command.C.cmd == MachO::LC_SEGMENT) {
1212 MachO::segment_command SLC = O->getSegmentLoadCommand(L: Command);
1213 Ret.push_back(Elt: SLC.segname);
1214 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1215 MachO::segment_command_64 SLC = O->getSegment64LoadCommand(L: Command);
1216 Ret.push_back(Elt: SLC.segname);
1217 }
1218 }
1219 return Ret;
1220}
1221
1222static void
1223PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
1224 outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
1225 outs() << " fixups_version = " << H.fixups_version << '\n';
1226 outs() << " starts_offset = " << H.starts_offset << '\n';
1227 outs() << " imports_offset = " << H.imports_offset << '\n';
1228 outs() << " symbols_offset = " << H.symbols_offset << '\n';
1229 outs() << " imports_count = " << H.imports_count << '\n';
1230
1231 outs() << " imports_format = " << H.imports_format;
1232 switch (H.imports_format) {
1233 case llvm::MachO::DYLD_CHAINED_IMPORT:
1234 outs() << " (DYLD_CHAINED_IMPORT)";
1235 break;
1236 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
1237 outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
1238 break;
1239 case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
1240 outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
1241 break;
1242 }
1243 outs() << '\n';
1244
1245 outs() << " symbols_format = " << H.symbols_format;
1246 if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
1247 outs() << " (zlib compressed)";
1248 outs() << '\n';
1249}
1250
1251static constexpr std::array<StringRef, 13> PointerFormats{
1252 "DYLD_CHAINED_PTR_ARM64E",
1253 "DYLD_CHAINED_PTR_64",
1254 "DYLD_CHAINED_PTR_32",
1255 "DYLD_CHAINED_PTR_32_CACHE",
1256 "DYLD_CHAINED_PTR_32_FIRMWARE",
1257 "DYLD_CHAINED_PTR_64_OFFSET",
1258 "DYLD_CHAINED_PTR_ARM64E_KERNEL",
1259 "DYLD_CHAINED_PTR_64_KERNEL_CACHE",
1260 "DYLD_CHAINED_PTR_ARM64E_USERLAND",
1261 "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
1262 "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
1263 "DYLD_CHAINED_PTR_ARM64E_USERLAND24",
1264};
1265
1266static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,
1267 StringRef SegName) {
1268 outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
1269 << ")\n";
1270 outs() << " size = " << Segment.Header.size << '\n';
1271 outs() << " page_size = " << format(Fmt: "0x%0" PRIx16, Vals: Segment.Header.page_size)
1272 << '\n';
1273
1274 outs() << " pointer_format = " << Segment.Header.pointer_format;
1275 if ((Segment.Header.pointer_format - 1) <
1276 MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
1277 outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
1278 outs() << '\n';
1279
1280 outs() << " segment_offset = "
1281 << format(Fmt: "0x%0" PRIx64, Vals: Segment.Header.segment_offset) << '\n';
1282 outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
1283 << '\n';
1284 outs() << " page_count = " << Segment.Header.page_count << '\n';
1285 for (auto [Index, PageStart] : enumerate(First: Segment.PageStarts)) {
1286 outs() << " page_start[" << Index << "] = " << PageStart;
1287 // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
1288 if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
1289 outs() << " (DYLD_CHAINED_PTR_START_NONE)";
1290 outs() << '\n';
1291 }
1292}
1293
1294static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,
1295 int Format, MachOObjectFile *O) {
1296 if (Format == MachO::DYLD_CHAINED_IMPORT)
1297 outs() << "dyld chained import";
1298 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
1299 outs() << "dyld chained import addend";
1300 else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
1301 outs() << "dyld chained import addend64";
1302 // FIXME: otool prints the encoded value as well.
1303 outs() << '[' << Idx << "]\n";
1304
1305 outs() << " lib_ordinal = " << Target.libOrdinal() << " ("
1306 << ordinalName(O, Target.libOrdinal()) << ")\n";
1307 outs() << " weak_import = " << Target.weakImport() << '\n';
1308 outs() << " name_offset = " << Target.nameOffset() << " ("
1309 << Target.symbolName() << ")\n";
1310 if (Format != MachO::DYLD_CHAINED_IMPORT)
1311 outs() << " addend = " << (int64_t)Target.addend() << '\n';
1312}
1313
1314static void PrintChainedFixups(MachOObjectFile *O) {
1315 // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
1316 // FIXME: Support chained fixups in __TEXT,__chain_starts section too.
1317 auto ChainedFixupHeader =
1318 unwrapOrError(EO: O->getChainedFixupsHeader(), Args: O->getFileName());
1319 if (!ChainedFixupHeader)
1320 return;
1321
1322 PrintChainedFixupsHeader(H: *ChainedFixupHeader);
1323
1324 auto [SegCount, Segments] =
1325 unwrapOrError(EO: O->getChainedFixupsSegments(), Args: O->getFileName());
1326
1327 auto SegNames = GetSegmentNames(O);
1328
1329 size_t StartsIdx = 0;
1330 outs() << "chained starts in image\n";
1331 outs() << " seg_count = " << SegCount << '\n';
1332 for (size_t I = 0; I < SegCount; ++I) {
1333 uint64_t SegOffset = 0;
1334 if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
1335 SegOffset = Segments[StartsIdx].Offset;
1336 ++StartsIdx;
1337 }
1338
1339 outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
1340 << SegNames[I] << ")\n";
1341 }
1342
1343 for (const ChainedFixupsSegment &S : Segments)
1344 PrintChainedFixupsSegment(Segment: S, SegName: SegNames[S.SegIdx]);
1345
1346 auto FixupTargets =
1347 unwrapOrError(EO: O->getDyldChainedFixupTargets(), Args: O->getFileName());
1348
1349 uint32_t ImportsFormat = ChainedFixupHeader->imports_format;
1350 for (auto [Idx, Target] : enumerate(First&: FixupTargets))
1351 PrintChainedFixupTarget(Target, Idx, Format: ImportsFormat, O);
1352}
1353
1354static void PrintDyldInfo(MachOObjectFile *O) {
1355 Error Err = Error::success();
1356
1357 size_t SegmentWidth = strlen(s: "segment");
1358 size_t SectionWidth = strlen(s: "section");
1359 size_t AddressWidth = strlen(s: "address");
1360 size_t AddendWidth = strlen(s: "addend");
1361 size_t DylibWidth = strlen(s: "dylib");
1362 const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;
1363
1364 auto HexLength = [](uint64_t Num) {
1365 return Num ? (size_t)divideCeil(Numerator: Log2_64(Value: Num), Denominator: 4) : 1;
1366 };
1367 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1368 SegmentWidth = std::max(a: SegmentWidth, b: Entry.segmentName().size());
1369 SectionWidth = std::max(a: SectionWidth, b: Entry.sectionName().size());
1370 AddressWidth = std::max(a: AddressWidth, b: HexLength(Entry.address()) + 2);
1371 if (Entry.isBind()) {
1372 AddendWidth = std::max(a: AddendWidth, b: HexLength(Entry.addend()) + 2);
1373 DylibWidth = std::max(a: DylibWidth, b: Entry.symbolName().size());
1374 }
1375 }
1376 // Errors will be handled when printing the table.
1377 if (Err)
1378 consumeError(Err: std::move(Err));
1379
1380 outs() << "dyld information:\n";
1381 outs() << left_justify(Str: "segment", Width: SegmentWidth) << ' '
1382 << left_justify(Str: "section", Width: SectionWidth) << ' '
1383 << left_justify(Str: "address", Width: AddressWidth) << ' '
1384 << left_justify(Str: "pointer", Width: PointerWidth) << " type "
1385 << left_justify(Str: "addend", Width: AddendWidth) << ' '
1386 << left_justify(Str: "dylib", Width: DylibWidth) << " symbol/vm address\n";
1387 for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1388 outs() << left_justify(Str: Entry.segmentName(), Width: SegmentWidth) << ' '
1389 << left_justify(Str: Entry.sectionName(), Width: SectionWidth) << ' ' << "0x"
1390 << left_justify(Str: utohexstr(X: Entry.address()), Width: AddressWidth - 2) << ' '
1391 << format_hex(N: Entry.rawValue(), Width: PointerWidth, Upper: true) << ' ';
1392 if (Entry.isBind()) {
1393 outs() << "bind "
1394 << "0x" << left_justify(Str: utohexstr(X: Entry.addend()), Width: AddendWidth - 2)
1395 << ' ' << left_justify(Str: ordinalName(O, Entry.ordinal()), Width: DylibWidth)
1396 << ' ' << Entry.symbolName();
1397 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
1398 outs() << " (weak import)";
1399 outs() << '\n';
1400 } else {
1401 assert(Entry.isRebase());
1402 outs() << "rebase";
1403 outs().indent(NumSpaces: AddendWidth + DylibWidth + 2);
1404 outs() << format(Fmt: "0x%" PRIX64, Vals: Entry.pointerValue()) << '\n';
1405 }
1406 }
1407 if (Err)
1408 reportError(E: std::move(Err), FileName: O->getFileName());
1409
1410 // TODO: Print opcode-based fixups if the object uses those.
1411}
1412
1413static void PrintDylibs(MachOObjectFile *O, bool JustId) {
1414 unsigned Index = 0;
1415 for (const auto &Load : O->load_commands()) {
1416 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
1417 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
1418 Load.C.cmd == MachO::LC_LOAD_DYLIB ||
1419 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
1420 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
1421 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
1422 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
1423 MachO::dylib_command dl = O->getDylibIDLoadCommand(L: Load);
1424 if (dl.dylib.name < dl.cmdsize) {
1425 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
1426 if (JustId)
1427 outs() << p << "\n";
1428 else {
1429 outs() << "\t" << p;
1430 outs() << " (compatibility version "
1431 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
1432 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
1433 << (dl.dylib.compatibility_version & 0xff) << ",";
1434 outs() << " current version "
1435 << ((dl.dylib.current_version >> 16) & 0xffff) << "."
1436 << ((dl.dylib.current_version >> 8) & 0xff) << "."
1437 << (dl.dylib.current_version & 0xff);
1438 if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1439 outs() << ", weak";
1440 if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1441 outs() << ", reexport";
1442 if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1443 outs() << ", upward";
1444 if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1445 outs() << ", lazy";
1446 outs() << ")\n";
1447 }
1448 } else {
1449 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
1450 if (Load.C.cmd == MachO::LC_ID_DYLIB)
1451 outs() << "LC_ID_DYLIB ";
1452 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
1453 outs() << "LC_LOAD_DYLIB ";
1454 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1455 outs() << "LC_LOAD_WEAK_DYLIB ";
1456 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1457 outs() << "LC_LAZY_LOAD_DYLIB ";
1458 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1459 outs() << "LC_REEXPORT_DYLIB ";
1460 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1461 outs() << "LC_LOAD_UPWARD_DYLIB ";
1462 else
1463 outs() << "LC_??? ";
1464 outs() << "command " << Index++ << "\n";
1465 }
1466 }
1467 }
1468}
1469
1470static void printRpaths(MachOObjectFile *O) {
1471 for (const auto &Command : O->load_commands()) {
1472 if (Command.C.cmd == MachO::LC_RPATH) {
1473 auto Rpath = O->getRpathCommand(L: Command);
1474 const char *P = (const char *)(Command.Ptr) + Rpath.path;
1475 outs() << P << "\n";
1476 }
1477 }
1478}
1479
1480typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
1481
1482static void CreateSymbolAddressMap(MachOObjectFile *O,
1483 SymbolAddressMap *AddrMap) {
1484 // Create a map of symbol addresses to symbol names.
1485 const StringRef FileName = O->getFileName();
1486 for (const SymbolRef &Symbol : O->symbols()) {
1487 SymbolRef::Type ST = unwrapOrError(EO: Symbol.getType(), Args: FileName);
1488 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
1489 ST == SymbolRef::ST_Other) {
1490 uint64_t Address = cantFail(ValOrErr: Symbol.getValue());
1491 StringRef SymName = unwrapOrError(EO: Symbol.getName(), Args: FileName);
1492 if (!SymName.starts_with(Prefix: ".objc"))
1493 (*AddrMap)[Address] = SymName;
1494 }
1495 }
1496}
1497
1498// GuessSymbolName is passed the address of what might be a symbol and a
1499// pointer to the SymbolAddressMap. It returns the name of a symbol
1500// with that address or nullptr if no symbol is found with that address.
1501static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
1502 const char *SymbolName = nullptr;
1503 // A DenseMap can't lookup up some values.
1504 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
1505 StringRef name = AddrMap->lookup(Val: value);
1506 if (!name.empty())
1507 SymbolName = name.data();
1508 }
1509 return SymbolName;
1510}
1511
1512static void DumpCstringChar(const char c) {
1513 char p[2];
1514 p[0] = c;
1515 p[1] = '\0';
1516 outs().write_escaped(Str: p);
1517}
1518
1519static void DumpCstringSection(MachOObjectFile *O, const char *sect,
1520 uint32_t sect_size, uint64_t sect_addr,
1521 bool print_addresses) {
1522 for (uint32_t i = 0; i < sect_size; i++) {
1523 if (print_addresses) {
1524 if (O->is64Bit())
1525 outs() << format(Fmt: "%016" PRIx64, Vals: sect_addr + i) << " ";
1526 else
1527 outs() << format(Fmt: "%08" PRIx64, Vals: sect_addr + i) << " ";
1528 }
1529 for (; i < sect_size && sect[i] != '\0'; i++)
1530 DumpCstringChar(c: sect[i]);
1531 if (i < sect_size && sect[i] == '\0')
1532 outs() << "\n";
1533 }
1534}
1535
1536static void DumpLiteral4(uint32_t l, float f) {
1537 outs() << format(Fmt: "0x%08" PRIx32, Vals: l);
1538 if ((l & 0x7f800000) != 0x7f800000)
1539 outs() << format(Fmt: " (%.16e)\n", Vals: f);
1540 else {
1541 if (l == 0x7f800000)
1542 outs() << " (+Infinity)\n";
1543 else if (l == 0xff800000)
1544 outs() << " (-Infinity)\n";
1545 else if ((l & 0x00400000) == 0x00400000)
1546 outs() << " (non-signaling Not-a-Number)\n";
1547 else
1548 outs() << " (signaling Not-a-Number)\n";
1549 }
1550}
1551
1552static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
1553 uint32_t sect_size, uint64_t sect_addr,
1554 bool print_addresses) {
1555 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
1556 if (print_addresses) {
1557 if (O->is64Bit())
1558 outs() << format(Fmt: "%016" PRIx64, Vals: sect_addr + i) << " ";
1559 else
1560 outs() << format(Fmt: "%08" PRIx64, Vals: sect_addr + i) << " ";
1561 }
1562 float f;
1563 memcpy(dest: &f, src: sect + i, n: sizeof(float));
1564 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1565 sys::swapByteOrder(Value&: f);
1566 uint32_t l;
1567 memcpy(dest: &l, src: sect + i, n: sizeof(uint32_t));
1568 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1569 sys::swapByteOrder(Value&: l);
1570 DumpLiteral4(l, f);
1571 }
1572}
1573
1574static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
1575 double d) {
1576 outs() << format(Fmt: "0x%08" PRIx32, Vals: l0) << " " << format(Fmt: "0x%08" PRIx32, Vals: l1);
1577 uint32_t Hi, Lo;
1578 Hi = (O->isLittleEndian()) ? l1 : l0;
1579 Lo = (O->isLittleEndian()) ? l0 : l1;
1580
1581 // Hi is the high word, so this is equivalent to if(isfinite(d))
1582 if ((Hi & 0x7ff00000) != 0x7ff00000)
1583 outs() << format(Fmt: " (%.16e)\n", Vals: d);
1584 else {
1585 if (Hi == 0x7ff00000 && Lo == 0)
1586 outs() << " (+Infinity)\n";
1587 else if (Hi == 0xfff00000 && Lo == 0)
1588 outs() << " (-Infinity)\n";
1589 else if ((Hi & 0x00080000) == 0x00080000)
1590 outs() << " (non-signaling Not-a-Number)\n";
1591 else
1592 outs() << " (signaling Not-a-Number)\n";
1593 }
1594}
1595
1596static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
1597 uint32_t sect_size, uint64_t sect_addr,
1598 bool print_addresses) {
1599 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
1600 if (print_addresses) {
1601 if (O->is64Bit())
1602 outs() << format(Fmt: "%016" PRIx64, Vals: sect_addr + i) << " ";
1603 else
1604 outs() << format(Fmt: "%08" PRIx64, Vals: sect_addr + i) << " ";
1605 }
1606 double d;
1607 memcpy(dest: &d, src: sect + i, n: sizeof(double));
1608 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1609 sys::swapByteOrder(Value&: d);
1610 uint32_t l0, l1;
1611 memcpy(dest: &l0, src: sect + i, n: sizeof(uint32_t));
1612 memcpy(dest: &l1, src: sect + i + sizeof(uint32_t), n: sizeof(uint32_t));
1613 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1614 sys::swapByteOrder(Value&: l0);
1615 sys::swapByteOrder(Value&: l1);
1616 }
1617 DumpLiteral8(O, l0, l1, d);
1618 }
1619}
1620
1621static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
1622 outs() << format(Fmt: "0x%08" PRIx32, Vals: l0) << " ";
1623 outs() << format(Fmt: "0x%08" PRIx32, Vals: l1) << " ";
1624 outs() << format(Fmt: "0x%08" PRIx32, Vals: l2) << " ";
1625 outs() << format(Fmt: "0x%08" PRIx32, Vals: l3) << "\n";
1626}
1627
1628static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
1629 uint32_t sect_size, uint64_t sect_addr,
1630 bool print_addresses) {
1631 for (uint32_t i = 0; i < sect_size; i += 16) {
1632 if (print_addresses) {
1633 if (O->is64Bit())
1634 outs() << format(Fmt: "%016" PRIx64, Vals: sect_addr + i) << " ";
1635 else
1636 outs() << format(Fmt: "%08" PRIx64, Vals: sect_addr + i) << " ";
1637 }
1638 uint32_t l0, l1, l2, l3;
1639 memcpy(dest: &l0, src: sect + i, n: sizeof(uint32_t));
1640 memcpy(dest: &l1, src: sect + i + sizeof(uint32_t), n: sizeof(uint32_t));
1641 memcpy(dest: &l2, src: sect + i + 2 * sizeof(uint32_t), n: sizeof(uint32_t));
1642 memcpy(dest: &l3, src: sect + i + 3 * sizeof(uint32_t), n: sizeof(uint32_t));
1643 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1644 sys::swapByteOrder(Value&: l0);
1645 sys::swapByteOrder(Value&: l1);
1646 sys::swapByteOrder(Value&: l2);
1647 sys::swapByteOrder(Value&: l3);
1648 }
1649 DumpLiteral16(l0, l1, l2, l3);
1650 }
1651}
1652
1653static void DumpLiteralPointerSection(MachOObjectFile *O,
1654 const SectionRef &Section,
1655 const char *sect, uint32_t sect_size,
1656 uint64_t sect_addr,
1657 bool print_addresses) {
1658 // Collect the literal sections in this Mach-O file.
1659 std::vector<SectionRef> LiteralSections;
1660 for (const SectionRef &Section : O->sections()) {
1661 DataRefImpl Ref = Section.getRawDataRefImpl();
1662 uint32_t section_type;
1663 if (O->is64Bit()) {
1664 const MachO::section_64 Sec = O->getSection64(DRI: Ref);
1665 section_type = Sec.flags & MachO::SECTION_TYPE;
1666 } else {
1667 const MachO::section Sec = O->getSection(DRI: Ref);
1668 section_type = Sec.flags & MachO::SECTION_TYPE;
1669 }
1670 if (section_type == MachO::S_CSTRING_LITERALS ||
1671 section_type == MachO::S_4BYTE_LITERALS ||
1672 section_type == MachO::S_8BYTE_LITERALS ||
1673 section_type == MachO::S_16BYTE_LITERALS)
1674 LiteralSections.push_back(x: Section);
1675 }
1676
1677 // Set the size of the literal pointer.
1678 uint32_t lp_size = O->is64Bit() ? 8 : 4;
1679
1680 // Collect the external relocation symbols for the literal pointers.
1681 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1682 for (const RelocationRef &Reloc : Section.relocations()) {
1683 DataRefImpl Rel;
1684 MachO::any_relocation_info RE;
1685 bool isExtern = false;
1686 Rel = Reloc.getRawDataRefImpl();
1687 RE = O->getRelocation(Rel);
1688 isExtern = O->getPlainRelocationExternal(RE);
1689 if (isExtern) {
1690 uint64_t RelocOffset = Reloc.getOffset();
1691 symbol_iterator RelocSym = Reloc.getSymbol();
1692 Relocs.push_back(x: std::make_pair(x&: RelocOffset, y: *RelocSym));
1693 }
1694 }
1695 array_pod_sort(Start: Relocs.begin(), End: Relocs.end());
1696
1697 // Dump each literal pointer.
1698 for (uint32_t i = 0; i < sect_size; i += lp_size) {
1699 if (print_addresses) {
1700 if (O->is64Bit())
1701 outs() << format(Fmt: "%016" PRIx64, Vals: sect_addr + i) << " ";
1702 else
1703 outs() << format(Fmt: "%08" PRIx64, Vals: sect_addr + i) << " ";
1704 }
1705 uint64_t lp;
1706 if (O->is64Bit()) {
1707 memcpy(dest: &lp, src: sect + i, n: sizeof(uint64_t));
1708 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1709 sys::swapByteOrder(Value&: lp);
1710 } else {
1711 uint32_t li;
1712 memcpy(dest: &li, src: sect + i, n: sizeof(uint32_t));
1713 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1714 sys::swapByteOrder(Value&: li);
1715 lp = li;
1716 }
1717
1718 // First look for an external relocation entry for this literal pointer.
1719 auto Reloc = find_if(Range&: Relocs, P: [&](const std::pair<uint64_t, SymbolRef> &P) {
1720 return P.first == i;
1721 });
1722 if (Reloc != Relocs.end()) {
1723 symbol_iterator RelocSym = Reloc->second;
1724 StringRef SymName = unwrapOrError(EO: RelocSym->getName(), Args: O->getFileName());
1725 outs() << "external relocation entry for symbol:" << SymName << "\n";
1726 continue;
1727 }
1728
1729 // For local references see what the section the literal pointer points to.
1730 auto Sect = find_if(Range&: LiteralSections, P: [&](const SectionRef &R) {
1731 return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();
1732 });
1733 if (Sect == LiteralSections.end()) {
1734 outs() << format(Fmt: "0x%" PRIx64, Vals: lp) << " (not in a literal section)\n";
1735 continue;
1736 }
1737
1738 uint64_t SectAddress = Sect->getAddress();
1739 uint64_t SectSize = Sect->getSize();
1740
1741 StringRef SectName;
1742 Expected<StringRef> SectNameOrErr = Sect->getName();
1743 if (SectNameOrErr)
1744 SectName = *SectNameOrErr;
1745 else
1746 consumeError(Err: SectNameOrErr.takeError());
1747
1748 DataRefImpl Ref = Sect->getRawDataRefImpl();
1749 StringRef SegmentName = O->getSectionFinalSegmentName(Sec: Ref);
1750 outs() << SegmentName << ":" << SectName << ":";
1751
1752 uint32_t section_type;
1753 if (O->is64Bit()) {
1754 const MachO::section_64 Sec = O->getSection64(DRI: Ref);
1755 section_type = Sec.flags & MachO::SECTION_TYPE;
1756 } else {
1757 const MachO::section Sec = O->getSection(DRI: Ref);
1758 section_type = Sec.flags & MachO::SECTION_TYPE;
1759 }
1760
1761 StringRef BytesStr = unwrapOrError(EO: Sect->getContents(), Args: O->getFileName());
1762
1763 const char *Contents = BytesStr.data();
1764
1765 switch (section_type) {
1766 case MachO::S_CSTRING_LITERALS:
1767 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
1768 i++) {
1769 DumpCstringChar(c: Contents[i]);
1770 }
1771 outs() << "\n";
1772 break;
1773 case MachO::S_4BYTE_LITERALS:
1774 float f;
1775 memcpy(dest: &f, src: Contents + (lp - SectAddress), n: sizeof(float));
1776 uint32_t l;
1777 memcpy(dest: &l, src: Contents + (lp - SectAddress), n: sizeof(uint32_t));
1778 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1779 sys::swapByteOrder(Value&: f);
1780 sys::swapByteOrder(Value&: l);
1781 }
1782 DumpLiteral4(l, f);
1783 break;
1784 case MachO::S_8BYTE_LITERALS: {
1785 double d;
1786 memcpy(dest: &d, src: Contents + (lp - SectAddress), n: sizeof(double));
1787 uint32_t l0, l1;
1788 memcpy(dest: &l0, src: Contents + (lp - SectAddress), n: sizeof(uint32_t));
1789 memcpy(dest: &l1, src: Contents + (lp - SectAddress) + sizeof(uint32_t),
1790 n: sizeof(uint32_t));
1791 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1792 sys::swapByteOrder(Value&: f);
1793 sys::swapByteOrder(Value&: l0);
1794 sys::swapByteOrder(Value&: l1);
1795 }
1796 DumpLiteral8(O, l0, l1, d);
1797 break;
1798 }
1799 case MachO::S_16BYTE_LITERALS: {
1800 uint32_t l0, l1, l2, l3;
1801 memcpy(dest: &l0, src: Contents + (lp - SectAddress), n: sizeof(uint32_t));
1802 memcpy(dest: &l1, src: Contents + (lp - SectAddress) + sizeof(uint32_t),
1803 n: sizeof(uint32_t));
1804 memcpy(dest: &l2, src: Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
1805 n: sizeof(uint32_t));
1806 memcpy(dest: &l3, src: Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
1807 n: sizeof(uint32_t));
1808 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1809 sys::swapByteOrder(Value&: l0);
1810 sys::swapByteOrder(Value&: l1);
1811 sys::swapByteOrder(Value&: l2);
1812 sys::swapByteOrder(Value&: l3);
1813 }
1814 DumpLiteral16(l0, l1, l2, l3);
1815 break;
1816 }
1817 }
1818 }
1819}
1820
1821static void DumpInitTermPointerSection(MachOObjectFile *O,
1822 const SectionRef &Section,
1823 const char *sect,
1824 uint32_t sect_size, uint64_t sect_addr,
1825 SymbolAddressMap *AddrMap,
1826 bool verbose) {
1827 uint32_t stride;
1828 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
1829
1830 // Collect the external relocation symbols for the pointers.
1831 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1832 for (const RelocationRef &Reloc : Section.relocations()) {
1833 DataRefImpl Rel;
1834 MachO::any_relocation_info RE;
1835 bool isExtern = false;
1836 Rel = Reloc.getRawDataRefImpl();
1837 RE = O->getRelocation(Rel);
1838 isExtern = O->getPlainRelocationExternal(RE);
1839 if (isExtern) {
1840 uint64_t RelocOffset = Reloc.getOffset();
1841 symbol_iterator RelocSym = Reloc.getSymbol();
1842 Relocs.push_back(x: std::make_pair(x&: RelocOffset, y: *RelocSym));
1843 }
1844 }
1845 array_pod_sort(Start: Relocs.begin(), End: Relocs.end());
1846
1847 for (uint32_t i = 0; i < sect_size; i += stride) {
1848 const char *SymbolName = nullptr;
1849 uint64_t p;
1850 if (O->is64Bit()) {
1851 outs() << format(Fmt: "0x%016" PRIx64, Vals: sect_addr + i * stride) << " ";
1852 uint64_t pointer_value;
1853 memcpy(dest: &pointer_value, src: sect + i, n: stride);
1854 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1855 sys::swapByteOrder(Value&: pointer_value);
1856 outs() << format(Fmt: "0x%016" PRIx64, Vals: pointer_value);
1857 p = pointer_value;
1858 } else {
1859 outs() << format(Fmt: "0x%08" PRIx64, Vals: sect_addr + i * stride) << " ";
1860 uint32_t pointer_value;
1861 memcpy(dest: &pointer_value, src: sect + i, n: stride);
1862 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1863 sys::swapByteOrder(Value&: pointer_value);
1864 outs() << format(Fmt: "0x%08" PRIx32, Vals: pointer_value);
1865 p = pointer_value;
1866 }
1867 if (verbose) {
1868 // First look for an external relocation entry for this pointer.
1869 auto Reloc = find_if(Range&: Relocs, P: [&](const std::pair<uint64_t, SymbolRef> &P) {
1870 return P.first == i;
1871 });
1872 if (Reloc != Relocs.end()) {
1873 symbol_iterator RelocSym = Reloc->second;
1874 outs() << " " << unwrapOrError(EO: RelocSym->getName(), Args: O->getFileName());
1875 } else {
1876 SymbolName = GuessSymbolName(value: p, AddrMap);
1877 if (SymbolName)
1878 outs() << " " << SymbolName;
1879 }
1880 }
1881 outs() << "\n";
1882 }
1883}
1884
1885static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
1886 uint32_t size, uint64_t addr) {
1887 uint32_t cputype = O->getHeader().cputype;
1888 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
1889 uint32_t j;
1890 for (uint32_t i = 0; i < size; i += j, addr += j) {
1891 if (O->is64Bit())
1892 outs() << format(Fmt: "%016" PRIx64, Vals: addr) << "\t";
1893 else
1894 outs() << format(Fmt: "%08" PRIx64, Vals: addr) << "\t";
1895 for (j = 0; j < 16 && i + j < size; j++) {
1896 uint8_t byte_word = *(sect + i + j);
1897 outs() << format(Fmt: "%02" PRIx32, Vals: (uint32_t)byte_word) << " ";
1898 }
1899 outs() << "\n";
1900 }
1901 } else {
1902 uint32_t j;
1903 for (uint32_t i = 0; i < size; i += j, addr += j) {
1904 if (O->is64Bit())
1905 outs() << format(Fmt: "%016" PRIx64, Vals: addr) << "\t";
1906 else
1907 outs() << format(Fmt: "%08" PRIx64, Vals: addr) << "\t";
1908 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
1909 j += sizeof(int32_t)) {
1910 if (i + j + sizeof(int32_t) <= size) {
1911 uint32_t long_word;
1912 memcpy(dest: &long_word, src: sect + i + j, n: sizeof(int32_t));
1913 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1914 sys::swapByteOrder(Value&: long_word);
1915 outs() << format(Fmt: "%08" PRIx32, Vals: long_word) << " ";
1916 } else {
1917 for (uint32_t k = 0; i + j + k < size; k++) {
1918 uint8_t byte_word = *(sect + i + j + k);
1919 outs() << format(Fmt: "%02" PRIx32, Vals: (uint32_t)byte_word) << " ";
1920 }
1921 }
1922 }
1923 outs() << "\n";
1924 }
1925 }
1926}
1927
1928static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
1929 StringRef DisSegName, StringRef DisSectName);
1930static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1931 uint32_t size, uint32_t addr);
1932static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1933 bool verbose) {
1934 SymbolAddressMap AddrMap;
1935 if (verbose)
1936 CreateSymbolAddressMap(O, AddrMap: &AddrMap);
1937
1938 for (unsigned i = 0; i < FilterSections.size(); ++i) {
1939 StringRef DumpSection = FilterSections[i];
1940 std::pair<StringRef, StringRef> DumpSegSectName;
1941 DumpSegSectName = DumpSection.split(Separator: ',');
1942 StringRef DumpSegName, DumpSectName;
1943 if (!DumpSegSectName.second.empty()) {
1944 DumpSegName = DumpSegSectName.first;
1945 DumpSectName = DumpSegSectName.second;
1946 } else {
1947 DumpSegName = "";
1948 DumpSectName = DumpSegSectName.first;
1949 }
1950 for (const SectionRef &Section : O->sections()) {
1951 StringRef SectName;
1952 Expected<StringRef> SecNameOrErr = Section.getName();
1953 if (SecNameOrErr)
1954 SectName = *SecNameOrErr;
1955 else
1956 consumeError(Err: SecNameOrErr.takeError());
1957
1958 if (!DumpSection.empty())
1959 FoundSectionSet.insert(key: DumpSection);
1960
1961 DataRefImpl Ref = Section.getRawDataRefImpl();
1962 StringRef SegName = O->getSectionFinalSegmentName(Sec: Ref);
1963 if ((DumpSegName.empty() || SegName == DumpSegName) &&
1964 (SectName == DumpSectName)) {
1965
1966 uint32_t section_flags;
1967 if (O->is64Bit()) {
1968 const MachO::section_64 Sec = O->getSection64(DRI: Ref);
1969 section_flags = Sec.flags;
1970
1971 } else {
1972 const MachO::section Sec = O->getSection(DRI: Ref);
1973 section_flags = Sec.flags;
1974 }
1975 uint32_t section_type = section_flags & MachO::SECTION_TYPE;
1976
1977 StringRef BytesStr =
1978 unwrapOrError(EO: Section.getContents(), Args: O->getFileName());
1979 const char *sect = BytesStr.data();
1980 uint32_t sect_size = BytesStr.size();
1981 uint64_t sect_addr = Section.getAddress();
1982
1983 if (LeadingHeaders)
1984 outs() << "Contents of (" << SegName << "," << SectName
1985 << ") section\n";
1986
1987 if (verbose) {
1988 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1989 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1990 DisassembleMachO(Filename, MachOOF: O, DisSegName: SegName, DisSectName: SectName);
1991 continue;
1992 }
1993 if (SegName == "__TEXT" && SectName == "__info_plist") {
1994 outs() << sect;
1995 continue;
1996 }
1997 if (SegName == "__OBJC" && SectName == "__protocol") {
1998 DumpProtocolSection(O, sect, size: sect_size, addr: sect_addr);
1999 continue;
2000 }
2001 switch (section_type) {
2002 case MachO::S_REGULAR:
2003 DumpRawSectionContents(O, sect, size: sect_size, addr: sect_addr);
2004 break;
2005 case MachO::S_ZEROFILL:
2006 outs() << "zerofill section and has no contents in the file\n";
2007 break;
2008 case MachO::S_CSTRING_LITERALS:
2009 DumpCstringSection(O, sect, sect_size, sect_addr, print_addresses: LeadingAddr);
2010 break;
2011 case MachO::S_4BYTE_LITERALS:
2012 DumpLiteral4Section(O, sect, sect_size, sect_addr, print_addresses: LeadingAddr);
2013 break;
2014 case MachO::S_8BYTE_LITERALS:
2015 DumpLiteral8Section(O, sect, sect_size, sect_addr, print_addresses: LeadingAddr);
2016 break;
2017 case MachO::S_16BYTE_LITERALS:
2018 DumpLiteral16Section(O, sect, sect_size, sect_addr, print_addresses: LeadingAddr);
2019 break;
2020 case MachO::S_LITERAL_POINTERS:
2021 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
2022 print_addresses: LeadingAddr);
2023 break;
2024 case MachO::S_MOD_INIT_FUNC_POINTERS:
2025 case MachO::S_MOD_TERM_FUNC_POINTERS:
2026 DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,
2027 AddrMap: &AddrMap, verbose);
2028 break;
2029 default:
2030 outs() << "Unknown section type ("
2031 << format(Fmt: "0x%08" PRIx32, Vals: section_type) << ")\n";
2032 DumpRawSectionContents(O, sect, size: sect_size, addr: sect_addr);
2033 break;
2034 }
2035 } else {
2036 if (section_type == MachO::S_ZEROFILL)
2037 outs() << "zerofill section and has no contents in the file\n";
2038 else
2039 DumpRawSectionContents(O, sect, size: sect_size, addr: sect_addr);
2040 }
2041 }
2042 }
2043 }
2044}
2045
2046static void DumpInfoPlistSectionContents(StringRef Filename,
2047 MachOObjectFile *O) {
2048 for (const SectionRef &Section : O->sections()) {
2049 StringRef SectName;
2050 Expected<StringRef> SecNameOrErr = Section.getName();
2051 if (SecNameOrErr)
2052 SectName = *SecNameOrErr;
2053 else
2054 consumeError(Err: SecNameOrErr.takeError());
2055
2056 DataRefImpl Ref = Section.getRawDataRefImpl();
2057 StringRef SegName = O->getSectionFinalSegmentName(Sec: Ref);
2058 if (SegName == "__TEXT" && SectName == "__info_plist") {
2059 if (LeadingHeaders)
2060 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
2061 StringRef BytesStr =
2062 unwrapOrError(EO: Section.getContents(), Args: O->getFileName());
2063 const char *sect = BytesStr.data();
2064 outs() << format(Fmt: "%.*s", Vals: BytesStr.size(), Vals: sect) << "\n";
2065 return;
2066 }
2067 }
2068}
2069
2070// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
2071// and if it is and there is a list of architecture flags is specified then
2072// check to make sure this Mach-O file is one of those architectures or all
2073// architectures were specified. If not then an error is generated and this
2074// routine returns false. Else it returns true.
2075static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
2076 auto *MachO = dyn_cast<MachOObjectFile>(Val: O);
2077
2078 if (!MachO || ArchAll || ArchFlags.empty())
2079 return true;
2080
2081 MachO::mach_header H;
2082 MachO::mach_header_64 H_64;
2083 Triple T;
2084 const char *McpuDefault, *ArchFlag;
2085 if (MachO->is64Bit()) {
2086 H_64 = MachO->MachOObjectFile::getHeader64();
2087 T = MachOObjectFile::getArchTriple(CPUType: H_64.cputype, CPUSubType: H_64.cpusubtype,
2088 McpuDefault: &McpuDefault, ArchFlag: &ArchFlag);
2089 } else {
2090 H = MachO->MachOObjectFile::getHeader();
2091 T = MachOObjectFile::getArchTriple(CPUType: H.cputype, CPUSubType: H.cpusubtype,
2092 McpuDefault: &McpuDefault, ArchFlag: &ArchFlag);
2093 }
2094 const std::string ArchFlagName(ArchFlag);
2095 if (!llvm::is_contained(Range&: ArchFlags, Element: ArchFlagName)) {
2096 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
2097 << Filename << ": no architecture specified.\n";
2098 return false;
2099 }
2100 return true;
2101}
2102
2103static void printObjcMetaData(MachOObjectFile *O, bool verbose);
2104
2105// ProcessMachO() is passed a single opened Mach-O file, which may be an
2106// archive member and or in a slice of a universal file. It prints the
2107// the file name and header info and then processes it according to the
2108// command line options.
2109static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
2110 StringRef ArchiveMemberName = StringRef(),
2111 StringRef ArchitectureName = StringRef()) {
2112 std::unique_ptr<Dumper> D = createMachODumper(Obj: *MachOOF);
2113
2114 // If we are doing some processing here on the Mach-O file print the header
2115 // info. And don't print it otherwise like in the case of printing the
2116 // UniversalHeaders or ArchiveHeaders.
2117 if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
2118 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
2119 DataInCode || FunctionStartsType != FunctionStartsMode::None ||
2120 LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
2121 Rpaths || ObjcMetaData || (!FilterSections.empty())) {
2122 if (LeadingHeaders) {
2123 outs() << Name;
2124 if (!ArchiveMemberName.empty())
2125 outs() << '(' << ArchiveMemberName << ')';
2126 if (!ArchitectureName.empty())
2127 outs() << " (architecture " << ArchitectureName << ")";
2128 outs() << ":\n";
2129 }
2130 }
2131 // To use the report_error() form with an ArchiveName and FileName set
2132 // these up based on what is passed for Name and ArchiveMemberName.
2133 StringRef ArchiveName;
2134 StringRef FileName;
2135 if (!ArchiveMemberName.empty()) {
2136 ArchiveName = Name;
2137 FileName = ArchiveMemberName;
2138 } else {
2139 ArchiveName = StringRef();
2140 FileName = Name;
2141 }
2142
2143 // If we need the symbol table to do the operation then check it here to
2144 // produce a good error message as to where the Mach-O file comes from in
2145 // the error message.
2146 if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)
2147 if (Error Err = MachOOF->checkSymbolTable())
2148 reportError(E: std::move(Err), FileName, ArchiveName, ArchitectureName);
2149
2150 if (DisassembleAll) {
2151 for (const SectionRef &Section : MachOOF->sections()) {
2152 StringRef SectName;
2153 if (Expected<StringRef> NameOrErr = Section.getName())
2154 SectName = *NameOrErr;
2155 else
2156 consumeError(Err: NameOrErr.takeError());
2157
2158 if (SectName == "__text") {
2159 DataRefImpl Ref = Section.getRawDataRefImpl();
2160 StringRef SegName = MachOOF->getSectionFinalSegmentName(Sec: Ref);
2161 DisassembleMachO(Filename: FileName, MachOOF, DisSegName: SegName, DisSectName: SectName);
2162 }
2163 }
2164 }
2165 else if (Disassemble) {
2166 if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
2167 MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
2168 DisassembleMachO(Filename: FileName, MachOOF, DisSegName: "__TEXT_EXEC", DisSectName: "__text");
2169 else
2170 DisassembleMachO(Filename: FileName, MachOOF, DisSegName: "__TEXT", DisSectName: "__text");
2171 }
2172 if (IndirectSymbols)
2173 PrintIndirectSymbols(O: MachOOF, verbose: Verbose);
2174 if (DataInCode)
2175 PrintDataInCodeTable(O: MachOOF, verbose: Verbose);
2176 if (FunctionStartsType != FunctionStartsMode::None)
2177 PrintFunctionStarts(O: MachOOF);
2178 if (LinkOptHints)
2179 PrintLinkOptHints(O: MachOOF);
2180 if (Relocations)
2181 PrintRelocations(O: MachOOF, verbose: Verbose);
2182 if (SectionHeaders)
2183 printSectionHeaders(O&: *MachOOF);
2184 if (SectionContents)
2185 printSectionContents(O: MachOOF);
2186 if (!FilterSections.empty())
2187 DumpSectionContents(Filename: FileName, O: MachOOF, verbose: Verbose);
2188 if (InfoPlist)
2189 DumpInfoPlistSectionContents(Filename: FileName, O: MachOOF);
2190 if (DyldInfo)
2191 PrintDyldInfo(O: MachOOF);
2192 if (ChainedFixups)
2193 PrintChainedFixups(O: MachOOF);
2194 if (DylibsUsed)
2195 PrintDylibs(O: MachOOF, JustId: false);
2196 if (DylibId)
2197 PrintDylibs(O: MachOOF, JustId: true);
2198 if (SymbolTable)
2199 D->printSymbolTable(ArchiveName, ArchitectureName);
2200 if (UnwindInfo)
2201 printMachOUnwindInfo(O: MachOOF);
2202 if (PrivateHeaders) {
2203 printMachOFileHeader(O: MachOOF);
2204 printMachOLoadCommands(O: MachOOF);
2205 }
2206 if (FirstPrivateHeader)
2207 printMachOFileHeader(O: MachOOF);
2208 if (ObjcMetaData)
2209 printObjcMetaData(O: MachOOF, verbose: Verbose);
2210 if (ExportsTrie)
2211 printExportsTrie(O: MachOOF);
2212 if (Rebase)
2213 printRebaseTable(O: MachOOF);
2214 if (Rpaths)
2215 printRpaths(O: MachOOF);
2216 if (Bind)
2217 printBindTable(O: MachOOF);
2218 if (LazyBind)
2219 printLazyBindTable(O: MachOOF);
2220 if (WeakBind)
2221 printWeakBindTable(O: MachOOF);
2222
2223 if (DwarfDumpType != DIDT_Null) {
2224 std::unique_ptr<DIContext> DICtx = DWARFContext::create(Obj: *MachOOF);
2225 // Dump the complete DWARF structure.
2226 DIDumpOptions DumpOpts;
2227 DumpOpts.DumpType = DwarfDumpType;
2228 DICtx->dump(OS&: outs(), DumpOpts);
2229 }
2230}
2231
2232// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
2233static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
2234 outs() << " cputype (" << cputype << ")\n";
2235 outs() << " cpusubtype (" << cpusubtype << ")\n";
2236}
2237
2238// printCPUType() helps print_fat_headers by printing the cputype and
2239// pusubtype (symbolically for the one's it knows about).
2240static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
2241 switch (cputype) {
2242 case MachO::CPU_TYPE_I386:
2243 switch (cpusubtype) {
2244 case MachO::CPU_SUBTYPE_I386_ALL:
2245 outs() << " cputype CPU_TYPE_I386\n";
2246 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
2247 break;
2248 default:
2249 printUnknownCPUType(cputype, cpusubtype);
2250 break;
2251 }
2252 break;
2253 case MachO::CPU_TYPE_X86_64:
2254 switch (cpusubtype) {
2255 case MachO::CPU_SUBTYPE_X86_64_ALL:
2256 outs() << " cputype CPU_TYPE_X86_64\n";
2257 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
2258 break;
2259 case MachO::CPU_SUBTYPE_X86_64_H:
2260 outs() << " cputype CPU_TYPE_X86_64\n";
2261 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
2262 break;
2263 default:
2264 printUnknownCPUType(cputype, cpusubtype);
2265 break;
2266 }
2267 break;
2268 case MachO::CPU_TYPE_ARM:
2269 switch (cpusubtype) {
2270 case MachO::CPU_SUBTYPE_ARM_ALL:
2271 outs() << " cputype CPU_TYPE_ARM\n";
2272 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
2273 break;
2274 case MachO::CPU_SUBTYPE_ARM_V4T:
2275 outs() << " cputype CPU_TYPE_ARM\n";
2276 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
2277 break;
2278 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
2279 outs() << " cputype CPU_TYPE_ARM\n";
2280 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
2281 break;
2282 case MachO::CPU_SUBTYPE_ARM_XSCALE:
2283 outs() << " cputype CPU_TYPE_ARM\n";
2284 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
2285 break;
2286 case MachO::CPU_SUBTYPE_ARM_V6:
2287 outs() << " cputype CPU_TYPE_ARM\n";
2288 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
2289 break;
2290 case MachO::CPU_SUBTYPE_ARM_V6M:
2291 outs() << " cputype CPU_TYPE_ARM\n";
2292 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
2293 break;
2294 case MachO::CPU_SUBTYPE_ARM_V7:
2295 outs() << " cputype CPU_TYPE_ARM\n";
2296 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
2297 break;
2298 case MachO::CPU_SUBTYPE_ARM_V7EM:
2299 outs() << " cputype CPU_TYPE_ARM\n";
2300 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
2301 break;
2302 case MachO::CPU_SUBTYPE_ARM_V7K:
2303 outs() << " cputype CPU_TYPE_ARM\n";
2304 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
2305 break;
2306 case MachO::CPU_SUBTYPE_ARM_V7M:
2307 outs() << " cputype CPU_TYPE_ARM\n";
2308 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
2309 break;
2310 case MachO::CPU_SUBTYPE_ARM_V7S:
2311 outs() << " cputype CPU_TYPE_ARM\n";
2312 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
2313 break;
2314 default:
2315 printUnknownCPUType(cputype, cpusubtype);
2316 break;
2317 }
2318 break;
2319 case MachO::CPU_TYPE_ARM64:
2320 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2321 case MachO::CPU_SUBTYPE_ARM64_ALL:
2322 outs() << " cputype CPU_TYPE_ARM64\n";
2323 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
2324 break;
2325 case MachO::CPU_SUBTYPE_ARM64_V8:
2326 outs() << " cputype CPU_TYPE_ARM64\n";
2327 outs() << " cpusubtype CPU_SUBTYPE_ARM64_V8\n";
2328 break;
2329 case MachO::CPU_SUBTYPE_ARM64E:
2330 outs() << " cputype CPU_TYPE_ARM64\n";
2331 outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";
2332 break;
2333 default:
2334 printUnknownCPUType(cputype, cpusubtype);
2335 break;
2336 }
2337 break;
2338 case MachO::CPU_TYPE_ARM64_32:
2339 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2340 case MachO::CPU_SUBTYPE_ARM64_32_V8:
2341 outs() << " cputype CPU_TYPE_ARM64_32\n";
2342 outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";
2343 break;
2344 default:
2345 printUnknownCPUType(cputype, cpusubtype);
2346 break;
2347 }
2348 break;
2349 default:
2350 printUnknownCPUType(cputype, cpusubtype);
2351 break;
2352 }
2353}
2354
2355static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
2356 bool verbose) {
2357 outs() << "Fat headers\n";
2358 if (verbose) {
2359 if (UB->getMagic() == MachO::FAT_MAGIC)
2360 outs() << "fat_magic FAT_MAGIC\n";
2361 else // UB->getMagic() == MachO::FAT_MAGIC_64
2362 outs() << "fat_magic FAT_MAGIC_64\n";
2363 } else
2364 outs() << "fat_magic " << format(Fmt: "0x%" PRIx32, Vals: MachO::FAT_MAGIC) << "\n";
2365
2366 uint32_t nfat_arch = UB->getNumberOfObjects();
2367 StringRef Buf = UB->getData();
2368 uint64_t size = Buf.size();
2369 uint64_t big_size = sizeof(struct MachO::fat_header) +
2370 nfat_arch * sizeof(struct MachO::fat_arch);
2371 outs() << "nfat_arch " << UB->getNumberOfObjects();
2372 if (nfat_arch == 0)
2373 outs() << " (malformed, contains zero architecture types)\n";
2374 else if (big_size > size)
2375 outs() << " (malformed, architectures past end of file)\n";
2376 else
2377 outs() << "\n";
2378
2379 for (uint32_t i = 0; i < nfat_arch; ++i) {
2380 MachOUniversalBinary::ObjectForArch OFA(UB, i);
2381 uint32_t cputype = OFA.getCPUType();
2382 uint32_t cpusubtype = OFA.getCPUSubType();
2383 outs() << "architecture ";
2384 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
2385 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
2386 uint32_t other_cputype = other_OFA.getCPUType();
2387 uint32_t other_cpusubtype = other_OFA.getCPUSubType();
2388 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
2389 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
2390 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
2391 outs() << "(illegal duplicate architecture) ";
2392 break;
2393 }
2394 }
2395 if (verbose) {
2396 outs() << OFA.getArchFlagName() << "\n";
2397 printCPUType(cputype, cpusubtype: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
2398 } else {
2399 outs() << i << "\n";
2400 outs() << " cputype " << cputype << "\n";
2401 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
2402 << "\n";
2403 }
2404 if (verbose && cputype == MachO::CPU_TYPE_ARM64 &&
2405 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(ST: cpusubtype)) {
2406 outs() << " capabilities CPU_SUBTYPE_ARM64E_";
2407 if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(ST: cpusubtype))
2408 outs() << "KERNEL_";
2409 outs() << format(Fmt: "PTRAUTH_VERSION %d",
2410 Vals: MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(ST: cpusubtype))
2411 << "\n";
2412 } else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
2413 MachO::CPU_SUBTYPE_LIB64)
2414 outs() << " capabilities CPU_SUBTYPE_LIB64\n";
2415 else
2416 outs() << " capabilities "
2417 << format(Fmt: "0x%" PRIx32,
2418 Vals: (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
2419 outs() << " offset " << OFA.getOffset();
2420 if (OFA.getOffset() > size)
2421 outs() << " (past end of file)";
2422 if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)
2423 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
2424 outs() << "\n";
2425 outs() << " size " << OFA.getSize();
2426 big_size = OFA.getOffset() + OFA.getSize();
2427 if (big_size > size)
2428 outs() << " (past end of file)";
2429 outs() << "\n";
2430 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
2431 << ")\n";
2432 }
2433}
2434
2435static void printArchiveChild(StringRef Filename, const Archive::Child &C,
2436 size_t ChildIndex, bool verbose,
2437 bool print_offset,
2438 StringRef ArchitectureName = StringRef()) {
2439 if (print_offset)
2440 outs() << C.getChildOffset() << "\t";
2441 sys::fs::perms Mode =
2442 unwrapOrError(EO: C.getAccessMode(), Args: getFileNameForError(C, Index: ChildIndex),
2443 Args&: Filename, Args&: ArchitectureName);
2444 if (verbose) {
2445 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
2446 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
2447 outs() << "-";
2448 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
2449 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
2450 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
2451 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
2452 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
2453 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
2454 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
2455 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
2456 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
2457 } else {
2458 outs() << format(Fmt: "0%o ", Vals: Mode);
2459 }
2460
2461 outs() << format(Fmt: "%3d/%-3d %5" PRId64 " ",
2462 Vals: unwrapOrError(EO: C.getUID(), Args: getFileNameForError(C, Index: ChildIndex),
2463 Args&: Filename, Args&: ArchitectureName),
2464 Vals: unwrapOrError(EO: C.getGID(), Args: getFileNameForError(C, Index: ChildIndex),
2465 Args&: Filename, Args&: ArchitectureName),
2466 Vals: unwrapOrError(EO: C.getRawSize(),
2467 Args: getFileNameForError(C, Index: ChildIndex), Args&: Filename,
2468 Args&: ArchitectureName));
2469
2470 StringRef RawLastModified = C.getRawLastModified();
2471 if (verbose) {
2472 unsigned Seconds;
2473 if (RawLastModified.getAsInteger(Radix: 10, Result&: Seconds))
2474 outs() << "(date: \"" << RawLastModified
2475 << "\" contains non-decimal chars) ";
2476 else {
2477 // Since cime(3) returns a 26 character string of the form:
2478 // "Sun Sep 16 01:03:52 1973\n\0"
2479 // just print 24 characters.
2480 time_t t = Seconds;
2481 outs() << format(Fmt: "%.24s ", Vals: ctime(timer: &t));
2482 }
2483 } else {
2484 outs() << RawLastModified << " ";
2485 }
2486
2487 if (verbose) {
2488 Expected<StringRef> NameOrErr = C.getName();
2489 if (!NameOrErr) {
2490 consumeError(Err: NameOrErr.takeError());
2491 outs() << unwrapOrError(EO: C.getRawName(),
2492 Args: getFileNameForError(C, Index: ChildIndex), Args&: Filename,
2493 Args&: ArchitectureName)
2494 << "\n";
2495 } else {
2496 StringRef Name = NameOrErr.get();
2497 outs() << Name << "\n";
2498 }
2499 } else {
2500 outs() << unwrapOrError(EO: C.getRawName(), Args: getFileNameForError(C, Index: ChildIndex),
2501 Args&: Filename, Args&: ArchitectureName)
2502 << "\n";
2503 }
2504}
2505
2506static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
2507 bool print_offset,
2508 StringRef ArchitectureName = StringRef()) {
2509 Error Err = Error::success();
2510 size_t I = 0;
2511 for (const auto &C : A->children(Err, SkipInternal: false))
2512 printArchiveChild(Filename, C, ChildIndex: I++, verbose, print_offset,
2513 ArchitectureName);
2514
2515 if (Err)
2516 reportError(E: std::move(Err), FileName: Filename, ArchiveName: "", ArchitectureName);
2517}
2518
2519static bool ValidateArchFlags() {
2520 // Check for -arch all and verifiy the -arch flags are valid.
2521 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2522 if (ArchFlags[i] == "all") {
2523 ArchAll = true;
2524 } else {
2525 if (!MachOObjectFile::isValidArch(ArchFlag: ArchFlags[i])) {
2526 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
2527 << "unknown architecture named '" + ArchFlags[i] +
2528 "'for the -arch option\n";
2529 return false;
2530 }
2531 }
2532 }
2533 return true;
2534}
2535
2536// ParseInputMachO() parses the named Mach-O file in Filename and handles the
2537// -arch flags selecting just those slices as specified by them and also parses
2538// archive files. Then for each individual Mach-O file ProcessMachO() is
2539// called to process the file based on the command line options.
2540void objdump::parseInputMachO(StringRef Filename) {
2541 if (!ValidateArchFlags())
2542 return;
2543
2544 // Attempt to open the binary.
2545 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Path: Filename);
2546 if (!BinaryOrErr) {
2547 if (Error E = isNotObjectErrorInvalidFileType(Err: BinaryOrErr.takeError()))
2548 reportError(E: std::move(E), FileName: Filename);
2549 else
2550 outs() << Filename << ": is not an object file\n";
2551 return;
2552 }
2553 Binary &Bin = *BinaryOrErr.get().getBinary();
2554
2555 if (Archive *A = dyn_cast<Archive>(Val: &Bin)) {
2556 outs() << "Archive : " << Filename << "\n";
2557 if (ArchiveHeaders)
2558 printArchiveHeaders(Filename, A, verbose: Verbose, print_offset: ArchiveMemberOffsets);
2559
2560 Error Err = Error::success();
2561 unsigned I = -1;
2562 for (auto &C : A->children(Err)) {
2563 ++I;
2564 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2565 if (!ChildOrErr) {
2566 if (Error E = isNotObjectErrorInvalidFileType(Err: ChildOrErr.takeError()))
2567 reportError(E: std::move(E), FileName: getFileNameForError(C, Index: I), ArchiveName: Filename);
2568 continue;
2569 }
2570 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(Val: &*ChildOrErr.get())) {
2571 if (!checkMachOAndArchFlags(O, Filename))
2572 return;
2573 ProcessMachO(Name: Filename, MachOOF: O, ArchiveMemberName: O->getFileName());
2574 }
2575 }
2576 if (Err)
2577 reportError(E: std::move(Err), FileName: Filename);
2578 return;
2579 }
2580 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Val: &Bin)) {
2581 parseInputMachO(UB);
2582 return;
2583 }
2584 if (ObjectFile *O = dyn_cast<ObjectFile>(Val: &Bin)) {
2585 if (!checkMachOAndArchFlags(O, Filename))
2586 return;
2587 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(Val: &*O))
2588 ProcessMachO(Name: Filename, MachOOF);
2589 else
2590 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
2591 << Filename << "': "
2592 << "object is not a Mach-O file type.\n";
2593 return;
2594 }
2595 llvm_unreachable("Input object can't be invalid at this point");
2596}
2597
2598void objdump::parseInputMachO(MachOUniversalBinary *UB) {
2599 if (!ValidateArchFlags())
2600 return;
2601
2602 auto Filename = UB->getFileName();
2603
2604 if (UniversalHeaders)
2605 printMachOUniversalHeaders(UB, verbose: Verbose);
2606
2607 // If we have a list of architecture flags specified dump only those.
2608 if (!ArchAll && !ArchFlags.empty()) {
2609 // Look for a slice in the universal binary that matches each ArchFlag.
2610 bool ArchFound;
2611 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2612 ArchFound = false;
2613 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2614 E = UB->end_objects();
2615 I != E; ++I) {
2616 if (ArchFlags[i] == I->getArchFlagName()) {
2617 ArchFound = true;
2618 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2619 I->getAsObjectFile();
2620 std::string ArchitectureName;
2621 if (ArchFlags.size() > 1)
2622 ArchitectureName = I->getArchFlagName();
2623 if (ObjOrErr) {
2624 ObjectFile &O = *ObjOrErr.get();
2625 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(Val: &O))
2626 ProcessMachO(Name: Filename, MachOOF, ArchiveMemberName: "", ArchitectureName);
2627 } else if (Error E = isNotObjectErrorInvalidFileType(
2628 Err: ObjOrErr.takeError())) {
2629 reportError(E: std::move(E), FileName: "", ArchiveName: Filename, ArchitectureName);
2630 continue;
2631 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2632 I->getAsArchive()) {
2633 std::unique_ptr<Archive> &A = *AOrErr;
2634 outs() << "Archive : " << Filename;
2635 if (!ArchitectureName.empty())
2636 outs() << " (architecture " << ArchitectureName << ")";
2637 outs() << "\n";
2638 if (ArchiveHeaders)
2639 printArchiveHeaders(Filename, A: A.get(), verbose: Verbose,
2640 print_offset: ArchiveMemberOffsets, ArchitectureName);
2641 Error Err = Error::success();
2642 unsigned I = -1;
2643 for (auto &C : A->children(Err)) {
2644 ++I;
2645 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2646 if (!ChildOrErr) {
2647 if (Error E =
2648 isNotObjectErrorInvalidFileType(Err: ChildOrErr.takeError()))
2649 reportError(E: std::move(E), FileName: getFileNameForError(C, Index: I), ArchiveName: Filename,
2650 ArchitectureName);
2651 continue;
2652 }
2653 if (MachOObjectFile *O =
2654 dyn_cast<MachOObjectFile>(Val: &*ChildOrErr.get()))
2655 ProcessMachO(Name: Filename, MachOOF: O, ArchiveMemberName: O->getFileName(), ArchitectureName);
2656 }
2657 if (Err)
2658 reportError(E: std::move(Err), FileName: Filename);
2659 } else {
2660 consumeError(Err: AOrErr.takeError());
2661 reportError(File: Filename,
2662 Message: "Mach-O universal file for architecture " +
2663 StringRef(I->getArchFlagName()) +
2664 " is not a Mach-O file or an archive file");
2665 }
2666 }
2667 }
2668 if (!ArchFound) {
2669 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
2670 << "file: " + Filename + " does not contain "
2671 << "architecture: " + ArchFlags[i] + "\n";
2672 return;
2673 }
2674 }
2675 return;
2676 }
2677 // No architecture flags were specified so if this contains a slice that
2678 // matches the host architecture dump only that.
2679 if (!ArchAll) {
2680 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2681 E = UB->end_objects();
2682 I != E; ++I) {
2683 if (MachOObjectFile::getHostArch().getArchName() ==
2684 I->getArchFlagName()) {
2685 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2686 std::string ArchiveName;
2687 ArchiveName.clear();
2688 if (ObjOrErr) {
2689 ObjectFile &O = *ObjOrErr.get();
2690 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(Val: &O))
2691 ProcessMachO(Name: Filename, MachOOF);
2692 } else if (Error E =
2693 isNotObjectErrorInvalidFileType(Err: ObjOrErr.takeError())) {
2694 reportError(E: std::move(E), FileName: Filename);
2695 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
2696 I->getAsArchive()) {
2697 std::unique_ptr<Archive> &A = *AOrErr;
2698 outs() << "Archive : " << Filename << "\n";
2699 if (ArchiveHeaders)
2700 printArchiveHeaders(Filename, A: A.get(), verbose: Verbose,
2701 print_offset: ArchiveMemberOffsets);
2702 Error Err = Error::success();
2703 unsigned I = -1;
2704 for (auto &C : A->children(Err)) {
2705 ++I;
2706 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2707 if (!ChildOrErr) {
2708 if (Error E =
2709 isNotObjectErrorInvalidFileType(Err: ChildOrErr.takeError()))
2710 reportError(E: std::move(E), FileName: getFileNameForError(C, Index: I), ArchiveName: Filename);
2711 continue;
2712 }
2713 if (MachOObjectFile *O =
2714 dyn_cast<MachOObjectFile>(Val: &*ChildOrErr.get()))
2715 ProcessMachO(Name: Filename, MachOOF: O, ArchiveMemberName: O->getFileName());
2716 }
2717 if (Err)
2718 reportError(E: std::move(Err), FileName: Filename);
2719 } else {
2720 consumeError(Err: AOrErr.takeError());
2721 reportError(File: Filename, Message: "Mach-O universal file for architecture " +
2722 StringRef(I->getArchFlagName()) +
2723 " is not a Mach-O file or an archive file");
2724 }
2725 return;
2726 }
2727 }
2728 }
2729 // Either all architectures have been specified or none have been specified
2730 // and this does not contain the host architecture so dump all the slices.
2731 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
2732 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2733 E = UB->end_objects();
2734 I != E; ++I) {
2735 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2736 std::string ArchitectureName;
2737 if (moreThanOneArch)
2738 ArchitectureName = I->getArchFlagName();
2739 if (ObjOrErr) {
2740 ObjectFile &Obj = *ObjOrErr.get();
2741 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(Val: &Obj))
2742 ProcessMachO(Name: Filename, MachOOF, ArchiveMemberName: "", ArchitectureName);
2743 } else if (Error E =
2744 isNotObjectErrorInvalidFileType(Err: ObjOrErr.takeError())) {
2745 reportError(E: std::move(E), FileName: Filename, ArchiveName: "", ArchitectureName);
2746 } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
2747 std::unique_ptr<Archive> &A = *AOrErr;
2748 outs() << "Archive : " << Filename;
2749 if (!ArchitectureName.empty())
2750 outs() << " (architecture " << ArchitectureName << ")";
2751 outs() << "\n";
2752 if (ArchiveHeaders)
2753 printArchiveHeaders(Filename, A: A.get(), verbose: Verbose, print_offset: ArchiveMemberOffsets,
2754 ArchitectureName);
2755 Error Err = Error::success();
2756 unsigned I = -1;
2757 for (auto &C : A->children(Err)) {
2758 ++I;
2759 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2760 if (!ChildOrErr) {
2761 if (Error E = isNotObjectErrorInvalidFileType(Err: ChildOrErr.takeError()))
2762 reportError(E: std::move(E), FileName: getFileNameForError(C, Index: I), ArchiveName: Filename,
2763 ArchitectureName);
2764 continue;
2765 }
2766 if (MachOObjectFile *O =
2767 dyn_cast<MachOObjectFile>(Val: &*ChildOrErr.get())) {
2768 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(Val: O))
2769 ProcessMachO(Name: Filename, MachOOF, ArchiveMemberName: MachOOF->getFileName(),
2770 ArchitectureName);
2771 }
2772 }
2773 if (Err)
2774 reportError(E: std::move(Err), FileName: Filename);
2775 } else {
2776 consumeError(Err: AOrErr.takeError());
2777 reportError(File: Filename, Message: "Mach-O universal file for architecture " +
2778 StringRef(I->getArchFlagName()) +
2779 " is not a Mach-O file or an archive file");
2780 }
2781 }
2782}
2783
2784namespace {
2785// The block of info used by the Symbolizer call backs.
2786struct DisassembleInfo {
2787 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2788 std::vector<SectionRef> *Sections, bool verbose)
2789 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
2790 bool verbose;
2791 MachOObjectFile *O;
2792 SectionRef S;
2793 SymbolAddressMap *AddrMap;
2794 std::vector<SectionRef> *Sections;
2795 const char *class_name = nullptr;
2796 const char *selector_name = nullptr;
2797 std::unique_ptr<char[]> method = nullptr;
2798 char *demangled_name = nullptr;
2799 uint64_t adrp_addr = 0;
2800 uint32_t adrp_inst = 0;
2801 std::unique_ptr<SymbolAddressMap> bindtable;
2802 uint32_t depth = 0;
2803};
2804} // namespace
2805
2806// SymbolizerGetOpInfo() is the operand information call back function.
2807// This is called to get the symbolic information for operand(s) of an
2808// instruction when it is being done. This routine does this from
2809// the relocation information, symbol table, etc. That block of information
2810// is a pointer to the struct DisassembleInfo that was passed when the
2811// disassembler context was created and passed to back to here when
2812// called back by the disassembler for instruction operands that could have
2813// relocation information. The address of the instruction containing operand is
2814// at the Pc parameter. The immediate value the operand has is passed in
2815// op_info->Value and is at Offset past the start of the instruction and has a
2816// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2817// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2818// names and addends of the symbolic expression to add for the operand. The
2819// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2820// information is returned then this function returns 1 else it returns 0.
2821static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2822 uint64_t OpSize, uint64_t InstSize, int TagType,
2823 void *TagBuf) {
2824 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2825 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
2826 uint64_t value = op_info->Value;
2827
2828 // Make sure all fields returned are zero if we don't set them.
2829 memset(s: (void *)op_info, c: '\0', n: sizeof(struct LLVMOpInfo1));
2830 op_info->Value = value;
2831
2832 // If the TagType is not the value 1 which it code knows about or if no
2833 // verbose symbolic information is wanted then just return 0, indicating no
2834 // information is being returned.
2835 if (TagType != 1 || !info->verbose)
2836 return 0;
2837
2838 unsigned int Arch = info->O->getArch();
2839 if (Arch == Triple::x86) {
2840 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2841 return 0;
2842 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2843 // TODO:
2844 // Search the external relocation entries of a fully linked image
2845 // (if any) for an entry that matches this segment offset.
2846 // uint32_t seg_offset = (Pc + Offset);
2847 return 0;
2848 }
2849 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2850 // for an entry for this section offset.
2851 uint32_t sect_addr = info->S.getAddress();
2852 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2853 bool reloc_found = false;
2854 DataRefImpl Rel;
2855 MachO::any_relocation_info RE;
2856 bool isExtern = false;
2857 SymbolRef Symbol;
2858 bool r_scattered = false;
2859 uint32_t r_value, pair_r_value, r_type;
2860 for (const RelocationRef &Reloc : info->S.relocations()) {
2861 uint64_t RelocOffset = Reloc.getOffset();
2862 if (RelocOffset == sect_offset) {
2863 Rel = Reloc.getRawDataRefImpl();
2864 RE = info->O->getRelocation(Rel);
2865 r_type = info->O->getAnyRelocationType(RE);
2866 r_scattered = info->O->isRelocationScattered(RE);
2867 if (r_scattered) {
2868 r_value = info->O->getScatteredRelocationValue(RE);
2869 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2870 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2871 DataRefImpl RelNext = Rel;
2872 info->O->moveRelocationNext(Rel&: RelNext);
2873 MachO::any_relocation_info RENext;
2874 RENext = info->O->getRelocation(Rel: RelNext);
2875 if (info->O->isRelocationScattered(RE: RENext))
2876 pair_r_value = info->O->getScatteredRelocationValue(RE: RENext);
2877 else
2878 return 0;
2879 }
2880 } else {
2881 isExtern = info->O->getPlainRelocationExternal(RE);
2882 if (isExtern) {
2883 symbol_iterator RelocSym = Reloc.getSymbol();
2884 Symbol = *RelocSym;
2885 }
2886 }
2887 reloc_found = true;
2888 break;
2889 }
2890 }
2891 if (reloc_found && isExtern) {
2892 op_info->AddSymbol.Present = 1;
2893 op_info->AddSymbol.Name =
2894 unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName()).data();
2895 // For i386 extern relocation entries the value in the instruction is
2896 // the offset from the symbol, and value is already set in op_info->Value.
2897 return 1;
2898 }
2899 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2900 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
2901 const char *add = GuessSymbolName(value: r_value, AddrMap: info->AddrMap);
2902 const char *sub = GuessSymbolName(value: pair_r_value, AddrMap: info->AddrMap);
2903 uint32_t offset = value - (r_value - pair_r_value);
2904 op_info->AddSymbol.Present = 1;
2905 if (add != nullptr)
2906 op_info->AddSymbol.Name = add;
2907 else
2908 op_info->AddSymbol.Value = r_value;
2909 op_info->SubtractSymbol.Present = 1;
2910 if (sub != nullptr)
2911 op_info->SubtractSymbol.Name = sub;
2912 else
2913 op_info->SubtractSymbol.Value = pair_r_value;
2914 op_info->Value = offset;
2915 return 1;
2916 }
2917 return 0;
2918 }
2919 if (Arch == Triple::x86_64) {
2920 if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2921 return 0;
2922 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2923 // relocation entries of a linked image (if any) for an entry that matches
2924 // this segment offset.
2925 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2926 uint64_t seg_offset = Pc + Offset;
2927 bool reloc_found = false;
2928 DataRefImpl Rel;
2929 MachO::any_relocation_info RE;
2930 bool isExtern = false;
2931 SymbolRef Symbol;
2932 for (const RelocationRef &Reloc : info->O->external_relocations()) {
2933 uint64_t RelocOffset = Reloc.getOffset();
2934 if (RelocOffset == seg_offset) {
2935 Rel = Reloc.getRawDataRefImpl();
2936 RE = info->O->getRelocation(Rel);
2937 // external relocation entries should always be external.
2938 isExtern = info->O->getPlainRelocationExternal(RE);
2939 if (isExtern) {
2940 symbol_iterator RelocSym = Reloc.getSymbol();
2941 Symbol = *RelocSym;
2942 }
2943 reloc_found = true;
2944 break;
2945 }
2946 }
2947 if (reloc_found && isExtern) {
2948 // The Value passed in will be adjusted by the Pc if the instruction
2949 // adds the Pc. But for x86_64 external relocation entries the Value
2950 // is the offset from the external symbol.
2951 if (info->O->getAnyRelocationPCRel(RE))
2952 op_info->Value -= Pc + InstSize;
2953 const char *name =
2954 unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName()).data();
2955 op_info->AddSymbol.Present = 1;
2956 op_info->AddSymbol.Name = name;
2957 return 1;
2958 }
2959 return 0;
2960 }
2961 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2962 // for an entry for this section offset.
2963 uint64_t sect_addr = info->S.getAddress();
2964 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2965 bool reloc_found = false;
2966 DataRefImpl Rel;
2967 MachO::any_relocation_info RE;
2968 bool isExtern = false;
2969 SymbolRef Symbol;
2970 for (const RelocationRef &Reloc : info->S.relocations()) {
2971 uint64_t RelocOffset = Reloc.getOffset();
2972 if (RelocOffset == sect_offset) {
2973 Rel = Reloc.getRawDataRefImpl();
2974 RE = info->O->getRelocation(Rel);
2975 // NOTE: Scattered relocations don't exist on x86_64.
2976 isExtern = info->O->getPlainRelocationExternal(RE);
2977 if (isExtern) {
2978 symbol_iterator RelocSym = Reloc.getSymbol();
2979 Symbol = *RelocSym;
2980 }
2981 reloc_found = true;
2982 break;
2983 }
2984 }
2985 if (reloc_found && isExtern) {
2986 // The Value passed in will be adjusted by the Pc if the instruction
2987 // adds the Pc. But for x86_64 external relocation entries the Value
2988 // is the offset from the external symbol.
2989 if (info->O->getAnyRelocationPCRel(RE))
2990 op_info->Value -= Pc + InstSize;
2991 const char *name =
2992 unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName()).data();
2993 unsigned Type = info->O->getAnyRelocationType(RE);
2994 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2995 DataRefImpl RelNext = Rel;
2996 info->O->moveRelocationNext(Rel&: RelNext);
2997 MachO::any_relocation_info RENext = info->O->getRelocation(Rel: RelNext);
2998 unsigned TypeNext = info->O->getAnyRelocationType(RE: RENext);
2999 bool isExternNext = info->O->getPlainRelocationExternal(RE: RENext);
3000 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RE: RENext);
3001 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
3002 op_info->SubtractSymbol.Present = 1;
3003 op_info->SubtractSymbol.Name = name;
3004 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(Index: SymbolNum);
3005 Symbol = *RelocSymNext;
3006 name = unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName()).data();
3007 }
3008 }
3009 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
3010 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
3011 op_info->AddSymbol.Present = 1;
3012 op_info->AddSymbol.Name = name;
3013 return 1;
3014 }
3015 return 0;
3016 }
3017 if (Arch == Triple::arm) {
3018 if (Offset != 0 || (InstSize != 4 && InstSize != 2))
3019 return 0;
3020 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3021 // TODO:
3022 // Search the external relocation entries of a fully linked image
3023 // (if any) for an entry that matches this segment offset.
3024 // uint32_t seg_offset = (Pc + Offset);
3025 return 0;
3026 }
3027 // In MH_OBJECT filetypes search the section's relocation entries (if any)
3028 // for an entry for this section offset.
3029 uint32_t sect_addr = info->S.getAddress();
3030 uint32_t sect_offset = (Pc + Offset) - sect_addr;
3031 DataRefImpl Rel;
3032 MachO::any_relocation_info RE;
3033 bool isExtern = false;
3034 SymbolRef Symbol;
3035 bool r_scattered = false;
3036 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
3037 auto Reloc =
3038 find_if(Range: info->S.relocations(), P: [&](const RelocationRef &Reloc) {
3039 uint64_t RelocOffset = Reloc.getOffset();
3040 return RelocOffset == sect_offset;
3041 });
3042
3043 if (Reloc == info->S.relocations().end())
3044 return 0;
3045
3046 Rel = Reloc->getRawDataRefImpl();
3047 RE = info->O->getRelocation(Rel);
3048 r_length = info->O->getAnyRelocationLength(RE);
3049 r_scattered = info->O->isRelocationScattered(RE);
3050 if (r_scattered) {
3051 r_value = info->O->getScatteredRelocationValue(RE);
3052 r_type = info->O->getScatteredRelocationType(RE);
3053 } else {
3054 r_type = info->O->getAnyRelocationType(RE);
3055 isExtern = info->O->getPlainRelocationExternal(RE);
3056 if (isExtern) {
3057 symbol_iterator RelocSym = Reloc->getSymbol();
3058 Symbol = *RelocSym;
3059 }
3060 }
3061 if (r_type == MachO::ARM_RELOC_HALF ||
3062 r_type == MachO::ARM_RELOC_SECTDIFF ||
3063 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
3064 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3065 DataRefImpl RelNext = Rel;
3066 info->O->moveRelocationNext(Rel&: RelNext);
3067 MachO::any_relocation_info RENext;
3068 RENext = info->O->getRelocation(Rel: RelNext);
3069 other_half = info->O->getAnyRelocationAddress(RE: RENext) & 0xffff;
3070 if (info->O->isRelocationScattered(RE: RENext))
3071 pair_r_value = info->O->getScatteredRelocationValue(RE: RENext);
3072 }
3073
3074 if (isExtern) {
3075 const char *name =
3076 unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName()).data();
3077 op_info->AddSymbol.Present = 1;
3078 op_info->AddSymbol.Name = name;
3079 switch (r_type) {
3080 case MachO::ARM_RELOC_HALF:
3081 if ((r_length & 0x1) == 1) {
3082 op_info->Value = value << 16 | other_half;
3083 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3084 } else {
3085 op_info->Value = other_half << 16 | value;
3086 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3087 }
3088 break;
3089 default:
3090 break;
3091 }
3092 return 1;
3093 }
3094 // If we have a branch that is not an external relocation entry then
3095 // return 0 so the code in tryAddingSymbolicOperand() can use the
3096 // SymbolLookUp call back with the branch target address to look up the
3097 // symbol and possibility add an annotation for a symbol stub.
3098 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
3099 r_type == MachO::ARM_THUMB_RELOC_BR22))
3100 return 0;
3101
3102 uint32_t offset = 0;
3103 if (r_type == MachO::ARM_RELOC_HALF ||
3104 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3105 if ((r_length & 0x1) == 1)
3106 value = value << 16 | other_half;
3107 else
3108 value = other_half << 16 | value;
3109 }
3110 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
3111 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
3112 offset = value - r_value;
3113 value = r_value;
3114 }
3115
3116 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3117 if ((r_length & 0x1) == 1)
3118 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3119 else
3120 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3121 const char *add = GuessSymbolName(value: r_value, AddrMap: info->AddrMap);
3122 const char *sub = GuessSymbolName(value: pair_r_value, AddrMap: info->AddrMap);
3123 int32_t offset = value - (r_value - pair_r_value);
3124 op_info->AddSymbol.Present = 1;
3125 if (add != nullptr)
3126 op_info->AddSymbol.Name = add;
3127 else
3128 op_info->AddSymbol.Value = r_value;
3129 op_info->SubtractSymbol.Present = 1;
3130 if (sub != nullptr)
3131 op_info->SubtractSymbol.Name = sub;
3132 else
3133 op_info->SubtractSymbol.Value = pair_r_value;
3134 op_info->Value = offset;
3135 return 1;
3136 }
3137
3138 op_info->AddSymbol.Present = 1;
3139 op_info->Value = offset;
3140 if (r_type == MachO::ARM_RELOC_HALF) {
3141 if ((r_length & 0x1) == 1)
3142 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3143 else
3144 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3145 }
3146 const char *add = GuessSymbolName(value, AddrMap: info->AddrMap);
3147 if (add != nullptr) {
3148 op_info->AddSymbol.Name = add;
3149 return 1;
3150 }
3151 op_info->AddSymbol.Value = value;
3152 return 1;
3153 }
3154 if (Arch == Triple::aarch64 || Arch == Triple::aarch64_32) {
3155 if (Offset != 0 || InstSize != 4)
3156 return 0;
3157 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3158 // TODO:
3159 // Search the external relocation entries of a fully linked image
3160 // (if any) for an entry that matches this segment offset.
3161 // uint64_t seg_offset = (Pc + Offset);
3162 return 0;
3163 }
3164 // In MH_OBJECT filetypes search the section's relocation entries (if any)
3165 // for an entry for this section offset.
3166 uint64_t sect_addr = info->S.getAddress();
3167 uint64_t sect_offset = (Pc + Offset) - sect_addr;
3168 auto Reloc =
3169 find_if(Range: info->S.relocations(), P: [&](const RelocationRef &Reloc) {
3170 uint64_t RelocOffset = Reloc.getOffset();
3171 return RelocOffset == sect_offset;
3172 });
3173
3174 if (Reloc == info->S.relocations().end())
3175 return 0;
3176
3177 DataRefImpl Rel = Reloc->getRawDataRefImpl();
3178 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
3179 uint32_t r_type = info->O->getAnyRelocationType(RE);
3180 if (r_type == MachO::ARM64_RELOC_ADDEND) {
3181 DataRefImpl RelNext = Rel;
3182 info->O->moveRelocationNext(Rel&: RelNext);
3183 MachO::any_relocation_info RENext = info->O->getRelocation(Rel: RelNext);
3184 if (value == 0) {
3185 value = info->O->getPlainRelocationSymbolNum(RE: RENext);
3186 op_info->Value = value;
3187 }
3188 }
3189 // NOTE: Scattered relocations don't exist on arm64.
3190 if (!info->O->getPlainRelocationExternal(RE))
3191 return 0;
3192 const char *name =
3193 unwrapOrError(EO: Reloc->getSymbol()->getName(), Args: info->O->getFileName())
3194 .data();
3195 op_info->AddSymbol.Present = 1;
3196 op_info->AddSymbol.Name = name;
3197
3198 switch (r_type) {
3199 case MachO::ARM64_RELOC_PAGE21:
3200 /* @page */
3201 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
3202 break;
3203 case MachO::ARM64_RELOC_PAGEOFF12:
3204 /* @pageoff */
3205 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
3206 break;
3207 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
3208 /* @gotpage */
3209 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
3210 break;
3211 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
3212 /* @gotpageoff */
3213 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
3214 break;
3215 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
3216 /* @tvlppage is not implemented in llvm-mc */
3217 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
3218 break;
3219 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
3220 /* @tvlppageoff is not implemented in llvm-mc */
3221 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
3222 break;
3223 default:
3224 case MachO::ARM64_RELOC_BRANCH26:
3225 op_info->VariantKind = LLVMDisassembler_VariantKind_None;
3226 break;
3227 }
3228 return 1;
3229 }
3230 return 0;
3231}
3232
3233// GuessCstringPointer is passed the address of what might be a pointer to a
3234// literal string in a cstring section. If that address is in a cstring section
3235// it returns a pointer to that string. Else it returns nullptr.
3236static const char *GuessCstringPointer(uint64_t ReferenceValue,
3237 struct DisassembleInfo *info) {
3238 for (const auto &Load : info->O->load_commands()) {
3239 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3240 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(L: Load);
3241 for (unsigned J = 0; J < Seg.nsects; ++J) {
3242 MachO::section_64 Sec = info->O->getSection64(L: Load, Index: J);
3243 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3244 if (section_type == MachO::S_CSTRING_LITERALS &&
3245 ReferenceValue >= Sec.addr &&
3246 ReferenceValue < Sec.addr + Sec.size) {
3247 uint64_t sect_offset = ReferenceValue - Sec.addr;
3248 uint64_t object_offset = Sec.offset + sect_offset;
3249 StringRef MachOContents = info->O->getData();
3250 uint64_t object_size = MachOContents.size();
3251 const char *object_addr = MachOContents.data();
3252 if (object_offset < object_size) {
3253 const char *name = object_addr + object_offset;
3254 return name;
3255 } else {
3256 return nullptr;
3257 }
3258 }
3259 }
3260 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
3261 MachO::segment_command Seg = info->O->getSegmentLoadCommand(L: Load);
3262 for (unsigned J = 0; J < Seg.nsects; ++J) {
3263 MachO::section Sec = info->O->getSection(L: Load, Index: J);
3264 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3265 if (section_type == MachO::S_CSTRING_LITERALS &&
3266 ReferenceValue >= Sec.addr &&
3267 ReferenceValue < Sec.addr + Sec.size) {
3268 uint64_t sect_offset = ReferenceValue - Sec.addr;
3269 uint64_t object_offset = Sec.offset + sect_offset;
3270 StringRef MachOContents = info->O->getData();
3271 uint64_t object_size = MachOContents.size();
3272 const char *object_addr = MachOContents.data();
3273 if (object_offset < object_size) {
3274 const char *name = object_addr + object_offset;
3275 return name;
3276 } else {
3277 return nullptr;
3278 }
3279 }
3280 }
3281 }
3282 }
3283 return nullptr;
3284}
3285
3286// GuessIndirectSymbol returns the name of the indirect symbol for the
3287// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
3288// an address of a symbol stub or a lazy or non-lazy pointer to associate the
3289// symbol name being referenced by the stub or pointer.
3290static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
3291 struct DisassembleInfo *info) {
3292 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
3293 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
3294 for (const auto &Load : info->O->load_commands()) {
3295 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3296 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(L: Load);
3297 for (unsigned J = 0; J < Seg.nsects; ++J) {
3298 MachO::section_64 Sec = info->O->getSection64(L: Load, Index: J);
3299 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3300 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3301 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3302 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3303 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3304 section_type == MachO::S_SYMBOL_STUBS) &&
3305 ReferenceValue >= Sec.addr &&
3306 ReferenceValue < Sec.addr + Sec.size) {
3307 uint32_t stride;
3308 if (section_type == MachO::S_SYMBOL_STUBS)
3309 stride = Sec.reserved2;
3310 else
3311 stride = 8;
3312 if (stride == 0)
3313 return nullptr;
3314 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3315 if (index < Dysymtab.nindirectsyms) {
3316 uint32_t indirect_symbol =
3317 info->O->getIndirectSymbolTableEntry(DLC: Dysymtab, Index: index);
3318 if (indirect_symbol < Symtab.nsyms) {
3319 symbol_iterator Sym = info->O->getSymbolByIndex(Index: indirect_symbol);
3320 return unwrapOrError(EO: Sym->getName(), Args: info->O->getFileName())
3321 .data();
3322 }
3323 }
3324 }
3325 }
3326 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
3327 MachO::segment_command Seg = info->O->getSegmentLoadCommand(L: Load);
3328 for (unsigned J = 0; J < Seg.nsects; ++J) {
3329 MachO::section Sec = info->O->getSection(L: Load, Index: J);
3330 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3331 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3332 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3333 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3334 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3335 section_type == MachO::S_SYMBOL_STUBS) &&
3336 ReferenceValue >= Sec.addr &&
3337 ReferenceValue < Sec.addr + Sec.size) {
3338 uint32_t stride;
3339 if (section_type == MachO::S_SYMBOL_STUBS)
3340 stride = Sec.reserved2;
3341 else
3342 stride = 4;
3343 if (stride == 0)
3344 return nullptr;
3345 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3346 if (index < Dysymtab.nindirectsyms) {
3347 uint32_t indirect_symbol =
3348 info->O->getIndirectSymbolTableEntry(DLC: Dysymtab, Index: index);
3349 if (indirect_symbol < Symtab.nsyms) {
3350 symbol_iterator Sym = info->O->getSymbolByIndex(Index: indirect_symbol);
3351 return unwrapOrError(EO: Sym->getName(), Args: info->O->getFileName())
3352 .data();
3353 }
3354 }
3355 }
3356 }
3357 }
3358 }
3359 return nullptr;
3360}
3361
3362// method_reference() is called passing it the ReferenceName that might be
3363// a reference it to an Objective-C method call. If so then it allocates and
3364// assembles a method call string with the values last seen and saved in
3365// the DisassembleInfo's class_name and selector_name fields. This is saved
3366// into the method field of the info and any previous string is free'ed.
3367// Then the class_name field in the info is set to nullptr. The method call
3368// string is set into ReferenceName and ReferenceType is set to
3369// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
3370// then both ReferenceType and ReferenceName are left unchanged.
3371static void method_reference(struct DisassembleInfo *info,
3372 uint64_t *ReferenceType,
3373 const char **ReferenceName) {
3374 unsigned int Arch = info->O->getArch();
3375 if (*ReferenceName != nullptr) {
3376 if (strcmp(s1: *ReferenceName, s2: "_objc_msgSend") == 0) {
3377 if (info->selector_name != nullptr) {
3378 if (info->class_name != nullptr) {
3379 info->method = std::make_unique<char[]>(
3380 num: 5 + strlen(s: info->class_name) + strlen(s: info->selector_name));
3381 char *method = info->method.get();
3382 if (method != nullptr) {
3383 strcpy(dest: method, src: "+[");
3384 strcat(dest: method, src: info->class_name);
3385 strcat(dest: method, src: " ");
3386 strcat(dest: method, src: info->selector_name);
3387 strcat(dest: method, src: "]");
3388 *ReferenceName = method;
3389 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3390 }
3391 } else {
3392 info->method =
3393 std::make_unique<char[]>(num: 9 + strlen(s: info->selector_name));
3394 char *method = info->method.get();
3395 if (method != nullptr) {
3396 if (Arch == Triple::x86_64)
3397 strcpy(dest: method, src: "-[%rdi ");
3398 else if (Arch == Triple::aarch64 || Arch == Triple::aarch64_32)
3399 strcpy(dest: method, src: "-[x0 ");
3400 else
3401 strcpy(dest: method, src: "-[r? ");
3402 strcat(dest: method, src: info->selector_name);
3403 strcat(dest: method, src: "]");
3404 *ReferenceName = method;
3405 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3406 }
3407 }
3408 info->class_name = nullptr;
3409 }
3410 } else if (strcmp(s1: *ReferenceName, s2: "_objc_msgSendSuper2") == 0) {
3411 if (info->selector_name != nullptr) {
3412 info->method =
3413 std::make_unique<char[]>(num: 17 + strlen(s: info->selector_name));
3414 char *method = info->method.get();
3415 if (method != nullptr) {
3416 if (Arch == Triple::x86_64)
3417 strcpy(dest: method, src: "-[[%rdi super] ");
3418 else if (Arch == Triple::aarch64 || Arch == Triple::aarch64_32)
3419 strcpy(dest: method, src: "-[[x0 super] ");
3420 else
3421 strcpy(dest: method, src: "-[[r? super] ");
3422 strcat(dest: method, src: info->selector_name);
3423 strcat(dest: method, src: "]");
3424 *ReferenceName = method;
3425 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3426 }
3427 info->class_name = nullptr;
3428 }
3429 }
3430 }
3431}
3432
3433// GuessPointerPointer() is passed the address of what might be a pointer to
3434// a reference to an Objective-C class, selector, message ref or cfstring.
3435// If so the value of the pointer is returned and one of the booleans are set
3436// to true. If not zero is returned and all the booleans are set to false.
3437static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
3438 struct DisassembleInfo *info,
3439 bool &classref, bool &selref, bool &msgref,
3440 bool &cfstring) {
3441 classref = false;
3442 selref = false;
3443 msgref = false;
3444 cfstring = false;
3445 for (const auto &Load : info->O->load_commands()) {
3446 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3447 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(L: Load);
3448 for (unsigned J = 0; J < Seg.nsects; ++J) {
3449 MachO::section_64 Sec = info->O->getSection64(L: Load, Index: J);
3450 if ((strncmp(s1: Sec.sectname, s2: "__objc_selrefs", n: 16) == 0 ||
3451 strncmp(s1: Sec.sectname, s2: "__objc_classrefs", n: 16) == 0 ||
3452 strncmp(s1: Sec.sectname, s2: "__objc_superrefs", n: 16) == 0 ||
3453 strncmp(s1: Sec.sectname, s2: "__objc_msgrefs", n: 16) == 0 ||
3454 strncmp(s1: Sec.sectname, s2: "__cfstring", n: 16) == 0) &&
3455 ReferenceValue >= Sec.addr &&
3456 ReferenceValue < Sec.addr + Sec.size) {
3457 uint64_t sect_offset = ReferenceValue - Sec.addr;
3458 uint64_t object_offset = Sec.offset + sect_offset;
3459 StringRef MachOContents = info->O->getData();
3460 uint64_t object_size = MachOContents.size();
3461 const char *object_addr = MachOContents.data();
3462 if (object_offset < object_size) {
3463 uint64_t pointer_value;
3464 memcpy(dest: &pointer_value, src: object_addr + object_offset,
3465 n: sizeof(uint64_t));
3466 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3467 sys::swapByteOrder(Value&: pointer_value);
3468 if (strncmp(s1: Sec.sectname, s2: "__objc_selrefs", n: 16) == 0)
3469 selref = true;
3470 else if (strncmp(s1: Sec.sectname, s2: "__objc_classrefs", n: 16) == 0 ||
3471 strncmp(s1: Sec.sectname, s2: "__objc_superrefs", n: 16) == 0)
3472 classref = true;
3473 else if (strncmp(s1: Sec.sectname, s2: "__objc_msgrefs", n: 16) == 0 &&
3474 ReferenceValue + 8 < Sec.addr + Sec.size) {
3475 msgref = true;
3476 memcpy(dest: &pointer_value, src: object_addr + object_offset + 8,
3477 n: sizeof(uint64_t));
3478 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3479 sys::swapByteOrder(Value&: pointer_value);
3480 } else if (strncmp(s1: Sec.sectname, s2: "__cfstring", n: 16) == 0)
3481 cfstring = true;
3482 return pointer_value;
3483 } else {
3484 return 0;
3485 }
3486 }
3487 }
3488 }
3489 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
3490 }
3491 return 0;
3492}
3493
3494// get_pointer_64 returns a pointer to the bytes in the object file at the
3495// Address from a section in the Mach-O file. And indirectly returns the
3496// offset into the section, number of bytes left in the section past the offset
3497// and which section is was being referenced. If the Address is not in a
3498// section nullptr is returned.
3499static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
3500 uint32_t &left, SectionRef &S,
3501 DisassembleInfo *info,
3502 bool objc_only = false) {
3503 offset = 0;
3504 left = 0;
3505 S = SectionRef();
3506 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
3507 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
3508 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
3509 if (SectSize == 0)
3510 continue;
3511 if (objc_only) {
3512 StringRef SectName;
3513 Expected<StringRef> SecNameOrErr =
3514 ((*(info->Sections))[SectIdx]).getName();
3515 if (SecNameOrErr)
3516 SectName = *SecNameOrErr;
3517 else
3518 consumeError(Err: SecNameOrErr.takeError());
3519
3520 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
3521 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
3522 if (SegName != "__OBJC" && SectName != "__cstring")
3523 continue;
3524 }
3525 if (Address >= SectAddress && Address < SectAddress + SectSize) {
3526 S = (*(info->Sections))[SectIdx];
3527 offset = Address - SectAddress;
3528 left = SectSize - offset;
3529 StringRef SectContents = unwrapOrError(
3530 EO: ((*(info->Sections))[SectIdx]).getContents(), Args: info->O->getFileName());
3531 return SectContents.data() + offset;
3532 }
3533 }
3534 return nullptr;
3535}
3536
3537static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
3538 uint32_t &left, SectionRef &S,
3539 DisassembleInfo *info,
3540 bool objc_only = false) {
3541 return get_pointer_64(Address, offset, left, S, info, objc_only);
3542}
3543
3544// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
3545// the symbol indirectly through n_value. Based on the relocation information
3546// for the specified section offset in the specified section reference.
3547// If no relocation information is found and a non-zero ReferenceValue for the
3548// symbol is passed, look up that address in the info's AddrMap.
3549static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
3550 DisassembleInfo *info, uint64_t &n_value,
3551 uint64_t ReferenceValue = 0) {
3552 n_value = 0;
3553 if (!info->verbose)
3554 return nullptr;
3555
3556 // See if there is an external relocation entry at the sect_offset.
3557 bool reloc_found = false;
3558 DataRefImpl Rel;
3559 MachO::any_relocation_info RE;
3560 bool isExtern = false;
3561 SymbolRef Symbol;
3562 for (const RelocationRef &Reloc : S.relocations()) {
3563 uint64_t RelocOffset = Reloc.getOffset();
3564 if (RelocOffset == sect_offset) {
3565 Rel = Reloc.getRawDataRefImpl();
3566 RE = info->O->getRelocation(Rel);
3567 if (info->O->isRelocationScattered(RE))
3568 continue;
3569 isExtern = info->O->getPlainRelocationExternal(RE);
3570 if (isExtern) {
3571 symbol_iterator RelocSym = Reloc.getSymbol();
3572 Symbol = *RelocSym;
3573 }
3574 reloc_found = true;
3575 break;
3576 }
3577 }
3578 // If there is an external relocation entry for a symbol in this section
3579 // at this section_offset then use that symbol's value for the n_value
3580 // and return its name.
3581 const char *SymbolName = nullptr;
3582 if (reloc_found && isExtern) {
3583 n_value = cantFail(ValOrErr: Symbol.getValue());
3584 StringRef Name = unwrapOrError(EO: Symbol.getName(), Args: info->O->getFileName());
3585 if (!Name.empty()) {
3586 SymbolName = Name.data();
3587 return SymbolName;
3588 }
3589 }
3590
3591 // TODO: For fully linked images, look through the external relocation
3592 // entries off the dynamic symtab command. For these the r_offset is from the
3593 // start of the first writeable segment in the Mach-O file. So the offset
3594 // to this section from that segment is passed to this routine by the caller,
3595 // as the database_offset. Which is the difference of the section's starting
3596 // address and the first writable segment.
3597 //
3598 // NOTE: need add passing the database_offset to this routine.
3599
3600 // We did not find an external relocation entry so look up the ReferenceValue
3601 // as an address of a symbol and if found return that symbol's name.
3602 SymbolName = GuessSymbolName(value: ReferenceValue, AddrMap: info->AddrMap);
3603
3604 return SymbolName;
3605}
3606
3607static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3608 DisassembleInfo *info,
3609 uint32_t ReferenceValue) {
3610 uint64_t n_value64;
3611 return get_symbol_64(sect_offset, S, info, n_value&: n_value64, ReferenceValue);
3612}
3613
3614namespace {
3615
3616// These are structs in the Objective-C meta data and read to produce the
3617// comments for disassembly. While these are part of the ABI they are no
3618// public definitions. So the are here not in include/llvm/BinaryFormat/MachO.h
3619// .
3620
3621// The cfstring object in a 64-bit Mach-O file.
3622struct cfstring64_t {
3623 uint64_t isa; // class64_t * (64-bit pointer)
3624 uint64_t flags; // flag bits
3625 uint64_t characters; // char * (64-bit pointer)
3626 uint64_t length; // number of non-NULL characters in above
3627};
3628
3629// The class object in a 64-bit Mach-O file.
3630struct class64_t {
3631 uint64_t isa; // class64_t * (64-bit pointer)
3632 uint64_t superclass; // class64_t * (64-bit pointer)
3633 uint64_t cache; // Cache (64-bit pointer)
3634 uint64_t vtable; // IMP * (64-bit pointer)
3635 uint64_t data; // class_ro64_t * (64-bit pointer)
3636};
3637
3638struct class32_t {
3639 uint32_t isa; /* class32_t * (32-bit pointer) */
3640 uint32_t superclass; /* class32_t * (32-bit pointer) */
3641 uint32_t cache; /* Cache (32-bit pointer) */
3642 uint32_t vtable; /* IMP * (32-bit pointer) */
3643 uint32_t data; /* class_ro32_t * (32-bit pointer) */
3644};
3645
3646struct class_ro64_t {
3647 uint32_t flags;
3648 uint32_t instanceStart;
3649 uint32_t instanceSize;
3650 uint32_t reserved;
3651 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3652 uint64_t name; // const char * (64-bit pointer)
3653 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3654 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3655 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3656 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3657 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3658};
3659
3660struct class_ro32_t {
3661 uint32_t flags;
3662 uint32_t instanceStart;
3663 uint32_t instanceSize;
3664 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3665 uint32_t name; /* const char * (32-bit pointer) */
3666 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3667 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3668 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3669 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3670 uint32_t baseProperties; /* const struct objc_property_list *
3671 (32-bit pointer) */
3672};
3673
3674/* Values for class_ro{64,32}_t->flags */
3675#define RO_META (1 << 0)
3676#define RO_ROOT (1 << 1)
3677#define RO_HAS_CXX_STRUCTORS (1 << 2)
3678
3679/* Values for method_list{64,32}_t->entsize */
3680#define ML_HAS_RELATIVE_PTRS (1 << 31)
3681#define ML_ENTSIZE_MASK 0xFFFF
3682
3683struct method_list64_t {
3684 uint32_t entsize;
3685 uint32_t count;
3686 /* struct method64_t first; These structures follow inline */
3687};
3688
3689struct method_list32_t {
3690 uint32_t entsize;
3691 uint32_t count;
3692 /* struct method32_t first; These structures follow inline */
3693};
3694
3695struct method64_t {
3696 uint64_t name; /* SEL (64-bit pointer) */
3697 uint64_t types; /* const char * (64-bit pointer) */
3698 uint64_t imp; /* IMP (64-bit pointer) */
3699};
3700
3701struct method32_t {
3702 uint32_t name; /* SEL (32-bit pointer) */
3703 uint32_t types; /* const char * (32-bit pointer) */
3704 uint32_t imp; /* IMP (32-bit pointer) */
3705};
3706
3707struct method_relative_t {
3708 int32_t name; /* SEL (32-bit relative) */
3709 int32_t types; /* const char * (32-bit relative) */
3710 int32_t imp; /* IMP (32-bit relative) */
3711};
3712
3713struct protocol_list64_t {
3714 uint64_t count; /* uintptr_t (a 64-bit value) */
3715 /* struct protocol64_t * list[0]; These pointers follow inline */
3716};
3717
3718struct protocol_list32_t {
3719 uint32_t count; /* uintptr_t (a 32-bit value) */
3720 /* struct protocol32_t * list[0]; These pointers follow inline */
3721};
3722
3723struct protocol64_t {
3724 uint64_t isa; /* id * (64-bit pointer) */
3725 uint64_t name; /* const char * (64-bit pointer) */
3726 uint64_t protocols; /* struct protocol_list64_t *
3727 (64-bit pointer) */
3728 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3729 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3730 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3731 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3732 uint64_t instanceProperties; /* struct objc_property_list *
3733 (64-bit pointer) */
3734};
3735
3736struct protocol32_t {
3737 uint32_t isa; /* id * (32-bit pointer) */
3738 uint32_t name; /* const char * (32-bit pointer) */
3739 uint32_t protocols; /* struct protocol_list_t *
3740 (32-bit pointer) */
3741 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3742 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3743 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3744 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3745 uint32_t instanceProperties; /* struct objc_property_list *
3746 (32-bit pointer) */
3747};
3748
3749struct ivar_list64_t {
3750 uint32_t entsize;
3751 uint32_t count;
3752 /* struct ivar64_t first; These structures follow inline */
3753};
3754
3755struct ivar_list32_t {
3756 uint32_t entsize;
3757 uint32_t count;
3758 /* struct ivar32_t first; These structures follow inline */
3759};
3760
3761struct ivar64_t {
3762 uint64_t offset; /* uintptr_t * (64-bit pointer) */
3763 uint64_t name; /* const char * (64-bit pointer) */
3764 uint64_t type; /* const char * (64-bit pointer) */
3765 uint32_t alignment;
3766 uint32_t size;
3767};
3768
3769struct ivar32_t {
3770 uint32_t offset; /* uintptr_t * (32-bit pointer) */
3771 uint32_t name; /* const char * (32-bit pointer) */
3772 uint32_t type; /* const char * (32-bit pointer) */
3773 uint32_t alignment;
3774 uint32_t size;
3775};
3776
3777struct objc_property_list64 {
3778 uint32_t entsize;
3779 uint32_t count;
3780 /* struct objc_property64 first; These structures follow inline */
3781};
3782
3783struct objc_property_list32 {
3784 uint32_t entsize;
3785 uint32_t count;
3786 /* struct objc_property32 first; These structures follow inline */
3787};
3788
3789struct objc_property64 {
3790 uint64_t name; /* const char * (64-bit pointer) */
3791 uint64_t attributes; /* const char * (64-bit pointer) */
3792};
3793
3794struct objc_property32 {
3795 uint32_t name; /* const char * (32-bit pointer) */
3796 uint32_t attributes; /* const char * (32-bit pointer) */
3797};
3798
3799struct category64_t {
3800 uint64_t name; /* const char * (64-bit pointer) */
3801 uint64_t cls; /* struct class_t * (64-bit pointer) */
3802 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3803 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3804 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3805 uint64_t instanceProperties; /* struct objc_property_list *
3806 (64-bit pointer) */
3807};
3808
3809struct category32_t {
3810 uint32_t name; /* const char * (32-bit pointer) */
3811 uint32_t cls; /* struct class_t * (32-bit pointer) */
3812 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3813 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3814 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3815 uint32_t instanceProperties; /* struct objc_property_list *
3816 (32-bit pointer) */
3817};
3818
3819struct objc_image_info64 {
3820 uint32_t version;
3821 uint32_t flags;
3822};
3823struct objc_image_info32 {
3824 uint32_t version;
3825 uint32_t flags;
3826};
3827struct imageInfo_t {
3828 uint32_t version;
3829 uint32_t flags;
3830};
3831/* masks for objc_image_info.flags */
3832#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
3833#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
3834#define OBJC_IMAGE_IS_SIMULATED (1 << 5)
3835#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)
3836
3837struct message_ref64 {
3838 uint64_t imp; /* IMP (64-bit pointer) */
3839 uint64_t sel; /* SEL (64-bit pointer) */
3840};
3841
3842struct message_ref32 {
3843 uint32_t imp; /* IMP (32-bit pointer) */
3844 uint32_t sel; /* SEL (32-bit pointer) */
3845};
3846
3847// Objective-C 1 (32-bit only) meta data structs.
3848
3849struct objc_module_t {
3850 uint32_t version;
3851 uint32_t size;
3852 uint32_t name; /* char * (32-bit pointer) */
3853 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3854};
3855
3856struct objc_symtab_t {
3857 uint32_t sel_ref_cnt;
3858 uint32_t refs; /* SEL * (32-bit pointer) */
3859 uint16_t cls_def_cnt;
3860 uint16_t cat_def_cnt;
3861 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3862};
3863
3864struct objc_class_t {
3865 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3866 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3867 uint32_t name; /* const char * (32-bit pointer) */
3868 int32_t version;
3869 int32_t info;
3870 int32_t instance_size;
3871 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3872 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3873 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3874 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3875};
3876
3877#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
3878// class is not a metaclass
3879#define CLS_CLASS 0x1
3880// class is a metaclass
3881#define CLS_META 0x2
3882
3883struct objc_category_t {
3884 uint32_t category_name; /* char * (32-bit pointer) */
3885 uint32_t class_name; /* char * (32-bit pointer) */
3886 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3887 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3888 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3889};
3890
3891struct objc_ivar_t {
3892 uint32_t ivar_name; /* char * (32-bit pointer) */
3893 uint32_t ivar_type; /* char * (32-bit pointer) */
3894 int32_t ivar_offset;
3895};
3896
3897struct objc_ivar_list_t {
3898 int32_t ivar_count;
3899 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
3900};
3901
3902struct objc_method_list_t {
3903 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3904 int32_t method_count;
3905 // struct objc_method_t method_list[1]; /* variable length structure */
3906};
3907
3908struct objc_method_t {
3909 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3910 uint32_t method_types; /* char * (32-bit pointer) */
3911 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3912 (32-bit pointer) */
3913};
3914
3915struct objc_protocol_list_t {
3916 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3917 int32_t count;
3918 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3919 // (32-bit pointer) */
3920};
3921
3922struct objc_protocol_t {
3923 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3924 uint32_t protocol_name; /* char * (32-bit pointer) */
3925 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3926 uint32_t instance_methods; /* struct objc_method_description_list *
3927 (32-bit pointer) */
3928 uint32_t class_methods; /* struct objc_method_description_list *
3929 (32-bit pointer) */
3930};
3931
3932struct objc_method_description_list_t {
3933 int32_t count;
3934 // struct objc_method_description_t list[1];
3935};
3936
3937struct objc_method_description_t {
3938 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3939 uint32_t types; /* char * (32-bit pointer) */
3940};
3941
3942inline void swapStruct(struct cfstring64_t &cfs) {
3943 sys::swapByteOrder(Value&: cfs.isa);
3944 sys::swapByteOrder(Value&: cfs.flags);
3945 sys::swapByteOrder(Value&: cfs.characters);
3946 sys::swapByteOrder(Value&: cfs.length);
3947}
3948
3949inline void swapStruct(struct class64_t &c) {
3950 sys::swapByteOrder(Value&: c.isa);
3951 sys::swapByteOrder(Value&: c.superclass);
3952 sys::swapByteOrder(Value&: c.cache);
3953 sys::swapByteOrder(Value&: c.vtable);
3954 sys::swapByteOrder(Value&: c.data);
3955}
3956
3957inline void swapStruct(struct class32_t &c) {
3958 sys::swapByteOrder(Value&: c.isa);
3959 sys::swapByteOrder(Value&: c.superclass);
3960 sys::swapByteOrder(Value&: c.cache);
3961 sys::swapByteOrder(Value&: c.vtable);
3962 sys::swapByteOrder(Value&: c.data);
3963}
3964
3965inline void swapStruct(struct class_ro64_t &cro) {
3966 sys::swapByteOrder(Value&: cro.flags);
3967 sys::swapByteOrder(Value&: cro.instanceStart);
3968 sys::swapByteOrder(Value&: cro.instanceSize);
3969 sys::swapByteOrder(Value&: cro.reserved);
3970 sys::swapByteOrder(Value&: cro.ivarLayout);
3971 sys::swapByteOrder(Value&: cro.name);
3972 sys::swapByteOrder(Value&: cro.baseMethods);
3973 sys::swapByteOrder(Value&: cro.baseProtocols);
3974 sys::swapByteOrder(Value&: cro.ivars);
3975 sys::swapByteOrder(Value&: cro.weakIvarLayout);
3976 sys::swapByteOrder(Value&: cro.baseProperties);
3977}
3978
3979inline void swapStruct(struct class_ro32_t &cro) {
3980 sys::swapByteOrder(Value&: cro.flags);
3981 sys::swapByteOrder(Value&: cro.instanceStart);
3982 sys::swapByteOrder(Value&: cro.instanceSize);
3983 sys::swapByteOrder(Value&: cro.ivarLayout);
3984 sys::swapByteOrder(Value&: cro.name);
3985 sys::swapByteOrder(Value&: cro.baseMethods);
3986 sys::swapByteOrder(Value&: cro.baseProtocols);
3987 sys::swapByteOrder(Value&: cro.ivars);
3988 sys::swapByteOrder(Value&: cro.weakIvarLayout);
3989 sys::swapByteOrder(Value&: cro.baseProperties);
3990}
3991
3992inline void swapStruct(struct method_list64_t &ml) {
3993 sys::swapByteOrder(Value&: ml.entsize);
3994 sys::swapByteOrder(Value&: ml.count);
3995}
3996
3997inline void swapStruct(struct method_list32_t &ml) {
3998 sys::swapByteOrder(Value&: ml.entsize);
3999 sys::swapByteOrder(Value&: ml.count);
4000}
4001
4002inline void swapStruct(struct method64_t &m) {
4003 sys::swapByteOrder(Value&: m.name);
4004 sys::swapByteOrder(Value&: m.types);
4005 sys::swapByteOrder(Value&: m.imp);
4006}
4007
4008inline void swapStruct(struct method32_t &m) {
4009 sys::swapByteOrder(Value&: m.name);
4010 sys::swapByteOrder(Value&: m.types);
4011 sys::swapByteOrder(Value&: m.imp);
4012}
4013
4014inline void swapStruct(struct method_relative_t &m) {
4015 sys::swapByteOrder(Value&: m.name);
4016 sys::swapByteOrder(Value&: m.types);
4017 sys::swapByteOrder(Value&: m.imp);
4018}
4019
4020inline void swapStruct(struct protocol_list64_t &pl) {
4021 sys::swapByteOrder(Value&: pl.count);
4022}
4023
4024inline void swapStruct(struct protocol_list32_t &pl) {
4025 sys::swapByteOrder(Value&: pl.count);
4026}
4027
4028inline void swapStruct(struct protocol64_t &p) {
4029 sys::swapByteOrder(Value&: p.isa);
4030 sys::swapByteOrder(Value&: p.name);
4031 sys::swapByteOrder(Value&: p.protocols);
4032 sys::swapByteOrder(Value&: p.instanceMethods);
4033 sys::swapByteOrder(Value&: p.classMethods);
4034 sys::swapByteOrder(Value&: p.optionalInstanceMethods);
4035 sys::swapByteOrder(Value&: p.optionalClassMethods);
4036 sys::swapByteOrder(Value&: p.instanceProperties);
4037}
4038
4039inline void swapStruct(struct protocol32_t &p) {
4040 sys::swapByteOrder(Value&: p.isa);
4041 sys::swapByteOrder(Value&: p.name);
4042 sys::swapByteOrder(Value&: p.protocols);
4043 sys::swapByteOrder(Value&: p.instanceMethods);
4044 sys::swapByteOrder(Value&: p.classMethods);
4045 sys::swapByteOrder(Value&: p.optionalInstanceMethods);
4046 sys::swapByteOrder(Value&: p.optionalClassMethods);
4047 sys::swapByteOrder(Value&: p.instanceProperties);
4048}
4049
4050inline void swapStruct(struct ivar_list64_t &il) {
4051 sys::swapByteOrder(Value&: il.entsize);
4052 sys::swapByteOrder(Value&: il.count);
4053}
4054
4055inline void swapStruct(struct ivar_list32_t &il) {
4056 sys::swapByteOrder(Value&: il.entsize);
4057 sys::swapByteOrder(Value&: il.count);
4058}
4059
4060inline void swapStruct(struct ivar64_t &i) {
4061 sys::swapByteOrder(Value&: i.offset);
4062 sys::swapByteOrder(Value&: i.name);
4063 sys::swapByteOrder(Value&: i.type);
4064 sys::swapByteOrder(Value&: i.alignment);
4065 sys::swapByteOrder(Value&: i.size);
4066}
4067
4068inline void swapStruct(struct ivar32_t &i) {
4069 sys::swapByteOrder(Value&: i.offset);
4070 sys::swapByteOrder(Value&: i.name);
4071 sys::swapByteOrder(Value&: i.type);
4072 sys::swapByteOrder(Value&: i.alignment);
4073 sys::swapByteOrder(Value&: i.size);
4074}
4075
4076inline void swapStruct(struct objc_property_list64 &pl) {
4077 sys::swapByteOrder(Value&: pl.entsize);
4078 sys::swapByteOrder(Value&: pl.count);
4079}
4080
4081inline void swapStruct(struct objc_property_list32 &pl) {
4082 sys::swapByteOrder(Value&: pl.entsize);
4083 sys::swapByteOrder(Value&: pl.count);
4084}
4085
4086inline void swapStruct(struct objc_property64 &op) {
4087 sys::swapByteOrder(Value&: op.name);
4088 sys::swapByteOrder(Value&: op.attributes);
4089}
4090
4091inline void swapStruct(struct objc_property32 &op) {
4092 sys::swapByteOrder(Value&: op.name);
4093 sys::swapByteOrder(Value&: op.attributes);
4094}
4095
4096inline void swapStruct(struct category64_t &c) {
4097 sys::swapByteOrder(Value&: c.name);
4098 sys::swapByteOrder(Value&: c.cls);
4099 sys::swapByteOrder(Value&: c.instanceMethods);
4100 sys::swapByteOrder(Value&: c.classMethods);
4101 sys::swapByteOrder(Value&: c.protocols);
4102 sys::swapByteOrder(Value&: c.instanceProperties);
4103}
4104
4105inline void swapStruct(struct category32_t &c) {
4106 sys::swapByteOrder(Value&: c.name);
4107 sys::swapByteOrder(Value&: c.cls);
4108 sys::swapByteOrder(Value&: c.instanceMethods);
4109 sys::swapByteOrder(Value&: c.classMethods);
4110 sys::swapByteOrder(Value&: c.protocols);
4111 sys::swapByteOrder(Value&: c.instanceProperties);
4112}
4113
4114inline void swapStruct(struct objc_image_info64 &o) {
4115 sys::swapByteOrder(Value&: o.version);
4116 sys::swapByteOrder(Value&: o.flags);
4117}
4118
4119inline void swapStruct(struct objc_image_info32 &o) {
4120 sys::swapByteOrder(Value&: o.version);
4121 sys::swapByteOrder(Value&: o.flags);
4122}
4123
4124inline void swapStruct(struct imageInfo_t &o) {
4125 sys::swapByteOrder(Value&: o.version);
4126 sys::swapByteOrder(Value&: o.flags);
4127}
4128
4129inline void swapStruct(struct message_ref64 &mr) {
4130 sys::swapByteOrder(Value&: mr.imp);
4131 sys::swapByteOrder(Value&: mr.sel);
4132}
4133
4134inline void swapStruct(struct message_ref32 &mr) {
4135 sys::swapByteOrder(Value&: mr.imp);
4136 sys::swapByteOrder(Value&: mr.sel);
4137}
4138
4139inline void swapStruct(struct objc_module_t &module) {
4140 sys::swapByteOrder(Value&: module.version);
4141 sys::swapByteOrder(Value&: module.size);
4142 sys::swapByteOrder(Value&: module.name);
4143 sys::swapByteOrder(Value&: module.symtab);
4144}
4145
4146inline void swapStruct(struct objc_symtab_t &symtab) {
4147 sys::swapByteOrder(Value&: symtab.sel_ref_cnt);
4148 sys::swapByteOrder(Value&: symtab.refs);
4149 sys::swapByteOrder(Value&: symtab.cls_def_cnt);
4150 sys::swapByteOrder(Value&: symtab.cat_def_cnt);
4151}
4152
4153inline void swapStruct(struct objc_class_t &objc_class) {
4154 sys::swapByteOrder(Value&: objc_class.isa);
4155 sys::swapByteOrder(Value&: objc_class.super_class);
4156 sys::swapByteOrder(Value&: objc_class.name);
4157 sys::swapByteOrder(Value&: objc_class.version);
4158 sys::swapByteOrder(Value&: objc_class.info);
4159 sys::swapByteOrder(Value&: objc_class.instance_size);
4160 sys::swapByteOrder(Value&: objc_class.ivars);
4161 sys::swapByteOrder(Value&: objc_class.methodLists);
4162 sys::swapByteOrder(Value&: objc_class.cache);
4163 sys::swapByteOrder(Value&: objc_class.protocols);
4164}
4165
4166inline void swapStruct(struct objc_category_t &objc_category) {
4167 sys::swapByteOrder(Value&: objc_category.category_name);
4168 sys::swapByteOrder(Value&: objc_category.class_name);
4169 sys::swapByteOrder(Value&: objc_category.instance_methods);
4170 sys::swapByteOrder(Value&: objc_category.class_methods);
4171 sys::swapByteOrder(Value&: objc_category.protocols);
4172}
4173
4174inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
4175 sys::swapByteOrder(Value&: objc_ivar_list.ivar_count);
4176}
4177
4178inline void swapStruct(struct objc_ivar_t &objc_ivar) {
4179 sys::swapByteOrder(Value&: objc_ivar.ivar_name);
4180 sys::swapByteOrder(Value&: objc_ivar.ivar_type);
4181 sys::swapByteOrder(Value&: objc_ivar.ivar_offset);
4182}
4183
4184inline void swapStruct(struct objc_method_list_t &method_list) {
4185 sys::swapByteOrder(Value&: method_list.obsolete);
4186 sys::swapByteOrder(Value&: method_list.method_count);
4187}
4188
4189inline void swapStruct(struct objc_method_t &method) {
4190 sys::swapByteOrder(Value&: method.method_name);
4191 sys::swapByteOrder(Value&: method.method_types);
4192 sys::swapByteOrder(Value&: method.method_imp);
4193}
4194
4195inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
4196 sys::swapByteOrder(Value&: protocol_list.next);
4197 sys::swapByteOrder(Value&: protocol_list.count);
4198}
4199
4200inline void swapStruct(struct objc_protocol_t &protocol) {
4201 sys::swapByteOrder(Value&: protocol.isa);
4202 sys::swapByteOrder(Value&: protocol.protocol_name);
4203 sys::swapByteOrder(Value&: protocol.protocol_list);
4204 sys::swapByteOrder(Value&: protocol.instance_methods);
4205 sys::swapByteOrder(Value&: protocol.class_methods);
4206}
4207
4208inline void swapStruct(struct objc_method_description_list_t &mdl) {
4209 sys::swapByteOrder(Value&: mdl.count);
4210}
4211
4212inline void swapStruct(struct objc_method_description_t &md) {
4213 sys::swapByteOrder(Value&: md.name);
4214 sys::swapByteOrder(Value&: md.types);
4215}
4216
4217} // namespace
4218
4219static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
4220 struct DisassembleInfo *info);
4221
4222// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
4223// to an Objective-C class and returns the class name. It is also passed the
4224// address of the pointer, so when the pointer is zero as it can be in an .o
4225// file, that is used to look for an external relocation entry with a symbol
4226// name.
4227static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
4228 uint64_t ReferenceValue,
4229 struct DisassembleInfo *info) {
4230 const char *r;
4231 uint32_t offset, left;
4232 SectionRef S;
4233
4234 // The pointer_value can be 0 in an object file and have a relocation
4235 // entry for the class symbol at the ReferenceValue (the address of the
4236 // pointer).
4237 if (pointer_value == 0) {
4238 r = get_pointer_64(Address: ReferenceValue, offset, left, S, info);
4239 if (r == nullptr || left < sizeof(uint64_t))
4240 return nullptr;
4241 uint64_t n_value;
4242 const char *symbol_name = get_symbol_64(sect_offset: offset, S, info, n_value);
4243 if (symbol_name == nullptr)
4244 return nullptr;
4245 const char *class_name = strrchr(s: symbol_name, c: '$');
4246 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
4247 return class_name + 2;
4248 else
4249 return nullptr;
4250 }
4251
4252 // The case were the pointer_value is non-zero and points to a class defined
4253 // in this Mach-O file.
4254 r = get_pointer_64(Address: pointer_value, offset, left, S, info);
4255 if (r == nullptr || left < sizeof(struct class64_t))
4256 return nullptr;
4257 struct class64_t c;
4258 memcpy(dest: &c, src: r, n: sizeof(struct class64_t));
4259 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4260 swapStruct(c);
4261 if (c.data == 0)
4262 return nullptr;
4263 r = get_pointer_64(Address: c.data, offset, left, S, info);
4264 if (r == nullptr || left < sizeof(struct class_ro64_t))
4265 return nullptr;
4266 struct class_ro64_t cro;
4267 memcpy(dest: &cro, src: r, n: sizeof(struct class_ro64_t));
4268 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4269 swapStruct(cro);
4270 if (cro.name == 0)
4271 return nullptr;
4272 const char *name = get_pointer_64(Address: cro.name, offset, left, S, info);
4273 return name;
4274}
4275
4276// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
4277// pointer to a cfstring and returns its name or nullptr.
4278static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
4279 struct DisassembleInfo *info) {
4280 const char *r, *name;
4281 uint32_t offset, left;
4282 SectionRef S;
4283 struct cfstring64_t cfs;
4284 uint64_t cfs_characters;
4285
4286 r = get_pointer_64(Address: ReferenceValue, offset, left, S, info);
4287 if (r == nullptr || left < sizeof(struct cfstring64_t))
4288 return nullptr;
4289 memcpy(dest: &cfs, src: r, n: sizeof(struct cfstring64_t));
4290 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4291 swapStruct(cfs);
4292 if (cfs.characters == 0) {
4293 uint64_t n_value;
4294 const char *symbol_name = get_symbol_64(
4295 sect_offset: offset + offsetof(struct cfstring64_t, characters), S, info, n_value);
4296 if (symbol_name == nullptr)
4297 return nullptr;
4298 cfs_characters = n_value;
4299 } else
4300 cfs_characters = cfs.characters;
4301 name = get_pointer_64(Address: cfs_characters, offset, left, S, info);
4302
4303 return name;
4304}
4305
4306// get_objc2_64bit_selref() is used for disassembly and is passed a the address
4307// of a pointer to an Objective-C selector reference when the pointer value is
4308// zero as in a .o file and is likely to have a external relocation entry with
4309// who's symbol's n_value is the real pointer to the selector name. If that is
4310// the case the real pointer to the selector name is returned else 0 is
4311// returned
4312static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
4313 struct DisassembleInfo *info) {
4314 uint32_t offset, left;
4315 SectionRef S;
4316
4317 const char *r = get_pointer_64(Address: ReferenceValue, offset, left, S, info);
4318 if (r == nullptr || left < sizeof(uint64_t))
4319 return 0;
4320 uint64_t n_value;
4321 const char *symbol_name = get_symbol_64(sect_offset: offset, S, info, n_value);
4322 if (symbol_name == nullptr)
4323 return 0;
4324 return n_value;
4325}
4326
4327static const SectionRef get_section(MachOObjectFile *O, const char *segname,
4328 const char *sectname) {
4329 for (const SectionRef &Section : O->sections()) {
4330 StringRef SectName;
4331 Expected<StringRef> SecNameOrErr = Section.getName();
4332 if (SecNameOrErr)
4333 SectName = *SecNameOrErr;
4334 else
4335 consumeError(Err: SecNameOrErr.takeError());
4336
4337 DataRefImpl Ref = Section.getRawDataRefImpl();
4338 StringRef SegName = O->getSectionFinalSegmentName(Sec: Ref);
4339 if (SegName == segname && SectName == sectname)
4340 return Section;
4341 }
4342 return SectionRef();
4343}
4344
4345static void
4346walk_pointer_list_64(const char *listname, const SectionRef S,
4347 MachOObjectFile *O, struct DisassembleInfo *info,
4348 void (*func)(uint64_t, struct DisassembleInfo *info)) {
4349 if (S == SectionRef())
4350 return;
4351
4352 StringRef SectName;
4353 Expected<StringRef> SecNameOrErr = S.getName();
4354 if (SecNameOrErr)
4355 SectName = *SecNameOrErr;
4356 else
4357 consumeError(Err: SecNameOrErr.takeError());
4358
4359 DataRefImpl Ref = S.getRawDataRefImpl();
4360 StringRef SegName = O->getSectionFinalSegmentName(Sec: Ref);
4361 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4362
4363 StringRef BytesStr = unwrapOrError(EO: S.getContents(), Args: O->getFileName());
4364 const char *Contents = BytesStr.data();
4365
4366 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
4367 uint32_t left = S.getSize() - i;
4368 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
4369 uint64_t p = 0;
4370 memcpy(dest: &p, src: Contents + i, n: size);
4371 if (i + sizeof(uint64_t) > S.getSize())
4372 outs() << listname << " list pointer extends past end of (" << SegName
4373 << "," << SectName << ") section\n";
4374 outs() << format(Fmt: "%016" PRIx64, Vals: S.getAddress() + i) << " ";
4375
4376 if (O->isLittleEndian() != sys::IsLittleEndianHost)
4377 sys::swapByteOrder(Value&: p);
4378
4379 uint64_t n_value = 0;
4380 const char *name = get_symbol_64(sect_offset: i, S, info, n_value, ReferenceValue: p);
4381 if (name == nullptr)
4382 name = get_dyld_bind_info_symbolname(ReferenceValue: S.getAddress() + i, info);
4383
4384 if (n_value != 0) {
4385 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4386 if (p != 0)
4387 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: p);
4388 } else
4389 outs() << format(Fmt: "0x%" PRIx64, Vals: p);
4390 if (name != nullptr)
4391 outs() << " " << name;
4392 outs() << "\n";
4393
4394 p += n_value;
4395 if (func)
4396 func(p, info);
4397 }
4398}
4399
4400static void
4401walk_pointer_list_32(const char *listname, const SectionRef S,
4402 MachOObjectFile *O, struct DisassembleInfo *info,
4403 void (*func)(uint32_t, struct DisassembleInfo *info)) {
4404 if (S == SectionRef())
4405 return;
4406
4407 StringRef SectName = unwrapOrError(EO: S.getName(), Args: O->getFileName());
4408 DataRefImpl Ref = S.getRawDataRefImpl();
4409 StringRef SegName = O->getSectionFinalSegmentName(Sec: Ref);
4410 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4411
4412 StringRef BytesStr = unwrapOrError(EO: S.getContents(), Args: O->getFileName());
4413 const char *Contents = BytesStr.data();
4414
4415 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
4416 uint32_t left = S.getSize() - i;
4417 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
4418 uint32_t p = 0;
4419 memcpy(dest: &p, src: Contents + i, n: size);
4420 if (i + sizeof(uint32_t) > S.getSize())
4421 outs() << listname << " list pointer extends past end of (" << SegName
4422 << "," << SectName << ") section\n";
4423 uint32_t Address = S.getAddress() + i;
4424 outs() << format(Fmt: "%08" PRIx32, Vals: Address) << " ";
4425
4426 if (O->isLittleEndian() != sys::IsLittleEndianHost)
4427 sys::swapByteOrder(Value&: p);
4428 outs() << format(Fmt: "0x%" PRIx32, Vals: p);
4429
4430 const char *name = get_symbol_32(sect_offset: i, S, info, ReferenceValue: p);
4431 if (name != nullptr)
4432 outs() << " " << name;
4433 outs() << "\n";
4434
4435 if (func)
4436 func(p, info);
4437 }
4438}
4439
4440static void print_layout_map(const char *layout_map, uint32_t left) {
4441 if (layout_map == nullptr)
4442 return;
4443 outs() << " layout map: ";
4444 do {
4445 outs() << format(Fmt: "0x%02" PRIx32, Vals: (*layout_map) & 0xff) << " ";
4446 left--;
4447 layout_map++;
4448 } while (*layout_map != '\0' && left != 0);
4449 outs() << "\n";
4450}
4451
4452static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
4453 uint32_t offset, left;
4454 SectionRef S;
4455 const char *layout_map;
4456
4457 if (p == 0)
4458 return;
4459 layout_map = get_pointer_64(Address: p, offset, left, S, info);
4460 print_layout_map(layout_map, left);
4461}
4462
4463static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
4464 uint32_t offset, left;
4465 SectionRef S;
4466 const char *layout_map;
4467
4468 if (p == 0)
4469 return;
4470 layout_map = get_pointer_32(Address: p, offset, left, S, info);
4471 print_layout_map(layout_map, left);
4472}
4473
4474static void print_relative_method_list(uint32_t structSizeAndFlags,
4475 uint32_t structCount, uint64_t p,
4476 struct DisassembleInfo *info,
4477 const char *indent,
4478 uint32_t pointerBits) {
4479 struct method_relative_t m;
4480 const char *r, *name;
4481 uint32_t offset, xoffset, left, i;
4482 SectionRef S, xS;
4483
4484 assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&
4485 "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");
4486
4487 outs() << indent << "\t\t entsize "
4488 << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";
4489 outs() << indent << "\t\t count " << structCount << "\n";
4490
4491 for (i = 0; i < structCount; i++) {
4492 r = get_pointer_64(Address: p, offset, left, S, info);
4493 memset(s: &m, c: '\0', n: sizeof(struct method_relative_t));
4494 if (left < sizeof(struct method_relative_t)) {
4495 memcpy(dest: &m, src: r, n: left);
4496 outs() << indent << " (method_t extends past the end of the section)\n";
4497 } else
4498 memcpy(dest: &m, src: r, n: sizeof(struct method_relative_t));
4499 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4500 swapStruct(m);
4501
4502 outs() << indent << "\t\t name " << format(Fmt: "0x%" PRIx32, Vals: m.name);
4503 uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);
4504 uint64_t absNameRefVA = relNameRefVA + m.name;
4505 outs() << " (" << format(Fmt: "0x%" PRIx32, Vals: absNameRefVA) << ")";
4506
4507 // since this is a relative list, absNameRefVA is the address of the
4508 // __objc_selrefs entry, so a pointer, not the actual name
4509 const char *nameRefPtr =
4510 get_pointer_64(Address: absNameRefVA, offset&: xoffset, left, S&: xS, info);
4511 if (nameRefPtr) {
4512 uint32_t pointerSize = pointerBits / CHAR_BIT;
4513 if (left < pointerSize)
4514 outs() << indent << " (nameRefPtr extends past the end of the section)";
4515 else {
4516 if (pointerSize == 64) {
4517 uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);
4518 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4519 sys::swapByteOrder(Value&: nameOff_64);
4520 name = get_pointer_64(Address: nameOff_64, offset&: xoffset, left, S&: xS, info);
4521 } else {
4522 uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);
4523 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4524 sys::swapByteOrder(Value&: nameOff_32);
4525 name = get_pointer_32(Address: nameOff_32, offset&: xoffset, left, S&: xS, info);
4526 }
4527 if (name != nullptr)
4528 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4529 }
4530 }
4531 outs() << "\n";
4532
4533 outs() << indent << "\t\t types " << format(Fmt: "0x%" PRIx32, Vals: m.types);
4534 uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);
4535 uint64_t absTypesVA = relTypesVA + m.types;
4536 outs() << " (" << format(Fmt: "0x%" PRIx32, Vals: absTypesVA) << ")";
4537 name = get_pointer_32(Address: absTypesVA, offset&: xoffset, left, S&: xS, info);
4538 if (name != nullptr)
4539 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4540 outs() << "\n";
4541
4542 outs() << indent << "\t\t imp " << format(Fmt: "0x%" PRIx32, Vals: m.imp);
4543 uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);
4544 uint64_t absImpVA = relImpVA + m.imp;
4545 outs() << " (" << format(Fmt: "0x%" PRIx32, Vals: absImpVA) << ")";
4546 name = GuessSymbolName(value: absImpVA, AddrMap: info->AddrMap);
4547 if (name != nullptr)
4548 outs() << " " << name;
4549 outs() << "\n";
4550
4551 p += sizeof(struct method_relative_t);
4552 offset += sizeof(struct method_relative_t);
4553 }
4554}
4555
4556static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
4557 const char *indent) {
4558 struct method_list64_t ml;
4559 struct method64_t m;
4560 const char *r;
4561 uint32_t offset, xoffset, left, i;
4562 SectionRef S, xS;
4563 const char *name, *sym_name;
4564 uint64_t n_value;
4565
4566 r = get_pointer_64(Address: p, offset, left, S, info);
4567 if (r == nullptr)
4568 return;
4569 memset(s: &ml, c: '\0', n: sizeof(struct method_list64_t));
4570 if (left < sizeof(struct method_list64_t)) {
4571 memcpy(dest: &ml, src: r, n: left);
4572 outs() << " (method_list_t entends past the end of the section)\n";
4573 } else
4574 memcpy(dest: &ml, src: r, n: sizeof(struct method_list64_t));
4575 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4576 swapStruct(ml);
4577 p += sizeof(struct method_list64_t);
4578
4579 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4580 print_relative_method_list(structSizeAndFlags: ml.entsize, structCount: ml.count, p, info, indent,
4581 /*pointerBits=*/64);
4582 return;
4583 }
4584
4585 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4586 outs() << indent << "\t\t count " << ml.count << "\n";
4587
4588 offset += sizeof(struct method_list64_t);
4589 for (i = 0; i < ml.count; i++) {
4590 r = get_pointer_64(Address: p, offset, left, S, info);
4591 if (r == nullptr)
4592 return;
4593 memset(s: &m, c: '\0', n: sizeof(struct method64_t));
4594 if (left < sizeof(struct method64_t)) {
4595 memcpy(dest: &m, src: r, n: left);
4596 outs() << indent << " (method_t extends past the end of the section)\n";
4597 } else
4598 memcpy(dest: &m, src: r, n: sizeof(struct method64_t));
4599 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4600 swapStruct(m);
4601
4602 outs() << indent << "\t\t name ";
4603 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct method64_t, name), S,
4604 info, n_value, ReferenceValue: m.name);
4605 if (n_value != 0) {
4606 if (info->verbose && sym_name != nullptr)
4607 outs() << sym_name;
4608 else
4609 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4610 if (m.name != 0)
4611 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: m.name);
4612 } else
4613 outs() << format(Fmt: "0x%" PRIx64, Vals: m.name);
4614 name = get_pointer_64(Address: m.name + n_value, offset&: xoffset, left, S&: xS, info);
4615 if (name != nullptr)
4616 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4617 outs() << "\n";
4618
4619 outs() << indent << "\t\t types ";
4620 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct method64_t, types), S,
4621 info, n_value, ReferenceValue: m.types);
4622 if (n_value != 0) {
4623 if (info->verbose && sym_name != nullptr)
4624 outs() << sym_name;
4625 else
4626 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4627 if (m.types != 0)
4628 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: m.types);
4629 } else
4630 outs() << format(Fmt: "0x%" PRIx64, Vals: m.types);
4631 name = get_pointer_64(Address: m.types + n_value, offset&: xoffset, left, S&: xS, info);
4632 if (name != nullptr)
4633 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4634 outs() << "\n";
4635
4636 outs() << indent << "\t\t imp ";
4637 name = get_symbol_64(sect_offset: offset + offsetof(struct method64_t, imp), S, info,
4638 n_value, ReferenceValue: m.imp);
4639 if (info->verbose && name == nullptr) {
4640 if (n_value != 0) {
4641 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value) << " ";
4642 if (m.imp != 0)
4643 outs() << "+ " << format(Fmt: "0x%" PRIx64, Vals: m.imp) << " ";
4644 } else
4645 outs() << format(Fmt: "0x%" PRIx64, Vals: m.imp) << " ";
4646 }
4647 if (name != nullptr)
4648 outs() << name;
4649 outs() << "\n";
4650
4651 p += sizeof(struct method64_t);
4652 offset += sizeof(struct method64_t);
4653 }
4654}
4655
4656static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
4657 const char *indent) {
4658 struct method_list32_t ml;
4659 struct method32_t m;
4660 const char *r, *name;
4661 uint32_t offset, xoffset, left, i;
4662 SectionRef S, xS;
4663
4664 r = get_pointer_32(Address: p, offset, left, S, info);
4665 if (r == nullptr)
4666 return;
4667 memset(s: &ml, c: '\0', n: sizeof(struct method_list32_t));
4668 if (left < sizeof(struct method_list32_t)) {
4669 memcpy(dest: &ml, src: r, n: left);
4670 outs() << " (method_list_t entends past the end of the section)\n";
4671 } else
4672 memcpy(dest: &ml, src: r, n: sizeof(struct method_list32_t));
4673 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4674 swapStruct(ml);
4675 p += sizeof(struct method_list32_t);
4676
4677 if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4678 print_relative_method_list(structSizeAndFlags: ml.entsize, structCount: ml.count, p, info, indent,
4679 /*pointerBits=*/32);
4680 return;
4681 }
4682
4683 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4684 outs() << indent << "\t\t count " << ml.count << "\n";
4685
4686 offset += sizeof(struct method_list32_t);
4687 for (i = 0; i < ml.count; i++) {
4688 r = get_pointer_32(Address: p, offset, left, S, info);
4689 if (r == nullptr)
4690 return;
4691 memset(s: &m, c: '\0', n: sizeof(struct method32_t));
4692 if (left < sizeof(struct method32_t)) {
4693 memcpy(dest: &ml, src: r, n: left);
4694 outs() << indent << " (method_t entends past the end of the section)\n";
4695 } else
4696 memcpy(dest: &m, src: r, n: sizeof(struct method32_t));
4697 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4698 swapStruct(m);
4699
4700 outs() << indent << "\t\t name " << format(Fmt: "0x%" PRIx32, Vals: m.name);
4701 name = get_pointer_32(Address: m.name, offset&: xoffset, left, S&: xS, info);
4702 if (name != nullptr)
4703 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4704 outs() << "\n";
4705
4706 outs() << indent << "\t\t types " << format(Fmt: "0x%" PRIx32, Vals: m.types);
4707 name = get_pointer_32(Address: m.types, offset&: xoffset, left, S&: xS, info);
4708 if (name != nullptr)
4709 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4710 outs() << "\n";
4711
4712 outs() << indent << "\t\t imp " << format(Fmt: "0x%" PRIx32, Vals: m.imp);
4713 name = get_symbol_32(sect_offset: offset + offsetof(struct method32_t, imp), S, info,
4714 ReferenceValue: m.imp);
4715 if (name != nullptr)
4716 outs() << " " << name;
4717 outs() << "\n";
4718
4719 p += sizeof(struct method32_t);
4720 offset += sizeof(struct method32_t);
4721 }
4722}
4723
4724static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4725 uint32_t offset, left, xleft;
4726 SectionRef S;
4727 struct objc_method_list_t method_list;
4728 struct objc_method_t method;
4729 const char *r, *methods, *name, *SymbolName;
4730 int32_t i;
4731
4732 r = get_pointer_32(Address: p, offset, left, S, info, objc_only: true);
4733 if (r == nullptr)
4734 return true;
4735
4736 outs() << "\n";
4737 if (left > sizeof(struct objc_method_list_t)) {
4738 memcpy(dest: &method_list, src: r, n: sizeof(struct objc_method_list_t));
4739 } else {
4740 outs() << "\t\t objc_method_list extends past end of the section\n";
4741 memset(s: &method_list, c: '\0', n: sizeof(struct objc_method_list_t));
4742 memcpy(dest: &method_list, src: r, n: left);
4743 }
4744 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4745 swapStruct(method_list);
4746
4747 outs() << "\t\t obsolete "
4748 << format(Fmt: "0x%08" PRIx32, Vals: method_list.obsolete) << "\n";
4749 outs() << "\t\t method_count " << method_list.method_count << "\n";
4750
4751 methods = r + sizeof(struct objc_method_list_t);
4752 for (i = 0; i < method_list.method_count; i++) {
4753 if ((i + 1) * sizeof(struct objc_method_t) > left) {
4754 outs() << "\t\t remaining method's extend past the of the section\n";
4755 break;
4756 }
4757 memcpy(dest: &method, src: methods + i * sizeof(struct objc_method_t),
4758 n: sizeof(struct objc_method_t));
4759 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4760 swapStruct(method);
4761
4762 outs() << "\t\t method_name "
4763 << format(Fmt: "0x%08" PRIx32, Vals: method.method_name);
4764 if (info->verbose) {
4765 name = get_pointer_32(Address: method.method_name, offset, left&: xleft, S, info, objc_only: true);
4766 if (name != nullptr)
4767 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
4768 else
4769 outs() << " (not in an __OBJC section)";
4770 }
4771 outs() << "\n";
4772
4773 outs() << "\t\t method_types "
4774 << format(Fmt: "0x%08" PRIx32, Vals: method.method_types);
4775 if (info->verbose) {
4776 name = get_pointer_32(Address: method.method_types, offset, left&: xleft, S, info, objc_only: true);
4777 if (name != nullptr)
4778 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
4779 else
4780 outs() << " (not in an __OBJC section)";
4781 }
4782 outs() << "\n";
4783
4784 outs() << "\t\t method_imp "
4785 << format(Fmt: "0x%08" PRIx32, Vals: method.method_imp) << " ";
4786 if (info->verbose) {
4787 SymbolName = GuessSymbolName(value: method.method_imp, AddrMap: info->AddrMap);
4788 if (SymbolName != nullptr)
4789 outs() << SymbolName;
4790 }
4791 outs() << "\n";
4792 }
4793 return false;
4794}
4795
4796static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4797 struct protocol_list64_t pl;
4798 uint64_t q, n_value;
4799 struct protocol64_t pc;
4800 const char *r;
4801 uint32_t offset, xoffset, left, i;
4802 SectionRef S, xS;
4803 const char *name, *sym_name;
4804
4805 r = get_pointer_64(Address: p, offset, left, S, info);
4806 if (r == nullptr)
4807 return;
4808 memset(s: &pl, c: '\0', n: sizeof(struct protocol_list64_t));
4809 if (left < sizeof(struct protocol_list64_t)) {
4810 memcpy(dest: &pl, src: r, n: left);
4811 outs() << " (protocol_list_t entends past the end of the section)\n";
4812 } else
4813 memcpy(dest: &pl, src: r, n: sizeof(struct protocol_list64_t));
4814 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4815 swapStruct(pl);
4816 outs() << " count " << pl.count << "\n";
4817
4818 p += sizeof(struct protocol_list64_t);
4819 offset += sizeof(struct protocol_list64_t);
4820 for (i = 0; i < pl.count; i++) {
4821 r = get_pointer_64(Address: p, offset, left, S, info);
4822 if (r == nullptr)
4823 return;
4824 q = 0;
4825 if (left < sizeof(uint64_t)) {
4826 memcpy(dest: &q, src: r, n: left);
4827 outs() << " (protocol_t * entends past the end of the section)\n";
4828 } else
4829 memcpy(dest: &q, src: r, n: sizeof(uint64_t));
4830 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4831 sys::swapByteOrder(Value&: q);
4832
4833 outs() << "\t\t list[" << i << "] ";
4834 sym_name = get_symbol_64(sect_offset: offset, S, info, n_value, ReferenceValue: q);
4835 if (n_value != 0) {
4836 if (info->verbose && sym_name != nullptr)
4837 outs() << sym_name;
4838 else
4839 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4840 if (q != 0)
4841 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: q);
4842 } else
4843 outs() << format(Fmt: "0x%" PRIx64, Vals: q);
4844 outs() << " (struct protocol_t *)\n";
4845
4846 r = get_pointer_64(Address: q + n_value, offset, left, S, info);
4847 if (r == nullptr)
4848 return;
4849 memset(s: &pc, c: '\0', n: sizeof(struct protocol64_t));
4850 if (left < sizeof(struct protocol64_t)) {
4851 memcpy(dest: &pc, src: r, n: left);
4852 outs() << " (protocol_t entends past the end of the section)\n";
4853 } else
4854 memcpy(dest: &pc, src: r, n: sizeof(struct protocol64_t));
4855 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4856 swapStruct(p&: pc);
4857
4858 outs() << "\t\t\t isa " << format(Fmt: "0x%" PRIx64, Vals: pc.isa) << "\n";
4859
4860 outs() << "\t\t\t name ";
4861 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct protocol64_t, name), S,
4862 info, n_value, ReferenceValue: pc.name);
4863 if (n_value != 0) {
4864 if (info->verbose && sym_name != nullptr)
4865 outs() << sym_name;
4866 else
4867 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4868 if (pc.name != 0)
4869 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: pc.name);
4870 } else
4871 outs() << format(Fmt: "0x%" PRIx64, Vals: pc.name);
4872 name = get_pointer_64(Address: pc.name + n_value, offset&: xoffset, left, S&: xS, info);
4873 if (name != nullptr)
4874 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4875 outs() << "\n";
4876
4877 outs() << "\t\t\tprotocols " << format(Fmt: "0x%" PRIx64, Vals: pc.protocols) << "\n";
4878
4879 outs() << "\t\t instanceMethods ";
4880 sym_name =
4881 get_symbol_64(sect_offset: offset + offsetof(struct protocol64_t, instanceMethods),
4882 S, info, n_value, ReferenceValue: pc.instanceMethods);
4883 if (n_value != 0) {
4884 if (info->verbose && sym_name != nullptr)
4885 outs() << sym_name;
4886 else
4887 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4888 if (pc.instanceMethods != 0)
4889 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: pc.instanceMethods);
4890 } else
4891 outs() << format(Fmt: "0x%" PRIx64, Vals: pc.instanceMethods);
4892 outs() << " (struct method_list_t *)\n";
4893 if (pc.instanceMethods + n_value != 0)
4894 print_method_list64_t(p: pc.instanceMethods + n_value, info, indent: "\t");
4895
4896 outs() << "\t\t classMethods ";
4897 sym_name =
4898 get_symbol_64(sect_offset: offset + offsetof(struct protocol64_t, classMethods), S,
4899 info, n_value, ReferenceValue: pc.classMethods);
4900 if (n_value != 0) {
4901 if (info->verbose && sym_name != nullptr)
4902 outs() << sym_name;
4903 else
4904 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
4905 if (pc.classMethods != 0)
4906 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: pc.classMethods);
4907 } else
4908 outs() << format(Fmt: "0x%" PRIx64, Vals: pc.classMethods);
4909 outs() << " (struct method_list_t *)\n";
4910 if (pc.classMethods + n_value != 0)
4911 print_method_list64_t(p: pc.classMethods + n_value, info, indent: "\t");
4912
4913 outs() << "\t optionalInstanceMethods "
4914 << format(Fmt: "0x%" PRIx64, Vals: pc.optionalInstanceMethods) << "\n";
4915 outs() << "\t optionalClassMethods "
4916 << format(Fmt: "0x%" PRIx64, Vals: pc.optionalClassMethods) << "\n";
4917 outs() << "\t instanceProperties "
4918 << format(Fmt: "0x%" PRIx64, Vals: pc.instanceProperties) << "\n";
4919
4920 p += sizeof(uint64_t);
4921 offset += sizeof(uint64_t);
4922 }
4923}
4924
4925static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4926 struct protocol_list32_t pl;
4927 uint32_t q;
4928 struct protocol32_t pc;
4929 const char *r;
4930 uint32_t offset, xoffset, left, i;
4931 SectionRef S, xS;
4932 const char *name;
4933
4934 r = get_pointer_32(Address: p, offset, left, S, info);
4935 if (r == nullptr)
4936 return;
4937 memset(s: &pl, c: '\0', n: sizeof(struct protocol_list32_t));
4938 if (left < sizeof(struct protocol_list32_t)) {
4939 memcpy(dest: &pl, src: r, n: left);
4940 outs() << " (protocol_list_t entends past the end of the section)\n";
4941 } else
4942 memcpy(dest: &pl, src: r, n: sizeof(struct protocol_list32_t));
4943 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4944 swapStruct(pl);
4945 outs() << " count " << pl.count << "\n";
4946
4947 p += sizeof(struct protocol_list32_t);
4948 offset += sizeof(struct protocol_list32_t);
4949 for (i = 0; i < pl.count; i++) {
4950 r = get_pointer_32(Address: p, offset, left, S, info);
4951 if (r == nullptr)
4952 return;
4953 q = 0;
4954 if (left < sizeof(uint32_t)) {
4955 memcpy(dest: &q, src: r, n: left);
4956 outs() << " (protocol_t * entends past the end of the section)\n";
4957 } else
4958 memcpy(dest: &q, src: r, n: sizeof(uint32_t));
4959 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4960 sys::swapByteOrder(Value&: q);
4961 outs() << "\t\t list[" << i << "] " << format(Fmt: "0x%" PRIx32, Vals: q)
4962 << " (struct protocol_t *)\n";
4963 r = get_pointer_32(Address: q, offset, left, S, info);
4964 if (r == nullptr)
4965 return;
4966 memset(s: &pc, c: '\0', n: sizeof(struct protocol32_t));
4967 if (left < sizeof(struct protocol32_t)) {
4968 memcpy(dest: &pc, src: r, n: left);
4969 outs() << " (protocol_t entends past the end of the section)\n";
4970 } else
4971 memcpy(dest: &pc, src: r, n: sizeof(struct protocol32_t));
4972 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4973 swapStruct(p&: pc);
4974 outs() << "\t\t\t isa " << format(Fmt: "0x%" PRIx32, Vals: pc.isa) << "\n";
4975 outs() << "\t\t\t name " << format(Fmt: "0x%" PRIx32, Vals: pc.name);
4976 name = get_pointer_32(Address: pc.name, offset&: xoffset, left, S&: xS, info);
4977 if (name != nullptr)
4978 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
4979 outs() << "\n";
4980 outs() << "\t\t\tprotocols " << format(Fmt: "0x%" PRIx32, Vals: pc.protocols) << "\n";
4981 outs() << "\t\t instanceMethods "
4982 << format(Fmt: "0x%" PRIx32, Vals: pc.instanceMethods)
4983 << " (struct method_list_t *)\n";
4984 if (pc.instanceMethods != 0)
4985 print_method_list32_t(p: pc.instanceMethods, info, indent: "\t");
4986 outs() << "\t\t classMethods " << format(Fmt: "0x%" PRIx32, Vals: pc.classMethods)
4987 << " (struct method_list_t *)\n";
4988 if (pc.classMethods != 0)
4989 print_method_list32_t(p: pc.classMethods, info, indent: "\t");
4990 outs() << "\t optionalInstanceMethods "
4991 << format(Fmt: "0x%" PRIx32, Vals: pc.optionalInstanceMethods) << "\n";
4992 outs() << "\t optionalClassMethods "
4993 << format(Fmt: "0x%" PRIx32, Vals: pc.optionalClassMethods) << "\n";
4994 outs() << "\t instanceProperties "
4995 << format(Fmt: "0x%" PRIx32, Vals: pc.instanceProperties) << "\n";
4996 p += sizeof(uint32_t);
4997 offset += sizeof(uint32_t);
4998 }
4999}
5000
5001static void print_indent(uint32_t indent) {
5002 for (uint32_t i = 0; i < indent;) {
5003 if (indent - i >= 8) {
5004 outs() << "\t";
5005 i += 8;
5006 } else {
5007 for (uint32_t j = i; j < indent; j++)
5008 outs() << " ";
5009 return;
5010 }
5011 }
5012}
5013
5014static bool print_method_description_list(uint32_t p, uint32_t indent,
5015 struct DisassembleInfo *info) {
5016 uint32_t offset, left, xleft;
5017 SectionRef S;
5018 struct objc_method_description_list_t mdl;
5019 struct objc_method_description_t md;
5020 const char *r, *list, *name;
5021 int32_t i;
5022
5023 r = get_pointer_32(Address: p, offset, left, S, info, objc_only: true);
5024 if (r == nullptr)
5025 return true;
5026
5027 outs() << "\n";
5028 if (left > sizeof(struct objc_method_description_list_t)) {
5029 memcpy(dest: &mdl, src: r, n: sizeof(struct objc_method_description_list_t));
5030 } else {
5031 print_indent(indent);
5032 outs() << " objc_method_description_list extends past end of the section\n";
5033 memset(s: &mdl, c: '\0', n: sizeof(struct objc_method_description_list_t));
5034 memcpy(dest: &mdl, src: r, n: left);
5035 }
5036 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5037 swapStruct(mdl);
5038
5039 print_indent(indent);
5040 outs() << " count " << mdl.count << "\n";
5041
5042 list = r + sizeof(struct objc_method_description_list_t);
5043 for (i = 0; i < mdl.count; i++) {
5044 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
5045 print_indent(indent);
5046 outs() << " remaining list entries extend past the of the section\n";
5047 break;
5048 }
5049 print_indent(indent);
5050 outs() << " list[" << i << "]\n";
5051 memcpy(dest: &md, src: list + i * sizeof(struct objc_method_description_t),
5052 n: sizeof(struct objc_method_description_t));
5053 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5054 swapStruct(md);
5055
5056 print_indent(indent);
5057 outs() << " name " << format(Fmt: "0x%08" PRIx32, Vals: md.name);
5058 if (info->verbose) {
5059 name = get_pointer_32(Address: md.name, offset, left&: xleft, S, info, objc_only: true);
5060 if (name != nullptr)
5061 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
5062 else
5063 outs() << " (not in an __OBJC section)";
5064 }
5065 outs() << "\n";
5066
5067 print_indent(indent);
5068 outs() << " types " << format(Fmt: "0x%08" PRIx32, Vals: md.types);
5069 if (info->verbose) {
5070 name = get_pointer_32(Address: md.types, offset, left&: xleft, S, info, objc_only: true);
5071 if (name != nullptr)
5072 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
5073 else
5074 outs() << " (not in an __OBJC section)";
5075 }
5076 outs() << "\n";
5077 }
5078 return false;
5079}
5080
5081static bool print_protocol_list(uint32_t p, uint32_t indent,
5082 struct DisassembleInfo *info);
5083
5084static bool print_protocol(uint32_t p, uint32_t indent,
5085 struct DisassembleInfo *info) {
5086 uint32_t offset, left;
5087 SectionRef S;
5088 struct objc_protocol_t protocol;
5089 const char *r, *name;
5090
5091 r = get_pointer_32(Address: p, offset, left, S, info, objc_only: true);
5092 if (r == nullptr)
5093 return true;
5094
5095 outs() << "\n";
5096 if (left >= sizeof(struct objc_protocol_t)) {
5097 memcpy(dest: &protocol, src: r, n: sizeof(struct objc_protocol_t));
5098 } else {
5099 print_indent(indent);
5100 outs() << " Protocol extends past end of the section\n";
5101 memset(s: &protocol, c: '\0', n: sizeof(struct objc_protocol_t));
5102 memcpy(dest: &protocol, src: r, n: left);
5103 }
5104 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5105 swapStruct(protocol);
5106
5107 print_indent(indent);
5108 outs() << " isa " << format(Fmt: "0x%08" PRIx32, Vals: protocol.isa)
5109 << "\n";
5110
5111 print_indent(indent);
5112 outs() << " protocol_name "
5113 << format(Fmt: "0x%08" PRIx32, Vals: protocol.protocol_name);
5114 if (info->verbose) {
5115 name = get_pointer_32(Address: protocol.protocol_name, offset, left, S, info, objc_only: true);
5116 if (name != nullptr)
5117 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5118 else
5119 outs() << " (not in an __OBJC section)";
5120 }
5121 outs() << "\n";
5122
5123 print_indent(indent);
5124 outs() << " protocol_list "
5125 << format(Fmt: "0x%08" PRIx32, Vals: protocol.protocol_list);
5126 if (print_protocol_list(p: protocol.protocol_list, indent: indent + 4, info))
5127 outs() << " (not in an __OBJC section)\n";
5128
5129 print_indent(indent);
5130 outs() << " instance_methods "
5131 << format(Fmt: "0x%08" PRIx32, Vals: protocol.instance_methods);
5132 if (print_method_description_list(p: protocol.instance_methods, indent, info))
5133 outs() << " (not in an __OBJC section)\n";
5134
5135 print_indent(indent);
5136 outs() << " class_methods "
5137 << format(Fmt: "0x%08" PRIx32, Vals: protocol.class_methods);
5138 if (print_method_description_list(p: protocol.class_methods, indent, info))
5139 outs() << " (not in an __OBJC section)\n";
5140
5141 return false;
5142}
5143
5144static bool print_protocol_list(uint32_t p, uint32_t indent,
5145 struct DisassembleInfo *info) {
5146 uint32_t offset, left, l;
5147 SectionRef S;
5148 struct objc_protocol_list_t protocol_list;
5149 const char *r, *list;
5150 int32_t i;
5151
5152 r = get_pointer_32(Address: p, offset, left, S, info, objc_only: true);
5153 if (r == nullptr)
5154 return true;
5155
5156 outs() << "\n";
5157 if (left > sizeof(struct objc_protocol_list_t)) {
5158 memcpy(dest: &protocol_list, src: r, n: sizeof(struct objc_protocol_list_t));
5159 } else {
5160 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
5161 memset(s: &protocol_list, c: '\0', n: sizeof(struct objc_protocol_list_t));
5162 memcpy(dest: &protocol_list, src: r, n: left);
5163 }
5164 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5165 swapStruct(protocol_list);
5166
5167 print_indent(indent);
5168 outs() << " next " << format(Fmt: "0x%08" PRIx32, Vals: protocol_list.next)
5169 << "\n";
5170 print_indent(indent);
5171 outs() << " count " << protocol_list.count << "\n";
5172
5173 list = r + sizeof(struct objc_protocol_list_t);
5174 for (i = 0; i < protocol_list.count; i++) {
5175 if ((i + 1) * sizeof(uint32_t) > left) {
5176 outs() << "\t\t remaining list entries extend past the of the section\n";
5177 break;
5178 }
5179 memcpy(dest: &l, src: list + i * sizeof(uint32_t), n: sizeof(uint32_t));
5180 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5181 sys::swapByteOrder(Value&: l);
5182
5183 print_indent(indent);
5184 outs() << " list[" << i << "] " << format(Fmt: "0x%08" PRIx32, Vals: l);
5185 if (print_protocol(p: l, indent, info))
5186 outs() << "(not in an __OBJC section)\n";
5187 }
5188 return false;
5189}
5190
5191static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
5192 struct ivar_list64_t il;
5193 struct ivar64_t i;
5194 const char *r;
5195 uint32_t offset, xoffset, left, j;
5196 SectionRef S, xS;
5197 const char *name, *sym_name, *ivar_offset_p;
5198 uint64_t ivar_offset, n_value;
5199
5200 r = get_pointer_64(Address: p, offset, left, S, info);
5201 if (r == nullptr)
5202 return;
5203 memset(s: &il, c: '\0', n: sizeof(struct ivar_list64_t));
5204 if (left < sizeof(struct ivar_list64_t)) {
5205 memcpy(dest: &il, src: r, n: left);
5206 outs() << " (ivar_list_t entends past the end of the section)\n";
5207 } else
5208 memcpy(dest: &il, src: r, n: sizeof(struct ivar_list64_t));
5209 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5210 swapStruct(il);
5211 outs() << " entsize " << il.entsize << "\n";
5212 outs() << " count " << il.count << "\n";
5213
5214 p += sizeof(struct ivar_list64_t);
5215 offset += sizeof(struct ivar_list64_t);
5216 for (j = 0; j < il.count; j++) {
5217 r = get_pointer_64(Address: p, offset, left, S, info);
5218 if (r == nullptr)
5219 return;
5220 memset(s: &i, c: '\0', n: sizeof(struct ivar64_t));
5221 if (left < sizeof(struct ivar64_t)) {
5222 memcpy(dest: &i, src: r, n: left);
5223 outs() << " (ivar_t entends past the end of the section)\n";
5224 } else
5225 memcpy(dest: &i, src: r, n: sizeof(struct ivar64_t));
5226 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5227 swapStruct(i);
5228
5229 outs() << "\t\t\t offset ";
5230 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct ivar64_t, offset), S,
5231 info, n_value, ReferenceValue: i.offset);
5232 if (n_value != 0) {
5233 if (info->verbose && sym_name != nullptr)
5234 outs() << sym_name;
5235 else
5236 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5237 if (i.offset != 0)
5238 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: i.offset);
5239 } else
5240 outs() << format(Fmt: "0x%" PRIx64, Vals: i.offset);
5241 ivar_offset_p = get_pointer_64(Address: i.offset + n_value, offset&: xoffset, left, S&: xS, info);
5242 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5243 memcpy(dest: &ivar_offset, src: ivar_offset_p, n: sizeof(ivar_offset));
5244 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5245 sys::swapByteOrder(Value&: ivar_offset);
5246 outs() << " " << ivar_offset << "\n";
5247 } else
5248 outs() << "\n";
5249
5250 outs() << "\t\t\t name ";
5251 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct ivar64_t, name), S, info,
5252 n_value, ReferenceValue: i.name);
5253 if (n_value != 0) {
5254 if (info->verbose && sym_name != nullptr)
5255 outs() << sym_name;
5256 else
5257 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5258 if (i.name != 0)
5259 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: i.name);
5260 } else
5261 outs() << format(Fmt: "0x%" PRIx64, Vals: i.name);
5262 name = get_pointer_64(Address: i.name + n_value, offset&: xoffset, left, S&: xS, info);
5263 if (name != nullptr)
5264 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5265 outs() << "\n";
5266
5267 outs() << "\t\t\t type ";
5268 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct ivar64_t, type), S, info,
5269 n_value, ReferenceValue: i.name);
5270 name = get_pointer_64(Address: i.type + n_value, offset&: xoffset, left, S&: xS, info);
5271 if (n_value != 0) {
5272 if (info->verbose && sym_name != nullptr)
5273 outs() << sym_name;
5274 else
5275 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5276 if (i.type != 0)
5277 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: i.type);
5278 } else
5279 outs() << format(Fmt: "0x%" PRIx64, Vals: i.type);
5280 if (name != nullptr)
5281 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5282 outs() << "\n";
5283
5284 outs() << "\t\t\talignment " << i.alignment << "\n";
5285 outs() << "\t\t\t size " << i.size << "\n";
5286
5287 p += sizeof(struct ivar64_t);
5288 offset += sizeof(struct ivar64_t);
5289 }
5290}
5291
5292static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
5293 struct ivar_list32_t il;
5294 struct ivar32_t i;
5295 const char *r;
5296 uint32_t offset, xoffset, left, j;
5297 SectionRef S, xS;
5298 const char *name, *ivar_offset_p;
5299 uint32_t ivar_offset;
5300
5301 r = get_pointer_32(Address: p, offset, left, S, info);
5302 if (r == nullptr)
5303 return;
5304 memset(s: &il, c: '\0', n: sizeof(struct ivar_list32_t));
5305 if (left < sizeof(struct ivar_list32_t)) {
5306 memcpy(dest: &il, src: r, n: left);
5307 outs() << " (ivar_list_t entends past the end of the section)\n";
5308 } else
5309 memcpy(dest: &il, src: r, n: sizeof(struct ivar_list32_t));
5310 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5311 swapStruct(il);
5312 outs() << " entsize " << il.entsize << "\n";
5313 outs() << " count " << il.count << "\n";
5314
5315 p += sizeof(struct ivar_list32_t);
5316 offset += sizeof(struct ivar_list32_t);
5317 for (j = 0; j < il.count; j++) {
5318 r = get_pointer_32(Address: p, offset, left, S, info);
5319 if (r == nullptr)
5320 return;
5321 memset(s: &i, c: '\0', n: sizeof(struct ivar32_t));
5322 if (left < sizeof(struct ivar32_t)) {
5323 memcpy(dest: &i, src: r, n: left);
5324 outs() << " (ivar_t entends past the end of the section)\n";
5325 } else
5326 memcpy(dest: &i, src: r, n: sizeof(struct ivar32_t));
5327 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5328 swapStruct(i);
5329
5330 outs() << "\t\t\t offset " << format(Fmt: "0x%" PRIx32, Vals: i.offset);
5331 ivar_offset_p = get_pointer_32(Address: i.offset, offset&: xoffset, left, S&: xS, info);
5332 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5333 memcpy(dest: &ivar_offset, src: ivar_offset_p, n: sizeof(ivar_offset));
5334 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5335 sys::swapByteOrder(Value&: ivar_offset);
5336 outs() << " " << ivar_offset << "\n";
5337 } else
5338 outs() << "\n";
5339
5340 outs() << "\t\t\t name " << format(Fmt: "0x%" PRIx32, Vals: i.name);
5341 name = get_pointer_32(Address: i.name, offset&: xoffset, left, S&: xS, info);
5342 if (name != nullptr)
5343 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5344 outs() << "\n";
5345
5346 outs() << "\t\t\t type " << format(Fmt: "0x%" PRIx32, Vals: i.type);
5347 name = get_pointer_32(Address: i.type, offset&: xoffset, left, S&: xS, info);
5348 if (name != nullptr)
5349 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5350 outs() << "\n";
5351
5352 outs() << "\t\t\talignment " << i.alignment << "\n";
5353 outs() << "\t\t\t size " << i.size << "\n";
5354
5355 p += sizeof(struct ivar32_t);
5356 offset += sizeof(struct ivar32_t);
5357 }
5358}
5359
5360static void print_objc_property_list64(uint64_t p,
5361 struct DisassembleInfo *info) {
5362 struct objc_property_list64 opl;
5363 struct objc_property64 op;
5364 const char *r;
5365 uint32_t offset, xoffset, left, j;
5366 SectionRef S, xS;
5367 const char *name, *sym_name;
5368 uint64_t n_value;
5369
5370 r = get_pointer_64(Address: p, offset, left, S, info);
5371 if (r == nullptr)
5372 return;
5373 memset(s: &opl, c: '\0', n: sizeof(struct objc_property_list64));
5374 if (left < sizeof(struct objc_property_list64)) {
5375 memcpy(dest: &opl, src: r, n: left);
5376 outs() << " (objc_property_list entends past the end of the section)\n";
5377 } else
5378 memcpy(dest: &opl, src: r, n: sizeof(struct objc_property_list64));
5379 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5380 swapStruct(pl&: opl);
5381 outs() << " entsize " << opl.entsize << "\n";
5382 outs() << " count " << opl.count << "\n";
5383
5384 p += sizeof(struct objc_property_list64);
5385 offset += sizeof(struct objc_property_list64);
5386 for (j = 0; j < opl.count; j++) {
5387 r = get_pointer_64(Address: p, offset, left, S, info);
5388 if (r == nullptr)
5389 return;
5390 memset(s: &op, c: '\0', n: sizeof(struct objc_property64));
5391 if (left < sizeof(struct objc_property64)) {
5392 memcpy(dest: &op, src: r, n: left);
5393 outs() << " (objc_property entends past the end of the section)\n";
5394 } else
5395 memcpy(dest: &op, src: r, n: sizeof(struct objc_property64));
5396 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5397 swapStruct(op);
5398
5399 outs() << "\t\t\t name ";
5400 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct objc_property64, name), S,
5401 info, n_value, ReferenceValue: op.name);
5402 if (n_value != 0) {
5403 if (info->verbose && sym_name != nullptr)
5404 outs() << sym_name;
5405 else
5406 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5407 if (op.name != 0)
5408 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: op.name);
5409 } else
5410 outs() << format(Fmt: "0x%" PRIx64, Vals: op.name);
5411 name = get_pointer_64(Address: op.name + n_value, offset&: xoffset, left, S&: xS, info);
5412 if (name != nullptr)
5413 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5414 outs() << "\n";
5415
5416 outs() << "\t\t\tattributes ";
5417 sym_name =
5418 get_symbol_64(sect_offset: offset + offsetof(struct objc_property64, attributes), S,
5419 info, n_value, ReferenceValue: op.attributes);
5420 if (n_value != 0) {
5421 if (info->verbose && sym_name != nullptr)
5422 outs() << sym_name;
5423 else
5424 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5425 if (op.attributes != 0)
5426 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: op.attributes);
5427 } else
5428 outs() << format(Fmt: "0x%" PRIx64, Vals: op.attributes);
5429 name = get_pointer_64(Address: op.attributes + n_value, offset&: xoffset, left, S&: xS, info);
5430 if (name != nullptr)
5431 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5432 outs() << "\n";
5433
5434 p += sizeof(struct objc_property64);
5435 offset += sizeof(struct objc_property64);
5436 }
5437}
5438
5439static void print_objc_property_list32(uint32_t p,
5440 struct DisassembleInfo *info) {
5441 struct objc_property_list32 opl;
5442 struct objc_property32 op;
5443 const char *r;
5444 uint32_t offset, xoffset, left, j;
5445 SectionRef S, xS;
5446 const char *name;
5447
5448 r = get_pointer_32(Address: p, offset, left, S, info);
5449 if (r == nullptr)
5450 return;
5451 memset(s: &opl, c: '\0', n: sizeof(struct objc_property_list32));
5452 if (left < sizeof(struct objc_property_list32)) {
5453 memcpy(dest: &opl, src: r, n: left);
5454 outs() << " (objc_property_list entends past the end of the section)\n";
5455 } else
5456 memcpy(dest: &opl, src: r, n: sizeof(struct objc_property_list32));
5457 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5458 swapStruct(pl&: opl);
5459 outs() << " entsize " << opl.entsize << "\n";
5460 outs() << " count " << opl.count << "\n";
5461
5462 p += sizeof(struct objc_property_list32);
5463 offset += sizeof(struct objc_property_list32);
5464 for (j = 0; j < opl.count; j++) {
5465 r = get_pointer_32(Address: p, offset, left, S, info);
5466 if (r == nullptr)
5467 return;
5468 memset(s: &op, c: '\0', n: sizeof(struct objc_property32));
5469 if (left < sizeof(struct objc_property32)) {
5470 memcpy(dest: &op, src: r, n: left);
5471 outs() << " (objc_property entends past the end of the section)\n";
5472 } else
5473 memcpy(dest: &op, src: r, n: sizeof(struct objc_property32));
5474 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5475 swapStruct(op);
5476
5477 outs() << "\t\t\t name " << format(Fmt: "0x%" PRIx32, Vals: op.name);
5478 name = get_pointer_32(Address: op.name, offset&: xoffset, left, S&: xS, info);
5479 if (name != nullptr)
5480 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5481 outs() << "\n";
5482
5483 outs() << "\t\t\tattributes " << format(Fmt: "0x%" PRIx32, Vals: op.attributes);
5484 name = get_pointer_32(Address: op.attributes, offset&: xoffset, left, S&: xS, info);
5485 if (name != nullptr)
5486 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5487 outs() << "\n";
5488
5489 p += sizeof(struct objc_property32);
5490 offset += sizeof(struct objc_property32);
5491 }
5492}
5493
5494static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
5495 bool &is_meta_class) {
5496 struct class_ro64_t cro;
5497 const char *r;
5498 uint32_t offset, xoffset, left;
5499 SectionRef S, xS;
5500 const char *name, *sym_name;
5501 uint64_t n_value;
5502
5503 r = get_pointer_64(Address: p, offset, left, S, info);
5504 if (r == nullptr || left < sizeof(struct class_ro64_t))
5505 return false;
5506 memcpy(dest: &cro, src: r, n: sizeof(struct class_ro64_t));
5507 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5508 swapStruct(cro);
5509 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: cro.flags);
5510 if (cro.flags & RO_META)
5511 outs() << " RO_META";
5512 if (cro.flags & RO_ROOT)
5513 outs() << " RO_ROOT";
5514 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5515 outs() << " RO_HAS_CXX_STRUCTORS";
5516 outs() << "\n";
5517 outs() << " instanceStart " << cro.instanceStart << "\n";
5518 outs() << " instanceSize " << cro.instanceSize << "\n";
5519 outs() << " reserved " << format(Fmt: "0x%" PRIx32, Vals: cro.reserved)
5520 << "\n";
5521 outs() << " ivarLayout " << format(Fmt: "0x%" PRIx64, Vals: cro.ivarLayout)
5522 << "\n";
5523 print_layout_map64(p: cro.ivarLayout, info);
5524
5525 outs() << " name ";
5526 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, name), S,
5527 info, n_value, ReferenceValue: cro.name);
5528 if (n_value != 0) {
5529 if (info->verbose && sym_name != nullptr)
5530 outs() << sym_name;
5531 else
5532 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5533 if (cro.name != 0)
5534 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.name);
5535 } else
5536 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.name);
5537 name = get_pointer_64(Address: cro.name + n_value, offset&: xoffset, left, S&: xS, info);
5538 if (name != nullptr)
5539 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5540 outs() << "\n";
5541
5542 outs() << " baseMethods ";
5543 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, baseMethods),
5544 S, info, n_value, ReferenceValue: cro.baseMethods);
5545 if (n_value != 0) {
5546 if (info->verbose && sym_name != nullptr)
5547 outs() << sym_name;
5548 else
5549 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5550 if (cro.baseMethods != 0)
5551 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.baseMethods);
5552 } else
5553 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.baseMethods);
5554 outs() << " (struct method_list_t *)\n";
5555 if (cro.baseMethods + n_value != 0)
5556 print_method_list64_t(p: cro.baseMethods + n_value, info, indent: "");
5557
5558 outs() << " baseProtocols ";
5559 sym_name =
5560 get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, baseProtocols), S,
5561 info, n_value, ReferenceValue: cro.baseProtocols);
5562 if (n_value != 0) {
5563 if (info->verbose && sym_name != nullptr)
5564 outs() << sym_name;
5565 else
5566 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5567 if (cro.baseProtocols != 0)
5568 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.baseProtocols);
5569 } else
5570 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.baseProtocols);
5571 outs() << "\n";
5572 if (cro.baseProtocols + n_value != 0)
5573 print_protocol_list64_t(p: cro.baseProtocols + n_value, info);
5574
5575 outs() << " ivars ";
5576 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, ivars), S,
5577 info, n_value, ReferenceValue: cro.ivars);
5578 if (n_value != 0) {
5579 if (info->verbose && sym_name != nullptr)
5580 outs() << sym_name;
5581 else
5582 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5583 if (cro.ivars != 0)
5584 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.ivars);
5585 } else
5586 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.ivars);
5587 outs() << "\n";
5588 if (cro.ivars + n_value != 0)
5589 print_ivar_list64_t(p: cro.ivars + n_value, info);
5590
5591 outs() << " weakIvarLayout ";
5592 sym_name =
5593 get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, weakIvarLayout), S,
5594 info, n_value, ReferenceValue: cro.weakIvarLayout);
5595 if (n_value != 0) {
5596 if (info->verbose && sym_name != nullptr)
5597 outs() << sym_name;
5598 else
5599 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5600 if (cro.weakIvarLayout != 0)
5601 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.weakIvarLayout);
5602 } else
5603 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.weakIvarLayout);
5604 outs() << "\n";
5605 print_layout_map64(p: cro.weakIvarLayout + n_value, info);
5606
5607 outs() << " baseProperties ";
5608 sym_name =
5609 get_symbol_64(sect_offset: offset + offsetof(struct class_ro64_t, baseProperties), S,
5610 info, n_value, ReferenceValue: cro.baseProperties);
5611 if (n_value != 0) {
5612 if (info->verbose && sym_name != nullptr)
5613 outs() << sym_name;
5614 else
5615 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5616 if (cro.baseProperties != 0)
5617 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: cro.baseProperties);
5618 } else
5619 outs() << format(Fmt: "0x%" PRIx64, Vals: cro.baseProperties);
5620 outs() << "\n";
5621 if (cro.baseProperties + n_value != 0)
5622 print_objc_property_list64(p: cro.baseProperties + n_value, info);
5623
5624 is_meta_class = (cro.flags & RO_META) != 0;
5625 return true;
5626}
5627
5628static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
5629 bool &is_meta_class) {
5630 struct class_ro32_t cro;
5631 const char *r;
5632 uint32_t offset, xoffset, left;
5633 SectionRef S, xS;
5634 const char *name;
5635
5636 r = get_pointer_32(Address: p, offset, left, S, info);
5637 if (r == nullptr)
5638 return false;
5639 memset(s: &cro, c: '\0', n: sizeof(struct class_ro32_t));
5640 if (left < sizeof(struct class_ro32_t)) {
5641 memcpy(dest: &cro, src: r, n: left);
5642 outs() << " (class_ro_t entends past the end of the section)\n";
5643 } else
5644 memcpy(dest: &cro, src: r, n: sizeof(struct class_ro32_t));
5645 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5646 swapStruct(cro);
5647 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: cro.flags);
5648 if (cro.flags & RO_META)
5649 outs() << " RO_META";
5650 if (cro.flags & RO_ROOT)
5651 outs() << " RO_ROOT";
5652 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5653 outs() << " RO_HAS_CXX_STRUCTORS";
5654 outs() << "\n";
5655 outs() << " instanceStart " << cro.instanceStart << "\n";
5656 outs() << " instanceSize " << cro.instanceSize << "\n";
5657 outs() << " ivarLayout " << format(Fmt: "0x%" PRIx32, Vals: cro.ivarLayout)
5658 << "\n";
5659 print_layout_map32(p: cro.ivarLayout, info);
5660
5661 outs() << " name " << format(Fmt: "0x%" PRIx32, Vals: cro.name);
5662 name = get_pointer_32(Address: cro.name, offset&: xoffset, left, S&: xS, info);
5663 if (name != nullptr)
5664 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5665 outs() << "\n";
5666
5667 outs() << " baseMethods "
5668 << format(Fmt: "0x%" PRIx32, Vals: cro.baseMethods)
5669 << " (struct method_list_t *)\n";
5670 if (cro.baseMethods != 0)
5671 print_method_list32_t(p: cro.baseMethods, info, indent: "");
5672
5673 outs() << " baseProtocols "
5674 << format(Fmt: "0x%" PRIx32, Vals: cro.baseProtocols) << "\n";
5675 if (cro.baseProtocols != 0)
5676 print_protocol_list32_t(p: cro.baseProtocols, info);
5677 outs() << " ivars " << format(Fmt: "0x%" PRIx32, Vals: cro.ivars)
5678 << "\n";
5679 if (cro.ivars != 0)
5680 print_ivar_list32_t(p: cro.ivars, info);
5681 outs() << " weakIvarLayout "
5682 << format(Fmt: "0x%" PRIx32, Vals: cro.weakIvarLayout) << "\n";
5683 print_layout_map32(p: cro.weakIvarLayout, info);
5684 outs() << " baseProperties "
5685 << format(Fmt: "0x%" PRIx32, Vals: cro.baseProperties) << "\n";
5686 if (cro.baseProperties != 0)
5687 print_objc_property_list32(p: cro.baseProperties, info);
5688 is_meta_class = (cro.flags & RO_META) != 0;
5689 return true;
5690}
5691
5692static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
5693 struct class64_t c;
5694 const char *r;
5695 uint32_t offset, left;
5696 SectionRef S;
5697 const char *name;
5698 uint64_t isa_n_value, n_value;
5699
5700 r = get_pointer_64(Address: p, offset, left, S, info);
5701 if (r == nullptr || left < sizeof(struct class64_t))
5702 return;
5703 memcpy(dest: &c, src: r, n: sizeof(struct class64_t));
5704 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5705 swapStruct(c);
5706
5707 outs() << " isa " << format(Fmt: "0x%" PRIx64, Vals: c.isa);
5708 name = get_symbol_64(sect_offset: offset + offsetof(struct class64_t, isa), S, info,
5709 n_value&: isa_n_value, ReferenceValue: c.isa);
5710 if (name != nullptr)
5711 outs() << " " << name;
5712 outs() << "\n";
5713
5714 outs() << " superclass " << format(Fmt: "0x%" PRIx64, Vals: c.superclass);
5715 name = get_symbol_64(sect_offset: offset + offsetof(struct class64_t, superclass), S, info,
5716 n_value, ReferenceValue: c.superclass);
5717 if (name != nullptr)
5718 outs() << " " << name;
5719 else {
5720 name = get_dyld_bind_info_symbolname(ReferenceValue: S.getAddress() +
5721 offset + offsetof(struct class64_t, superclass), info);
5722 if (name != nullptr)
5723 outs() << " " << name;
5724 }
5725 outs() << "\n";
5726
5727 outs() << " cache " << format(Fmt: "0x%" PRIx64, Vals: c.cache);
5728 name = get_symbol_64(sect_offset: offset + offsetof(struct class64_t, cache), S, info,
5729 n_value, ReferenceValue: c.cache);
5730 if (name != nullptr)
5731 outs() << " " << name;
5732 outs() << "\n";
5733
5734 outs() << " vtable " << format(Fmt: "0x%" PRIx64, Vals: c.vtable);
5735 name = get_symbol_64(sect_offset: offset + offsetof(struct class64_t, vtable), S, info,
5736 n_value, ReferenceValue: c.vtable);
5737 if (name != nullptr)
5738 outs() << " " << name;
5739 outs() << "\n";
5740
5741 name = get_symbol_64(sect_offset: offset + offsetof(struct class64_t, data), S, info,
5742 n_value, ReferenceValue: c.data);
5743 outs() << " data ";
5744 if (n_value != 0) {
5745 if (info->verbose && name != nullptr)
5746 outs() << name;
5747 else
5748 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
5749 if (c.data != 0)
5750 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.data);
5751 } else
5752 outs() << format(Fmt: "0x%" PRIx64, Vals: c.data);
5753 outs() << " (struct class_ro_t *)";
5754
5755 // This is a Swift class if some of the low bits of the pointer are set.
5756 if ((c.data + n_value) & 0x7)
5757 outs() << " Swift class";
5758 outs() << "\n";
5759 bool is_meta_class;
5760 if (!print_class_ro64_t(p: (c.data + n_value) & ~0x7, info, is_meta_class))
5761 return;
5762
5763 if (!is_meta_class &&
5764 c.isa + isa_n_value != p &&
5765 c.isa + isa_n_value != 0 &&
5766 info->depth < 100) {
5767 info->depth++;
5768 outs() << "Meta Class\n";
5769 print_class64_t(p: c.isa + isa_n_value, info);
5770 }
5771}
5772
5773static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5774 struct class32_t c;
5775 const char *r;
5776 uint32_t offset, left;
5777 SectionRef S;
5778 const char *name;
5779
5780 r = get_pointer_32(Address: p, offset, left, S, info);
5781 if (r == nullptr)
5782 return;
5783 memset(s: &c, c: '\0', n: sizeof(struct class32_t));
5784 if (left < sizeof(struct class32_t)) {
5785 memcpy(dest: &c, src: r, n: left);
5786 outs() << " (class_t entends past the end of the section)\n";
5787 } else
5788 memcpy(dest: &c, src: r, n: sizeof(struct class32_t));
5789 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5790 swapStruct(c);
5791
5792 outs() << " isa " << format(Fmt: "0x%" PRIx32, Vals: c.isa);
5793 name =
5794 get_symbol_32(sect_offset: offset + offsetof(struct class32_t, isa), S, info, ReferenceValue: c.isa);
5795 if (name != nullptr)
5796 outs() << " " << name;
5797 outs() << "\n";
5798
5799 outs() << " superclass " << format(Fmt: "0x%" PRIx32, Vals: c.superclass);
5800 name = get_symbol_32(sect_offset: offset + offsetof(struct class32_t, superclass), S, info,
5801 ReferenceValue: c.superclass);
5802 if (name != nullptr)
5803 outs() << " " << name;
5804 outs() << "\n";
5805
5806 outs() << " cache " << format(Fmt: "0x%" PRIx32, Vals: c.cache);
5807 name = get_symbol_32(sect_offset: offset + offsetof(struct class32_t, cache), S, info,
5808 ReferenceValue: c.cache);
5809 if (name != nullptr)
5810 outs() << " " << name;
5811 outs() << "\n";
5812
5813 outs() << " vtable " << format(Fmt: "0x%" PRIx32, Vals: c.vtable);
5814 name = get_symbol_32(sect_offset: offset + offsetof(struct class32_t, vtable), S, info,
5815 ReferenceValue: c.vtable);
5816 if (name != nullptr)
5817 outs() << " " << name;
5818 outs() << "\n";
5819
5820 name =
5821 get_symbol_32(sect_offset: offset + offsetof(struct class32_t, data), S, info, ReferenceValue: c.data);
5822 outs() << " data " << format(Fmt: "0x%" PRIx32, Vals: c.data)
5823 << " (struct class_ro_t *)";
5824
5825 // This is a Swift class if some of the low bits of the pointer are set.
5826 if (c.data & 0x3)
5827 outs() << " Swift class";
5828 outs() << "\n";
5829 bool is_meta_class;
5830 if (!print_class_ro32_t(p: c.data & ~0x3, info, is_meta_class))
5831 return;
5832
5833 if (!is_meta_class) {
5834 outs() << "Meta Class\n";
5835 print_class32_t(p: c.isa, info);
5836 }
5837}
5838
5839static void print_objc_class_t(struct objc_class_t *objc_class,
5840 struct DisassembleInfo *info) {
5841 uint32_t offset, left, xleft;
5842 const char *name, *p, *ivar_list;
5843 SectionRef S;
5844 int32_t i;
5845 struct objc_ivar_list_t objc_ivar_list;
5846 struct objc_ivar_t ivar;
5847
5848 outs() << "\t\t isa " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->isa);
5849 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {
5850 name = get_pointer_32(Address: objc_class->isa, offset, left, S, info, objc_only: true);
5851 if (name != nullptr)
5852 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5853 else
5854 outs() << " (not in an __OBJC section)";
5855 }
5856 outs() << "\n";
5857
5858 outs() << "\t super_class "
5859 << format(Fmt: "0x%08" PRIx32, Vals: objc_class->super_class);
5860 if (info->verbose) {
5861 name = get_pointer_32(Address: objc_class->super_class, offset, left, S, info, objc_only: true);
5862 if (name != nullptr)
5863 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5864 else
5865 outs() << " (not in an __OBJC section)";
5866 }
5867 outs() << "\n";
5868
5869 outs() << "\t\t name " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->name);
5870 if (info->verbose) {
5871 name = get_pointer_32(Address: objc_class->name, offset, left, S, info, objc_only: true);
5872 if (name != nullptr)
5873 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5874 else
5875 outs() << " (not in an __OBJC section)";
5876 }
5877 outs() << "\n";
5878
5879 outs() << "\t\t version " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->version)
5880 << "\n";
5881
5882 outs() << "\t\t info " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->info);
5883 if (info->verbose) {
5884 if (CLS_GETINFO(objc_class, CLS_CLASS))
5885 outs() << " CLS_CLASS";
5886 else if (CLS_GETINFO(objc_class, CLS_META))
5887 outs() << " CLS_META";
5888 }
5889 outs() << "\n";
5890
5891 outs() << "\t instance_size "
5892 << format(Fmt: "0x%08" PRIx32, Vals: objc_class->instance_size) << "\n";
5893
5894 p = get_pointer_32(Address: objc_class->ivars, offset, left, S, info, objc_only: true);
5895 outs() << "\t\t ivars " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->ivars);
5896 if (p != nullptr) {
5897 if (left > sizeof(struct objc_ivar_list_t)) {
5898 outs() << "\n";
5899 memcpy(dest: &objc_ivar_list, src: p, n: sizeof(struct objc_ivar_list_t));
5900 } else {
5901 outs() << " (entends past the end of the section)\n";
5902 memset(s: &objc_ivar_list, c: '\0', n: sizeof(struct objc_ivar_list_t));
5903 memcpy(dest: &objc_ivar_list, src: p, n: left);
5904 }
5905 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5906 swapStruct(objc_ivar_list);
5907 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5908 ivar_list = p + sizeof(struct objc_ivar_list_t);
5909 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5910 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5911 outs() << "\t\t remaining ivar's extend past the of the section\n";
5912 break;
5913 }
5914 memcpy(dest: &ivar, src: ivar_list + i * sizeof(struct objc_ivar_t),
5915 n: sizeof(struct objc_ivar_t));
5916 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5917 swapStruct(objc_ivar&: ivar);
5918
5919 outs() << "\t\t\tivar_name " << format(Fmt: "0x%08" PRIx32, Vals: ivar.ivar_name);
5920 if (info->verbose) {
5921 name = get_pointer_32(Address: ivar.ivar_name, offset, left&: xleft, S, info, objc_only: true);
5922 if (name != nullptr)
5923 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
5924 else
5925 outs() << " (not in an __OBJC section)";
5926 }
5927 outs() << "\n";
5928
5929 outs() << "\t\t\tivar_type " << format(Fmt: "0x%08" PRIx32, Vals: ivar.ivar_type);
5930 if (info->verbose) {
5931 name = get_pointer_32(Address: ivar.ivar_type, offset, left&: xleft, S, info, objc_only: true);
5932 if (name != nullptr)
5933 outs() << format(Fmt: " %.*s", Vals: xleft, Vals: name);
5934 else
5935 outs() << " (not in an __OBJC section)";
5936 }
5937 outs() << "\n";
5938
5939 outs() << "\t\t ivar_offset "
5940 << format(Fmt: "0x%08" PRIx32, Vals: ivar.ivar_offset) << "\n";
5941 }
5942 } else {
5943 outs() << " (not in an __OBJC section)\n";
5944 }
5945
5946 outs() << "\t\t methods " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->methodLists);
5947 if (print_method_list(p: objc_class->methodLists, info))
5948 outs() << " (not in an __OBJC section)\n";
5949
5950 outs() << "\t\t cache " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->cache)
5951 << "\n";
5952
5953 outs() << "\t\tprotocols " << format(Fmt: "0x%08" PRIx32, Vals: objc_class->protocols);
5954 if (print_protocol_list(p: objc_class->protocols, indent: 16, info))
5955 outs() << " (not in an __OBJC section)\n";
5956}
5957
5958static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5959 struct DisassembleInfo *info) {
5960 uint32_t offset, left;
5961 const char *name;
5962 SectionRef S;
5963
5964 outs() << "\t category name "
5965 << format(Fmt: "0x%08" PRIx32, Vals: objc_category->category_name);
5966 if (info->verbose) {
5967 name = get_pointer_32(Address: objc_category->category_name, offset, left, S, info,
5968 objc_only: true);
5969 if (name != nullptr)
5970 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5971 else
5972 outs() << " (not in an __OBJC section)";
5973 }
5974 outs() << "\n";
5975
5976 outs() << "\t\t class name "
5977 << format(Fmt: "0x%08" PRIx32, Vals: objc_category->class_name);
5978 if (info->verbose) {
5979 name =
5980 get_pointer_32(Address: objc_category->class_name, offset, left, S, info, objc_only: true);
5981 if (name != nullptr)
5982 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
5983 else
5984 outs() << " (not in an __OBJC section)";
5985 }
5986 outs() << "\n";
5987
5988 outs() << "\t instance methods "
5989 << format(Fmt: "0x%08" PRIx32, Vals: objc_category->instance_methods);
5990 if (print_method_list(p: objc_category->instance_methods, info))
5991 outs() << " (not in an __OBJC section)\n";
5992
5993 outs() << "\t class methods "
5994 << format(Fmt: "0x%08" PRIx32, Vals: objc_category->class_methods);
5995 if (print_method_list(p: objc_category->class_methods, info))
5996 outs() << " (not in an __OBJC section)\n";
5997}
5998
5999static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
6000 struct category64_t c;
6001 const char *r;
6002 uint32_t offset, xoffset, left;
6003 SectionRef S, xS;
6004 const char *name, *sym_name;
6005 uint64_t n_value;
6006
6007 r = get_pointer_64(Address: p, offset, left, S, info);
6008 if (r == nullptr)
6009 return;
6010 memset(s: &c, c: '\0', n: sizeof(struct category64_t));
6011 if (left < sizeof(struct category64_t)) {
6012 memcpy(dest: &c, src: r, n: left);
6013 outs() << " (category_t entends past the end of the section)\n";
6014 } else
6015 memcpy(dest: &c, src: r, n: sizeof(struct category64_t));
6016 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6017 swapStruct(c);
6018
6019 outs() << " name ";
6020 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct category64_t, name), S,
6021 info, n_value, ReferenceValue: c.name);
6022 if (n_value != 0) {
6023 if (info->verbose && sym_name != nullptr)
6024 outs() << sym_name;
6025 else
6026 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6027 if (c.name != 0)
6028 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.name);
6029 } else
6030 outs() << format(Fmt: "0x%" PRIx64, Vals: c.name);
6031 name = get_pointer_64(Address: c.name + n_value, offset&: xoffset, left, S&: xS, info);
6032 if (name != nullptr)
6033 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
6034 outs() << "\n";
6035
6036 outs() << " cls ";
6037 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct category64_t, cls), S, info,
6038 n_value, ReferenceValue: c.cls);
6039 if (n_value != 0) {
6040 if (info->verbose && sym_name != nullptr)
6041 outs() << sym_name;
6042 else
6043 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6044 if (c.cls != 0)
6045 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.cls);
6046 } else
6047 outs() << format(Fmt: "0x%" PRIx64, Vals: c.cls);
6048 outs() << "\n";
6049 if (c.cls + n_value != 0)
6050 print_class64_t(p: c.cls + n_value, info);
6051
6052 outs() << " instanceMethods ";
6053 sym_name =
6054 get_symbol_64(sect_offset: offset + offsetof(struct category64_t, instanceMethods), S,
6055 info, n_value, ReferenceValue: c.instanceMethods);
6056 if (n_value != 0) {
6057 if (info->verbose && sym_name != nullptr)
6058 outs() << sym_name;
6059 else
6060 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6061 if (c.instanceMethods != 0)
6062 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.instanceMethods);
6063 } else
6064 outs() << format(Fmt: "0x%" PRIx64, Vals: c.instanceMethods);
6065 outs() << "\n";
6066 if (c.instanceMethods + n_value != 0)
6067 print_method_list64_t(p: c.instanceMethods + n_value, info, indent: "");
6068
6069 outs() << " classMethods ";
6070 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct category64_t, classMethods),
6071 S, info, n_value, ReferenceValue: c.classMethods);
6072 if (n_value != 0) {
6073 if (info->verbose && sym_name != nullptr)
6074 outs() << sym_name;
6075 else
6076 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6077 if (c.classMethods != 0)
6078 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.classMethods);
6079 } else
6080 outs() << format(Fmt: "0x%" PRIx64, Vals: c.classMethods);
6081 outs() << "\n";
6082 if (c.classMethods + n_value != 0)
6083 print_method_list64_t(p: c.classMethods + n_value, info, indent: "");
6084
6085 outs() << " protocols ";
6086 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct category64_t, protocols), S,
6087 info, n_value, ReferenceValue: c.protocols);
6088 if (n_value != 0) {
6089 if (info->verbose && sym_name != nullptr)
6090 outs() << sym_name;
6091 else
6092 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6093 if (c.protocols != 0)
6094 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.protocols);
6095 } else
6096 outs() << format(Fmt: "0x%" PRIx64, Vals: c.protocols);
6097 outs() << "\n";
6098 if (c.protocols + n_value != 0)
6099 print_protocol_list64_t(p: c.protocols + n_value, info);
6100
6101 outs() << "instanceProperties ";
6102 sym_name =
6103 get_symbol_64(sect_offset: offset + offsetof(struct category64_t, instanceProperties),
6104 S, info, n_value, ReferenceValue: c.instanceProperties);
6105 if (n_value != 0) {
6106 if (info->verbose && sym_name != nullptr)
6107 outs() << sym_name;
6108 else
6109 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6110 if (c.instanceProperties != 0)
6111 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: c.instanceProperties);
6112 } else
6113 outs() << format(Fmt: "0x%" PRIx64, Vals: c.instanceProperties);
6114 outs() << "\n";
6115 if (c.instanceProperties + n_value != 0)
6116 print_objc_property_list64(p: c.instanceProperties + n_value, info);
6117}
6118
6119static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
6120 struct category32_t c;
6121 const char *r;
6122 uint32_t offset, left;
6123 SectionRef S, xS;
6124 const char *name;
6125
6126 r = get_pointer_32(Address: p, offset, left, S, info);
6127 if (r == nullptr)
6128 return;
6129 memset(s: &c, c: '\0', n: sizeof(struct category32_t));
6130 if (left < sizeof(struct category32_t)) {
6131 memcpy(dest: &c, src: r, n: left);
6132 outs() << " (category_t entends past the end of the section)\n";
6133 } else
6134 memcpy(dest: &c, src: r, n: sizeof(struct category32_t));
6135 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6136 swapStruct(c);
6137
6138 outs() << " name " << format(Fmt: "0x%" PRIx32, Vals: c.name);
6139 name = get_symbol_32(sect_offset: offset + offsetof(struct category32_t, name), S, info,
6140 ReferenceValue: c.name);
6141 if (name)
6142 outs() << " " << name;
6143 outs() << "\n";
6144
6145 outs() << " cls " << format(Fmt: "0x%" PRIx32, Vals: c.cls) << "\n";
6146 if (c.cls != 0)
6147 print_class32_t(p: c.cls, info);
6148 outs() << " instanceMethods " << format(Fmt: "0x%" PRIx32, Vals: c.instanceMethods)
6149 << "\n";
6150 if (c.instanceMethods != 0)
6151 print_method_list32_t(p: c.instanceMethods, info, indent: "");
6152 outs() << " classMethods " << format(Fmt: "0x%" PRIx32, Vals: c.classMethods)
6153 << "\n";
6154 if (c.classMethods != 0)
6155 print_method_list32_t(p: c.classMethods, info, indent: "");
6156 outs() << " protocols " << format(Fmt: "0x%" PRIx32, Vals: c.protocols) << "\n";
6157 if (c.protocols != 0)
6158 print_protocol_list32_t(p: c.protocols, info);
6159 outs() << "instanceProperties " << format(Fmt: "0x%" PRIx32, Vals: c.instanceProperties)
6160 << "\n";
6161 if (c.instanceProperties != 0)
6162 print_objc_property_list32(p: c.instanceProperties, info);
6163}
6164
6165static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
6166 uint32_t i, left, offset, xoffset;
6167 uint64_t p, n_value;
6168 struct message_ref64 mr;
6169 const char *name, *sym_name;
6170 const char *r;
6171 SectionRef xS;
6172
6173 if (S == SectionRef())
6174 return;
6175
6176 StringRef SectName;
6177 Expected<StringRef> SecNameOrErr = S.getName();
6178 if (SecNameOrErr)
6179 SectName = *SecNameOrErr;
6180 else
6181 consumeError(Err: SecNameOrErr.takeError());
6182
6183 DataRefImpl Ref = S.getRawDataRefImpl();
6184 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
6185 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6186 offset = 0;
6187 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6188 p = S.getAddress() + i;
6189 r = get_pointer_64(Address: p, offset, left, S, info);
6190 if (r == nullptr)
6191 return;
6192 memset(s: &mr, c: '\0', n: sizeof(struct message_ref64));
6193 if (left < sizeof(struct message_ref64)) {
6194 memcpy(dest: &mr, src: r, n: left);
6195 outs() << " (message_ref entends past the end of the section)\n";
6196 } else
6197 memcpy(dest: &mr, src: r, n: sizeof(struct message_ref64));
6198 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6199 swapStruct(mr);
6200
6201 outs() << " imp ";
6202 name = get_symbol_64(sect_offset: offset + offsetof(struct message_ref64, imp), S, info,
6203 n_value, ReferenceValue: mr.imp);
6204 if (n_value != 0) {
6205 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value) << " ";
6206 if (mr.imp != 0)
6207 outs() << "+ " << format(Fmt: "0x%" PRIx64, Vals: mr.imp) << " ";
6208 } else
6209 outs() << format(Fmt: "0x%" PRIx64, Vals: mr.imp) << " ";
6210 if (name != nullptr)
6211 outs() << " " << name;
6212 outs() << "\n";
6213
6214 outs() << " sel ";
6215 sym_name = get_symbol_64(sect_offset: offset + offsetof(struct message_ref64, sel), S,
6216 info, n_value, ReferenceValue: mr.sel);
6217 if (n_value != 0) {
6218 if (info->verbose && sym_name != nullptr)
6219 outs() << sym_name;
6220 else
6221 outs() << format(Fmt: "0x%" PRIx64, Vals: n_value);
6222 if (mr.sel != 0)
6223 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: mr.sel);
6224 } else
6225 outs() << format(Fmt: "0x%" PRIx64, Vals: mr.sel);
6226 name = get_pointer_64(Address: mr.sel + n_value, offset&: xoffset, left, S&: xS, info);
6227 if (name != nullptr)
6228 outs() << format(Fmt: " %.*s", Vals: left, Vals: name);
6229 outs() << "\n";
6230
6231 offset += sizeof(struct message_ref64);
6232 }
6233}
6234
6235static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
6236 uint32_t i, left, offset, xoffset, p;
6237 struct message_ref32 mr;
6238 const char *name, *r;
6239 SectionRef xS;
6240
6241 if (S == SectionRef())
6242 return;
6243
6244 StringRef SectName;
6245 Expected<StringRef> SecNameOrErr = S.getName();
6246 if (SecNameOrErr)
6247 SectName = *SecNameOrErr;
6248 else
6249 consumeError(Err: SecNameOrErr.takeError());
6250
6251 DataRefImpl Ref = S.getRawDataRefImpl();
6252 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
6253 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6254 offset = 0;
6255 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6256 p = S.getAddress() + i;
6257 r = get_pointer_32(Address: p, offset, left, S, info);
6258 if (r == nullptr)
6259 return;
6260 memset(s: &mr, c: '\0', n: sizeof(struct message_ref32));
6261 if (left < sizeof(struct message_ref32)) {
6262 memcpy(dest: &mr, src: r, n: left);
6263 outs() << " (message_ref entends past the end of the section)\n";
6264 } else
6265 memcpy(dest: &mr, src: r, n: sizeof(struct message_ref32));
6266 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6267 swapStruct(mr);
6268
6269 outs() << " imp " << format(Fmt: "0x%" PRIx32, Vals: mr.imp);
6270 name = get_symbol_32(sect_offset: offset + offsetof(struct message_ref32, imp), S, info,
6271 ReferenceValue: mr.imp);
6272 if (name != nullptr)
6273 outs() << " " << name;
6274 outs() << "\n";
6275
6276 outs() << " sel " << format(Fmt: "0x%" PRIx32, Vals: mr.sel);
6277 name = get_pointer_32(Address: mr.sel, offset&: xoffset, left, S&: xS, info);
6278 if (name != nullptr)
6279 outs() << " " << name;
6280 outs() << "\n";
6281
6282 offset += sizeof(struct message_ref32);
6283 }
6284}
6285
6286static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
6287 uint32_t left, offset, swift_version;
6288 uint64_t p;
6289 struct objc_image_info64 o;
6290 const char *r;
6291
6292 if (S == SectionRef())
6293 return;
6294
6295 StringRef SectName;
6296 Expected<StringRef> SecNameOrErr = S.getName();
6297 if (SecNameOrErr)
6298 SectName = *SecNameOrErr;
6299 else
6300 consumeError(Err: SecNameOrErr.takeError());
6301
6302 DataRefImpl Ref = S.getRawDataRefImpl();
6303 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
6304 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6305 p = S.getAddress();
6306 r = get_pointer_64(Address: p, offset, left, S, info);
6307 if (r == nullptr)
6308 return;
6309 memset(s: &o, c: '\0', n: sizeof(struct objc_image_info64));
6310 if (left < sizeof(struct objc_image_info64)) {
6311 memcpy(dest: &o, src: r, n: left);
6312 outs() << " (objc_image_info entends past the end of the section)\n";
6313 } else
6314 memcpy(dest: &o, src: r, n: sizeof(struct objc_image_info64));
6315 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6316 swapStruct(o);
6317 outs() << " version " << o.version << "\n";
6318 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: o.flags);
6319 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6320 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6321 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6322 outs() << " OBJC_IMAGE_SUPPORTS_GC";
6323 if (o.flags & OBJC_IMAGE_IS_SIMULATED)
6324 outs() << " OBJC_IMAGE_IS_SIMULATED";
6325 if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)
6326 outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";
6327 swift_version = (o.flags >> 8) & 0xff;
6328 if (swift_version != 0) {
6329 if (swift_version == 1)
6330 outs() << " Swift 1.0";
6331 else if (swift_version == 2)
6332 outs() << " Swift 1.1";
6333 else if(swift_version == 3)
6334 outs() << " Swift 2.0";
6335 else if(swift_version == 4)
6336 outs() << " Swift 3.0";
6337 else if(swift_version == 5)
6338 outs() << " Swift 4.0";
6339 else if(swift_version == 6)
6340 outs() << " Swift 4.1/Swift 4.2";
6341 else if(swift_version == 7)
6342 outs() << " Swift 5 or later";
6343 else
6344 outs() << " unknown future Swift version (" << swift_version << ")";
6345 }
6346 outs() << "\n";
6347}
6348
6349static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
6350 uint32_t left, offset, swift_version, p;
6351 struct objc_image_info32 o;
6352 const char *r;
6353
6354 if (S == SectionRef())
6355 return;
6356
6357 StringRef SectName;
6358 Expected<StringRef> SecNameOrErr = S.getName();
6359 if (SecNameOrErr)
6360 SectName = *SecNameOrErr;
6361 else
6362 consumeError(Err: SecNameOrErr.takeError());
6363
6364 DataRefImpl Ref = S.getRawDataRefImpl();
6365 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
6366 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6367 p = S.getAddress();
6368 r = get_pointer_32(Address: p, offset, left, S, info);
6369 if (r == nullptr)
6370 return;
6371 memset(s: &o, c: '\0', n: sizeof(struct objc_image_info32));
6372 if (left < sizeof(struct objc_image_info32)) {
6373 memcpy(dest: &o, src: r, n: left);
6374 outs() << " (objc_image_info entends past the end of the section)\n";
6375 } else
6376 memcpy(dest: &o, src: r, n: sizeof(struct objc_image_info32));
6377 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6378 swapStruct(o);
6379 outs() << " version " << o.version << "\n";
6380 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: o.flags);
6381 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6382 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6383 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6384 outs() << " OBJC_IMAGE_SUPPORTS_GC";
6385 swift_version = (o.flags >> 8) & 0xff;
6386 if (swift_version != 0) {
6387 if (swift_version == 1)
6388 outs() << " Swift 1.0";
6389 else if (swift_version == 2)
6390 outs() << " Swift 1.1";
6391 else if(swift_version == 3)
6392 outs() << " Swift 2.0";
6393 else if(swift_version == 4)
6394 outs() << " Swift 3.0";
6395 else if(swift_version == 5)
6396 outs() << " Swift 4.0";
6397 else if(swift_version == 6)
6398 outs() << " Swift 4.1/Swift 4.2";
6399 else if(swift_version == 7)
6400 outs() << " Swift 5 or later";
6401 else
6402 outs() << " unknown future Swift version (" << swift_version << ")";
6403 }
6404 outs() << "\n";
6405}
6406
6407static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
6408 uint32_t left, offset, p;
6409 struct imageInfo_t o;
6410 const char *r;
6411
6412 StringRef SectName;
6413 Expected<StringRef> SecNameOrErr = S.getName();
6414 if (SecNameOrErr)
6415 SectName = *SecNameOrErr;
6416 else
6417 consumeError(Err: SecNameOrErr.takeError());
6418
6419 DataRefImpl Ref = S.getRawDataRefImpl();
6420 StringRef SegName = info->O->getSectionFinalSegmentName(Sec: Ref);
6421 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6422 p = S.getAddress();
6423 r = get_pointer_32(Address: p, offset, left, S, info);
6424 if (r == nullptr)
6425 return;
6426 memset(s: &o, c: '\0', n: sizeof(struct imageInfo_t));
6427 if (left < sizeof(struct imageInfo_t)) {
6428 memcpy(dest: &o, src: r, n: left);
6429 outs() << " (imageInfo entends past the end of the section)\n";
6430 } else
6431 memcpy(dest: &o, src: r, n: sizeof(struct imageInfo_t));
6432 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6433 swapStruct(o);
6434 outs() << " version " << o.version << "\n";
6435 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: o.flags);
6436 if (o.flags & 0x1)
6437 outs() << " F&C";
6438 if (o.flags & 0x2)
6439 outs() << " GC";
6440 if (o.flags & 0x4)
6441 outs() << " GC-only";
6442 else
6443 outs() << " RR";
6444 outs() << "\n";
6445}
6446
6447static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
6448 SymbolAddressMap AddrMap;
6449 if (verbose)
6450 CreateSymbolAddressMap(O, AddrMap: &AddrMap);
6451
6452 std::vector<SectionRef> Sections;
6453 append_range(C&: Sections, R: O->sections());
6454
6455 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6456
6457 SectionRef CL = get_section(O, segname: "__OBJC2", sectname: "__class_list");
6458 if (CL == SectionRef())
6459 CL = get_section(O, segname: "__DATA", sectname: "__objc_classlist");
6460 if (CL == SectionRef())
6461 CL = get_section(O, segname: "__DATA_CONST", sectname: "__objc_classlist");
6462 if (CL == SectionRef())
6463 CL = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_classlist");
6464 info.S = CL;
6465 walk_pointer_list_64(listname: "class", S: CL, O, info: &info, func: print_class64_t);
6466
6467 SectionRef CR = get_section(O, segname: "__OBJC2", sectname: "__class_refs");
6468 if (CR == SectionRef())
6469 CR = get_section(O, segname: "__DATA", sectname: "__objc_classrefs");
6470 if (CR == SectionRef())
6471 CR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_classrefs");
6472 if (CR == SectionRef())
6473 CR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_classrefs");
6474 info.S = CR;
6475 walk_pointer_list_64(listname: "class refs", S: CR, O, info: &info, func: nullptr);
6476
6477 SectionRef SR = get_section(O, segname: "__OBJC2", sectname: "__super_refs");
6478 if (SR == SectionRef())
6479 SR = get_section(O, segname: "__DATA", sectname: "__objc_superrefs");
6480 if (SR == SectionRef())
6481 SR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_superrefs");
6482 if (SR == SectionRef())
6483 SR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_superrefs");
6484 info.S = SR;
6485 walk_pointer_list_64(listname: "super refs", S: SR, O, info: &info, func: nullptr);
6486
6487 SectionRef CA = get_section(O, segname: "__OBJC2", sectname: "__category_list");
6488 if (CA == SectionRef())
6489 CA = get_section(O, segname: "__DATA", sectname: "__objc_catlist");
6490 if (CA == SectionRef())
6491 CA = get_section(O, segname: "__DATA_CONST", sectname: "__objc_catlist");
6492 if (CA == SectionRef())
6493 CA = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_catlist");
6494 info.S = CA;
6495 walk_pointer_list_64(listname: "category", S: CA, O, info: &info, func: print_category64_t);
6496
6497 SectionRef PL = get_section(O, segname: "__OBJC2", sectname: "__protocol_list");
6498 if (PL == SectionRef())
6499 PL = get_section(O, segname: "__DATA", sectname: "__objc_protolist");
6500 if (PL == SectionRef())
6501 PL = get_section(O, segname: "__DATA_CONST", sectname: "__objc_protolist");
6502 if (PL == SectionRef())
6503 PL = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_protolist");
6504 info.S = PL;
6505 walk_pointer_list_64(listname: "protocol", S: PL, O, info: &info, func: nullptr);
6506
6507 SectionRef MR = get_section(O, segname: "__OBJC2", sectname: "__message_refs");
6508 if (MR == SectionRef())
6509 MR = get_section(O, segname: "__DATA", sectname: "__objc_msgrefs");
6510 if (MR == SectionRef())
6511 MR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_msgrefs");
6512 if (MR == SectionRef())
6513 MR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_msgrefs");
6514 info.S = MR;
6515 print_message_refs64(S: MR, info: &info);
6516
6517 SectionRef II = get_section(O, segname: "__OBJC2", sectname: "__image_info");
6518 if (II == SectionRef())
6519 II = get_section(O, segname: "__DATA", sectname: "__objc_imageinfo");
6520 if (II == SectionRef())
6521 II = get_section(O, segname: "__DATA_CONST", sectname: "__objc_imageinfo");
6522 if (II == SectionRef())
6523 II = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_imageinfo");
6524 info.S = II;
6525 print_image_info64(S: II, info: &info);
6526}
6527
6528static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6529 SymbolAddressMap AddrMap;
6530 if (verbose)
6531 CreateSymbolAddressMap(O, AddrMap: &AddrMap);
6532
6533 std::vector<SectionRef> Sections;
6534 append_range(C&: Sections, R: O->sections());
6535
6536 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6537
6538 SectionRef CL = get_section(O, segname: "__OBJC2", sectname: "__class_list");
6539 if (CL == SectionRef())
6540 CL = get_section(O, segname: "__DATA", sectname: "__objc_classlist");
6541 if (CL == SectionRef())
6542 CL = get_section(O, segname: "__DATA_CONST", sectname: "__objc_classlist");
6543 if (CL == SectionRef())
6544 CL = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_classlist");
6545 info.S = CL;
6546 walk_pointer_list_32(listname: "class", S: CL, O, info: &info, func: print_class32_t);
6547
6548 SectionRef CR = get_section(O, segname: "__OBJC2", sectname: "__class_refs");
6549 if (CR == SectionRef())
6550 CR = get_section(O, segname: "__DATA", sectname: "__objc_classrefs");
6551 if (CR == SectionRef())
6552 CR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_classrefs");
6553 if (CR == SectionRef())
6554 CR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_classrefs");
6555 info.S = CR;
6556 walk_pointer_list_32(listname: "class refs", S: CR, O, info: &info, func: nullptr);
6557
6558 SectionRef SR = get_section(O, segname: "__OBJC2", sectname: "__super_refs");
6559 if (SR == SectionRef())
6560 SR = get_section(O, segname: "__DATA", sectname: "__objc_superrefs");
6561 if (SR == SectionRef())
6562 SR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_superrefs");
6563 if (SR == SectionRef())
6564 SR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_superrefs");
6565 info.S = SR;
6566 walk_pointer_list_32(listname: "super refs", S: SR, O, info: &info, func: nullptr);
6567
6568 SectionRef CA = get_section(O, segname: "__OBJC2", sectname: "__category_list");
6569 if (CA == SectionRef())
6570 CA = get_section(O, segname: "__DATA", sectname: "__objc_catlist");
6571 if (CA == SectionRef())
6572 CA = get_section(O, segname: "__DATA_CONST", sectname: "__objc_catlist");
6573 if (CA == SectionRef())
6574 CA = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_catlist");
6575 info.S = CA;
6576 walk_pointer_list_32(listname: "category", S: CA, O, info: &info, func: print_category32_t);
6577
6578 SectionRef PL = get_section(O, segname: "__OBJC2", sectname: "__protocol_list");
6579 if (PL == SectionRef())
6580 PL = get_section(O, segname: "__DATA", sectname: "__objc_protolist");
6581 if (PL == SectionRef())
6582 PL = get_section(O, segname: "__DATA_CONST", sectname: "__objc_protolist");
6583 if (PL == SectionRef())
6584 PL = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_protolist");
6585 info.S = PL;
6586 walk_pointer_list_32(listname: "protocol", S: PL, O, info: &info, func: nullptr);
6587
6588 SectionRef MR = get_section(O, segname: "__OBJC2", sectname: "__message_refs");
6589 if (MR == SectionRef())
6590 MR = get_section(O, segname: "__DATA", sectname: "__objc_msgrefs");
6591 if (MR == SectionRef())
6592 MR = get_section(O, segname: "__DATA_CONST", sectname: "__objc_msgrefs");
6593 if (MR == SectionRef())
6594 MR = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_msgrefs");
6595 info.S = MR;
6596 print_message_refs32(S: MR, info: &info);
6597
6598 SectionRef II = get_section(O, segname: "__OBJC2", sectname: "__image_info");
6599 if (II == SectionRef())
6600 II = get_section(O, segname: "__DATA", sectname: "__objc_imageinfo");
6601 if (II == SectionRef())
6602 II = get_section(O, segname: "__DATA_CONST", sectname: "__objc_imageinfo");
6603 if (II == SectionRef())
6604 II = get_section(O, segname: "__DATA_DIRTY", sectname: "__objc_imageinfo");
6605 info.S = II;
6606 print_image_info32(S: II, info: &info);
6607}
6608
6609static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6610 uint32_t i, j, p, offset, xoffset, left, defs_left, def;
6611 const char *r, *name, *defs;
6612 struct objc_module_t module;
6613 SectionRef S, xS;
6614 struct objc_symtab_t symtab;
6615 struct objc_class_t objc_class;
6616 struct objc_category_t objc_category;
6617
6618 outs() << "Objective-C segment\n";
6619 S = get_section(O, segname: "__OBJC", sectname: "__module_info");
6620 if (S == SectionRef())
6621 return false;
6622
6623 SymbolAddressMap AddrMap;
6624 if (verbose)
6625 CreateSymbolAddressMap(O, AddrMap: &AddrMap);
6626
6627 std::vector<SectionRef> Sections;
6628 append_range(C&: Sections, R: O->sections());
6629
6630 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6631
6632 for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
6633 p = S.getAddress() + i;
6634 r = get_pointer_32(Address: p, offset, left, S, info: &info, objc_only: true);
6635 if (r == nullptr)
6636 return true;
6637 memset(s: &module, c: '\0', n: sizeof(struct objc_module_t));
6638 if (left < sizeof(struct objc_module_t)) {
6639 memcpy(dest: &module, src: r, n: left);
6640 outs() << " (module extends past end of __module_info section)\n";
6641 } else
6642 memcpy(dest: &module, src: r, n: sizeof(struct objc_module_t));
6643 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6644 swapStruct(module);
6645
6646 outs() << "Module " << format(Fmt: "0x%" PRIx32, Vals: p) << "\n";
6647 outs() << " version " << module.version << "\n";
6648 outs() << " size " << module.size << "\n";
6649 outs() << " name ";
6650 name = get_pointer_32(Address: module.name, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6651 if (name != nullptr)
6652 outs() << format(Fmt: "%.*s", Vals: left, Vals: name);
6653 else
6654 outs() << format(Fmt: "0x%08" PRIx32, Vals: module.name)
6655 << "(not in an __OBJC section)";
6656 outs() << "\n";
6657
6658 r = get_pointer_32(Address: module.symtab, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6659 if (module.symtab == 0 || r == nullptr) {
6660 outs() << " symtab " << format(Fmt: "0x%08" PRIx32, Vals: module.symtab)
6661 << " (not in an __OBJC section)\n";
6662 continue;
6663 }
6664 outs() << " symtab " << format(Fmt: "0x%08" PRIx32, Vals: module.symtab) << "\n";
6665 memset(s: &symtab, c: '\0', n: sizeof(struct objc_symtab_t));
6666 defs_left = 0;
6667 defs = nullptr;
6668 if (left < sizeof(struct objc_symtab_t)) {
6669 memcpy(dest: &symtab, src: r, n: left);
6670 outs() << "\tsymtab extends past end of an __OBJC section)\n";
6671 } else {
6672 memcpy(dest: &symtab, src: r, n: sizeof(struct objc_symtab_t));
6673 if (left > sizeof(struct objc_symtab_t)) {
6674 defs_left = left - sizeof(struct objc_symtab_t);
6675 defs = r + sizeof(struct objc_symtab_t);
6676 }
6677 }
6678 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6679 swapStruct(symtab);
6680
6681 outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
6682 r = get_pointer_32(Address: symtab.refs, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6683 outs() << "\trefs " << format(Fmt: "0x%08" PRIx32, Vals: symtab.refs);
6684 if (r == nullptr)
6685 outs() << " (not in an __OBJC section)";
6686 outs() << "\n";
6687 outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
6688 outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
6689 if (symtab.cls_def_cnt > 0)
6690 outs() << "\tClass Definitions\n";
6691 for (j = 0; j < symtab.cls_def_cnt; j++) {
6692 if ((j + 1) * sizeof(uint32_t) > defs_left) {
6693 outs() << "\t(remaining class defs entries entends past the end of the "
6694 << "section)\n";
6695 break;
6696 }
6697 memcpy(dest: &def, src: defs + j * sizeof(uint32_t), n: sizeof(uint32_t));
6698 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6699 sys::swapByteOrder(Value&: def);
6700
6701 r = get_pointer_32(Address: def, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6702 outs() << "\tdefs[" << j << "] " << format(Fmt: "0x%08" PRIx32, Vals: def);
6703 if (r != nullptr) {
6704 if (left > sizeof(struct objc_class_t)) {
6705 outs() << "\n";
6706 memcpy(dest: &objc_class, src: r, n: sizeof(struct objc_class_t));
6707 } else {
6708 outs() << " (entends past the end of the section)\n";
6709 memset(s: &objc_class, c: '\0', n: sizeof(struct objc_class_t));
6710 memcpy(dest: &objc_class, src: r, n: left);
6711 }
6712 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6713 swapStruct(objc_class);
6714 print_objc_class_t(objc_class: &objc_class, info: &info);
6715 } else {
6716 outs() << "(not in an __OBJC section)\n";
6717 }
6718
6719 if (CLS_GETINFO(&objc_class, CLS_CLASS)) {
6720 outs() << "\tMeta Class";
6721 r = get_pointer_32(Address: objc_class.isa, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6722 if (r != nullptr) {
6723 if (left > sizeof(struct objc_class_t)) {
6724 outs() << "\n";
6725 memcpy(dest: &objc_class, src: r, n: sizeof(struct objc_class_t));
6726 } else {
6727 outs() << " (entends past the end of the section)\n";
6728 memset(s: &objc_class, c: '\0', n: sizeof(struct objc_class_t));
6729 memcpy(dest: &objc_class, src: r, n: left);
6730 }
6731 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6732 swapStruct(objc_class);
6733 print_objc_class_t(objc_class: &objc_class, info: &info);
6734 } else {
6735 outs() << "(not in an __OBJC section)\n";
6736 }
6737 }
6738 }
6739 if (symtab.cat_def_cnt > 0)
6740 outs() << "\tCategory Definitions\n";
6741 for (j = 0; j < symtab.cat_def_cnt; j++) {
6742 if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
6743 outs() << "\t(remaining category defs entries entends past the end of "
6744 << "the section)\n";
6745 break;
6746 }
6747 memcpy(dest: &def, src: defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
6748 n: sizeof(uint32_t));
6749 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6750 sys::swapByteOrder(Value&: def);
6751
6752 r = get_pointer_32(Address: def, offset&: xoffset, left, S&: xS, info: &info, objc_only: true);
6753 outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
6754 << format(Fmt: "0x%08" PRIx32, Vals: def);
6755 if (r != nullptr) {
6756 if (left > sizeof(struct objc_category_t)) {
6757 outs() << "\n";
6758 memcpy(dest: &objc_category, src: r, n: sizeof(struct objc_category_t));
6759 } else {
6760 outs() << " (entends past the end of the section)\n";
6761 memset(s: &objc_category, c: '\0', n: sizeof(struct objc_category_t));
6762 memcpy(dest: &objc_category, src: r, n: left);
6763 }
6764 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6765 swapStruct(objc_category);
6766 print_objc_objc_category_t(objc_category: &objc_category, info: &info);
6767 } else {
6768 outs() << "(not in an __OBJC section)\n";
6769 }
6770 }
6771 }
6772 const SectionRef II = get_section(O, segname: "__OBJC", sectname: "__image_info");
6773 if (II != SectionRef())
6774 print_image_info(S: II, info: &info);
6775
6776 return true;
6777}
6778
6779static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
6780 uint32_t size, uint32_t addr) {
6781 SymbolAddressMap AddrMap;
6782 CreateSymbolAddressMap(O, AddrMap: &AddrMap);
6783
6784 std::vector<SectionRef> Sections;
6785 append_range(C&: Sections, R: O->sections());
6786
6787 struct DisassembleInfo info(O, &AddrMap, &Sections, true);
6788
6789 const char *p;
6790 struct objc_protocol_t protocol;
6791 uint32_t left, paddr;
6792 for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
6793 memset(s: &protocol, c: '\0', n: sizeof(struct objc_protocol_t));
6794 left = size - (p - sect);
6795 if (left < sizeof(struct objc_protocol_t)) {
6796 outs() << "Protocol extends past end of __protocol section\n";
6797 memcpy(dest: &protocol, src: p, n: left);
6798 } else
6799 memcpy(dest: &protocol, src: p, n: sizeof(struct objc_protocol_t));
6800 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6801 swapStruct(protocol);
6802 paddr = addr + (p - sect);
6803 outs() << "Protocol " << format(Fmt: "0x%" PRIx32, Vals: paddr);
6804 if (print_protocol(p: paddr, indent: 0, info: &info))
6805 outs() << "(not in an __OBJC section)\n";
6806 }
6807}
6808
6809static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
6810 if (O->is64Bit())
6811 printObjc2_64bit_MetaData(O, verbose);
6812 else {
6813 MachO::mach_header H;
6814 H = O->getHeader();
6815 if (H.cputype == MachO::CPU_TYPE_ARM)
6816 printObjc2_32bit_MetaData(O, verbose);
6817 else {
6818 // This is the 32-bit non-arm cputype case. Which is normally
6819 // the first Objective-C ABI. But it may be the case of a
6820 // binary for the iOS simulator which is the second Objective-C
6821 // ABI. In that case printObjc1_32bit_MetaData() will determine that
6822 // and return false.
6823 if (!printObjc1_32bit_MetaData(O, verbose))
6824 printObjc2_32bit_MetaData(O, verbose);
6825 }
6826 }
6827}
6828
6829// GuessLiteralPointer returns a string which for the item in the Mach-O file
6830// for the address passed in as ReferenceValue for printing as a comment with
6831// the instruction and also returns the corresponding type of that item
6832// indirectly through ReferenceType.
6833//
6834// If ReferenceValue is an address of literal cstring then a pointer to the
6835// cstring is returned and ReferenceType is set to
6836// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
6837//
6838// If ReferenceValue is an address of an Objective-C CFString, Selector ref or
6839// Class ref that name is returned and the ReferenceType is set accordingly.
6840//
6841// Lastly, literals which are Symbol address in a literal pool are looked for
6842// and if found the symbol name is returned and ReferenceType is set to
6843// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
6844//
6845// If there is no item in the Mach-O file for the address passed in as
6846// ReferenceValue nullptr is returned and ReferenceType is unchanged.
6847static const char *GuessLiteralPointer(uint64_t ReferenceValue,
6848 uint64_t ReferencePC,
6849 uint64_t *ReferenceType,
6850 struct DisassembleInfo *info) {
6851 // First see if there is an external relocation entry at the ReferencePC.
6852 if (info->O->getHeader().filetype == MachO::MH_OBJECT) {
6853 uint64_t sect_addr = info->S.getAddress();
6854 uint64_t sect_offset = ReferencePC - sect_addr;
6855 bool reloc_found = false;
6856 DataRefImpl Rel;
6857 MachO::any_relocation_info RE;
6858 bool isExtern = false;
6859 SymbolRef Symbol;
6860 for (const RelocationRef &Reloc : info->S.relocations()) {
6861 uint64_t RelocOffset = Reloc.getOffset();
6862 if (RelocOffset == sect_offset) {
6863 Rel = Reloc.getRawDataRefImpl();
6864 RE = info->O->getRelocation(Rel);
6865 if (info->O->isRelocationScattered(RE))
6866 continue;
6867 isExtern = info->O->getPlainRelocationExternal(RE);
6868 if (isExtern) {
6869 symbol_iterator RelocSym = Reloc.getSymbol();
6870 Symbol = *RelocSym;
6871 }
6872 reloc_found = true;
6873 break;
6874 }
6875 }
6876 // If there is an external relocation entry for a symbol in a section
6877 // then used that symbol's value for the value of the reference.
6878 if (reloc_found && isExtern) {
6879 if (info->O->getAnyRelocationPCRel(RE)) {
6880 unsigned Type = info->O->getAnyRelocationType(RE);
6881 if (Type == MachO::X86_64_RELOC_SIGNED) {
6882 ReferenceValue = cantFail(ValOrErr: Symbol.getValue());
6883 }
6884 }
6885 }
6886 }
6887
6888 // Look for literals such as Objective-C CFStrings refs, Selector refs,
6889 // Message refs and Class refs.
6890 bool classref, selref, msgref, cfstring;
6891 uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
6892 selref, msgref, cfstring);
6893 if (classref && pointer_value == 0) {
6894 // Note the ReferenceValue is a pointer into the __objc_classrefs section.
6895 // And the pointer_value in that section is typically zero as it will be
6896 // set by dyld as part of the "bind information".
6897 const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
6898 if (name != nullptr) {
6899 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6900 const char *class_name = strrchr(s: name, c: '$');
6901 if (class_name != nullptr && class_name[1] == '_' &&
6902 class_name[2] != '\0') {
6903 info->class_name = class_name + 2;
6904 return name;
6905 }
6906 }
6907 }
6908
6909 if (classref) {
6910 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6911 const char *name =
6912 get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
6913 if (name != nullptr)
6914 info->class_name = name;
6915 else
6916 name = "bad class ref";
6917 return name;
6918 }
6919
6920 if (cfstring) {
6921 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
6922 const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
6923 return name;
6924 }
6925
6926 if (selref && pointer_value == 0)
6927 pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
6928
6929 if (pointer_value != 0)
6930 ReferenceValue = pointer_value;
6931
6932 const char *name = GuessCstringPointer(ReferenceValue, info);
6933 if (name) {
6934 if (pointer_value != 0 && selref) {
6935 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
6936 info->selector_name = name;
6937 } else if (pointer_value != 0 && msgref) {
6938 info->class_name = nullptr;
6939 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
6940 info->selector_name = name;
6941 } else
6942 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;
6943 return name;
6944 }
6945
6946 // Lastly look for an indirect symbol with this ReferenceValue which is in
6947 // a literal pool. If found return that symbol name.
6948 name = GuessIndirectSymbol(ReferenceValue, info);
6949 if (name) {
6950 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
6951 return name;
6952 }
6953
6954 return nullptr;
6955}
6956
6957// SymbolizerSymbolLookUp is the symbol lookup function passed when creating
6958// the Symbolizer. It looks up the ReferenceValue using the info passed via the
6959// pointer to the struct DisassembleInfo that was passed when MCSymbolizer
6960// is created and returns the symbol name that matches the ReferenceValue or
6961// nullptr if none. The ReferenceType is passed in for the IN type of
6962// reference the instruction is making from the values in defined in the header
6963// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
6964// Out type and the ReferenceName will also be set which is added as a comment
6965// to the disassembled instruction.
6966//
6967// If the symbol name is a C++ mangled name then the demangled name is
6968// returned through ReferenceName and ReferenceType is set to
6969// LLVMDisassembler_ReferenceType_DeMangled_Name .
6970//
6971// When this is called to get a symbol name for a branch target then the
6972// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
6973// SymbolValue will be looked for in the indirect symbol table to determine if
6974// it is an address for a symbol stub. If so then the symbol name for that
6975// stub is returned indirectly through ReferenceName and then ReferenceType is
6976// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
6977//
6978// When this is called with an value loaded via a PC relative load then
6979// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
6980// SymbolValue is checked to be an address of literal pointer, symbol pointer,
6981// or an Objective-C meta data reference. If so the output ReferenceType is
6982// set to correspond to that as well as setting the ReferenceName.
6983static const char *SymbolizerSymbolLookUp(void *DisInfo,
6984 uint64_t ReferenceValue,
6985 uint64_t *ReferenceType,
6986 uint64_t ReferencePC,
6987 const char **ReferenceName) {
6988 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
6989 // If no verbose symbolic information is wanted then just return nullptr.
6990 if (!info->verbose) {
6991 *ReferenceName = nullptr;
6992 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6993 return nullptr;
6994 }
6995
6996 const char *SymbolName = GuessSymbolName(value: ReferenceValue, AddrMap: info->AddrMap);
6997
6998 if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
6999 *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
7000 if (*ReferenceName != nullptr) {
7001 method_reference(info, ReferenceType, ReferenceName);
7002 if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
7003 *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
7004 } else if (SymbolName != nullptr && strncmp(s1: SymbolName, s2: "__Z", n: 3) == 0) {
7005 if (info->demangled_name != nullptr)
7006 free(ptr: info->demangled_name);
7007 info->demangled_name = itaniumDemangle(mangled_name: SymbolName + 1);
7008 if (info->demangled_name != nullptr) {
7009 *ReferenceName = info->demangled_name;
7010 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
7011 } else
7012 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7013 } else
7014 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7015 } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
7016 *ReferenceName =
7017 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7018 if (*ReferenceName)
7019 method_reference(info, ReferenceType, ReferenceName);
7020 else
7021 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7022 // If this is arm64 and the reference is an adrp instruction save the
7023 // instruction, passed in ReferenceValue and the address of the instruction
7024 // for use later if we see and add immediate instruction.
7025 } else if ((info->O->getArch() == Triple::aarch64 ||
7026 info->O->getArch() == Triple::aarch64_32) &&
7027 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
7028 info->adrp_inst = ReferenceValue;
7029 info->adrp_addr = ReferencePC;
7030 SymbolName = nullptr;
7031 *ReferenceName = nullptr;
7032 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7033 // If this is arm64 and reference is an add immediate instruction and we
7034 // have
7035 // seen an adrp instruction just before it and the adrp's Xd register
7036 // matches
7037 // this add's Xn register reconstruct the value being referenced and look to
7038 // see if it is a literal pointer. Note the add immediate instruction is
7039 // passed in ReferenceValue.
7040 } else if ((info->O->getArch() == Triple::aarch64 ||
7041 info->O->getArch() == Triple::aarch64_32) &&
7042 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
7043 ReferencePC - 4 == info->adrp_addr &&
7044 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
7045 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7046 uint32_t addxri_inst;
7047 uint64_t adrp_imm, addxri_imm;
7048
7049 adrp_imm =
7050 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7051 if (info->adrp_inst & 0x0200000)
7052 adrp_imm |= 0xfffffffffc000000LL;
7053
7054 addxri_inst = ReferenceValue;
7055 addxri_imm = (addxri_inst >> 10) & 0xfff;
7056 if (((addxri_inst >> 22) & 0x3) == 1)
7057 addxri_imm <<= 12;
7058
7059 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7060 (adrp_imm << 12) + addxri_imm;
7061
7062 *ReferenceName =
7063 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7064 if (*ReferenceName == nullptr)
7065 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7066 // If this is arm64 and the reference is a load register instruction and we
7067 // have seen an adrp instruction just before it and the adrp's Xd register
7068 // matches this add's Xn register reconstruct the value being referenced and
7069 // look to see if it is a literal pointer. Note the load register
7070 // instruction is passed in ReferenceValue.
7071 } else if ((info->O->getArch() == Triple::aarch64 ||
7072 info->O->getArch() == Triple::aarch64_32) &&
7073 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&
7074 ReferencePC - 4 == info->adrp_addr &&
7075 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
7076 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7077 uint32_t ldrxui_inst;
7078 uint64_t adrp_imm, ldrxui_imm;
7079
7080 adrp_imm =
7081 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7082 if (info->adrp_inst & 0x0200000)
7083 adrp_imm |= 0xfffffffffc000000LL;
7084
7085 ldrxui_inst = ReferenceValue;
7086 ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
7087
7088 // The size field (bits [31:30]) determines the scaling.
7089 unsigned Scale = (ldrxui_inst >> 30) & 0x3;
7090 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7091 (adrp_imm << 12) + (ldrxui_imm << Scale);
7092
7093 *ReferenceName =
7094 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7095 if (*ReferenceName == nullptr)
7096 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7097 }
7098 // If this arm64 and is an load register (PC-relative) instruction the
7099 // ReferenceValue is the PC plus the immediate value.
7100 else if ((info->O->getArch() == Triple::aarch64 ||
7101 info->O->getArch() == Triple::aarch64_32) &&
7102 (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||
7103 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {
7104 *ReferenceName =
7105 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7106 if (*ReferenceName == nullptr)
7107 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7108 } else if (SymbolName != nullptr && strncmp(s1: SymbolName, s2: "__Z", n: 3) == 0) {
7109 if (info->demangled_name != nullptr)
7110 free(ptr: info->demangled_name);
7111 info->demangled_name = itaniumDemangle(mangled_name: SymbolName + 1);
7112 if (info->demangled_name != nullptr) {
7113 *ReferenceName = info->demangled_name;
7114 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
7115 }
7116 } else {
7117 *ReferenceName = nullptr;
7118 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7119 }
7120
7121 return SymbolName;
7122}
7123
7124/// Emits the comments that are stored in the CommentStream.
7125/// Each comment in the CommentStream must end with a newline.
7126static void emitComments(raw_svector_ostream &CommentStream,
7127 SmallString<128> &CommentsToEmit,
7128 formatted_raw_ostream &FormattedOS,
7129 const MCAsmInfo &MAI) {
7130 // Flush the stream before taking its content.
7131 StringRef Comments = CommentsToEmit.str();
7132 // Get the default information for printing a comment.
7133 StringRef CommentBegin = MAI.getCommentString();
7134 unsigned CommentColumn = MAI.getCommentColumn();
7135 ListSeparator LS("\n");
7136 while (!Comments.empty()) {
7137 FormattedOS << LS;
7138 // Emit a line of comments.
7139 FormattedOS.PadToColumn(NewCol: CommentColumn);
7140 size_t Position = Comments.find(C: '\n');
7141 FormattedOS << CommentBegin << ' ' << Comments.substr(Start: 0, N: Position);
7142 // Move after the newline character.
7143 Comments = Comments.substr(Start: Position + 1);
7144 }
7145 FormattedOS.flush();
7146
7147 // Tell the comment stream that the vector changed underneath it.
7148 CommentsToEmit.clear();
7149}
7150
7151const MachOObjectFile *
7152objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,
7153 std::unique_ptr<Binary> &DSYMBinary,
7154 std::unique_ptr<MemoryBuffer> &DSYMBuf) {
7155 const MachOObjectFile *DbgObj = MachOOF;
7156 std::string DSYMPath;
7157
7158 // Auto-detect w/o --dsym.
7159 if (DSYMFile.empty()) {
7160 sys::fs::file_status DSYMStatus;
7161 Twine FilenameDSYM = Filename + ".dSYM";
7162 if (!status(path: FilenameDSYM, result&: DSYMStatus)) {
7163 if (sys::fs::is_directory(status: DSYMStatus)) {
7164 SmallString<1024> Path;
7165 FilenameDSYM.toVector(Out&: Path);
7166 sys::path::append(path&: Path, a: "Contents", b: "Resources", c: "DWARF",
7167 d: sys::path::filename(path: Filename));
7168 DSYMPath = std::string(Path);
7169 } else if (sys::fs::is_regular_file(status: DSYMStatus)) {
7170 DSYMPath = FilenameDSYM.str();
7171 }
7172 }
7173 }
7174
7175 if (DSYMPath.empty() && !DSYMFile.empty()) {
7176 // If DSYMPath is a .dSYM directory, append the Mach-O file.
7177 if (sys::fs::is_directory(Path: DSYMFile) &&
7178 sys::path::extension(path: DSYMFile) == ".dSYM") {
7179 SmallString<128> ShortName(sys::path::filename(path: DSYMFile));
7180 sys::path::replace_extension(path&: ShortName, extension: "");
7181 SmallString<1024> FullPath(DSYMFile);
7182 sys::path::append(path&: FullPath, a: "Contents", b: "Resources", c: "DWARF", d: ShortName);
7183 DSYMPath = FullPath.str();
7184 } else {
7185 DSYMPath = DSYMFile;
7186 }
7187 }
7188
7189 if (!DSYMPath.empty()) {
7190 // Load the file.
7191 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
7192 MemoryBuffer::getFileOrSTDIN(Filename: DSYMPath);
7193 if (std::error_code EC = BufOrErr.getError()) {
7194 reportError(E: errorCodeToError(EC), FileName: DSYMPath);
7195 return nullptr;
7196 }
7197
7198 // We need to keep the file alive, because we're replacing DbgObj with it.
7199 DSYMBuf = std::move(BufOrErr.get());
7200
7201 Expected<std::unique_ptr<Binary>> BinaryOrErr =
7202 createBinary(Source: DSYMBuf->getMemBufferRef());
7203 if (!BinaryOrErr) {
7204 reportError(E: BinaryOrErr.takeError(), FileName: DSYMPath);
7205 return nullptr;
7206 }
7207
7208 // We need to keep the Binary alive with the buffer
7209 DSYMBinary = std::move(BinaryOrErr.get());
7210 if (ObjectFile *O = dyn_cast<ObjectFile>(Val: DSYMBinary.get())) {
7211 // this is a Mach-O object file, use it
7212 if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(Val: &*O)) {
7213 DbgObj = MachDSYM;
7214 } else {
7215 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
7216 << DSYMPath << " is not a Mach-O file type.\n";
7217 return nullptr;
7218 }
7219 } else if (auto *UB = dyn_cast<MachOUniversalBinary>(Val: DSYMBinary.get())) {
7220 // this is a Universal Binary, find a Mach-O for this architecture
7221 uint32_t CPUType, CPUSubType;
7222 const char *ArchFlag;
7223 if (MachOOF->is64Bit()) {
7224 const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
7225 CPUType = H_64.cputype;
7226 CPUSubType = H_64.cpusubtype;
7227 } else {
7228 const MachO::mach_header H = MachOOF->getHeader();
7229 CPUType = H.cputype;
7230 CPUSubType = H.cpusubtype;
7231 }
7232 Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, McpuDefault: nullptr,
7233 ArchFlag: &ArchFlag);
7234 Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
7235 UB->getMachOObjectForArch(ArchName: ArchFlag);
7236 if (!MachDSYM) {
7237 reportError(E: MachDSYM.takeError(), FileName: DSYMPath);
7238 return nullptr;
7239 }
7240
7241 // We need to keep the Binary alive with the buffer
7242 DbgObj = &*MachDSYM.get();
7243 DSYMBinary = std::move(*MachDSYM);
7244 } else {
7245 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
7246 << DSYMPath << " is not a Mach-O or Universal file type.\n";
7247 return nullptr;
7248 }
7249 }
7250 return DbgObj;
7251}
7252
7253static bool shouldInstPrinterUseColor() {
7254 switch (DisassemblyColor) {
7255 case ColorOutput::Enable:
7256 return true;
7257 case ColorOutput::Auto:
7258 return outs().has_colors();
7259 case ColorOutput::Disable:
7260 case ColorOutput::Invalid:
7261 return false;
7262 }
7263 return false;
7264}
7265
7266static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
7267 StringRef DisSegName, StringRef DisSectName) {
7268 const char *McpuDefault = nullptr;
7269 const Target *ThumbTarget = nullptr;
7270 Triple ThumbTriple;
7271 const Target *TheTarget =
7272 GetTarget(MachOObj: MachOOF, McpuDefault: &McpuDefault, ThumbTarget: &ThumbTarget, ThumbTriple);
7273 if (!TheTarget) {
7274 // GetTarget prints out stuff.
7275 return;
7276 }
7277 std::string MachOMCPU;
7278 if (MCPU.empty() && McpuDefault)
7279 MachOMCPU = McpuDefault;
7280 else
7281 MachOMCPU = MCPU;
7282
7283#define CHECK_TARGET_INFO_CREATION(NAME) \
7284 do { \
7285 if (!NAME) { \
7286 WithColor::error(errs(), "llvm-objdump") \
7287 << "couldn't initialize disassembler for target " << TripleName \
7288 << '\n'; \
7289 return; \
7290 } \
7291 } while (false)
7292#define CHECK_THUMB_TARGET_INFO_CREATION(NAME) \
7293 do { \
7294 if (!NAME) { \
7295 WithColor::error(errs(), "llvm-objdump") \
7296 << "couldn't initialize disassembler for target " << ThumbTripleName \
7297 << '\n'; \
7298 return; \
7299 } \
7300 } while (false)
7301
7302 std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
7303 CHECK_TARGET_INFO_CREATION(InstrInfo);
7304 std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
7305 if (ThumbTarget) {
7306 ThumbInstrInfo.reset(p: ThumbTarget->createMCInstrInfo());
7307 CHECK_THUMB_TARGET_INFO_CREATION(ThumbInstrInfo);
7308 }
7309
7310 // Package up features to be passed to target/subtarget
7311 std::string FeaturesStr;
7312 if (!MAttrs.empty()) {
7313 SubtargetFeatures Features;
7314 for (unsigned i = 0; i != MAttrs.size(); ++i)
7315 Features.AddFeature(String: MAttrs[i]);
7316 FeaturesStr = Features.getString();
7317 }
7318
7319 Triple TheTriple(TripleName);
7320
7321 MCTargetOptions MCOptions;
7322 // Set up disassembler.
7323 std::unique_ptr<const MCRegisterInfo> MRI(
7324 TheTarget->createMCRegInfo(TT: TheTriple));
7325 CHECK_TARGET_INFO_CREATION(MRI);
7326 std::unique_ptr<const MCAsmInfo> AsmInfo(
7327 TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple, Options: MCOptions));
7328 CHECK_TARGET_INFO_CREATION(AsmInfo);
7329 std::unique_ptr<const MCSubtargetInfo> STI(
7330 TheTarget->createMCSubtargetInfo(TheTriple, CPU: MachOMCPU, Features: FeaturesStr));
7331 CHECK_TARGET_INFO_CREATION(STI);
7332 MCContext Ctx(TheTriple, AsmInfo.get(), MRI.get(), STI.get());
7333 std::unique_ptr<MCDisassembler> DisAsm(
7334 TheTarget->createMCDisassembler(STI: *STI, Ctx));
7335 CHECK_TARGET_INFO_CREATION(DisAsm);
7336 std::unique_ptr<MCSymbolizer> Symbolizer;
7337 struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);
7338 std::unique_ptr<MCRelocationInfo> RelInfo(
7339 TheTarget->createMCRelocationInfo(TT: TheTriple, Ctx));
7340 if (RelInfo) {
7341 Symbolizer.reset(p: TheTarget->createMCSymbolizer(
7342 TT: TheTriple, GetOpInfo: SymbolizerGetOpInfo, SymbolLookUp: SymbolizerSymbolLookUp, DisInfo: &SymbolizerInfo,
7343 Ctx: &Ctx, RelInfo: std::move(RelInfo)));
7344 DisAsm->setSymbolizer(std::move(Symbolizer));
7345 }
7346 int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
7347 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
7348 T: TheTriple, SyntaxVariant: AsmPrinterVariant, MAI: *AsmInfo, MII: *InstrInfo, MRI: *MRI));
7349 CHECK_TARGET_INFO_CREATION(IP);
7350 IP->setPrintImmHex(PrintImmHex);
7351 IP->setUseColor(shouldInstPrinterUseColor());
7352
7353 // Comment stream and backing vector.
7354 SmallString<128> CommentsToEmit;
7355 raw_svector_ostream CommentStream(CommentsToEmit);
7356 // FIXME: Setting the CommentStream in the InstPrinter is problematic in that
7357 // if it is done then arm64 comments for string literals don't get printed
7358 // and some constant get printed instead and not setting it causes intel
7359 // (32-bit and 64-bit) comments printed with different spacing before the
7360 // comment causing different diffs with the 'C' disassembler library API.
7361 // IP->setCommentStream(CommentStream);
7362
7363 for (StringRef Opt : DisassemblerOptions)
7364 if (!IP->applyTargetSpecificCLOption(Opt))
7365 reportError(File: Filename, Message: "unrecognized disassembler option: " + Opt);
7366
7367 // Set up separate thumb disassembler if needed.
7368 std::unique_ptr<const MCRegisterInfo> ThumbMRI;
7369 std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
7370 std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
7371 std::unique_ptr<MCDisassembler> ThumbDisAsm;
7372 std::unique_ptr<MCInstPrinter> ThumbIP;
7373 std::unique_ptr<MCContext> ThumbCtx;
7374 std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
7375 struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);
7376 std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
7377 if (ThumbTarget) {
7378 ThumbMRI.reset(p: ThumbTarget->createMCRegInfo(TT: ThumbTriple));
7379 CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);
7380 ThumbAsmInfo.reset(
7381 p: ThumbTarget->createMCAsmInfo(MRI: *ThumbMRI, TheTriple: ThumbTriple, Options: MCOptions));
7382 CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);
7383 ThumbSTI.reset(p: ThumbTarget->createMCSubtargetInfo(TheTriple: ThumbTriple, CPU: MachOMCPU,
7384 Features: FeaturesStr));
7385 CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);
7386 ThumbCtx.reset(p: new MCContext(ThumbTriple, ThumbAsmInfo.get(),
7387 ThumbMRI.get(), ThumbSTI.get()));
7388 ThumbDisAsm.reset(p: ThumbTarget->createMCDisassembler(STI: *ThumbSTI, Ctx&: *ThumbCtx));
7389 CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);
7390 MCContext *PtrThumbCtx = ThumbCtx.get();
7391 ThumbRelInfo.reset(
7392 p: ThumbTarget->createMCRelocationInfo(TT: ThumbTriple, Ctx&: *PtrThumbCtx));
7393 if (ThumbRelInfo) {
7394 ThumbSymbolizer.reset(p: ThumbTarget->createMCSymbolizer(
7395 TT: ThumbTriple, GetOpInfo: SymbolizerGetOpInfo, SymbolLookUp: SymbolizerSymbolLookUp,
7396 DisInfo: &ThumbSymbolizerInfo, Ctx: PtrThumbCtx, RelInfo: std::move(ThumbRelInfo)));
7397 ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
7398 }
7399 int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
7400 ThumbIP.reset(p: ThumbTarget->createMCInstPrinter(
7401 T: ThumbTriple, SyntaxVariant: ThumbAsmPrinterVariant, MAI: *ThumbAsmInfo, MII: *ThumbInstrInfo,
7402 MRI: *ThumbMRI));
7403 CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);
7404 ThumbIP->setPrintImmHex(PrintImmHex);
7405 ThumbIP->setUseColor(shouldInstPrinterUseColor());
7406 }
7407
7408#undef CHECK_TARGET_INFO_CREATION
7409#undef CHECK_THUMB_TARGET_INFO_CREATION
7410
7411 MachO::mach_header Header = MachOOF->getHeader();
7412
7413 // FIXME: Using the -cfg command line option, this code used to be able to
7414 // annotate relocations with the referenced symbol's name, and if this was
7415 // inside a __[cf]string section, the data it points to. This is now replaced
7416 // by the upcoming MCSymbolizer, which needs the appropriate setup done above.
7417 std::vector<SectionRef> Sections;
7418 std::vector<SymbolRef> Symbols;
7419 SmallVector<uint64_t, 8> FoundFns;
7420 uint64_t BaseSegmentAddress = 0;
7421
7422 getSectionsAndSymbols(MachOObj: MachOOF, Sections, Symbols, FoundFns,
7423 BaseSegmentAddress);
7424
7425 // Sort the symbols by address, just in case they didn't come in that way.
7426 llvm::stable_sort(Range&: Symbols, C: SymbolSorter());
7427
7428 // Build a data in code table that is sorted on by the address of each entry.
7429 uint64_t BaseAddress = 0;
7430 if (Header.filetype == MachO::MH_OBJECT)
7431 BaseAddress = Sections[0].getAddress();
7432 else
7433 BaseAddress = BaseSegmentAddress;
7434 DiceTable Dices;
7435 for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
7436 DI != DE; ++DI) {
7437 uint32_t Offset;
7438 DI->getOffset(Result&: Offset);
7439 Dices.push_back(x: std::make_pair(x: BaseAddress + Offset, y: *DI));
7440 }
7441 array_pod_sort(Start: Dices.begin(), End: Dices.end());
7442
7443 // Try to find debug info and set up the DIContext for it.
7444 std::unique_ptr<DIContext> diContext;
7445 std::unique_ptr<Binary> DSYMBinary;
7446 std::unique_ptr<MemoryBuffer> DSYMBuf;
7447 const ObjectFile *DbgObj = MachOOF;
7448 if (UseDbg || PrintSource || PrintLines) {
7449 // Look for debug info in external dSYM file or embedded in the object.
7450 // getMachODSymObject returns MachOOF by default if no external dSYM found.
7451 const ObjectFile *DSym =
7452 getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf);
7453 if (!DSym)
7454 return;
7455 DbgObj = DSym;
7456 if (UseDbg || PrintLines) {
7457 // Setup the DIContext
7458 diContext = DWARFContext::create(Obj: *DbgObj);
7459 }
7460 }
7461
7462 std::optional<SourcePrinter> SP;
7463 std::optional<LiveElementPrinter> LEP;
7464 if (PrintSource || PrintLines) {
7465 SP.emplace(args&: DbgObj, args: TheTarget->getName());
7466 LEP.emplace(args: *MRI, args: *STI);
7467 }
7468
7469 if (FilterSections.empty())
7470 outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
7471
7472 for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
7473 Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();
7474 if (!SecNameOrErr) {
7475 consumeError(Err: SecNameOrErr.takeError());
7476 continue;
7477 }
7478 if (*SecNameOrErr != DisSectName)
7479 continue;
7480
7481 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
7482
7483 StringRef SegmentName = MachOOF->getSectionFinalSegmentName(Sec: DR);
7484 if (SegmentName != DisSegName)
7485 continue;
7486
7487 StringRef BytesStr =
7488 unwrapOrError(EO: Sections[SectIdx].getContents(), Args&: Filename);
7489 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Input: BytesStr);
7490 uint64_t SectAddress = Sections[SectIdx].getAddress();
7491
7492 bool symbolTableWorked = false;
7493
7494 // Create a map of symbol addresses to symbol names for use by
7495 // the SymbolizerSymbolLookUp() routine.
7496 SymbolAddressMap AddrMap;
7497 bool DisSymNameFound = false;
7498 for (const SymbolRef &Symbol : MachOOF->symbols()) {
7499 SymbolRef::Type ST =
7500 unwrapOrError(EO: Symbol.getType(), Args: MachOOF->getFileName());
7501 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
7502 ST == SymbolRef::ST_Other) {
7503 uint64_t Address = cantFail(ValOrErr: Symbol.getValue());
7504 StringRef SymName =
7505 unwrapOrError(EO: Symbol.getName(), Args: MachOOF->getFileName());
7506 AddrMap[Address] = SymName;
7507 if (!DisSymName.empty() && DisSymName == SymName)
7508 DisSymNameFound = true;
7509 }
7510 }
7511 if (!DisSymName.empty() && !DisSymNameFound) {
7512 outs() << "Can't find " << (IsOtool ? "-p symbol" : "--dis-symname")
7513 << ": " << DisSymName << "\n";
7514 return;
7515 }
7516 // Set up the block of info used by the Symbolizer call backs.
7517 SymbolizerInfo.verbose = SymbolicOperands;
7518 SymbolizerInfo.O = MachOOF;
7519 SymbolizerInfo.S = Sections[SectIdx];
7520 SymbolizerInfo.AddrMap = &AddrMap;
7521 SymbolizerInfo.Sections = &Sections;
7522 // Same for the ThumbSymbolizer
7523 ThumbSymbolizerInfo.verbose = SymbolicOperands;
7524 ThumbSymbolizerInfo.O = MachOOF;
7525 ThumbSymbolizerInfo.S = Sections[SectIdx];
7526 ThumbSymbolizerInfo.AddrMap = &AddrMap;
7527 ThumbSymbolizerInfo.Sections = &Sections;
7528
7529 unsigned int Arch = MachOOF->getArch();
7530
7531 // Skip all symbols if this is a stubs file.
7532 if (Bytes.empty())
7533 return;
7534
7535 // If the section has symbols but no symbol at the start of the section
7536 // these are used to make sure the bytes before the first symbol are
7537 // disassembled.
7538 bool FirstSymbol = true;
7539 bool FirstSymbolAtSectionStart = true;
7540
7541 // Disassemble symbol by symbol.
7542 for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
7543 StringRef SymName =
7544 unwrapOrError(EO: Symbols[SymIdx].getName(), Args: MachOOF->getFileName());
7545 SymbolRef::Type ST =
7546 unwrapOrError(EO: Symbols[SymIdx].getType(), Args: MachOOF->getFileName());
7547 if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
7548 continue;
7549
7550 // Make sure the symbol is defined in this section.
7551 bool containsSym = Sections[SectIdx].containsSymbol(S: Symbols[SymIdx]);
7552 if (!containsSym) {
7553 if (!DisSymName.empty() && DisSymName == SymName) {
7554 outs() << (IsOtool ? "-p symbol" : "--dis-symname") << ": "
7555 << DisSymName << " not in the section\n";
7556 return;
7557 }
7558 continue;
7559 }
7560 // The __mh_execute_header is special and we need to deal with that fact
7561 // this symbol is before the start of the (__TEXT,__text) section and at the
7562 // address of the start of the __TEXT segment. This is because this symbol
7563 // is an N_SECT symbol in the (__TEXT,__text) but its address is before the
7564 // start of the section in a standard MH_EXECUTE filetype.
7565 if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {
7566 outs() << (IsOtool ? "-p symbol" : "--dis-symname")
7567 << ": __mh_execute_header not in any section\n";
7568 return;
7569 }
7570 // When this code is trying to disassemble a symbol at a time and in the
7571 // case there is only the __mh_execute_header symbol left as in a stripped
7572 // executable, we need to deal with this by ignoring this symbol so the
7573 // whole section is disassembled and this symbol is then not displayed.
7574 if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||
7575 SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||
7576 SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")
7577 continue;
7578
7579 // If we are only disassembling one symbol see if this is that symbol.
7580 if (!DisSymName.empty() && DisSymName != SymName)
7581 continue;
7582
7583 // Start at the address of the symbol relative to the section's address.
7584 uint64_t SectSize = Sections[SectIdx].getSize();
7585 uint64_t Start = cantFail(ValOrErr: Symbols[SymIdx].getValue());
7586 uint64_t SectionAddress = Sections[SectIdx].getAddress();
7587 Start -= SectionAddress;
7588
7589 if (Start > SectSize) {
7590 outs() << "section data ends, " << SymName
7591 << " lies outside valid range\n";
7592 return;
7593 }
7594
7595 // Stop disassembling either at the beginning of the next symbol or at
7596 // the end of the section.
7597 bool containsNextSym = false;
7598 uint64_t NextSym = 0;
7599 uint64_t NextSymIdx = SymIdx + 1;
7600 while (Symbols.size() > NextSymIdx) {
7601 SymbolRef::Type NextSymType = unwrapOrError(
7602 EO: Symbols[NextSymIdx].getType(), Args: MachOOF->getFileName());
7603 if (NextSymType == SymbolRef::ST_Function) {
7604 containsNextSym =
7605 Sections[SectIdx].containsSymbol(S: Symbols[NextSymIdx]);
7606 NextSym = cantFail(ValOrErr: Symbols[NextSymIdx].getValue());
7607 NextSym -= SectionAddress;
7608 break;
7609 }
7610 ++NextSymIdx;
7611 }
7612
7613 uint64_t End = containsNextSym ? std::min(a: NextSym, b: SectSize) : SectSize;
7614 uint64_t Size;
7615
7616 symbolTableWorked = true;
7617
7618 DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
7619 uint32_t SymbolFlags = cantFail(ValOrErr: MachOOF->getSymbolFlags(Symb));
7620 bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;
7621
7622 // We only need the dedicated Thumb target if there's a real choice
7623 // (i.e. we're not targeting M-class) and the function is Thumb.
7624 bool UseThumbTarget = IsThumb && ThumbTarget;
7625
7626 // If we are not specifying a symbol to start disassembly with and this
7627 // is the first symbol in the section but not at the start of the section
7628 // then move the disassembly index to the start of the section and
7629 // don't print the symbol name just yet. This is so the bytes before the
7630 // first symbol are disassembled.
7631 uint64_t SymbolStart = Start;
7632 if (DisSymName.empty() && FirstSymbol && Start != 0) {
7633 FirstSymbolAtSectionStart = false;
7634 Start = 0;
7635 }
7636 else
7637 outs() << SymName << ":\n";
7638
7639 DILineInfo lastLine;
7640 for (uint64_t Index = Start; Index < End; Index += Size) {
7641 MCInst Inst;
7642
7643 // If this is the first symbol in the section and it was not at the
7644 // start of the section, see if we are at its Index now and if so print
7645 // the symbol name.
7646 if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
7647 outs() << SymName << ":\n";
7648
7649 uint64_t PC = SectAddress + Index;
7650
7651 if (PrintSource || PrintLines) {
7652 formatted_raw_ostream FOS(outs());
7653 SP->printSourceLine(OS&: FOS, Address: {.Address: PC, .SectionIndex: SectIdx}, ObjectFilename: Filename, LEP&: *LEP);
7654 }
7655
7656 if (LeadingAddr) {
7657 if (FullLeadingAddr) {
7658 if (MachOOF->is64Bit())
7659 outs() << format(Fmt: "%016" PRIx64, Vals: PC);
7660 else
7661 outs() << format(Fmt: "%08" PRIx64, Vals: PC);
7662 } else {
7663 outs() << format(Fmt: "%8" PRIx64 ":", Vals: PC);
7664 }
7665 }
7666 if (ShowRawInsn || Arch == Triple::arm)
7667 outs() << "\t";
7668
7669 if (DumpAndSkipDataInCode(PC, bytes: Bytes.data() + Index, Dices, InstSize&: Size))
7670 continue;
7671
7672 SmallVector<char, 64> AnnotationsBytes;
7673 raw_svector_ostream Annotations(AnnotationsBytes);
7674
7675 bool gotInst;
7676 if (UseThumbTarget)
7677 gotInst = ThumbDisAsm->getInstruction(Instr&: Inst, Size, Bytes: Bytes.slice(N: Index),
7678 Address: PC, CStream&: Annotations);
7679 else
7680 gotInst = DisAsm->getInstruction(Instr&: Inst, Size, Bytes: Bytes.slice(N: Index), Address: PC,
7681 CStream&: Annotations);
7682 if (gotInst) {
7683 if (ShowRawInsn || Arch == Triple::arm) {
7684 dumpBytes(Bytes: ArrayRef(Bytes.data() + Index, Size), OS&: outs());
7685 }
7686 formatted_raw_ostream FormattedOS(outs());
7687 StringRef AnnotationsStr = Annotations.str();
7688 if (UseThumbTarget)
7689 ThumbIP->printInst(MI: &Inst, Address: PC, Annot: AnnotationsStr, STI: *ThumbSTI,
7690 OS&: FormattedOS);
7691 else
7692 IP->printInst(MI: &Inst, Address: PC, Annot: AnnotationsStr, STI: *STI, OS&: FormattedOS);
7693 emitComments(CommentStream, CommentsToEmit, FormattedOS, MAI: *AsmInfo);
7694
7695 // Print debug info.
7696 if (diContext) {
7697 DILineInfo dli = diContext->getLineInfoForAddress(Address: {.Address: PC, .SectionIndex: SectIdx})
7698 .value_or(u: DILineInfo());
7699 // Print valid line info if it changed.
7700 if (dli != lastLine && dli.Line != 0)
7701 outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
7702 << dli.Column;
7703 lastLine = dli;
7704 }
7705 outs() << "\n";
7706 } else {
7707 if (MachOOF->getArchTriple().isX86()) {
7708 outs() << format(Fmt: "\t.byte 0x%02x #bad opcode\n",
7709 Vals: *(Bytes.data() + Index) & 0xff);
7710 Size = 1; // skip exactly one illegible byte and move on.
7711 } else if (Arch == Triple::aarch64 || Arch == Triple::aarch64_32 ||
7712 (Arch == Triple::arm && !IsThumb)) {
7713 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7714 (*(Bytes.data() + Index + 1) & 0xff) << 8 |
7715 (*(Bytes.data() + Index + 2) & 0xff) << 16 |
7716 (*(Bytes.data() + Index + 3) & 0xff) << 24;
7717 outs() << format(Fmt: "\t.long\t0x%08x\n", Vals: opcode);
7718 Size = 4;
7719 } else if (Arch == Triple::arm) {
7720 assert(IsThumb && "ARM mode should have been dealt with above");
7721 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7722 (*(Bytes.data() + Index + 1) & 0xff) << 8;
7723 outs() << format(Fmt: "\t.short\t0x%04x\n", Vals: opcode);
7724 Size = 2;
7725 } else {
7726 WithColor::warning(OS&: errs(), Prefix: "llvm-objdump")
7727 << "invalid instruction encoding\n";
7728 if (Size == 0)
7729 Size = 1; // skip illegible bytes
7730 }
7731 }
7732 }
7733 // Now that we are done disassembled the first symbol set the bool that
7734 // were doing this to false.
7735 FirstSymbol = false;
7736 }
7737 if (!symbolTableWorked) {
7738 // Reading the symbol table didn't work, disassemble the whole section.
7739 uint64_t SectAddress = Sections[SectIdx].getAddress();
7740 uint64_t SectSize = Sections[SectIdx].getSize();
7741 uint64_t InstSize;
7742 for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
7743 MCInst Inst;
7744
7745 uint64_t PC = SectAddress + Index;
7746
7747 if (PrintSource || PrintLines) {
7748 formatted_raw_ostream FOS(outs());
7749 SP->printSourceLine(OS&: FOS, Address: {.Address: PC, .SectionIndex: SectIdx}, ObjectFilename: Filename, LEP&: *LEP);
7750 }
7751
7752 if (DumpAndSkipDataInCode(PC, bytes: Bytes.data() + Index, Dices, InstSize))
7753 continue;
7754
7755 SmallVector<char, 64> AnnotationsBytes;
7756 raw_svector_ostream Annotations(AnnotationsBytes);
7757 if (DisAsm->getInstruction(Instr&: Inst, Size&: InstSize, Bytes: Bytes.slice(N: Index), Address: PC,
7758 CStream&: Annotations)) {
7759 if (LeadingAddr) {
7760 if (FullLeadingAddr) {
7761 if (MachOOF->is64Bit())
7762 outs() << format(Fmt: "%016" PRIx64, Vals: PC);
7763 else
7764 outs() << format(Fmt: "%08" PRIx64, Vals: PC);
7765 } else {
7766 outs() << format(Fmt: "%8" PRIx64 ":", Vals: PC);
7767 }
7768 }
7769 if (ShowRawInsn || Arch == Triple::arm) {
7770 outs() << "\t";
7771 dumpBytes(Bytes: ArrayRef(Bytes.data() + Index, InstSize), OS&: outs());
7772 }
7773 StringRef AnnotationsStr = Annotations.str();
7774 IP->printInst(MI: &Inst, Address: PC, Annot: AnnotationsStr, STI: *STI, OS&: outs());
7775 outs() << "\n";
7776 } else {
7777 if (MachOOF->getArchTriple().isX86()) {
7778 outs() << format(Fmt: "\t.byte 0x%02x #bad opcode\n",
7779 Vals: *(Bytes.data() + Index) & 0xff);
7780 InstSize = 1; // skip exactly one illegible byte and move on.
7781 } else {
7782 WithColor::warning(OS&: errs(), Prefix: "llvm-objdump")
7783 << "invalid instruction encoding\n";
7784 if (InstSize == 0)
7785 InstSize = 1; // skip illegible bytes
7786 }
7787 }
7788 }
7789 }
7790 // The TripleName's need to be reset if we are called again for a different
7791 // architecture.
7792 TripleName = "";
7793 ThumbTripleName = "";
7794
7795 if (SymbolizerInfo.demangled_name != nullptr)
7796 free(ptr: SymbolizerInfo.demangled_name);
7797 if (ThumbSymbolizerInfo.demangled_name != nullptr)
7798 free(ptr: ThumbSymbolizerInfo.demangled_name);
7799 }
7800}
7801
7802//===----------------------------------------------------------------------===//
7803// __compact_unwind section dumping
7804//===----------------------------------------------------------------------===//
7805
7806namespace {
7807
7808template <typename T>
7809static uint64_t read(StringRef Contents, ptrdiff_t Offset) {
7810 if (Offset + sizeof(T) > Contents.size()) {
7811 outs() << "warning: attempt to read past end of buffer\n";
7812 return T();
7813 }
7814
7815 uint64_t Val = support::endian::read<T, llvm::endianness::little>(
7816 Contents.data() + Offset);
7817 return Val;
7818}
7819
7820template <typename T>
7821static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {
7822 T Val = read<T>(Contents, Offset);
7823 Offset += sizeof(T);
7824 return Val;
7825}
7826
7827struct CompactUnwindEntry {
7828 uint32_t OffsetInSection;
7829
7830 uint64_t FunctionAddr;
7831 uint32_t Length;
7832 uint32_t CompactEncoding;
7833 uint64_t PersonalityAddr;
7834 uint64_t LSDAAddr;
7835
7836 RelocationRef FunctionReloc;
7837 RelocationRef PersonalityReloc;
7838 RelocationRef LSDAReloc;
7839
7840 CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
7841 : OffsetInSection(Offset) {
7842 if (Is64)
7843 read<uint64_t>(Contents, Offset);
7844 else
7845 read<uint32_t>(Contents, Offset);
7846 }
7847
7848private:
7849 template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {
7850 FunctionAddr = readNext<UIntPtr>(Contents, Offset);
7851 Length = readNext<uint32_t>(Contents, Offset);
7852 CompactEncoding = readNext<uint32_t>(Contents, Offset);
7853 PersonalityAddr = readNext<UIntPtr>(Contents, Offset);
7854 LSDAAddr = readNext<UIntPtr>(Contents, Offset);
7855 }
7856};
7857}
7858
7859/// Given a relocation from __compact_unwind, consisting of the RelocationRef
7860/// and data being relocated, determine the best base Name and Addend to use for
7861/// display purposes.
7862///
7863/// 1. An Extern relocation will directly reference a symbol (and the data is
7864/// then already an addend), so use that.
7865/// 2. Otherwise the data is an offset in the object file's layout; try to find
7866// a symbol before it in the same section, and use the offset from there.
7867/// 3. Finally, if all that fails, fall back to an offset from the start of the
7868/// referenced section.
7869static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
7870 std::map<uint64_t, SymbolRef> &Symbols,
7871 const RelocationRef &Reloc, uint64_t Addr,
7872 StringRef &Name, uint64_t &Addend) {
7873 if (Reloc.getSymbol() != Obj->symbol_end()) {
7874 Name = unwrapOrError(EO: Reloc.getSymbol()->getName(), Args: Obj->getFileName());
7875 Addend = Addr;
7876 return;
7877 }
7878
7879 auto RE = Obj->getRelocation(Rel: Reloc.getRawDataRefImpl());
7880 SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
7881
7882 uint64_t SectionAddr = RelocSection.getAddress();
7883
7884 auto Sym = Symbols.upper_bound(x: Addr);
7885 if (Sym == Symbols.begin()) {
7886 // The first symbol in the object is after this reference, the best we can
7887 // do is section-relative notation.
7888 if (Expected<StringRef> NameOrErr = RelocSection.getName())
7889 Name = *NameOrErr;
7890 else
7891 consumeError(Err: NameOrErr.takeError());
7892
7893 Addend = Addr - SectionAddr;
7894 return;
7895 }
7896
7897 // Go back one so that SymbolAddress <= Addr.
7898 --Sym;
7899
7900 section_iterator SymSection =
7901 unwrapOrError(EO: Sym->second.getSection(), Args: Obj->getFileName());
7902 if (RelocSection == *SymSection) {
7903 // There's a valid symbol in the same section before this reference.
7904 Name = unwrapOrError(EO: Sym->second.getName(), Args: Obj->getFileName());
7905 Addend = Addr - Sym->first;
7906 return;
7907 }
7908
7909 // There is a symbol before this reference, but it's in a different
7910 // section. Probably not helpful to mention it, so use the section name.
7911 if (Expected<StringRef> NameOrErr = RelocSection.getName())
7912 Name = *NameOrErr;
7913 else
7914 consumeError(Err: NameOrErr.takeError());
7915
7916 Addend = Addr - SectionAddr;
7917}
7918
7919static void printUnwindRelocDest(const MachOObjectFile *Obj,
7920 std::map<uint64_t, SymbolRef> &Symbols,
7921 const RelocationRef &Reloc, uint64_t Addr) {
7922 StringRef Name;
7923 uint64_t Addend;
7924
7925 if (!Reloc.getObject())
7926 return;
7927
7928 findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
7929
7930 outs() << Name;
7931 if (Addend)
7932 outs() << " + " << format(Fmt: "0x%" PRIx64, Vals: Addend);
7933}
7934
7935static void
7936printMachOCompactUnwindSection(const MachOObjectFile *Obj,
7937 std::map<uint64_t, SymbolRef> &Symbols,
7938 const SectionRef &CompactUnwind) {
7939
7940 if (!Obj->isLittleEndian()) {
7941 outs() << "Skipping big-endian __compact_unwind section\n";
7942 return;
7943 }
7944
7945 bool Is64 = Obj->is64Bit();
7946 uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
7947 uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
7948
7949 StringRef Contents =
7950 unwrapOrError(EO: CompactUnwind.getContents(), Args: Obj->getFileName());
7951 SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
7952
7953 // First populate the initial raw offsets, encodings and so on from the entry.
7954 for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
7955 CompactUnwindEntry Entry(Contents, Offset, Is64);
7956 CompactUnwinds.push_back(Elt: Entry);
7957 }
7958
7959 // Next we need to look at the relocations to find out what objects are
7960 // actually being referred to.
7961 for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
7962 uint64_t RelocAddress = Reloc.getOffset();
7963
7964 uint32_t EntryIdx = RelocAddress / EntrySize;
7965 uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
7966 CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
7967
7968 if (OffsetInEntry == 0)
7969 Entry.FunctionReloc = Reloc;
7970 else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
7971 Entry.PersonalityReloc = Reloc;
7972 else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
7973 Entry.LSDAReloc = Reloc;
7974 else {
7975 outs() << "Invalid relocation in __compact_unwind section\n";
7976 return;
7977 }
7978 }
7979
7980 // Finally, we're ready to print the data we've gathered.
7981 outs() << "Contents of __compact_unwind section:\n";
7982 for (auto &Entry : CompactUnwinds) {
7983 outs() << " Entry at offset "
7984 << format(Fmt: "0x%" PRIx32, Vals: Entry.OffsetInSection) << ":\n";
7985
7986 // 1. Start of the region this entry applies to.
7987 outs() << " start: " << format(Fmt: "0x%" PRIx64,
7988 Vals: Entry.FunctionAddr) << ' ';
7989 printUnwindRelocDest(Obj, Symbols, Reloc: Entry.FunctionReloc, Addr: Entry.FunctionAddr);
7990 outs() << '\n';
7991
7992 // 2. Length of the region this entry applies to.
7993 outs() << " length: " << format(Fmt: "0x%" PRIx32, Vals: Entry.Length)
7994 << '\n';
7995 // 3. The 32-bit compact encoding.
7996 outs() << " compact encoding: "
7997 << format(Fmt: "0x%08" PRIx32, Vals: Entry.CompactEncoding) << '\n';
7998
7999 // 4. The personality function, if present.
8000 if (Entry.PersonalityReloc.getObject()) {
8001 outs() << " personality function: "
8002 << format(Fmt: "0x%" PRIx64, Vals: Entry.PersonalityAddr) << ' ';
8003 printUnwindRelocDest(Obj, Symbols, Reloc: Entry.PersonalityReloc,
8004 Addr: Entry.PersonalityAddr);
8005 outs() << '\n';
8006 }
8007
8008 // 5. This entry's language-specific data area.
8009 if (Entry.LSDAReloc.getObject()) {
8010 outs() << " LSDA: " << format(Fmt: "0x%" PRIx64,
8011 Vals: Entry.LSDAAddr) << ' ';
8012 printUnwindRelocDest(Obj, Symbols, Reloc: Entry.LSDAReloc, Addr: Entry.LSDAAddr);
8013 outs() << '\n';
8014 }
8015 }
8016}
8017
8018//===----------------------------------------------------------------------===//
8019// __unwind_info section dumping
8020//===----------------------------------------------------------------------===//
8021
8022static void printRegularSecondLevelUnwindPage(StringRef PageData) {
8023 ptrdiff_t Pos = 0;
8024 uint32_t Kind = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8025 (void)Kind;
8026 assert(Kind == 2 && "kind for a regular 2nd level index should be 2");
8027
8028 uint16_t EntriesStart = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8029 uint16_t NumEntries = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8030
8031 Pos = EntriesStart;
8032 for (unsigned i = 0; i < NumEntries; ++i) {
8033 uint32_t FunctionOffset = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8034 uint32_t Encoding = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8035
8036 outs() << " [" << i << "]: "
8037 << "function offset=" << format(Fmt: "0x%08" PRIx32, Vals: FunctionOffset)
8038 << ", "
8039 << "encoding=" << format(Fmt: "0x%08" PRIx32, Vals: Encoding) << '\n';
8040 }
8041}
8042
8043static void printCompressedSecondLevelUnwindPage(
8044 StringRef PageData, uint32_t FunctionBase,
8045 const SmallVectorImpl<uint32_t> &CommonEncodings) {
8046 ptrdiff_t Pos = 0;
8047 uint32_t Kind = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8048 (void)Kind;
8049 assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");
8050
8051 uint32_t NumCommonEncodings = CommonEncodings.size();
8052 uint16_t EntriesStart = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8053 uint16_t NumEntries = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8054
8055 uint16_t PageEncodingsStart = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8056 uint16_t NumPageEncodings = readNext<uint16_t>(Contents: PageData, Offset&: Pos);
8057 SmallVector<uint32_t, 64> PageEncodings;
8058 if (NumPageEncodings) {
8059 outs() << " Page encodings: (count = " << NumPageEncodings << ")\n";
8060 Pos = PageEncodingsStart;
8061 for (unsigned i = 0; i < NumPageEncodings; ++i) {
8062 uint32_t Encoding = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8063 PageEncodings.push_back(Elt: Encoding);
8064 outs() << " encoding[" << (i + NumCommonEncodings)
8065 << "]: " << format(Fmt: "0x%08" PRIx32, Vals: Encoding) << '\n';
8066 }
8067 }
8068
8069 Pos = EntriesStart;
8070 for (unsigned i = 0; i < NumEntries; ++i) {
8071 uint32_t Entry = readNext<uint32_t>(Contents: PageData, Offset&: Pos);
8072 uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
8073 uint32_t EncodingIdx = Entry >> 24;
8074
8075 uint32_t Encoding;
8076 if (EncodingIdx < NumCommonEncodings)
8077 Encoding = CommonEncodings[EncodingIdx];
8078 else
8079 Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];
8080
8081 outs() << " [" << i << "]: "
8082 << "function offset=" << format(Fmt: "0x%08" PRIx32, Vals: FunctionOffset)
8083 << ", "
8084 << "encoding[" << EncodingIdx
8085 << "]=" << format(Fmt: "0x%08" PRIx32, Vals: Encoding) << '\n';
8086 }
8087}
8088
8089static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
8090 std::map<uint64_t, SymbolRef> &Symbols,
8091 const SectionRef &UnwindInfo) {
8092
8093 if (!Obj->isLittleEndian()) {
8094 outs() << "Skipping big-endian __unwind_info section\n";
8095 return;
8096 }
8097
8098 outs() << "Contents of __unwind_info section:\n";
8099
8100 StringRef Contents =
8101 unwrapOrError(EO: UnwindInfo.getContents(), Args: Obj->getFileName());
8102 ptrdiff_t Pos = 0;
8103
8104 //===----------------------------------
8105 // Section header
8106 //===----------------------------------
8107
8108 uint32_t Version = readNext<uint32_t>(Contents, Offset&: Pos);
8109 outs() << " Version: "
8110 << format(Fmt: "0x%" PRIx32, Vals: Version) << '\n';
8111 if (Version != 1) {
8112 outs() << " Skipping section with unknown version\n";
8113 return;
8114 }
8115
8116 uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Offset&: Pos);
8117 outs() << " Common encodings array section offset: "
8118 << format(Fmt: "0x%" PRIx32, Vals: CommonEncodingsStart) << '\n';
8119 uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Offset&: Pos);
8120 outs() << " Number of common encodings in array: "
8121 << format(Fmt: "0x%" PRIx32, Vals: NumCommonEncodings) << '\n';
8122
8123 uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Offset&: Pos);
8124 outs() << " Personality function array section offset: "
8125 << format(Fmt: "0x%" PRIx32, Vals: PersonalitiesStart) << '\n';
8126 uint32_t NumPersonalities = readNext<uint32_t>(Contents, Offset&: Pos);
8127 outs() << " Number of personality functions in array: "
8128 << format(Fmt: "0x%" PRIx32, Vals: NumPersonalities) << '\n';
8129
8130 uint32_t IndicesStart = readNext<uint32_t>(Contents, Offset&: Pos);
8131 outs() << " Index array section offset: "
8132 << format(Fmt: "0x%" PRIx32, Vals: IndicesStart) << '\n';
8133 uint32_t NumIndices = readNext<uint32_t>(Contents, Offset&: Pos);
8134 outs() << " Number of indices in array: "
8135 << format(Fmt: "0x%" PRIx32, Vals: NumIndices) << '\n';
8136
8137 //===----------------------------------
8138 // A shared list of common encodings
8139 //===----------------------------------
8140
8141 // These occupy indices in the range [0, N] whenever an encoding is referenced
8142 // from a compressed 2nd level index table. In practice the linker only
8143 // creates ~128 of these, so that indices are available to embed encodings in
8144 // the 2nd level index.
8145
8146 SmallVector<uint32_t, 64> CommonEncodings;
8147 outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
8148 Pos = CommonEncodingsStart;
8149 for (unsigned i = 0; i < NumCommonEncodings; ++i) {
8150 uint32_t Encoding = readNext<uint32_t>(Contents, Offset&: Pos);
8151 CommonEncodings.push_back(Elt: Encoding);
8152
8153 outs() << " encoding[" << i << "]: " << format(Fmt: "0x%08" PRIx32, Vals: Encoding)
8154 << '\n';
8155 }
8156
8157 //===----------------------------------
8158 // Personality functions used in this executable
8159 //===----------------------------------
8160
8161 // There should be only a handful of these (one per source language,
8162 // roughly). Particularly since they only get 2 bits in the compact encoding.
8163
8164 outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
8165 Pos = PersonalitiesStart;
8166 for (unsigned i = 0; i < NumPersonalities; ++i) {
8167 uint32_t PersonalityFn = readNext<uint32_t>(Contents, Offset&: Pos);
8168 outs() << " personality[" << i + 1
8169 << "]: " << format(Fmt: "0x%08" PRIx32, Vals: PersonalityFn) << '\n';
8170 }
8171
8172 //===----------------------------------
8173 // The level 1 index entries
8174 //===----------------------------------
8175
8176 // These specify an approximate place to start searching for the more detailed
8177 // information, sorted by PC.
8178
8179 struct IndexEntry {
8180 uint32_t FunctionOffset;
8181 uint32_t SecondLevelPageStart;
8182 uint32_t LSDAStart;
8183 };
8184
8185 SmallVector<IndexEntry, 4> IndexEntries;
8186
8187 outs() << " Top level indices: (count = " << NumIndices << ")\n";
8188 Pos = IndicesStart;
8189 for (unsigned i = 0; i < NumIndices; ++i) {
8190 IndexEntry Entry;
8191
8192 Entry.FunctionOffset = readNext<uint32_t>(Contents, Offset&: Pos);
8193 Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Offset&: Pos);
8194 Entry.LSDAStart = readNext<uint32_t>(Contents, Offset&: Pos);
8195 IndexEntries.push_back(Elt: Entry);
8196
8197 outs() << " [" << i << "]: "
8198 << "function offset=" << format(Fmt: "0x%08" PRIx32, Vals: Entry.FunctionOffset)
8199 << ", "
8200 << "2nd level page offset="
8201 << format(Fmt: "0x%08" PRIx32, Vals: Entry.SecondLevelPageStart) << ", "
8202 << "LSDA offset=" << format(Fmt: "0x%08" PRIx32, Vals: Entry.LSDAStart) << '\n';
8203 }
8204
8205 //===----------------------------------
8206 // Next come the LSDA tables
8207 //===----------------------------------
8208
8209 // The LSDA layout is rather implicit: it's a contiguous array of entries from
8210 // the first top-level index's LSDAOffset to the last (sentinel).
8211
8212 outs() << " LSDA descriptors:\n";
8213 Pos = IndexEntries[0].LSDAStart;
8214 const uint32_t LSDASize = 2 * sizeof(uint32_t);
8215 int NumLSDAs =
8216 (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;
8217
8218 for (int i = 0; i < NumLSDAs; ++i) {
8219 uint32_t FunctionOffset = readNext<uint32_t>(Contents, Offset&: Pos);
8220 uint32_t LSDAOffset = readNext<uint32_t>(Contents, Offset&: Pos);
8221 outs() << " [" << i << "]: "
8222 << "function offset=" << format(Fmt: "0x%08" PRIx32, Vals: FunctionOffset)
8223 << ", "
8224 << "LSDA offset=" << format(Fmt: "0x%08" PRIx32, Vals: LSDAOffset) << '\n';
8225 }
8226
8227 //===----------------------------------
8228 // Finally, the 2nd level indices
8229 //===----------------------------------
8230
8231 // Generally these are 4K in size, and have 2 possible forms:
8232 // + Regular stores up to 511 entries with disparate encodings
8233 // + Compressed stores up to 1021 entries if few enough compact encoding
8234 // values are used.
8235 outs() << " Second level indices:\n";
8236 for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
8237 // The final sentinel top-level index has no associated 2nd level page
8238 if (IndexEntries[i].SecondLevelPageStart == 0)
8239 break;
8240
8241 outs() << " Second level index[" << i << "]: "
8242 << "offset in section="
8243 << format(Fmt: "0x%08" PRIx32, Vals: IndexEntries[i].SecondLevelPageStart)
8244 << ", "
8245 << "base function offset="
8246 << format(Fmt: "0x%08" PRIx32, Vals: IndexEntries[i].FunctionOffset) << '\n';
8247
8248 Pos = IndexEntries[i].SecondLevelPageStart;
8249 if (Pos + sizeof(uint32_t) > Contents.size()) {
8250 outs() << "warning: invalid offset for second level page: " << Pos << '\n';
8251 continue;
8252 }
8253
8254 uint32_t Kind =
8255 *reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);
8256 if (Kind == 2)
8257 printRegularSecondLevelUnwindPage(PageData: Contents.substr(Start: Pos, N: 4096));
8258 else if (Kind == 3)
8259 printCompressedSecondLevelUnwindPage(PageData: Contents.substr(Start: Pos, N: 4096),
8260 FunctionBase: IndexEntries[i].FunctionOffset,
8261 CommonEncodings);
8262 else
8263 outs() << " Skipping 2nd level page with unknown kind " << Kind
8264 << '\n';
8265 }
8266}
8267
8268void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {
8269 std::map<uint64_t, SymbolRef> Symbols;
8270 for (const SymbolRef &SymRef : Obj->symbols()) {
8271 // Discard any undefined or absolute symbols. They're not going to take part
8272 // in the convenience lookup for unwind info and just take up resources.
8273 auto SectOrErr = SymRef.getSection();
8274 if (!SectOrErr) {
8275 // TODO: Actually report errors helpfully.
8276 consumeError(Err: SectOrErr.takeError());
8277 continue;
8278 }
8279 section_iterator Section = *SectOrErr;
8280 if (Section == Obj->section_end())
8281 continue;
8282
8283 uint64_t Addr = cantFail(ValOrErr: SymRef.getValue());
8284 Symbols.insert(x: std::make_pair(x&: Addr, y: SymRef));
8285 }
8286
8287 for (const SectionRef &Section : Obj->sections()) {
8288 StringRef SectName;
8289 if (Expected<StringRef> NameOrErr = Section.getName())
8290 SectName = *NameOrErr;
8291 else
8292 consumeError(Err: NameOrErr.takeError());
8293
8294 if (SectName == "__compact_unwind")
8295 printMachOCompactUnwindSection(Obj, Symbols, CompactUnwind: Section);
8296 else if (SectName == "__unwind_info")
8297 printMachOUnwindInfoSection(Obj, Symbols, UnwindInfo: Section);
8298 }
8299}
8300
8301static void PrintMachHeader(uint32_t magic, uint32_t cputype,
8302 uint32_t cpusubtype, uint32_t filetype,
8303 uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
8304 bool verbose) {
8305 outs() << "Mach header\n";
8306 outs() << " magic cputype cpusubtype caps filetype ncmds "
8307 "sizeofcmds flags\n";
8308 if (verbose) {
8309 if (magic == MachO::MH_MAGIC)
8310 outs() << " MH_MAGIC";
8311 else if (magic == MachO::MH_MAGIC_64)
8312 outs() << "MH_MAGIC_64";
8313 else
8314 outs() << format(Fmt: " 0x%08" PRIx32, Vals: magic);
8315 switch (cputype) {
8316 case MachO::CPU_TYPE_I386:
8317 outs() << " I386";
8318 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8319 case MachO::CPU_SUBTYPE_I386_ALL:
8320 outs() << " ALL";
8321 break;
8322 default:
8323 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8324 break;
8325 }
8326 break;
8327 case MachO::CPU_TYPE_X86_64:
8328 outs() << " X86_64";
8329 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8330 case MachO::CPU_SUBTYPE_X86_64_ALL:
8331 outs() << " ALL";
8332 break;
8333 case MachO::CPU_SUBTYPE_X86_64_H:
8334 outs() << " Haswell";
8335 break;
8336 default:
8337 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8338 break;
8339 }
8340 break;
8341 case MachO::CPU_TYPE_ARM:
8342 outs() << " ARM";
8343 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8344 case MachO::CPU_SUBTYPE_ARM_ALL:
8345 outs() << " ALL";
8346 break;
8347 case MachO::CPU_SUBTYPE_ARM_V4T:
8348 outs() << " V4T";
8349 break;
8350 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
8351 outs() << " V5TEJ";
8352 break;
8353 case MachO::CPU_SUBTYPE_ARM_XSCALE:
8354 outs() << " XSCALE";
8355 break;
8356 case MachO::CPU_SUBTYPE_ARM_V6:
8357 outs() << " V6";
8358 break;
8359 case MachO::CPU_SUBTYPE_ARM_V6M:
8360 outs() << " V6M";
8361 break;
8362 case MachO::CPU_SUBTYPE_ARM_V7:
8363 outs() << " V7";
8364 break;
8365 case MachO::CPU_SUBTYPE_ARM_V7EM:
8366 outs() << " V7EM";
8367 break;
8368 case MachO::CPU_SUBTYPE_ARM_V7K:
8369 outs() << " V7K";
8370 break;
8371 case MachO::CPU_SUBTYPE_ARM_V7M:
8372 outs() << " V7M";
8373 break;
8374 case MachO::CPU_SUBTYPE_ARM_V7S:
8375 outs() << " V7S";
8376 break;
8377 default:
8378 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8379 break;
8380 }
8381 break;
8382 case MachO::CPU_TYPE_ARM64:
8383 outs() << " ARM64";
8384 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8385 case MachO::CPU_SUBTYPE_ARM64_ALL:
8386 outs() << " ALL";
8387 break;
8388 case MachO::CPU_SUBTYPE_ARM64_V8:
8389 outs() << " V8";
8390 break;
8391 case MachO::CPU_SUBTYPE_ARM64E:
8392 outs() << " E";
8393 break;
8394 default:
8395 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8396 break;
8397 }
8398 break;
8399 case MachO::CPU_TYPE_ARM64_32:
8400 outs() << " ARM64_32";
8401 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8402 case MachO::CPU_SUBTYPE_ARM64_32_V8:
8403 outs() << " V8";
8404 break;
8405 default:
8406 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8407 break;
8408 }
8409 break;
8410 case MachO::CPU_TYPE_POWERPC:
8411 outs() << " PPC";
8412 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8413 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8414 outs() << " ALL";
8415 break;
8416 default:
8417 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8418 break;
8419 }
8420 break;
8421 case MachO::CPU_TYPE_POWERPC64:
8422 outs() << " PPC64";
8423 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8424 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8425 outs() << " ALL";
8426 break;
8427 default:
8428 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8429 break;
8430 }
8431 break;
8432 default:
8433 outs() << format(Fmt: " %7d", Vals: cputype);
8434 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8435 break;
8436 }
8437
8438 if (cputype == MachO::CPU_TYPE_ARM64 &&
8439 MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(ST: cpusubtype)) {
8440 const char *Format =
8441 MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(ST: cpusubtype)
8442 ? " PAK%02d"
8443 : " PAC%02d";
8444 outs() << format(Fmt: Format,
8445 Vals: MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(ST: cpusubtype));
8446 } else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
8447 MachO::CPU_SUBTYPE_LIB64) {
8448 outs() << " LIB64";
8449 } else {
8450 outs() << format(Fmt: " 0x%02" PRIx32,
8451 Vals: (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8452 }
8453 switch (filetype) {
8454 case MachO::MH_OBJECT:
8455 outs() << " OBJECT";
8456 break;
8457 case MachO::MH_EXECUTE:
8458 outs() << " EXECUTE";
8459 break;
8460 case MachO::MH_FVMLIB:
8461 outs() << " FVMLIB";
8462 break;
8463 case MachO::MH_CORE:
8464 outs() << " CORE";
8465 break;
8466 case MachO::MH_PRELOAD:
8467 outs() << " PRELOAD";
8468 break;
8469 case MachO::MH_DYLIB:
8470 outs() << " DYLIB";
8471 break;
8472 case MachO::MH_DYLIB_STUB:
8473 outs() << " DYLIB_STUB";
8474 break;
8475 case MachO::MH_DYLINKER:
8476 outs() << " DYLINKER";
8477 break;
8478 case MachO::MH_BUNDLE:
8479 outs() << " BUNDLE";
8480 break;
8481 case MachO::MH_DSYM:
8482 outs() << " DSYM";
8483 break;
8484 case MachO::MH_KEXT_BUNDLE:
8485 outs() << " KEXTBUNDLE";
8486 break;
8487 case MachO::MH_FILESET:
8488 outs() << " FILESET";
8489 break;
8490 default:
8491 outs() << format(Fmt: " %10u", Vals: filetype);
8492 break;
8493 }
8494 outs() << format(Fmt: " %5u", Vals: ncmds);
8495 outs() << format(Fmt: " %10u", Vals: sizeofcmds);
8496 uint32_t f = flags;
8497 if (f & MachO::MH_NOUNDEFS) {
8498 outs() << " NOUNDEFS";
8499 f &= ~MachO::MH_NOUNDEFS;
8500 }
8501 if (f & MachO::MH_INCRLINK) {
8502 outs() << " INCRLINK";
8503 f &= ~MachO::MH_INCRLINK;
8504 }
8505 if (f & MachO::MH_DYLDLINK) {
8506 outs() << " DYLDLINK";
8507 f &= ~MachO::MH_DYLDLINK;
8508 }
8509 if (f & MachO::MH_BINDATLOAD) {
8510 outs() << " BINDATLOAD";
8511 f &= ~MachO::MH_BINDATLOAD;
8512 }
8513 if (f & MachO::MH_PREBOUND) {
8514 outs() << " PREBOUND";
8515 f &= ~MachO::MH_PREBOUND;
8516 }
8517 if (f & MachO::MH_SPLIT_SEGS) {
8518 outs() << " SPLIT_SEGS";
8519 f &= ~MachO::MH_SPLIT_SEGS;
8520 }
8521 if (f & MachO::MH_LAZY_INIT) {
8522 outs() << " LAZY_INIT";
8523 f &= ~MachO::MH_LAZY_INIT;
8524 }
8525 if (f & MachO::MH_TWOLEVEL) {
8526 outs() << " TWOLEVEL";
8527 f &= ~MachO::MH_TWOLEVEL;
8528 }
8529 if (f & MachO::MH_FORCE_FLAT) {
8530 outs() << " FORCE_FLAT";
8531 f &= ~MachO::MH_FORCE_FLAT;
8532 }
8533 if (f & MachO::MH_NOMULTIDEFS) {
8534 outs() << " NOMULTIDEFS";
8535 f &= ~MachO::MH_NOMULTIDEFS;
8536 }
8537 if (f & MachO::MH_NOFIXPREBINDING) {
8538 outs() << " NOFIXPREBINDING";
8539 f &= ~MachO::MH_NOFIXPREBINDING;
8540 }
8541 if (f & MachO::MH_PREBINDABLE) {
8542 outs() << " PREBINDABLE";
8543 f &= ~MachO::MH_PREBINDABLE;
8544 }
8545 if (f & MachO::MH_ALLMODSBOUND) {
8546 outs() << " ALLMODSBOUND";
8547 f &= ~MachO::MH_ALLMODSBOUND;
8548 }
8549 if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
8550 outs() << " SUBSECTIONS_VIA_SYMBOLS";
8551 f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
8552 }
8553 if (f & MachO::MH_CANONICAL) {
8554 outs() << " CANONICAL";
8555 f &= ~MachO::MH_CANONICAL;
8556 }
8557 if (f & MachO::MH_WEAK_DEFINES) {
8558 outs() << " WEAK_DEFINES";
8559 f &= ~MachO::MH_WEAK_DEFINES;
8560 }
8561 if (f & MachO::MH_BINDS_TO_WEAK) {
8562 outs() << " BINDS_TO_WEAK";
8563 f &= ~MachO::MH_BINDS_TO_WEAK;
8564 }
8565 if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
8566 outs() << " ALLOW_STACK_EXECUTION";
8567 f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
8568 }
8569 if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
8570 outs() << " DEAD_STRIPPABLE_DYLIB";
8571 f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
8572 }
8573 if (f & MachO::MH_PIE) {
8574 outs() << " PIE";
8575 f &= ~MachO::MH_PIE;
8576 }
8577 if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
8578 outs() << " NO_REEXPORTED_DYLIBS";
8579 f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
8580 }
8581 if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
8582 outs() << " MH_HAS_TLV_DESCRIPTORS";
8583 f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
8584 }
8585 if (f & MachO::MH_NO_HEAP_EXECUTION) {
8586 outs() << " MH_NO_HEAP_EXECUTION";
8587 f &= ~MachO::MH_NO_HEAP_EXECUTION;
8588 }
8589 if (f & MachO::MH_APP_EXTENSION_SAFE) {
8590 outs() << " APP_EXTENSION_SAFE";
8591 f &= ~MachO::MH_APP_EXTENSION_SAFE;
8592 }
8593 if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
8594 outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
8595 f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
8596 }
8597 if (f != 0 || flags == 0)
8598 outs() << format(Fmt: " 0x%08" PRIx32, Vals: f);
8599 } else {
8600 outs() << format(Fmt: " 0x%08" PRIx32, Vals: magic);
8601 outs() << format(Fmt: " %7d", Vals: cputype);
8602 outs() << format(Fmt: " %10d", Vals: cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8603 outs() << format(Fmt: " 0x%02" PRIx32,
8604 Vals: (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8605 outs() << format(Fmt: " %10u", Vals: filetype);
8606 outs() << format(Fmt: " %5u", Vals: ncmds);
8607 outs() << format(Fmt: " %10u", Vals: sizeofcmds);
8608 outs() << format(Fmt: " 0x%08" PRIx32, Vals: flags);
8609 }
8610 outs() << "\n";
8611}
8612
8613static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
8614 StringRef SegName, uint64_t vmaddr,
8615 uint64_t vmsize, uint64_t fileoff,
8616 uint64_t filesize, uint32_t maxprot,
8617 uint32_t initprot, uint32_t nsects,
8618 uint32_t flags, uint32_t object_size,
8619 bool verbose) {
8620 uint64_t expected_cmdsize;
8621 if (cmd == MachO::LC_SEGMENT) {
8622 outs() << " cmd LC_SEGMENT\n";
8623 expected_cmdsize = nsects;
8624 expected_cmdsize *= sizeof(struct MachO::section);
8625 expected_cmdsize += sizeof(struct MachO::segment_command);
8626 } else {
8627 outs() << " cmd LC_SEGMENT_64\n";
8628 expected_cmdsize = nsects;
8629 expected_cmdsize *= sizeof(struct MachO::section_64);
8630 expected_cmdsize += sizeof(struct MachO::segment_command_64);
8631 }
8632 outs() << " cmdsize " << cmdsize;
8633 if (cmdsize != expected_cmdsize)
8634 outs() << " Inconsistent size\n";
8635 else
8636 outs() << "\n";
8637 outs() << " segname " << SegName << "\n";
8638 if (cmd == MachO::LC_SEGMENT_64) {
8639 outs() << " vmaddr " << format(Fmt: "0x%016" PRIx64, Vals: vmaddr) << "\n";
8640 outs() << " vmsize " << format(Fmt: "0x%016" PRIx64, Vals: vmsize) << "\n";
8641 } else {
8642 outs() << " vmaddr " << format(Fmt: "0x%08" PRIx64, Vals: vmaddr) << "\n";
8643 outs() << " vmsize " << format(Fmt: "0x%08" PRIx64, Vals: vmsize) << "\n";
8644 }
8645 outs() << " fileoff " << fileoff;
8646 if (fileoff > object_size)
8647 outs() << " (past end of file)\n";
8648 else
8649 outs() << "\n";
8650 outs() << " filesize " << filesize;
8651 if (fileoff + filesize > object_size)
8652 outs() << " (past end of file)\n";
8653 else
8654 outs() << "\n";
8655 if (verbose) {
8656 if ((maxprot &
8657 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8658 MachO::VM_PROT_EXECUTE)) != 0)
8659 outs() << " maxprot ?" << format(Fmt: "0x%08" PRIx32, Vals: maxprot) << "\n";
8660 else {
8661 outs() << " maxprot ";
8662 outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");
8663 outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8664 outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8665 }
8666 if ((initprot &
8667 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8668 MachO::VM_PROT_EXECUTE)) != 0)
8669 outs() << " initprot ?" << format(Fmt: "0x%08" PRIx32, Vals: initprot) << "\n";
8670 else {
8671 outs() << " initprot ";
8672 outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");
8673 outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8674 outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8675 }
8676 } else {
8677 outs() << " maxprot " << format(Fmt: "0x%08" PRIx32, Vals: maxprot) << "\n";
8678 outs() << " initprot " << format(Fmt: "0x%08" PRIx32, Vals: initprot) << "\n";
8679 }
8680 outs() << " nsects " << nsects << "\n";
8681 if (verbose) {
8682 outs() << " flags";
8683 if (flags == 0)
8684 outs() << " (none)\n";
8685 else {
8686 if (flags & MachO::SG_HIGHVM) {
8687 outs() << " HIGHVM";
8688 flags &= ~MachO::SG_HIGHVM;
8689 }
8690 if (flags & MachO::SG_FVMLIB) {
8691 outs() << " FVMLIB";
8692 flags &= ~MachO::SG_FVMLIB;
8693 }
8694 if (flags & MachO::SG_NORELOC) {
8695 outs() << " NORELOC";
8696 flags &= ~MachO::SG_NORELOC;
8697 }
8698 if (flags & MachO::SG_PROTECTED_VERSION_1) {
8699 outs() << " PROTECTED_VERSION_1";
8700 flags &= ~MachO::SG_PROTECTED_VERSION_1;
8701 }
8702 if (flags & MachO::SG_READ_ONLY) {
8703 // Apple's otool prints the SG_ prefix for this flag, but not for the
8704 // others.
8705 outs() << " SG_READ_ONLY";
8706 flags &= ~MachO::SG_READ_ONLY;
8707 }
8708 if (flags)
8709 outs() << format(Fmt: " 0x%08" PRIx32, Vals: flags) << " (unknown flags)\n";
8710 else
8711 outs() << "\n";
8712 }
8713 } else {
8714 outs() << " flags " << format(Fmt: "0x%" PRIx32, Vals: flags) << "\n";
8715 }
8716}
8717
8718static void PrintSection(const char *sectname, const char *segname,
8719 uint64_t addr, uint64_t size, uint32_t offset,
8720 uint32_t align, uint32_t reloff, uint32_t nreloc,
8721 uint32_t flags, uint32_t reserved1, uint32_t reserved2,
8722 uint32_t cmd, const char *sg_segname,
8723 uint32_t filetype, uint32_t object_size,
8724 bool verbose) {
8725 outs() << "Section\n";
8726 outs() << " sectname " << format(Fmt: "%.16s\n", Vals: sectname);
8727 outs() << " segname " << format(Fmt: "%.16s", Vals: segname);
8728 if (filetype != MachO::MH_OBJECT && strncmp(s1: sg_segname, s2: segname, n: 16) != 0)
8729 outs() << " (does not match segment)\n";
8730 else
8731 outs() << "\n";
8732 if (cmd == MachO::LC_SEGMENT_64) {
8733 outs() << " addr " << format(Fmt: "0x%016" PRIx64, Vals: addr) << "\n";
8734 outs() << " size " << format(Fmt: "0x%016" PRIx64, Vals: size);
8735 } else {
8736 outs() << " addr " << format(Fmt: "0x%08" PRIx64, Vals: addr) << "\n";
8737 outs() << " size " << format(Fmt: "0x%08" PRIx64, Vals: size);
8738 }
8739 if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
8740 outs() << " (past end of file)\n";
8741 else
8742 outs() << "\n";
8743 outs() << " offset " << offset;
8744 if (offset > object_size)
8745 outs() << " (past end of file)\n";
8746 else
8747 outs() << "\n";
8748 uint32_t align_shifted = 1 << align;
8749 outs() << " align 2^" << align << " (" << align_shifted << ")\n";
8750 outs() << " reloff " << reloff;
8751 if (reloff > object_size)
8752 outs() << " (past end of file)\n";
8753 else
8754 outs() << "\n";
8755 outs() << " nreloc " << nreloc;
8756 if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
8757 outs() << " (past end of file)\n";
8758 else
8759 outs() << "\n";
8760 uint32_t section_type = flags & MachO::SECTION_TYPE;
8761 if (verbose) {
8762 outs() << " type";
8763 if (section_type == MachO::S_REGULAR)
8764 outs() << " S_REGULAR\n";
8765 else if (section_type == MachO::S_ZEROFILL)
8766 outs() << " S_ZEROFILL\n";
8767 else if (section_type == MachO::S_CSTRING_LITERALS)
8768 outs() << " S_CSTRING_LITERALS\n";
8769 else if (section_type == MachO::S_4BYTE_LITERALS)
8770 outs() << " S_4BYTE_LITERALS\n";
8771 else if (section_type == MachO::S_8BYTE_LITERALS)
8772 outs() << " S_8BYTE_LITERALS\n";
8773 else if (section_type == MachO::S_16BYTE_LITERALS)
8774 outs() << " S_16BYTE_LITERALS\n";
8775 else if (section_type == MachO::S_LITERAL_POINTERS)
8776 outs() << " S_LITERAL_POINTERS\n";
8777 else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
8778 outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
8779 else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
8780 outs() << " S_LAZY_SYMBOL_POINTERS\n";
8781 else if (section_type == MachO::S_SYMBOL_STUBS)
8782 outs() << " S_SYMBOL_STUBS\n";
8783 else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
8784 outs() << " S_MOD_INIT_FUNC_POINTERS\n";
8785 else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
8786 outs() << " S_MOD_TERM_FUNC_POINTERS\n";
8787 else if (section_type == MachO::S_COALESCED)
8788 outs() << " S_COALESCED\n";
8789 else if (section_type == MachO::S_INTERPOSING)
8790 outs() << " S_INTERPOSING\n";
8791 else if (section_type == MachO::S_DTRACE_DOF)
8792 outs() << " S_DTRACE_DOF\n";
8793 else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
8794 outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
8795 else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
8796 outs() << " S_THREAD_LOCAL_REGULAR\n";
8797 else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
8798 outs() << " S_THREAD_LOCAL_ZEROFILL\n";
8799 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
8800 outs() << " S_THREAD_LOCAL_VARIABLES\n";
8801 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8802 outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
8803 else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
8804 outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
8805 else if (section_type == MachO::S_INIT_FUNC_OFFSETS)
8806 outs() << " S_INIT_FUNC_OFFSETS\n";
8807 else
8808 outs() << format(Fmt: "0x%08" PRIx32, Vals: section_type) << "\n";
8809 outs() << "attributes";
8810 uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
8811 if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
8812 outs() << " PURE_INSTRUCTIONS";
8813 if (section_attributes & MachO::S_ATTR_NO_TOC)
8814 outs() << " NO_TOC";
8815 if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
8816 outs() << " STRIP_STATIC_SYMS";
8817 if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
8818 outs() << " NO_DEAD_STRIP";
8819 if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
8820 outs() << " LIVE_SUPPORT";
8821 if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
8822 outs() << " SELF_MODIFYING_CODE";
8823 if (section_attributes & MachO::S_ATTR_DEBUG)
8824 outs() << " DEBUG";
8825 if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
8826 outs() << " SOME_INSTRUCTIONS";
8827 if (section_attributes & MachO::S_ATTR_EXT_RELOC)
8828 outs() << " EXT_RELOC";
8829 if (section_attributes & MachO::S_ATTR_LOC_RELOC)
8830 outs() << " LOC_RELOC";
8831 if (section_attributes == 0)
8832 outs() << " (none)";
8833 outs() << "\n";
8834 } else
8835 outs() << " flags " << format(Fmt: "0x%08" PRIx32, Vals: flags) << "\n";
8836 outs() << " reserved1 " << reserved1;
8837 if (section_type == MachO::S_SYMBOL_STUBS ||
8838 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
8839 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
8840 section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
8841 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8842 outs() << " (index into indirect symbol table)\n";
8843 else
8844 outs() << "\n";
8845 outs() << " reserved2 " << reserved2;
8846 if (section_type == MachO::S_SYMBOL_STUBS)
8847 outs() << " (size of stubs)\n";
8848 else
8849 outs() << "\n";
8850}
8851
8852static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
8853 uint32_t object_size) {
8854 outs() << " cmd LC_SYMTAB\n";
8855 outs() << " cmdsize " << st.cmdsize;
8856 if (st.cmdsize != sizeof(struct MachO::symtab_command))
8857 outs() << " Incorrect size\n";
8858 else
8859 outs() << "\n";
8860 outs() << " symoff " << st.symoff;
8861 if (st.symoff > object_size)
8862 outs() << " (past end of file)\n";
8863 else
8864 outs() << "\n";
8865 outs() << " nsyms " << st.nsyms;
8866 uint64_t big_size;
8867 if (Is64Bit) {
8868 big_size = st.nsyms;
8869 big_size *= sizeof(struct MachO::nlist_64);
8870 big_size += st.symoff;
8871 if (big_size > object_size)
8872 outs() << " (past end of file)\n";
8873 else
8874 outs() << "\n";
8875 } else {
8876 big_size = st.nsyms;
8877 big_size *= sizeof(struct MachO::nlist);
8878 big_size += st.symoff;
8879 if (big_size > object_size)
8880 outs() << " (past end of file)\n";
8881 else
8882 outs() << "\n";
8883 }
8884 outs() << " stroff " << st.stroff;
8885 if (st.stroff > object_size)
8886 outs() << " (past end of file)\n";
8887 else
8888 outs() << "\n";
8889 outs() << " strsize " << st.strsize;
8890 big_size = st.stroff;
8891 big_size += st.strsize;
8892 if (big_size > object_size)
8893 outs() << " (past end of file)\n";
8894 else
8895 outs() << "\n";
8896}
8897
8898static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
8899 uint32_t nsyms, uint32_t object_size,
8900 bool Is64Bit) {
8901 outs() << " cmd LC_DYSYMTAB\n";
8902 outs() << " cmdsize " << dyst.cmdsize;
8903 if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
8904 outs() << " Incorrect size\n";
8905 else
8906 outs() << "\n";
8907 outs() << " ilocalsym " << dyst.ilocalsym;
8908 if (dyst.ilocalsym > nsyms)
8909 outs() << " (greater than the number of symbols)\n";
8910 else
8911 outs() << "\n";
8912 outs() << " nlocalsym " << dyst.nlocalsym;
8913 uint64_t big_size;
8914 big_size = dyst.ilocalsym;
8915 big_size += dyst.nlocalsym;
8916 if (big_size > nsyms)
8917 outs() << " (past the end of the symbol table)\n";
8918 else
8919 outs() << "\n";
8920 outs() << " iextdefsym " << dyst.iextdefsym;
8921 if (dyst.iextdefsym > nsyms)
8922 outs() << " (greater than the number of symbols)\n";
8923 else
8924 outs() << "\n";
8925 outs() << " nextdefsym " << dyst.nextdefsym;
8926 big_size = dyst.iextdefsym;
8927 big_size += dyst.nextdefsym;
8928 if (big_size > nsyms)
8929 outs() << " (past the end of the symbol table)\n";
8930 else
8931 outs() << "\n";
8932 outs() << " iundefsym " << dyst.iundefsym;
8933 if (dyst.iundefsym > nsyms)
8934 outs() << " (greater than the number of symbols)\n";
8935 else
8936 outs() << "\n";
8937 outs() << " nundefsym " << dyst.nundefsym;
8938 big_size = dyst.iundefsym;
8939 big_size += dyst.nundefsym;
8940 if (big_size > nsyms)
8941 outs() << " (past the end of the symbol table)\n";
8942 else
8943 outs() << "\n";
8944 outs() << " tocoff " << dyst.tocoff;
8945 if (dyst.tocoff > object_size)
8946 outs() << " (past end of file)\n";
8947 else
8948 outs() << "\n";
8949 outs() << " ntoc " << dyst.ntoc;
8950 big_size = dyst.ntoc;
8951 big_size *= sizeof(struct MachO::dylib_table_of_contents);
8952 big_size += dyst.tocoff;
8953 if (big_size > object_size)
8954 outs() << " (past end of file)\n";
8955 else
8956 outs() << "\n";
8957 outs() << " modtaboff " << dyst.modtaboff;
8958 if (dyst.modtaboff > object_size)
8959 outs() << " (past end of file)\n";
8960 else
8961 outs() << "\n";
8962 outs() << " nmodtab " << dyst.nmodtab;
8963 uint64_t modtabend;
8964 if (Is64Bit) {
8965 modtabend = dyst.nmodtab;
8966 modtabend *= sizeof(struct MachO::dylib_module_64);
8967 modtabend += dyst.modtaboff;
8968 } else {
8969 modtabend = dyst.nmodtab;
8970 modtabend *= sizeof(struct MachO::dylib_module);
8971 modtabend += dyst.modtaboff;
8972 }
8973 if (modtabend > object_size)
8974 outs() << " (past end of file)\n";
8975 else
8976 outs() << "\n";
8977 outs() << " extrefsymoff " << dyst.extrefsymoff;
8978 if (dyst.extrefsymoff > object_size)
8979 outs() << " (past end of file)\n";
8980 else
8981 outs() << "\n";
8982 outs() << " nextrefsyms " << dyst.nextrefsyms;
8983 big_size = dyst.nextrefsyms;
8984 big_size *= sizeof(struct MachO::dylib_reference);
8985 big_size += dyst.extrefsymoff;
8986 if (big_size > object_size)
8987 outs() << " (past end of file)\n";
8988 else
8989 outs() << "\n";
8990 outs() << " indirectsymoff " << dyst.indirectsymoff;
8991 if (dyst.indirectsymoff > object_size)
8992 outs() << " (past end of file)\n";
8993 else
8994 outs() << "\n";
8995 outs() << " nindirectsyms " << dyst.nindirectsyms;
8996 big_size = dyst.nindirectsyms;
8997 big_size *= sizeof(uint32_t);
8998 big_size += dyst.indirectsymoff;
8999 if (big_size > object_size)
9000 outs() << " (past end of file)\n";
9001 else
9002 outs() << "\n";
9003 outs() << " extreloff " << dyst.extreloff;
9004 if (dyst.extreloff > object_size)
9005 outs() << " (past end of file)\n";
9006 else
9007 outs() << "\n";
9008 outs() << " nextrel " << dyst.nextrel;
9009 big_size = dyst.nextrel;
9010 big_size *= sizeof(struct MachO::relocation_info);
9011 big_size += dyst.extreloff;
9012 if (big_size > object_size)
9013 outs() << " (past end of file)\n";
9014 else
9015 outs() << "\n";
9016 outs() << " locreloff " << dyst.locreloff;
9017 if (dyst.locreloff > object_size)
9018 outs() << " (past end of file)\n";
9019 else
9020 outs() << "\n";
9021 outs() << " nlocrel " << dyst.nlocrel;
9022 big_size = dyst.nlocrel;
9023 big_size *= sizeof(struct MachO::relocation_info);
9024 big_size += dyst.locreloff;
9025 if (big_size > object_size)
9026 outs() << " (past end of file)\n";
9027 else
9028 outs() << "\n";
9029}
9030
9031static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
9032 uint32_t object_size) {
9033 if (dc.cmd == MachO::LC_DYLD_INFO)
9034 outs() << " cmd LC_DYLD_INFO\n";
9035 else
9036 outs() << " cmd LC_DYLD_INFO_ONLY\n";
9037 outs() << " cmdsize " << dc.cmdsize;
9038 if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
9039 outs() << " Incorrect size\n";
9040 else
9041 outs() << "\n";
9042 outs() << " rebase_off " << dc.rebase_off;
9043 if (dc.rebase_off > object_size)
9044 outs() << " (past end of file)\n";
9045 else
9046 outs() << "\n";
9047 outs() << " rebase_size " << dc.rebase_size;
9048 uint64_t big_size;
9049 big_size = dc.rebase_off;
9050 big_size += dc.rebase_size;
9051 if (big_size > object_size)
9052 outs() << " (past end of file)\n";
9053 else
9054 outs() << "\n";
9055 outs() << " bind_off " << dc.bind_off;
9056 if (dc.bind_off > object_size)
9057 outs() << " (past end of file)\n";
9058 else
9059 outs() << "\n";
9060 outs() << " bind_size " << dc.bind_size;
9061 big_size = dc.bind_off;
9062 big_size += dc.bind_size;
9063 if (big_size > object_size)
9064 outs() << " (past end of file)\n";
9065 else
9066 outs() << "\n";
9067 outs() << " weak_bind_off " << dc.weak_bind_off;
9068 if (dc.weak_bind_off > object_size)
9069 outs() << " (past end of file)\n";
9070 else
9071 outs() << "\n";
9072 outs() << " weak_bind_size " << dc.weak_bind_size;
9073 big_size = dc.weak_bind_off;
9074 big_size += dc.weak_bind_size;
9075 if (big_size > object_size)
9076 outs() << " (past end of file)\n";
9077 else
9078 outs() << "\n";
9079 outs() << " lazy_bind_off " << dc.lazy_bind_off;
9080 if (dc.lazy_bind_off > object_size)
9081 outs() << " (past end of file)\n";
9082 else
9083 outs() << "\n";
9084 outs() << " lazy_bind_size " << dc.lazy_bind_size;
9085 big_size = dc.lazy_bind_off;
9086 big_size += dc.lazy_bind_size;
9087 if (big_size > object_size)
9088 outs() << " (past end of file)\n";
9089 else
9090 outs() << "\n";
9091 outs() << " export_off " << dc.export_off;
9092 if (dc.export_off > object_size)
9093 outs() << " (past end of file)\n";
9094 else
9095 outs() << "\n";
9096 outs() << " export_size " << dc.export_size;
9097 big_size = dc.export_off;
9098 big_size += dc.export_size;
9099 if (big_size > object_size)
9100 outs() << " (past end of file)\n";
9101 else
9102 outs() << "\n";
9103}
9104
9105static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
9106 const char *Ptr) {
9107 if (dyld.cmd == MachO::LC_ID_DYLINKER)
9108 outs() << " cmd LC_ID_DYLINKER\n";
9109 else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
9110 outs() << " cmd LC_LOAD_DYLINKER\n";
9111 else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
9112 outs() << " cmd LC_DYLD_ENVIRONMENT\n";
9113 else
9114 outs() << " cmd ?(" << dyld.cmd << ")\n";
9115 outs() << " cmdsize " << dyld.cmdsize;
9116 if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
9117 outs() << " Incorrect size\n";
9118 else
9119 outs() << "\n";
9120 if (dyld.name >= dyld.cmdsize)
9121 outs() << " name ?(bad offset " << dyld.name << ")\n";
9122 else {
9123 const char *P = Ptr + dyld.name;
9124 outs() << " name " << P << " (offset " << dyld.name << ")\n";
9125 }
9126}
9127
9128static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
9129 outs() << " cmd LC_UUID\n";
9130 outs() << " cmdsize " << uuid.cmdsize;
9131 if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
9132 outs() << " Incorrect size\n";
9133 else
9134 outs() << "\n";
9135 outs() << " uuid ";
9136 for (int i = 0; i < 16; ++i) {
9137 outs() << format(Fmt: "%02" PRIX32, Vals: uuid.uuid[i]);
9138 if (i == 3 || i == 5 || i == 7 || i == 9)
9139 outs() << "-";
9140 }
9141 outs() << "\n";
9142}
9143
9144static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
9145 outs() << " cmd LC_RPATH\n";
9146 outs() << " cmdsize " << rpath.cmdsize;
9147 if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
9148 outs() << " Incorrect size\n";
9149 else
9150 outs() << "\n";
9151 if (rpath.path >= rpath.cmdsize)
9152 outs() << " path ?(bad offset " << rpath.path << ")\n";
9153 else {
9154 const char *P = Ptr + rpath.path;
9155 outs() << " path " << P << " (offset " << rpath.path << ")\n";
9156 }
9157}
9158
9159static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
9160 StringRef LoadCmdName;
9161 switch (vd.cmd) {
9162 case MachO::LC_VERSION_MIN_MACOSX:
9163 LoadCmdName = "LC_VERSION_MIN_MACOSX";
9164 break;
9165 case MachO::LC_VERSION_MIN_IPHONEOS:
9166 LoadCmdName = "LC_VERSION_MIN_IPHONEOS";
9167 break;
9168 case MachO::LC_VERSION_MIN_TVOS:
9169 LoadCmdName = "LC_VERSION_MIN_TVOS";
9170 break;
9171 case MachO::LC_VERSION_MIN_WATCHOS:
9172 LoadCmdName = "LC_VERSION_MIN_WATCHOS";
9173 break;
9174 default:
9175 llvm_unreachable("Unknown version min load command");
9176 }
9177
9178 outs() << " cmd " << LoadCmdName << '\n';
9179 outs() << " cmdsize " << vd.cmdsize;
9180 if (vd.cmdsize != sizeof(struct MachO::version_min_command))
9181 outs() << " Incorrect size\n";
9182 else
9183 outs() << "\n";
9184 outs() << " version "
9185 << MachOObjectFile::getVersionMinMajor(C&: vd, SDK: false) << "."
9186 << MachOObjectFile::getVersionMinMinor(C&: vd, SDK: false);
9187 uint32_t Update = MachOObjectFile::getVersionMinUpdate(C&: vd, SDK: false);
9188 if (Update != 0)
9189 outs() << "." << Update;
9190 outs() << "\n";
9191 if (vd.sdk == 0)
9192 outs() << " sdk n/a";
9193 else {
9194 outs() << " sdk "
9195 << MachOObjectFile::getVersionMinMajor(C&: vd, SDK: true) << "."
9196 << MachOObjectFile::getVersionMinMinor(C&: vd, SDK: true);
9197 }
9198 Update = MachOObjectFile::getVersionMinUpdate(C&: vd, SDK: true);
9199 if (Update != 0)
9200 outs() << "." << Update;
9201 outs() << "\n";
9202}
9203
9204static void PrintNoteLoadCommand(MachO::note_command Nt) {
9205 outs() << " cmd LC_NOTE\n";
9206 outs() << " cmdsize " << Nt.cmdsize;
9207 if (Nt.cmdsize != sizeof(struct MachO::note_command))
9208 outs() << " Incorrect size\n";
9209 else
9210 outs() << "\n";
9211 const char *d = Nt.data_owner;
9212 outs() << "data_owner " << format(Fmt: "%.16s\n", Vals: d);
9213 outs() << " offset " << Nt.offset << "\n";
9214 outs() << " size " << Nt.size << "\n";
9215}
9216
9217static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {
9218 outs() << " tool ";
9219 if (verbose)
9220 outs() << MachOObjectFile::getBuildTool(tools: bv.tool);
9221 else
9222 outs() << bv.tool;
9223 outs() << "\n";
9224 outs() << " version " << MachOObjectFile::getVersionString(version: bv.version)
9225 << "\n";
9226}
9227
9228static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
9229 MachO::build_version_command bd,
9230 bool verbose) {
9231 outs() << " cmd LC_BUILD_VERSION\n";
9232 outs() << " cmdsize " << bd.cmdsize;
9233 if (bd.cmdsize !=
9234 sizeof(struct MachO::build_version_command) +
9235 bd.ntools * sizeof(struct MachO::build_tool_version))
9236 outs() << " Incorrect size\n";
9237 else
9238 outs() << "\n";
9239 outs() << " platform ";
9240 if (verbose)
9241 outs() << MachOObjectFile::getBuildPlatform(platform: bd.platform);
9242 else
9243 outs() << bd.platform;
9244 outs() << "\n";
9245 if (bd.sdk)
9246 outs() << " sdk " << MachOObjectFile::getVersionString(version: bd.sdk)
9247 << "\n";
9248 else
9249 outs() << " sdk n/a\n";
9250 outs() << " minos " << MachOObjectFile::getVersionString(version: bd.minos)
9251 << "\n";
9252 outs() << " ntools " << bd.ntools << "\n";
9253 for (unsigned i = 0; i < bd.ntools; ++i) {
9254 MachO::build_tool_version bv = obj->getBuildToolVersion(index: i);
9255 PrintBuildToolVersion(bv, verbose);
9256 }
9257}
9258
9259static void PrintSourceVersionCommand(MachO::source_version_command sd) {
9260 outs() << " cmd LC_SOURCE_VERSION\n";
9261 outs() << " cmdsize " << sd.cmdsize;
9262 if (sd.cmdsize != sizeof(struct MachO::source_version_command))
9263 outs() << " Incorrect size\n";
9264 else
9265 outs() << "\n";
9266 uint64_t a = (sd.version >> 40) & 0xffffff;
9267 uint64_t b = (sd.version >> 30) & 0x3ff;
9268 uint64_t c = (sd.version >> 20) & 0x3ff;
9269 uint64_t d = (sd.version >> 10) & 0x3ff;
9270 uint64_t e = sd.version & 0x3ff;
9271 outs() << " version " << a << "." << b;
9272 if (e != 0)
9273 outs() << "." << c << "." << d << "." << e;
9274 else if (d != 0)
9275 outs() << "." << c << "." << d;
9276 else if (c != 0)
9277 outs() << "." << c;
9278 outs() << "\n";
9279}
9280
9281static void PrintEntryPointCommand(MachO::entry_point_command ep) {
9282 outs() << " cmd LC_MAIN\n";
9283 outs() << " cmdsize " << ep.cmdsize;
9284 if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
9285 outs() << " Incorrect size\n";
9286 else
9287 outs() << "\n";
9288 outs() << " entryoff " << ep.entryoff << "\n";
9289 outs() << " stacksize " << ep.stacksize << "\n";
9290}
9291
9292static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
9293 uint32_t object_size) {
9294 outs() << " cmd LC_ENCRYPTION_INFO\n";
9295 outs() << " cmdsize " << ec.cmdsize;
9296 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
9297 outs() << " Incorrect size\n";
9298 else
9299 outs() << "\n";
9300 outs() << " cryptoff " << ec.cryptoff;
9301 if (ec.cryptoff > object_size)
9302 outs() << " (past end of file)\n";
9303 else
9304 outs() << "\n";
9305 outs() << " cryptsize " << ec.cryptsize;
9306 if (ec.cryptsize > object_size)
9307 outs() << " (past end of file)\n";
9308 else
9309 outs() << "\n";
9310 outs() << " cryptid " << ec.cryptid << "\n";
9311}
9312
9313static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
9314 uint32_t object_size) {
9315 outs() << " cmd LC_ENCRYPTION_INFO_64\n";
9316 outs() << " cmdsize " << ec.cmdsize;
9317 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
9318 outs() << " Incorrect size\n";
9319 else
9320 outs() << "\n";
9321 outs() << " cryptoff " << ec.cryptoff;
9322 if (ec.cryptoff > object_size)
9323 outs() << " (past end of file)\n";
9324 else
9325 outs() << "\n";
9326 outs() << " cryptsize " << ec.cryptsize;
9327 if (ec.cryptsize > object_size)
9328 outs() << " (past end of file)\n";
9329 else
9330 outs() << "\n";
9331 outs() << " cryptid " << ec.cryptid << "\n";
9332 outs() << " pad " << ec.pad << "\n";
9333}
9334
9335static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
9336 const char *Ptr) {
9337 outs() << " cmd LC_LINKER_OPTION\n";
9338 outs() << " cmdsize " << lo.cmdsize;
9339 if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
9340 outs() << " Incorrect size\n";
9341 else
9342 outs() << "\n";
9343 outs() << " count " << lo.count << "\n";
9344 const char *string = Ptr + sizeof(struct MachO::linker_option_command);
9345 uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
9346 uint32_t i = 0;
9347 while (left > 0) {
9348 while (*string == '\0' && left > 0) {
9349 string++;
9350 left--;
9351 }
9352 if (left > 0) {
9353 i++;
9354 outs() << " string #" << i << " " << format(Fmt: "%.*s\n", Vals: left, Vals: string);
9355 uint32_t NullPos = StringRef(string, left).find(C: '\0');
9356 uint32_t len = std::min(a: NullPos, b: left) + 1;
9357 string += len;
9358 left -= len;
9359 }
9360 }
9361 if (lo.count != i)
9362 outs() << " count " << lo.count << " does not match number of strings "
9363 << i << "\n";
9364}
9365
9366static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
9367 const char *Ptr) {
9368 outs() << " cmd LC_SUB_FRAMEWORK\n";
9369 outs() << " cmdsize " << sub.cmdsize;
9370 if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
9371 outs() << " Incorrect size\n";
9372 else
9373 outs() << "\n";
9374 if (sub.umbrella < sub.cmdsize) {
9375 const char *P = Ptr + sub.umbrella;
9376 outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
9377 } else {
9378 outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
9379 }
9380}
9381
9382static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
9383 const char *Ptr) {
9384 outs() << " cmd LC_SUB_UMBRELLA\n";
9385 outs() << " cmdsize " << sub.cmdsize;
9386 if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
9387 outs() << " Incorrect size\n";
9388 else
9389 outs() << "\n";
9390 if (sub.sub_umbrella < sub.cmdsize) {
9391 const char *P = Ptr + sub.sub_umbrella;
9392 outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
9393 } else {
9394 outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
9395 }
9396}
9397
9398static void PrintSubLibraryCommand(MachO::sub_library_command sub,
9399 const char *Ptr) {
9400 outs() << " cmd LC_SUB_LIBRARY\n";
9401 outs() << " cmdsize " << sub.cmdsize;
9402 if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
9403 outs() << " Incorrect size\n";
9404 else
9405 outs() << "\n";
9406 if (sub.sub_library < sub.cmdsize) {
9407 const char *P = Ptr + sub.sub_library;
9408 outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
9409 } else {
9410 outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
9411 }
9412}
9413
9414static void PrintSubClientCommand(MachO::sub_client_command sub,
9415 const char *Ptr) {
9416 outs() << " cmd LC_SUB_CLIENT\n";
9417 outs() << " cmdsize " << sub.cmdsize;
9418 if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
9419 outs() << " Incorrect size\n";
9420 else
9421 outs() << "\n";
9422 if (sub.client < sub.cmdsize) {
9423 const char *P = Ptr + sub.client;
9424 outs() << " client " << P << " (offset " << sub.client << ")\n";
9425 } else {
9426 outs() << " client ?(bad offset " << sub.client << ")\n";
9427 }
9428}
9429
9430static void PrintRoutinesCommand(MachO::routines_command r) {
9431 outs() << " cmd LC_ROUTINES\n";
9432 outs() << " cmdsize " << r.cmdsize;
9433 if (r.cmdsize != sizeof(struct MachO::routines_command))
9434 outs() << " Incorrect size\n";
9435 else
9436 outs() << "\n";
9437 outs() << " init_address " << format(Fmt: "0x%08" PRIx32, Vals: r.init_address) << "\n";
9438 outs() << " init_module " << r.init_module << "\n";
9439 outs() << " reserved1 " << r.reserved1 << "\n";
9440 outs() << " reserved2 " << r.reserved2 << "\n";
9441 outs() << " reserved3 " << r.reserved3 << "\n";
9442 outs() << " reserved4 " << r.reserved4 << "\n";
9443 outs() << " reserved5 " << r.reserved5 << "\n";
9444 outs() << " reserved6 " << r.reserved6 << "\n";
9445}
9446
9447static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
9448 outs() << " cmd LC_ROUTINES_64\n";
9449 outs() << " cmdsize " << r.cmdsize;
9450 if (r.cmdsize != sizeof(struct MachO::routines_command_64))
9451 outs() << " Incorrect size\n";
9452 else
9453 outs() << "\n";
9454 outs() << " init_address " << format(Fmt: "0x%016" PRIx64, Vals: r.init_address) << "\n";
9455 outs() << " init_module " << r.init_module << "\n";
9456 outs() << " reserved1 " << r.reserved1 << "\n";
9457 outs() << " reserved2 " << r.reserved2 << "\n";
9458 outs() << " reserved3 " << r.reserved3 << "\n";
9459 outs() << " reserved4 " << r.reserved4 << "\n";
9460 outs() << " reserved5 " << r.reserved5 << "\n";
9461 outs() << " reserved6 " << r.reserved6 << "\n";
9462}
9463
9464static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
9465 outs() << "\t eax " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.eax);
9466 outs() << " ebx " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.ebx);
9467 outs() << " ecx " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.ecx);
9468 outs() << " edx " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.edx) << "\n";
9469 outs() << "\t edi " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.edi);
9470 outs() << " esi " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.esi);
9471 outs() << " ebp " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.ebp);
9472 outs() << " esp " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.esp) << "\n";
9473 outs() << "\t ss " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.ss);
9474 outs() << " eflags " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.eflags);
9475 outs() << " eip " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.eip);
9476 outs() << " cs " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.cs) << "\n";
9477 outs() << "\t ds " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.ds);
9478 outs() << " es " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.es);
9479 outs() << " fs " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.fs);
9480 outs() << " gs " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.gs) << "\n";
9481}
9482
9483static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
9484 outs() << " rax " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rax);
9485 outs() << " rbx " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rbx);
9486 outs() << " rcx " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rcx) << "\n";
9487 outs() << " rdx " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rdx);
9488 outs() << " rdi " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rdi);
9489 outs() << " rsi " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rsi) << "\n";
9490 outs() << " rbp " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rbp);
9491 outs() << " rsp " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rsp);
9492 outs() << " r8 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r8) << "\n";
9493 outs() << " r9 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r9);
9494 outs() << " r10 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r10);
9495 outs() << " r11 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r11) << "\n";
9496 outs() << " r12 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r12);
9497 outs() << " r13 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r13);
9498 outs() << " r14 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r14) << "\n";
9499 outs() << " r15 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.r15);
9500 outs() << " rip " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rip) << "\n";
9501 outs() << "rflags " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.rflags);
9502 outs() << " cs " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.cs);
9503 outs() << " fs " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.fs) << "\n";
9504 outs() << " gs " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.gs) << "\n";
9505}
9506
9507static void Print_mmst_reg(MachO::mmst_reg_t &r) {
9508 uint32_t f;
9509 outs() << "\t mmst_reg ";
9510 for (f = 0; f < 10; f++)
9511 outs() << format(Fmt: "%02" PRIx32, Vals: (r.mmst_reg[f] & 0xff)) << " ";
9512 outs() << "\n";
9513 outs() << "\t mmst_rsrv ";
9514 for (f = 0; f < 6; f++)
9515 outs() << format(Fmt: "%02" PRIx32, Vals: (r.mmst_rsrv[f] & 0xff)) << " ";
9516 outs() << "\n";
9517}
9518
9519static void Print_xmm_reg(MachO::xmm_reg_t &r) {
9520 uint32_t f;
9521 outs() << "\t xmm_reg ";
9522 for (f = 0; f < 16; f++)
9523 outs() << format(Fmt: "%02" PRIx32, Vals: (r.xmm_reg[f] & 0xff)) << " ";
9524 outs() << "\n";
9525}
9526
9527static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
9528 outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
9529 outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
9530 outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
9531 outs() << " denorm " << fpu.fpu_fcw.denorm;
9532 outs() << " zdiv " << fpu.fpu_fcw.zdiv;
9533 outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
9534 outs() << " undfl " << fpu.fpu_fcw.undfl;
9535 outs() << " precis " << fpu.fpu_fcw.precis << "\n";
9536 outs() << "\t\t pc ";
9537 if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
9538 outs() << "FP_PREC_24B ";
9539 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
9540 outs() << "FP_PREC_53B ";
9541 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
9542 outs() << "FP_PREC_64B ";
9543 else
9544 outs() << fpu.fpu_fcw.pc << " ";
9545 outs() << "rc ";
9546 if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
9547 outs() << "FP_RND_NEAR ";
9548 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
9549 outs() << "FP_RND_DOWN ";
9550 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
9551 outs() << "FP_RND_UP ";
9552 else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
9553 outs() << "FP_CHOP ";
9554 outs() << "\n";
9555 outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
9556 outs() << " denorm " << fpu.fpu_fsw.denorm;
9557 outs() << " zdiv " << fpu.fpu_fsw.zdiv;
9558 outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
9559 outs() << " undfl " << fpu.fpu_fsw.undfl;
9560 outs() << " precis " << fpu.fpu_fsw.precis;
9561 outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
9562 outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
9563 outs() << " c0 " << fpu.fpu_fsw.c0;
9564 outs() << " c1 " << fpu.fpu_fsw.c1;
9565 outs() << " c2 " << fpu.fpu_fsw.c2;
9566 outs() << " tos " << fpu.fpu_fsw.tos;
9567 outs() << " c3 " << fpu.fpu_fsw.c3;
9568 outs() << " busy " << fpu.fpu_fsw.busy << "\n";
9569 outs() << "\t fpu_ftw " << format(Fmt: "0x%02" PRIx32, Vals: fpu.fpu_ftw);
9570 outs() << " fpu_rsrv1 " << format(Fmt: "0x%02" PRIx32, Vals: fpu.fpu_rsrv1);
9571 outs() << " fpu_fop " << format(Fmt: "0x%04" PRIx32, Vals: fpu.fpu_fop);
9572 outs() << " fpu_ip " << format(Fmt: "0x%08" PRIx32, Vals: fpu.fpu_ip) << "\n";
9573 outs() << "\t fpu_cs " << format(Fmt: "0x%04" PRIx32, Vals: fpu.fpu_cs);
9574 outs() << " fpu_rsrv2 " << format(Fmt: "0x%04" PRIx32, Vals: fpu.fpu_rsrv2);
9575 outs() << " fpu_dp " << format(Fmt: "0x%08" PRIx32, Vals: fpu.fpu_dp);
9576 outs() << " fpu_ds " << format(Fmt: "0x%04" PRIx32, Vals: fpu.fpu_ds) << "\n";
9577 outs() << "\t fpu_rsrv3 " << format(Fmt: "0x%04" PRIx32, Vals: fpu.fpu_rsrv3);
9578 outs() << " fpu_mxcsr " << format(Fmt: "0x%08" PRIx32, Vals: fpu.fpu_mxcsr);
9579 outs() << " fpu_mxcsrmask " << format(Fmt: "0x%08" PRIx32, Vals: fpu.fpu_mxcsrmask);
9580 outs() << "\n";
9581 outs() << "\t fpu_stmm0:\n";
9582 Print_mmst_reg(r&: fpu.fpu_stmm0);
9583 outs() << "\t fpu_stmm1:\n";
9584 Print_mmst_reg(r&: fpu.fpu_stmm1);
9585 outs() << "\t fpu_stmm2:\n";
9586 Print_mmst_reg(r&: fpu.fpu_stmm2);
9587 outs() << "\t fpu_stmm3:\n";
9588 Print_mmst_reg(r&: fpu.fpu_stmm3);
9589 outs() << "\t fpu_stmm4:\n";
9590 Print_mmst_reg(r&: fpu.fpu_stmm4);
9591 outs() << "\t fpu_stmm5:\n";
9592 Print_mmst_reg(r&: fpu.fpu_stmm5);
9593 outs() << "\t fpu_stmm6:\n";
9594 Print_mmst_reg(r&: fpu.fpu_stmm6);
9595 outs() << "\t fpu_stmm7:\n";
9596 Print_mmst_reg(r&: fpu.fpu_stmm7);
9597 outs() << "\t fpu_xmm0:\n";
9598 Print_xmm_reg(r&: fpu.fpu_xmm0);
9599 outs() << "\t fpu_xmm1:\n";
9600 Print_xmm_reg(r&: fpu.fpu_xmm1);
9601 outs() << "\t fpu_xmm2:\n";
9602 Print_xmm_reg(r&: fpu.fpu_xmm2);
9603 outs() << "\t fpu_xmm3:\n";
9604 Print_xmm_reg(r&: fpu.fpu_xmm3);
9605 outs() << "\t fpu_xmm4:\n";
9606 Print_xmm_reg(r&: fpu.fpu_xmm4);
9607 outs() << "\t fpu_xmm5:\n";
9608 Print_xmm_reg(r&: fpu.fpu_xmm5);
9609 outs() << "\t fpu_xmm6:\n";
9610 Print_xmm_reg(r&: fpu.fpu_xmm6);
9611 outs() << "\t fpu_xmm7:\n";
9612 Print_xmm_reg(r&: fpu.fpu_xmm7);
9613 outs() << "\t fpu_xmm8:\n";
9614 Print_xmm_reg(r&: fpu.fpu_xmm8);
9615 outs() << "\t fpu_xmm9:\n";
9616 Print_xmm_reg(r&: fpu.fpu_xmm9);
9617 outs() << "\t fpu_xmm10:\n";
9618 Print_xmm_reg(r&: fpu.fpu_xmm10);
9619 outs() << "\t fpu_xmm11:\n";
9620 Print_xmm_reg(r&: fpu.fpu_xmm11);
9621 outs() << "\t fpu_xmm12:\n";
9622 Print_xmm_reg(r&: fpu.fpu_xmm12);
9623 outs() << "\t fpu_xmm13:\n";
9624 Print_xmm_reg(r&: fpu.fpu_xmm13);
9625 outs() << "\t fpu_xmm14:\n";
9626 Print_xmm_reg(r&: fpu.fpu_xmm14);
9627 outs() << "\t fpu_xmm15:\n";
9628 Print_xmm_reg(r&: fpu.fpu_xmm15);
9629 outs() << "\t fpu_rsrv4:\n";
9630 for (uint32_t f = 0; f < 6; f++) {
9631 outs() << "\t ";
9632 for (uint32_t g = 0; g < 16; g++)
9633 outs() << format(Fmt: "%02" PRIx32, Vals: fpu.fpu_rsrv4[f * g]) << " ";
9634 outs() << "\n";
9635 }
9636 outs() << "\t fpu_reserved1 " << format(Fmt: "0x%08" PRIx32, Vals: fpu.fpu_reserved1);
9637 outs() << "\n";
9638}
9639
9640static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
9641 outs() << "\t trapno " << format(Fmt: "0x%08" PRIx32, Vals: exc64.trapno);
9642 outs() << " err " << format(Fmt: "0x%08" PRIx32, Vals: exc64.err);
9643 outs() << " faultvaddr " << format(Fmt: "0x%016" PRIx64, Vals: exc64.faultvaddr) << "\n";
9644}
9645
9646static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {
9647 outs() << "\t r0 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[0]);
9648 outs() << " r1 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[1]);
9649 outs() << " r2 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[2]);
9650 outs() << " r3 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[3]) << "\n";
9651 outs() << "\t r4 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[4]);
9652 outs() << " r5 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[5]);
9653 outs() << " r6 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[6]);
9654 outs() << " r7 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[7]) << "\n";
9655 outs() << "\t r8 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[8]);
9656 outs() << " r9 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[9]);
9657 outs() << " r10 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[10]);
9658 outs() << " r11 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[11]) << "\n";
9659 outs() << "\t r12 " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.r[12]);
9660 outs() << " sp " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.sp);
9661 outs() << " lr " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.lr);
9662 outs() << " pc " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.pc) << "\n";
9663 outs() << "\t cpsr " << format(Fmt: "0x%08" PRIx32, Vals: cpu32.cpsr) << "\n";
9664}
9665
9666static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {
9667 outs() << "\t x0 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[0]);
9668 outs() << " x1 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[1]);
9669 outs() << " x2 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[2]) << "\n";
9670 outs() << "\t x3 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[3]);
9671 outs() << " x4 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[4]);
9672 outs() << " x5 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[5]) << "\n";
9673 outs() << "\t x6 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[6]);
9674 outs() << " x7 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[7]);
9675 outs() << " x8 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[8]) << "\n";
9676 outs() << "\t x9 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[9]);
9677 outs() << " x10 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[10]);
9678 outs() << " x11 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[11]) << "\n";
9679 outs() << "\t x12 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[12]);
9680 outs() << " x13 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[13]);
9681 outs() << " x14 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[14]) << "\n";
9682 outs() << "\t x15 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[15]);
9683 outs() << " x16 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[16]);
9684 outs() << " x17 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[17]) << "\n";
9685 outs() << "\t x18 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[18]);
9686 outs() << " x19 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[19]);
9687 outs() << " x20 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[20]) << "\n";
9688 outs() << "\t x21 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[21]);
9689 outs() << " x22 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[22]);
9690 outs() << " x23 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[23]) << "\n";
9691 outs() << "\t x24 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[24]);
9692 outs() << " x25 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[25]);
9693 outs() << " x26 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[26]) << "\n";
9694 outs() << "\t x27 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[27]);
9695 outs() << " x28 " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.x[28]);
9696 outs() << " fp " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.fp) << "\n";
9697 outs() << "\t lr " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.lr);
9698 outs() << " sp " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.sp);
9699 outs() << " pc " << format(Fmt: "0x%016" PRIx64, Vals: cpu64.pc) << "\n";
9700 outs() << "\t cpsr " << format(Fmt: "0x%08" PRIx32, Vals: cpu64.cpsr) << "\n";
9701}
9702
9703static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
9704 bool isLittleEndian, uint32_t cputype) {
9705 if (t.cmd == MachO::LC_THREAD)
9706 outs() << " cmd LC_THREAD\n";
9707 else if (t.cmd == MachO::LC_UNIXTHREAD)
9708 outs() << " cmd LC_UNIXTHREAD\n";
9709 else
9710 outs() << " cmd " << t.cmd << " (unknown)\n";
9711 outs() << " cmdsize " << t.cmdsize;
9712 if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
9713 outs() << " Incorrect size\n";
9714 else
9715 outs() << "\n";
9716
9717 const char *begin = Ptr + sizeof(struct MachO::thread_command);
9718 const char *end = Ptr + t.cmdsize;
9719 uint32_t flavor, count, left;
9720 if (cputype == MachO::CPU_TYPE_I386) {
9721 while (begin < end) {
9722 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9723 memcpy(dest: (char *)&flavor, src: begin, n: sizeof(uint32_t));
9724 begin += sizeof(uint32_t);
9725 } else {
9726 flavor = 0;
9727 begin = end;
9728 }
9729 if (isLittleEndian != sys::IsLittleEndianHost)
9730 sys::swapByteOrder(Value&: flavor);
9731 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9732 memcpy(dest: (char *)&count, src: begin, n: sizeof(uint32_t));
9733 begin += sizeof(uint32_t);
9734 } else {
9735 count = 0;
9736 begin = end;
9737 }
9738 if (isLittleEndian != sys::IsLittleEndianHost)
9739 sys::swapByteOrder(Value&: count);
9740 if (flavor == MachO::x86_THREAD_STATE32) {
9741 outs() << " flavor i386_THREAD_STATE\n";
9742 if (count == MachO::x86_THREAD_STATE32_COUNT)
9743 outs() << " count i386_THREAD_STATE_COUNT\n";
9744 else
9745 outs() << " count " << count
9746 << " (not x86_THREAD_STATE32_COUNT)\n";
9747 MachO::x86_thread_state32_t cpu32;
9748 left = end - begin;
9749 if (left >= sizeof(MachO::x86_thread_state32_t)) {
9750 memcpy(dest: &cpu32, src: begin, n: sizeof(MachO::x86_thread_state32_t));
9751 begin += sizeof(MachO::x86_thread_state32_t);
9752 } else {
9753 memset(s: &cpu32, c: '\0', n: sizeof(MachO::x86_thread_state32_t));
9754 memcpy(dest: &cpu32, src: begin, n: left);
9755 begin += left;
9756 }
9757 if (isLittleEndian != sys::IsLittleEndianHost)
9758 swapStruct(x&: cpu32);
9759 Print_x86_thread_state32_t(cpu32);
9760 } else if (flavor == MachO::x86_THREAD_STATE) {
9761 outs() << " flavor x86_THREAD_STATE\n";
9762 if (count == MachO::x86_THREAD_STATE_COUNT)
9763 outs() << " count x86_THREAD_STATE_COUNT\n";
9764 else
9765 outs() << " count " << count
9766 << " (not x86_THREAD_STATE_COUNT)\n";
9767 struct MachO::x86_thread_state_t ts;
9768 left = end - begin;
9769 if (left >= sizeof(MachO::x86_thread_state_t)) {
9770 memcpy(dest: &ts, src: begin, n: sizeof(MachO::x86_thread_state_t));
9771 begin += sizeof(MachO::x86_thread_state_t);
9772 } else {
9773 memset(s: &ts, c: '\0', n: sizeof(MachO::x86_thread_state_t));
9774 memcpy(dest: &ts, src: begin, n: left);
9775 begin += left;
9776 }
9777 if (isLittleEndian != sys::IsLittleEndianHost)
9778 swapStruct(x&: ts);
9779 if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
9780 outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
9781 if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
9782 outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
9783 else
9784 outs() << "tsh.count " << ts.tsh.count
9785 << " (not x86_THREAD_STATE32_COUNT\n";
9786 Print_x86_thread_state32_t(cpu32&: ts.uts.ts32);
9787 } else {
9788 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9789 << ts.tsh.count << "\n";
9790 }
9791 } else {
9792 outs() << " flavor " << flavor << " (unknown)\n";
9793 outs() << " count " << count << "\n";
9794 outs() << " state (unknown)\n";
9795 begin += count * sizeof(uint32_t);
9796 }
9797 }
9798 } else if (cputype == MachO::CPU_TYPE_X86_64) {
9799 while (begin < end) {
9800 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9801 memcpy(dest: (char *)&flavor, src: begin, n: sizeof(uint32_t));
9802 begin += sizeof(uint32_t);
9803 } else {
9804 flavor = 0;
9805 begin = end;
9806 }
9807 if (isLittleEndian != sys::IsLittleEndianHost)
9808 sys::swapByteOrder(Value&: flavor);
9809 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9810 memcpy(dest: (char *)&count, src: begin, n: sizeof(uint32_t));
9811 begin += sizeof(uint32_t);
9812 } else {
9813 count = 0;
9814 begin = end;
9815 }
9816 if (isLittleEndian != sys::IsLittleEndianHost)
9817 sys::swapByteOrder(Value&: count);
9818 if (flavor == MachO::x86_THREAD_STATE64) {
9819 outs() << " flavor x86_THREAD_STATE64\n";
9820 if (count == MachO::x86_THREAD_STATE64_COUNT)
9821 outs() << " count x86_THREAD_STATE64_COUNT\n";
9822 else
9823 outs() << " count " << count
9824 << " (not x86_THREAD_STATE64_COUNT)\n";
9825 MachO::x86_thread_state64_t cpu64;
9826 left = end - begin;
9827 if (left >= sizeof(MachO::x86_thread_state64_t)) {
9828 memcpy(dest: &cpu64, src: begin, n: sizeof(MachO::x86_thread_state64_t));
9829 begin += sizeof(MachO::x86_thread_state64_t);
9830 } else {
9831 memset(s: &cpu64, c: '\0', n: sizeof(MachO::x86_thread_state64_t));
9832 memcpy(dest: &cpu64, src: begin, n: left);
9833 begin += left;
9834 }
9835 if (isLittleEndian != sys::IsLittleEndianHost)
9836 swapStruct(x&: cpu64);
9837 Print_x86_thread_state64_t(cpu64);
9838 } else if (flavor == MachO::x86_THREAD_STATE) {
9839 outs() << " flavor x86_THREAD_STATE\n";
9840 if (count == MachO::x86_THREAD_STATE_COUNT)
9841 outs() << " count x86_THREAD_STATE_COUNT\n";
9842 else
9843 outs() << " count " << count
9844 << " (not x86_THREAD_STATE_COUNT)\n";
9845 struct MachO::x86_thread_state_t ts;
9846 left = end - begin;
9847 if (left >= sizeof(MachO::x86_thread_state_t)) {
9848 memcpy(dest: &ts, src: begin, n: sizeof(MachO::x86_thread_state_t));
9849 begin += sizeof(MachO::x86_thread_state_t);
9850 } else {
9851 memset(s: &ts, c: '\0', n: sizeof(MachO::x86_thread_state_t));
9852 memcpy(dest: &ts, src: begin, n: left);
9853 begin += left;
9854 }
9855 if (isLittleEndian != sys::IsLittleEndianHost)
9856 swapStruct(x&: ts);
9857 if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
9858 outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
9859 if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
9860 outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
9861 else
9862 outs() << "tsh.count " << ts.tsh.count
9863 << " (not x86_THREAD_STATE64_COUNT\n";
9864 Print_x86_thread_state64_t(cpu64&: ts.uts.ts64);
9865 } else {
9866 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9867 << ts.tsh.count << "\n";
9868 }
9869 } else if (flavor == MachO::x86_FLOAT_STATE) {
9870 outs() << " flavor x86_FLOAT_STATE\n";
9871 if (count == MachO::x86_FLOAT_STATE_COUNT)
9872 outs() << " count x86_FLOAT_STATE_COUNT\n";
9873 else
9874 outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
9875 struct MachO::x86_float_state_t fs;
9876 left = end - begin;
9877 if (left >= sizeof(MachO::x86_float_state_t)) {
9878 memcpy(dest: &fs, src: begin, n: sizeof(MachO::x86_float_state_t));
9879 begin += sizeof(MachO::x86_float_state_t);
9880 } else {
9881 memset(s: &fs, c: '\0', n: sizeof(MachO::x86_float_state_t));
9882 memcpy(dest: &fs, src: begin, n: left);
9883 begin += left;
9884 }
9885 if (isLittleEndian != sys::IsLittleEndianHost)
9886 swapStruct(x&: fs);
9887 if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
9888 outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
9889 if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
9890 outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
9891 else
9892 outs() << "fsh.count " << fs.fsh.count
9893 << " (not x86_FLOAT_STATE64_COUNT\n";
9894 Print_x86_float_state_t(fpu&: fs.ufs.fs64);
9895 } else {
9896 outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
9897 << fs.fsh.count << "\n";
9898 }
9899 } else if (flavor == MachO::x86_EXCEPTION_STATE) {
9900 outs() << " flavor x86_EXCEPTION_STATE\n";
9901 if (count == MachO::x86_EXCEPTION_STATE_COUNT)
9902 outs() << " count x86_EXCEPTION_STATE_COUNT\n";
9903 else
9904 outs() << " count " << count
9905 << " (not x86_EXCEPTION_STATE_COUNT)\n";
9906 struct MachO::x86_exception_state_t es;
9907 left = end - begin;
9908 if (left >= sizeof(MachO::x86_exception_state_t)) {
9909 memcpy(dest: &es, src: begin, n: sizeof(MachO::x86_exception_state_t));
9910 begin += sizeof(MachO::x86_exception_state_t);
9911 } else {
9912 memset(s: &es, c: '\0', n: sizeof(MachO::x86_exception_state_t));
9913 memcpy(dest: &es, src: begin, n: left);
9914 begin += left;
9915 }
9916 if (isLittleEndian != sys::IsLittleEndianHost)
9917 swapStruct(x&: es);
9918 if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
9919 outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
9920 if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
9921 outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
9922 else
9923 outs() << "\t esh.count " << es.esh.count
9924 << " (not x86_EXCEPTION_STATE64_COUNT\n";
9925 Print_x86_exception_state_t(exc64&: es.ues.es64);
9926 } else {
9927 outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
9928 << es.esh.count << "\n";
9929 }
9930 } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
9931 outs() << " flavor x86_EXCEPTION_STATE64\n";
9932 if (count == MachO::x86_EXCEPTION_STATE64_COUNT)
9933 outs() << " count x86_EXCEPTION_STATE64_COUNT\n";
9934 else
9935 outs() << " count " << count
9936 << " (not x86_EXCEPTION_STATE64_COUNT)\n";
9937 struct MachO::x86_exception_state64_t es64;
9938 left = end - begin;
9939 if (left >= sizeof(MachO::x86_exception_state64_t)) {
9940 memcpy(dest: &es64, src: begin, n: sizeof(MachO::x86_exception_state64_t));
9941 begin += sizeof(MachO::x86_exception_state64_t);
9942 } else {
9943 memset(s: &es64, c: '\0', n: sizeof(MachO::x86_exception_state64_t));
9944 memcpy(dest: &es64, src: begin, n: left);
9945 begin += left;
9946 }
9947 if (isLittleEndian != sys::IsLittleEndianHost)
9948 swapStruct(x&: es64);
9949 Print_x86_exception_state_t(exc64&: es64);
9950 } else {
9951 outs() << " flavor " << flavor << " (unknown)\n";
9952 outs() << " count " << count << "\n";
9953 outs() << " state (unknown)\n";
9954 begin += count * sizeof(uint32_t);
9955 }
9956 }
9957 } else if (cputype == MachO::CPU_TYPE_ARM) {
9958 while (begin < end) {
9959 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9960 memcpy(dest: (char *)&flavor, src: begin, n: sizeof(uint32_t));
9961 begin += sizeof(uint32_t);
9962 } else {
9963 flavor = 0;
9964 begin = end;
9965 }
9966 if (isLittleEndian != sys::IsLittleEndianHost)
9967 sys::swapByteOrder(Value&: flavor);
9968 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9969 memcpy(dest: (char *)&count, src: begin, n: sizeof(uint32_t));
9970 begin += sizeof(uint32_t);
9971 } else {
9972 count = 0;
9973 begin = end;
9974 }
9975 if (isLittleEndian != sys::IsLittleEndianHost)
9976 sys::swapByteOrder(Value&: count);
9977 if (flavor == MachO::ARM_THREAD_STATE) {
9978 outs() << " flavor ARM_THREAD_STATE\n";
9979 if (count == MachO::ARM_THREAD_STATE_COUNT)
9980 outs() << " count ARM_THREAD_STATE_COUNT\n";
9981 else
9982 outs() << " count " << count
9983 << " (not ARM_THREAD_STATE_COUNT)\n";
9984 MachO::arm_thread_state32_t cpu32;
9985 left = end - begin;
9986 if (left >= sizeof(MachO::arm_thread_state32_t)) {
9987 memcpy(dest: &cpu32, src: begin, n: sizeof(MachO::arm_thread_state32_t));
9988 begin += sizeof(MachO::arm_thread_state32_t);
9989 } else {
9990 memset(s: &cpu32, c: '\0', n: sizeof(MachO::arm_thread_state32_t));
9991 memcpy(dest: &cpu32, src: begin, n: left);
9992 begin += left;
9993 }
9994 if (isLittleEndian != sys::IsLittleEndianHost)
9995 swapStruct(x&: cpu32);
9996 Print_arm_thread_state32_t(cpu32);
9997 } else {
9998 outs() << " flavor " << flavor << " (unknown)\n";
9999 outs() << " count " << count << "\n";
10000 outs() << " state (unknown)\n";
10001 begin += count * sizeof(uint32_t);
10002 }
10003 }
10004 } else if (cputype == MachO::CPU_TYPE_ARM64 ||
10005 cputype == MachO::CPU_TYPE_ARM64_32) {
10006 while (begin < end) {
10007 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10008 memcpy(dest: (char *)&flavor, src: begin, n: sizeof(uint32_t));
10009 begin += sizeof(uint32_t);
10010 } else {
10011 flavor = 0;
10012 begin = end;
10013 }
10014 if (isLittleEndian != sys::IsLittleEndianHost)
10015 sys::swapByteOrder(Value&: flavor);
10016 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10017 memcpy(dest: (char *)&count, src: begin, n: sizeof(uint32_t));
10018 begin += sizeof(uint32_t);
10019 } else {
10020 count = 0;
10021 begin = end;
10022 }
10023 if (isLittleEndian != sys::IsLittleEndianHost)
10024 sys::swapByteOrder(Value&: count);
10025 if (flavor == MachO::ARM_THREAD_STATE64) {
10026 outs() << " flavor ARM_THREAD_STATE64\n";
10027 if (count == MachO::ARM_THREAD_STATE64_COUNT)
10028 outs() << " count ARM_THREAD_STATE64_COUNT\n";
10029 else
10030 outs() << " count " << count
10031 << " (not ARM_THREAD_STATE64_COUNT)\n";
10032 MachO::arm_thread_state64_t cpu64;
10033 left = end - begin;
10034 if (left >= sizeof(MachO::arm_thread_state64_t)) {
10035 memcpy(dest: &cpu64, src: begin, n: sizeof(MachO::arm_thread_state64_t));
10036 begin += sizeof(MachO::arm_thread_state64_t);
10037 } else {
10038 memset(s: &cpu64, c: '\0', n: sizeof(MachO::arm_thread_state64_t));
10039 memcpy(dest: &cpu64, src: begin, n: left);
10040 begin += left;
10041 }
10042 if (isLittleEndian != sys::IsLittleEndianHost)
10043 swapStruct(x&: cpu64);
10044 Print_arm_thread_state64_t(cpu64);
10045 } else {
10046 outs() << " flavor " << flavor << " (unknown)\n";
10047 outs() << " count " << count << "\n";
10048 outs() << " state (unknown)\n";
10049 begin += count * sizeof(uint32_t);
10050 }
10051 }
10052 } else {
10053 while (begin < end) {
10054 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10055 memcpy(dest: (char *)&flavor, src: begin, n: sizeof(uint32_t));
10056 begin += sizeof(uint32_t);
10057 } else {
10058 flavor = 0;
10059 begin = end;
10060 }
10061 if (isLittleEndian != sys::IsLittleEndianHost)
10062 sys::swapByteOrder(Value&: flavor);
10063 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
10064 memcpy(dest: (char *)&count, src: begin, n: sizeof(uint32_t));
10065 begin += sizeof(uint32_t);
10066 } else {
10067 count = 0;
10068 begin = end;
10069 }
10070 if (isLittleEndian != sys::IsLittleEndianHost)
10071 sys::swapByteOrder(Value&: count);
10072 outs() << " flavor " << flavor << "\n";
10073 outs() << " count " << count << "\n";
10074 outs() << " state (Unknown cputype/cpusubtype)\n";
10075 begin += count * sizeof(uint32_t);
10076 }
10077 }
10078}
10079
10080static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
10081 if (dl.cmd == MachO::LC_ID_DYLIB)
10082 outs() << " cmd LC_ID_DYLIB\n";
10083 else if (dl.cmd == MachO::LC_LOAD_DYLIB)
10084 outs() << " cmd LC_LOAD_DYLIB\n";
10085 else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
10086 outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
10087 else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
10088 outs() << " cmd LC_REEXPORT_DYLIB\n";
10089 else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
10090 outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
10091 else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
10092 outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
10093 else
10094 outs() << " cmd " << dl.cmd << " (unknown)\n";
10095 outs() << " cmdsize " << dl.cmdsize;
10096 if (dl.cmdsize < sizeof(struct MachO::dylib_command))
10097 outs() << " Incorrect size\n";
10098 else
10099 outs() << "\n";
10100 if (dl.dylib.name < dl.cmdsize) {
10101 const char *P = Ptr + dl.dylib.name;
10102 outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
10103 } else {
10104 outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
10105 }
10106 outs() << " time stamp " << dl.dylib.timestamp << " ";
10107 time_t t = dl.dylib.timestamp;
10108 outs() << ctime(timer: &t);
10109 outs() << " current version ";
10110 if (dl.dylib.current_version == 0xffffffff)
10111 outs() << "n/a\n";
10112 else
10113 outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
10114 << ((dl.dylib.current_version >> 8) & 0xff) << "."
10115 << (dl.dylib.current_version & 0xff) << "\n";
10116 outs() << "compatibility version ";
10117 if (dl.dylib.compatibility_version == 0xffffffff)
10118 outs() << "n/a\n";
10119 else
10120 outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
10121 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
10122 << (dl.dylib.compatibility_version & 0xff) << "\n";
10123}
10124
10125static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
10126 uint32_t object_size) {
10127 if (ld.cmd == MachO::LC_CODE_SIGNATURE)
10128 outs() << " cmd LC_CODE_SIGNATURE\n";
10129 else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
10130 outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
10131 else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
10132 outs() << " cmd LC_FUNCTION_STARTS\n";
10133 else if (ld.cmd == MachO::LC_DATA_IN_CODE)
10134 outs() << " cmd LC_DATA_IN_CODE\n";
10135 else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
10136 outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
10137 else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
10138 outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
10139 else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)
10140 outs() << " cmd LC_DYLD_EXPORTS_TRIE\n";
10141 else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)
10142 outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n";
10143 else if (ld.cmd == MachO::LC_ATOM_INFO)
10144 outs() << " cmd LC_ATOM_INFO\n";
10145 else
10146 outs() << " cmd " << ld.cmd << " (?)\n";
10147 outs() << " cmdsize " << ld.cmdsize;
10148 if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
10149 outs() << " Incorrect size\n";
10150 else
10151 outs() << "\n";
10152 outs() << " dataoff " << ld.dataoff;
10153 if (ld.dataoff > object_size)
10154 outs() << " (past end of file)\n";
10155 else
10156 outs() << "\n";
10157 outs() << " datasize " << ld.datasize;
10158 uint64_t big_size = ld.dataoff;
10159 big_size += ld.datasize;
10160 if (big_size > object_size)
10161 outs() << " (past end of file)\n";
10162 else
10163 outs() << "\n";
10164}
10165
10166static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
10167 uint32_t cputype, bool verbose) {
10168 StringRef Buf = Obj->getData();
10169 unsigned Index = 0;
10170 for (const auto &Command : Obj->load_commands()) {
10171 outs() << "Load command " << Index++ << "\n";
10172 if (Command.C.cmd == MachO::LC_SEGMENT) {
10173 MachO::segment_command SLC = Obj->getSegmentLoadCommand(L: Command);
10174 const char *sg_segname = SLC.segname;
10175 PrintSegmentCommand(cmd: SLC.cmd, cmdsize: SLC.cmdsize, SegName: SLC.segname, vmaddr: SLC.vmaddr,
10176 vmsize: SLC.vmsize, fileoff: SLC.fileoff, filesize: SLC.filesize, maxprot: SLC.maxprot,
10177 initprot: SLC.initprot, nsects: SLC.nsects, flags: SLC.flags, object_size: Buf.size(),
10178 verbose);
10179 for (unsigned j = 0; j < SLC.nsects; j++) {
10180 MachO::section S = Obj->getSection(L: Command, Index: j);
10181 PrintSection(sectname: S.sectname, segname: S.segname, addr: S.addr, size: S.size, offset: S.offset, align: S.align,
10182 reloff: S.reloff, nreloc: S.nreloc, flags: S.flags, reserved1: S.reserved1, reserved2: S.reserved2,
10183 cmd: SLC.cmd, sg_segname, filetype, object_size: Buf.size(), verbose);
10184 }
10185 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10186 MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(L: Command);
10187 const char *sg_segname = SLC_64.segname;
10188 PrintSegmentCommand(cmd: SLC_64.cmd, cmdsize: SLC_64.cmdsize, SegName: SLC_64.segname,
10189 vmaddr: SLC_64.vmaddr, vmsize: SLC_64.vmsize, fileoff: SLC_64.fileoff,
10190 filesize: SLC_64.filesize, maxprot: SLC_64.maxprot, initprot: SLC_64.initprot,
10191 nsects: SLC_64.nsects, flags: SLC_64.flags, object_size: Buf.size(), verbose);
10192 for (unsigned j = 0; j < SLC_64.nsects; j++) {
10193 MachO::section_64 S_64 = Obj->getSection64(L: Command, Index: j);
10194 PrintSection(sectname: S_64.sectname, segname: S_64.segname, addr: S_64.addr, size: S_64.size,
10195 offset: S_64.offset, align: S_64.align, reloff: S_64.reloff, nreloc: S_64.nreloc,
10196 flags: S_64.flags, reserved1: S_64.reserved1, reserved2: S_64.reserved2, cmd: SLC_64.cmd,
10197 sg_segname, filetype, object_size: Buf.size(), verbose);
10198 }
10199 } else if (Command.C.cmd == MachO::LC_SYMTAB) {
10200 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10201 PrintSymtabLoadCommand(st: Symtab, Is64Bit: Obj->is64Bit(), object_size: Buf.size());
10202 } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
10203 MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
10204 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10205 PrintDysymtabLoadCommand(dyst: Dysymtab, nsyms: Symtab.nsyms, object_size: Buf.size(),
10206 Is64Bit: Obj->is64Bit());
10207 } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
10208 Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
10209 MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(L: Command);
10210 PrintDyldInfoLoadCommand(dc: DyldInfo, object_size: Buf.size());
10211 } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
10212 Command.C.cmd == MachO::LC_ID_DYLINKER ||
10213 Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
10214 MachO::dylinker_command Dyld = Obj->getDylinkerCommand(L: Command);
10215 PrintDyldLoadCommand(dyld: Dyld, Ptr: Command.Ptr);
10216 } else if (Command.C.cmd == MachO::LC_UUID) {
10217 MachO::uuid_command Uuid = Obj->getUuidCommand(L: Command);
10218 PrintUuidLoadCommand(uuid: Uuid);
10219 } else if (Command.C.cmd == MachO::LC_RPATH) {
10220 MachO::rpath_command Rpath = Obj->getRpathCommand(L: Command);
10221 PrintRpathLoadCommand(rpath: Rpath, Ptr: Command.Ptr);
10222 } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
10223 Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||
10224 Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||
10225 Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
10226 MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(L: Command);
10227 PrintVersionMinLoadCommand(vd: Vd);
10228 } else if (Command.C.cmd == MachO::LC_NOTE) {
10229 MachO::note_command Nt = Obj->getNoteLoadCommand(L: Command);
10230 PrintNoteLoadCommand(Nt);
10231 } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
10232 MachO::build_version_command Bv =
10233 Obj->getBuildVersionLoadCommand(L: Command);
10234 PrintBuildVersionLoadCommand(obj: Obj, bd: Bv, verbose);
10235 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
10236 MachO::source_version_command Sd = Obj->getSourceVersionCommand(L: Command);
10237 PrintSourceVersionCommand(sd: Sd);
10238 } else if (Command.C.cmd == MachO::LC_MAIN) {
10239 MachO::entry_point_command Ep = Obj->getEntryPointCommand(L: Command);
10240 PrintEntryPointCommand(ep: Ep);
10241 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
10242 MachO::encryption_info_command Ei =
10243 Obj->getEncryptionInfoCommand(L: Command);
10244 PrintEncryptionInfoCommand(ec: Ei, object_size: Buf.size());
10245 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
10246 MachO::encryption_info_command_64 Ei =
10247 Obj->getEncryptionInfoCommand64(L: Command);
10248 PrintEncryptionInfoCommand64(ec: Ei, object_size: Buf.size());
10249 } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
10250 MachO::linker_option_command Lo =
10251 Obj->getLinkerOptionLoadCommand(L: Command);
10252 PrintLinkerOptionCommand(lo: Lo, Ptr: Command.Ptr);
10253 } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
10254 MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(L: Command);
10255 PrintSubFrameworkCommand(sub: Sf, Ptr: Command.Ptr);
10256 } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
10257 MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(L: Command);
10258 PrintSubUmbrellaCommand(sub: Sf, Ptr: Command.Ptr);
10259 } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
10260 MachO::sub_library_command Sl = Obj->getSubLibraryCommand(L: Command);
10261 PrintSubLibraryCommand(sub: Sl, Ptr: Command.Ptr);
10262 } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
10263 MachO::sub_client_command Sc = Obj->getSubClientCommand(L: Command);
10264 PrintSubClientCommand(sub: Sc, Ptr: Command.Ptr);
10265 } else if (Command.C.cmd == MachO::LC_ROUTINES) {
10266 MachO::routines_command Rc = Obj->getRoutinesCommand(L: Command);
10267 PrintRoutinesCommand(r: Rc);
10268 } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
10269 MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(L: Command);
10270 PrintRoutinesCommand64(r: Rc);
10271 } else if (Command.C.cmd == MachO::LC_THREAD ||
10272 Command.C.cmd == MachO::LC_UNIXTHREAD) {
10273 MachO::thread_command Tc = Obj->getThreadCommand(L: Command);
10274 PrintThreadCommand(t: Tc, Ptr: Command.Ptr, isLittleEndian: Obj->isLittleEndian(), cputype);
10275 } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
10276 Command.C.cmd == MachO::LC_ID_DYLIB ||
10277 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
10278 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
10279 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
10280 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
10281 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(L: Command);
10282 PrintDylibCommand(dl: Dl, Ptr: Command.Ptr);
10283 } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
10284 Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
10285 Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
10286 Command.C.cmd == MachO::LC_DATA_IN_CODE ||
10287 Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
10288 Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||
10289 Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||
10290 Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||
10291 Command.C.cmd == MachO::LC_ATOM_INFO) {
10292 MachO::linkedit_data_command Ld =
10293 Obj->getLinkeditDataLoadCommand(L: Command);
10294 PrintLinkEditDataCommand(ld: Ld, object_size: Buf.size());
10295 } else {
10296 outs() << " cmd ?(" << format(Fmt: "0x%08" PRIx32, Vals: Command.C.cmd)
10297 << ")\n";
10298 outs() << " cmdsize " << Command.C.cmdsize << "\n";
10299 // TODO: get and print the raw bytes of the load command.
10300 }
10301 // TODO: print all the other kinds of load commands.
10302 }
10303}
10304
10305static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
10306 if (Obj->is64Bit()) {
10307 MachO::mach_header_64 H_64;
10308 H_64 = Obj->getHeader64();
10309 PrintMachHeader(magic: H_64.magic, cputype: H_64.cputype, cpusubtype: H_64.cpusubtype, filetype: H_64.filetype,
10310 ncmds: H_64.ncmds, sizeofcmds: H_64.sizeofcmds, flags: H_64.flags, verbose);
10311 } else {
10312 MachO::mach_header H;
10313 H = Obj->getHeader();
10314 PrintMachHeader(magic: H.magic, cputype: H.cputype, cpusubtype: H.cpusubtype, filetype: H.filetype, ncmds: H.ncmds,
10315 sizeofcmds: H.sizeofcmds, flags: H.flags, verbose);
10316 }
10317}
10318
10319void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {
10320 const MachOObjectFile *file = cast<const MachOObjectFile>(Val: Obj);
10321 PrintMachHeader(Obj: file, verbose: Verbose);
10322}
10323
10324void MachODumper::printPrivateHeaders() {
10325 printMachOFileHeader(Obj: &Obj);
10326 if (!FirstPrivateHeader)
10327 printMachOLoadCommands(O: &Obj);
10328}
10329
10330void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {
10331 const MachOObjectFile *file = cast<const MachOObjectFile>(Val: Obj);
10332 uint32_t filetype = 0;
10333 uint32_t cputype = 0;
10334 if (file->is64Bit()) {
10335 MachO::mach_header_64 H_64;
10336 H_64 = file->getHeader64();
10337 filetype = H_64.filetype;
10338 cputype = H_64.cputype;
10339 } else {
10340 MachO::mach_header H;
10341 H = file->getHeader();
10342 filetype = H.filetype;
10343 cputype = H.cputype;
10344 }
10345 PrintLoadCommands(Obj: file, filetype, cputype, verbose: Verbose);
10346}
10347
10348//===----------------------------------------------------------------------===//
10349// export trie dumping
10350//===----------------------------------------------------------------------===//
10351
10352static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {
10353 uint64_t BaseSegmentAddress = 0;
10354 for (const auto &Command : Obj->load_commands()) {
10355 if (Command.C.cmd == MachO::LC_SEGMENT) {
10356 MachO::segment_command Seg = Obj->getSegmentLoadCommand(L: Command);
10357 if (Seg.fileoff == 0 && Seg.filesize != 0) {
10358 BaseSegmentAddress = Seg.vmaddr;
10359 break;
10360 }
10361 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10362 MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(L: Command);
10363 if (Seg.fileoff == 0 && Seg.filesize != 0) {
10364 BaseSegmentAddress = Seg.vmaddr;
10365 break;
10366 }
10367 }
10368 }
10369 Error Err = Error::success();
10370 for (const object::ExportEntry &Entry : Obj->exports(Err)) {
10371 uint64_t Flags = Entry.flags();
10372 bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
10373 bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
10374 bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10375 MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
10376 bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10377 MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
10378 bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
10379 if (ReExport)
10380 outs() << "[re-export] ";
10381 else
10382 outs() << format(Fmt: "0x%08llX ",
10383 Vals: Entry.address() + BaseSegmentAddress);
10384 outs() << Entry.name();
10385 if (WeakDef || ThreadLocal || Resolver || Abs) {
10386 ListSeparator LS;
10387 outs() << " [";
10388 if (WeakDef)
10389 outs() << LS << "weak_def";
10390 if (ThreadLocal)
10391 outs() << LS << "per-thread";
10392 if (Abs)
10393 outs() << LS << "absolute";
10394 if (Resolver)
10395 outs() << LS << format(Fmt: "resolver=0x%08llX", Vals: Entry.other());
10396 outs() << "]";
10397 }
10398 if (ReExport) {
10399 StringRef DylibName = "unknown";
10400 int Ordinal = Entry.other() - 1;
10401 Obj->getLibraryShortNameByIndex(Index: Ordinal, DylibName);
10402 if (Entry.otherName().empty())
10403 outs() << " (from " << DylibName << ")";
10404 else
10405 outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
10406 }
10407 outs() << "\n";
10408 }
10409 if (Err)
10410 reportError(E: std::move(Err), FileName: Obj->getFileName());
10411}
10412
10413//===----------------------------------------------------------------------===//
10414// rebase table dumping
10415//===----------------------------------------------------------------------===//
10416
10417static void printMachORebaseTable(object::MachOObjectFile *Obj) {
10418 outs() << "segment section address type\n";
10419 Error Err = Error::success();
10420 for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
10421 StringRef SegmentName = Entry.segmentName();
10422 StringRef SectionName = Entry.sectionName();
10423 uint64_t Address = Entry.address();
10424
10425 // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
10426 outs() << format(Fmt: "%-8s %-18s 0x%08" PRIX64 " %s\n",
10427 Vals: SegmentName.str().c_str(), Vals: SectionName.str().c_str(),
10428 Vals: Address, Vals: Entry.typeName().str().c_str());
10429 }
10430 if (Err)
10431 reportError(E: std::move(Err), FileName: Obj->getFileName());
10432}
10433
10434static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
10435 StringRef DylibName;
10436 switch (Ordinal) {
10437 case MachO::BIND_SPECIAL_DYLIB_SELF:
10438 return "this-image";
10439 case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
10440 return "main-executable";
10441 case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
10442 return "flat-namespace";
10443 case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
10444 return "weak";
10445 default:
10446 if (Ordinal > 0) {
10447 std::error_code EC =
10448 Obj->getLibraryShortNameByIndex(Index: Ordinal - 1, DylibName);
10449 if (EC)
10450 return "<<bad library ordinal>>";
10451 return DylibName;
10452 }
10453 }
10454 return "<<unknown special ordinal>>";
10455}
10456
10457//===----------------------------------------------------------------------===//
10458// bind table dumping
10459//===----------------------------------------------------------------------===//
10460
10461static void printMachOBindTable(object::MachOObjectFile *Obj) {
10462 // Build table of sections so names can used in final output.
10463 outs() << "segment section address type "
10464 "addend dylib symbol\n";
10465 Error Err = Error::success();
10466 for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
10467 StringRef SegmentName = Entry.segmentName();
10468 StringRef SectionName = Entry.sectionName();
10469 uint64_t Address = Entry.address();
10470
10471 // Table lines look like:
10472 // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
10473 StringRef Attr;
10474 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
10475 Attr = " (weak_import)";
10476 outs() << left_justify(Str: SegmentName, Width: 8) << " "
10477 << left_justify(Str: SectionName, Width: 18) << " "
10478 << format_hex(N: Address, Width: 10, Upper: true) << " "
10479 << left_justify(Str: Entry.typeName(), Width: 8) << " "
10480 << format_decimal(N: Entry.addend(), Width: 8) << " "
10481 << left_justify(Str: ordinalName(Obj, Ordinal: Entry.ordinal()), Width: 16) << " "
10482 << Entry.symbolName() << Attr << "\n";
10483 }
10484 if (Err)
10485 reportError(E: std::move(Err), FileName: Obj->getFileName());
10486}
10487
10488//===----------------------------------------------------------------------===//
10489// lazy bind table dumping
10490//===----------------------------------------------------------------------===//
10491
10492static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {
10493 outs() << "segment section address "
10494 "dylib symbol\n";
10495 Error Err = Error::success();
10496 for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
10497 StringRef SegmentName = Entry.segmentName();
10498 StringRef SectionName = Entry.sectionName();
10499 uint64_t Address = Entry.address();
10500
10501 // Table lines look like:
10502 // __DATA __got 0x00012010 libSystem ___stack_chk_guard
10503 outs() << left_justify(Str: SegmentName, Width: 8) << " "
10504 << left_justify(Str: SectionName, Width: 18) << " "
10505 << format_hex(N: Address, Width: 10, Upper: true) << " "
10506 << left_justify(Str: ordinalName(Obj, Ordinal: Entry.ordinal()), Width: 16) << " "
10507 << Entry.symbolName() << "\n";
10508 }
10509 if (Err)
10510 reportError(E: std::move(Err), FileName: Obj->getFileName());
10511}
10512
10513//===----------------------------------------------------------------------===//
10514// weak bind table dumping
10515//===----------------------------------------------------------------------===//
10516
10517static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {
10518 outs() << "segment section address "
10519 "type addend symbol\n";
10520 Error Err = Error::success();
10521 for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
10522 // Strong symbols don't have a location to update.
10523 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
10524 outs() << " strong "
10525 << Entry.symbolName() << "\n";
10526 continue;
10527 }
10528 StringRef SegmentName = Entry.segmentName();
10529 StringRef SectionName = Entry.sectionName();
10530 uint64_t Address = Entry.address();
10531
10532 // Table lines look like:
10533 // __DATA __data 0x00001000 pointer 0 _foo
10534 outs() << left_justify(Str: SegmentName, Width: 8) << " "
10535 << left_justify(Str: SectionName, Width: 18) << " "
10536 << format_hex(N: Address, Width: 10, Upper: true) << " "
10537 << left_justify(Str: Entry.typeName(), Width: 8) << " "
10538 << format_decimal(N: Entry.addend(), Width: 8) << " " << Entry.symbolName()
10539 << "\n";
10540 }
10541 if (Err)
10542 reportError(E: std::move(Err), FileName: Obj->getFileName());
10543}
10544
10545// get_dyld_bind_info_symbolname() is used for disassembly and passed an
10546// address, ReferenceValue, in the Mach-O file and looks in the dyld bind
10547// information for that address. If the address is found its binding symbol
10548// name is returned. If not nullptr is returned.
10549static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
10550 struct DisassembleInfo *info) {
10551 if (info->bindtable == nullptr) {
10552 info->bindtable = std::make_unique<SymbolAddressMap>();
10553 Error Err = Error::success();
10554 for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
10555 uint64_t Address = Entry.address();
10556 StringRef name = Entry.symbolName();
10557 if (!name.empty())
10558 (*info->bindtable)[Address] = name;
10559 }
10560 if (Err)
10561 reportError(E: std::move(Err), FileName: info->O->getFileName());
10562 }
10563 auto name = info->bindtable->lookup(Val: ReferenceValue);
10564 return !name.empty() ? name.data() : nullptr;
10565}
10566
10567void objdump::printLazyBindTable(ObjectFile *o) {
10568 outs() << "\nLazy bind table:\n";
10569 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Val: o))
10570 printMachOLazyBindTable(Obj: MachO);
10571 else
10572 WithColor::error()
10573 << "This operation is only currently supported "
10574 "for Mach-O executable files.\n";
10575}
10576
10577void objdump::printWeakBindTable(ObjectFile *o) {
10578 outs() << "\nWeak bind table:\n";
10579 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Val: o))
10580 printMachOWeakBindTable(Obj: MachO);
10581 else
10582 WithColor::error()
10583 << "This operation is only currently supported "
10584 "for Mach-O executable files.\n";
10585}
10586
10587void objdump::printExportsTrie(const ObjectFile *o) {
10588 outs() << "\nExports trie:\n";
10589 if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Val: o))
10590 printMachOExportsTrie(Obj: MachO);
10591 else
10592 WithColor::error()
10593 << "This operation is only currently supported "
10594 "for Mach-O executable files.\n";
10595}
10596
10597void objdump::printRebaseTable(ObjectFile *o) {
10598 outs() << "\nRebase table:\n";
10599 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Val: o))
10600 printMachORebaseTable(Obj: MachO);
10601 else
10602 WithColor::error()
10603 << "This operation is only currently supported "
10604 "for Mach-O executable files.\n";
10605}
10606
10607void objdump::printBindTable(ObjectFile *o) {
10608 outs() << "\nBind table:\n";
10609 if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Val: o))
10610 printMachOBindTable(Obj: MachO);
10611 else
10612 WithColor::error()
10613 << "This operation is only currently supported "
10614 "for Mach-O executable files.\n";
10615}
10616