Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/tools/llvm-objdump/MachODump.cpp
Warning:line 3109, column 25
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

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