1//===- MachODumper.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-readobj.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ObjDumper.h"
14#include "StackMapPrinter.h"
15#include "llvm-readobj.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Object/MachO.h"
19#include "llvm/Support/BinaryStreamReader.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/ScopedPrinter.h"
22
23using namespace llvm;
24using namespace object;
25
26namespace {
27
28class MachODumper : public ObjDumper {
29public:
30 MachODumper(const MachOObjectFile *Obj, ScopedPrinter &Writer)
31 : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {}
32
33 void printFileHeaders() override;
34 void printSectionHeaders() override;
35 void printRelocations() override;
36 void printUnwindInfo() override;
37 void printStackMap() const override;
38 void printCGProfile() override;
39
40 void printNeededLibraries() override;
41
42 bool canCompareSymbols() const override { return true; }
43 bool compareSymbolsByName(object::SymbolRef LHS,
44 object::SymbolRef RHS) const override;
45 bool compareSymbolsByType(object::SymbolRef LHS,
46 object::SymbolRef RHS) const override;
47 // MachO-specific.
48 void printMachODataInCode() override;
49 void printMachOVersionMin() override;
50 void printMachOTargetTriple() override;
51 void printMachODysymtab() override;
52 void printMachOSegment() override;
53 void printMachOIndirectSymbols() override;
54 void printMachOLinkerOptions () override;
55
56private:
57 template<class MachHeader>
58 void printFileHeaders(const MachHeader &Header);
59
60 StringRef getSymbolName(const SymbolRef &Symbol) const;
61 uint8_t getSymbolType(const SymbolRef &Symbol) const;
62
63 void printSymbols(bool ExtraSymInfo) override;
64 void printSymbols(std::optional<SymbolComparator> SymComp) override;
65 void printDynamicSymbols() override;
66 void printDynamicSymbols(std::optional<SymbolComparator> SymComp) override;
67 void printSymbol(const SymbolRef &Symbol, ScopedPrinter &W);
68 void printSymbol(const SymbolRef &Symbol);
69
70 void printRelocation(const RelocationRef &Reloc);
71
72 void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc);
73
74 void printSectionHeaders(const MachOObjectFile *Obj);
75
76 const MachOObjectFile *Obj;
77};
78
79} // namespace
80
81
82namespace llvm {
83
84std::unique_ptr<ObjDumper> createMachODumper(const object::MachOObjectFile &Obj,
85 ScopedPrinter &Writer) {
86 return std::make_unique<MachODumper>(args: &Obj, args&: Writer);
87}
88
89} // namespace llvm
90
91constexpr EnumStringDef<uint32_t> MachOMagicsDefs[] = {
92 {.Names: {"Magic"}, .Value: MachO::MH_MAGIC}, {.Names: {"Cigam"}, .Value: MachO::MH_CIGAM},
93 {.Names: {"Magic64"}, .Value: MachO::MH_MAGIC_64}, {.Names: {"Cigam64"}, .Value: MachO::MH_CIGAM_64},
94 {.Names: {"FatMagic"}, .Value: MachO::FAT_MAGIC}, {.Names: {"FatCigam"}, .Value: MachO::FAT_CIGAM},
95};
96constexpr auto MachOMagics = BUILD_ENUM_STRINGS(MachOMagicsDefs);
97
98constexpr EnumStringDef<uint32_t> MachOHeaderFileTypesDefs[] = {
99 {.Names: {"Relocatable"}, .Value: MachO::MH_OBJECT},
100 {.Names: {"Executable"}, .Value: MachO::MH_EXECUTE},
101 {.Names: {"FixedVMLibrary"}, .Value: MachO::MH_FVMLIB},
102 {.Names: {"Core"}, .Value: MachO::MH_CORE},
103 {.Names: {"PreloadedExecutable"}, .Value: MachO::MH_PRELOAD},
104 {.Names: {"DynamicLibrary"}, .Value: MachO::MH_DYLIB},
105 {.Names: {"DynamicLinker"}, .Value: MachO::MH_DYLINKER},
106 {.Names: {"Bundle"}, .Value: MachO::MH_BUNDLE},
107 {.Names: {"DynamicLibraryStub"}, .Value: MachO::MH_DYLIB_STUB},
108 {.Names: {"DWARFSymbol"}, .Value: MachO::MH_DSYM},
109 {.Names: {"KextBundle"}, .Value: MachO::MH_KEXT_BUNDLE},
110};
111constexpr auto MachOHeaderFileTypes =
112 BUILD_ENUM_STRINGS(MachOHeaderFileTypesDefs);
113
114// clang-format off
115constexpr EnumStringDef<uint32_t> MachOHeaderCpuTypesDefs[] = {
116 { .Names: {"Any"} , .Value: static_cast<uint32_t>(MachO::CPU_TYPE_ANY) },
117 { .Names: {"X86"} , .Value: MachO::CPU_TYPE_X86 },
118 { .Names: {"X86-64"} , .Value: MachO::CPU_TYPE_X86_64 },
119 { .Names: {"Mc98000"} , .Value: MachO::CPU_TYPE_MC98000 },
120 { .Names: {"Arm"} , .Value: MachO::CPU_TYPE_ARM },
121 { .Names: {"Arm64"} , .Value: MachO::CPU_TYPE_ARM64 },
122 { .Names: {"Arm64 (ILP32)"}, .Value: MachO::CPU_TYPE_ARM64_32 },
123 { .Names: {"Sparc"} , .Value: MachO::CPU_TYPE_SPARC },
124 { .Names: {"PowerPC"} , .Value: MachO::CPU_TYPE_POWERPC },
125 { .Names: {"PowerPC64"} , .Value: MachO::CPU_TYPE_POWERPC64 },
126};
127constexpr auto MachOHeaderCpuTypes = BUILD_ENUM_STRINGS(MachOHeaderCpuTypesDefs);
128// clang-format on
129
130constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesX86Defs[] = {
131 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL),
132 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386),
133 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486),
134 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX),
135 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586),
136 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO),
137 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3),
138 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5),
139 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON),
140 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE),
141 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3),
142 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M),
143 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON),
144 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M),
145 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4),
146 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M),
147 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM),
148 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2),
149 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON),
150 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP),
151};
152constexpr auto MachOHeaderCpuSubtypesX86 =
153 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesX86Defs);
154
155constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesX64Defs[] = {
156 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL),
157 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1),
158 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H),
159};
160constexpr auto MachOHeaderCpuSubtypesX64 =
161 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesX64Defs);
162
163constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARMDefs[] = {
164 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL),
165 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T),
166 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6),
167 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5),
168 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ),
169 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE),
170 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7),
171 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S),
172 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K),
173 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M),
174 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M),
175 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM),
176 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V8M_MAIN),
177 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V8M_BASE),
178 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V8_1M_MAIN),
179};
180constexpr auto MachOHeaderCpuSubtypesARM =
181 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARMDefs);
182
183constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARM64_32Defs[] = {
184 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_32_V8),
185};
186constexpr auto MachOHeaderCpuSubtypesARM64_32 =
187 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARM64_32Defs);
188
189constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARM64Defs[] = {
190 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
191 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_V8),
192 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64E),
193};
194constexpr auto MachOHeaderCpuSubtypesARM64 =
195 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARM64Defs);
196
197constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesSPARCDefs[] = {
198 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL),
199};
200constexpr auto MachOHeaderCpuSubtypesSPARC =
201 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesSPARCDefs);
202
203constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesPPCDefs[] = {
204 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL),
205 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601),
206 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602),
207 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603),
208 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e),
209 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev),
210 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604),
211 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e),
212 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620),
213 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750),
214 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400),
215 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450),
216 LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970),
217};
218constexpr auto MachOHeaderCpuSubtypesPPC =
219 BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesPPCDefs);
220
221constexpr EnumStringDef<uint32_t> MachOHeaderFlagsDefs[] = {
222 LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS),
223 LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK),
224 LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK),
225 LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD),
226 LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND),
227 LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS),
228 LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT),
229 LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL),
230 LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT),
231 LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS),
232 LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING),
233 LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE),
234 LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND),
235 LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS),
236 LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL),
237 LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES),
238 LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK),
239 LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION),
240 LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE),
241 LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE),
242 LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS),
243 LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE),
244 LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB),
245 LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS),
246 LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION),
247 LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
248};
249constexpr auto MachOHeaderFlags = BUILD_ENUM_STRINGS(MachOHeaderFlagsDefs);
250
251constexpr EnumStringDef<unsigned> MachOSectionTypesDefs[] = {
252 {.Names: {"Regular"}, .Value: MachO::S_REGULAR},
253 {.Names: {"ZeroFill"}, .Value: MachO::S_ZEROFILL},
254 {.Names: {"CStringLiterals"}, .Value: MachO::S_CSTRING_LITERALS},
255 {.Names: {"4ByteLiterals"}, .Value: MachO::S_4BYTE_LITERALS},
256 {.Names: {"8ByteLiterals"}, .Value: MachO::S_8BYTE_LITERALS},
257 {.Names: {"LiteralPointers"}, .Value: MachO::S_LITERAL_POINTERS},
258 {.Names: {"NonLazySymbolPointers"}, .Value: MachO::S_NON_LAZY_SYMBOL_POINTERS},
259 {.Names: {"LazySymbolPointers"}, .Value: MachO::S_LAZY_SYMBOL_POINTERS},
260 {.Names: {"SymbolStubs"}, .Value: MachO::S_SYMBOL_STUBS},
261 {.Names: {"ModInitFuncPointers"}, .Value: MachO::S_MOD_INIT_FUNC_POINTERS},
262 {.Names: {"ModTermFuncPointers"}, .Value: MachO::S_MOD_TERM_FUNC_POINTERS},
263 {.Names: {"Coalesced"}, .Value: MachO::S_COALESCED},
264 {.Names: {"GBZeroFill"}, .Value: MachO::S_GB_ZEROFILL},
265 {.Names: {"Interposing"}, .Value: MachO::S_INTERPOSING},
266 {.Names: {"16ByteLiterals"}, .Value: MachO::S_16BYTE_LITERALS},
267 {.Names: {"DTraceDOF"}, .Value: MachO::S_DTRACE_DOF},
268 {.Names: {"LazyDylibSymbolPointers"}, .Value: MachO::S_LAZY_DYLIB_SYMBOL_POINTERS},
269 {.Names: {"ThreadLocalRegular"}, .Value: MachO::S_THREAD_LOCAL_REGULAR},
270 {.Names: {"ThreadLocalZerofill"}, .Value: MachO::S_THREAD_LOCAL_ZEROFILL},
271 {.Names: {"ThreadLocalVariables"}, .Value: MachO::S_THREAD_LOCAL_VARIABLES},
272 {.Names: {"ThreadLocalVariablePointers"}, .Value: MachO::S_THREAD_LOCAL_VARIABLE_POINTERS},
273 {.Names: {"ThreadLocalInitFunctionPointers"},
274 .Value: MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS}};
275constexpr auto MachOSectionTypes = BUILD_ENUM_STRINGS(MachOSectionTypesDefs);
276
277constexpr EnumStringDef<unsigned> MachOSectionAttributesDefs[] = {
278 {.Names: {"LocReloc"}, .Value: 1 << 0 /*S_ATTR_LOC_RELOC*/},
279 {.Names: {"ExtReloc"}, .Value: 1 << 1 /*S_ATTR_EXT_RELOC*/},
280 {.Names: {"SomeInstructions"}, .Value: 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS*/},
281 {.Names: {"Debug"}, .Value: 1 << 17 /*S_ATTR_DEBUG*/},
282 {.Names: {"SelfModifyingCode"}, .Value: 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/},
283 {.Names: {"LiveSupport"}, .Value: 1 << 19 /*S_ATTR_LIVE_SUPPORT*/},
284 {.Names: {"NoDeadStrip"}, .Value: 1 << 20 /*S_ATTR_NO_DEAD_STRIP*/},
285 {.Names: {"StripStaticSyms"}, .Value: 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS*/},
286 {.Names: {"NoTOC"}, .Value: 1 << 22 /*S_ATTR_NO_TOC*/},
287 {.Names: {"PureInstructions"}, .Value: 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS*/},
288};
289constexpr auto MachOSectionAttributes =
290 BUILD_ENUM_STRINGS(MachOSectionAttributesDefs);
291
292constexpr EnumStringDef<unsigned> MachOSymbolRefTypesDefs[] = {
293 {.Names: {"UndefinedNonLazy"}, .Value: 0},
294 {.Names: {"ReferenceFlagUndefinedLazy"}, .Value: 1},
295 {.Names: {"ReferenceFlagDefined"}, .Value: 2},
296 {.Names: {"ReferenceFlagPrivateDefined"}, .Value: 3},
297 {.Names: {"ReferenceFlagPrivateUndefinedNonLazy"}, .Value: 4},
298 {.Names: {"ReferenceFlagPrivateUndefinedLazy"}, .Value: 5}};
299constexpr auto MachOSymbolRefTypes =
300 BUILD_ENUM_STRINGS(MachOSymbolRefTypesDefs);
301
302constexpr EnumStringDef<unsigned> MachOSymbolFlagsDefs[] = {
303 {.Names: {"ThumbDef"}, .Value: 0x8}, {.Names: {"ReferencedDynamically"}, .Value: 0x10},
304 {.Names: {"NoDeadStrip"}, .Value: 0x20}, {.Names: {"WeakRef"}, .Value: 0x40},
305 {.Names: {"WeakDef"}, .Value: 0x80}, {.Names: {"SymbolResolver"}, .Value: 0x100},
306 {.Names: {"AltEntry"}, .Value: 0x200}, {.Names: {"ColdFunc"}, .Value: 0x400},
307};
308constexpr auto MachOSymbolFlags = BUILD_ENUM_STRINGS(MachOSymbolFlagsDefs);
309
310constexpr EnumStringDef<unsigned> MachOSymbolTypesDefs[] = {
311 {.Names: {"Undef"}, .Value: 0x0},
312 {.Names: {"Abs"}, .Value: 0x2},
313 {.Names: {"Indirect"}, .Value: 0xA},
314 {.Names: {"PreboundUndef"}, .Value: 0xC},
315 {.Names: {"Section"}, .Value: 0xE}};
316constexpr auto MachOSymbolTypes = BUILD_ENUM_STRINGS(MachOSymbolTypesDefs);
317
318namespace {
319 struct MachOSection {
320 ArrayRef<char> Name;
321 ArrayRef<char> SegmentName;
322 uint64_t Address;
323 uint64_t Size;
324 uint32_t Offset;
325 uint32_t Alignment;
326 uint32_t RelocationTableOffset;
327 uint32_t NumRelocationTableEntries;
328 uint32_t Flags;
329 uint32_t Reserved1;
330 uint32_t Reserved2;
331 uint32_t Reserved3;
332 };
333
334 struct MachOSegment {
335 std::string CmdName;
336 std::string SegName;
337 uint64_t cmdsize;
338 uint64_t vmaddr;
339 uint64_t vmsize;
340 uint64_t fileoff;
341 uint64_t filesize;
342 uint32_t maxprot;
343 uint32_t initprot;
344 uint32_t nsects;
345 uint32_t flags;
346 };
347
348 struct MachOSymbol {
349 uint32_t StringIndex;
350 uint8_t Type;
351 uint8_t SectionIndex;
352 uint16_t Flags;
353 uint64_t Value;
354 };
355}
356
357static std::string getMask(uint32_t prot)
358{
359 // TODO (davide): This always assumes prot is valid.
360 // Catch mistakes and report if needed.
361 std::string Prot;
362 Prot = "";
363 Prot += (prot & MachO::VM_PROT_READ) ? "r" : "-";
364 Prot += (prot & MachO::VM_PROT_WRITE) ? "w" : "-";
365 Prot += (prot & MachO::VM_PROT_EXECUTE) ? "x" : "-";
366 return Prot;
367}
368
369static void getSection(const MachOObjectFile *Obj,
370 DataRefImpl Sec,
371 MachOSection &Section) {
372 if (!Obj->is64Bit()) {
373 MachO::section Sect = Obj->getSection(DRI: Sec);
374 Section.Address = Sect.addr;
375 Section.Size = Sect.size;
376 Section.Offset = Sect.offset;
377 Section.Alignment = Sect.align;
378 Section.RelocationTableOffset = Sect.reloff;
379 Section.NumRelocationTableEntries = Sect.nreloc;
380 Section.Flags = Sect.flags;
381 Section.Reserved1 = Sect.reserved1;
382 Section.Reserved2 = Sect.reserved2;
383 return;
384 }
385 MachO::section_64 Sect = Obj->getSection64(DRI: Sec);
386 Section.Address = Sect.addr;
387 Section.Size = Sect.size;
388 Section.Offset = Sect.offset;
389 Section.Alignment = Sect.align;
390 Section.RelocationTableOffset = Sect.reloff;
391 Section.NumRelocationTableEntries = Sect.nreloc;
392 Section.Flags = Sect.flags;
393 Section.Reserved1 = Sect.reserved1;
394 Section.Reserved2 = Sect.reserved2;
395 Section.Reserved3 = Sect.reserved3;
396}
397
398static void getSegment(const MachOObjectFile *Obj,
399 const MachOObjectFile::LoadCommandInfo &L,
400 MachOSegment &Segment) {
401 if (!Obj->is64Bit()) {
402 MachO::segment_command SC = Obj->getSegmentLoadCommand(L);
403 Segment.CmdName = "LC_SEGMENT";
404 Segment.SegName = SC.segname;
405 Segment.cmdsize = SC.cmdsize;
406 Segment.vmaddr = SC.vmaddr;
407 Segment.vmsize = SC.vmsize;
408 Segment.fileoff = SC.fileoff;
409 Segment.filesize = SC.filesize;
410 Segment.maxprot = SC.maxprot;
411 Segment.initprot = SC.initprot;
412 Segment.nsects = SC.nsects;
413 Segment.flags = SC.flags;
414 return;
415 }
416 MachO::segment_command_64 SC = Obj->getSegment64LoadCommand(L);
417 Segment.CmdName = "LC_SEGMENT_64";
418 Segment.SegName = SC.segname;
419 Segment.cmdsize = SC.cmdsize;
420 Segment.vmaddr = SC.vmaddr;
421 Segment.vmsize = SC.vmsize;
422 Segment.fileoff = SC.fileoff;
423 Segment.filesize = SC.filesize;
424 Segment.maxprot = SC.maxprot;
425 Segment.initprot = SC.initprot;
426 Segment.nsects = SC.nsects;
427 Segment.flags = SC.flags;
428}
429
430static void getSymbol(const MachOObjectFile *Obj,
431 DataRefImpl DRI,
432 MachOSymbol &Symbol) {
433 if (!Obj->is64Bit()) {
434 MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
435 Symbol.StringIndex = Entry.n_strx;
436 Symbol.Type = Entry.n_type;
437 Symbol.SectionIndex = Entry.n_sect;
438 Symbol.Flags = Entry.n_desc;
439 Symbol.Value = Entry.n_value;
440 return;
441 }
442 MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
443 Symbol.StringIndex = Entry.n_strx;
444 Symbol.Type = Entry.n_type;
445 Symbol.SectionIndex = Entry.n_sect;
446 Symbol.Flags = Entry.n_desc;
447 Symbol.Value = Entry.n_value;
448}
449
450void MachODumper::printFileHeaders() {
451 DictScope H(W, "MachHeader");
452 if (!Obj->is64Bit()) {
453 printFileHeaders(Header: Obj->getHeader());
454 } else {
455 printFileHeaders(Header: Obj->getHeader64());
456 W.printHex(Label: "Reserved", Value: Obj->getHeader64().reserved);
457 }
458}
459
460template<class MachHeader>
461void MachODumper::printFileHeaders(const MachHeader &Header) {
462 W.printEnum("Magic", Header.magic, EnumStrings(MachOMagics));
463 W.printEnum("CpuType", Header.cputype, EnumStrings(MachOHeaderCpuTypes));
464 uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
465 switch (Header.cputype) {
466 case MachO::CPU_TYPE_X86:
467 W.printEnum(Label: "CpuSubType", Value: subtype, EnumValues: EnumStrings(MachOHeaderCpuSubtypesX86));
468 break;
469 case MachO::CPU_TYPE_X86_64:
470 W.printEnum(Label: "CpuSubType", Value: subtype, EnumValues: EnumStrings(MachOHeaderCpuSubtypesX64));
471 break;
472 case MachO::CPU_TYPE_ARM:
473 W.printEnum(Label: "CpuSubType", Value: subtype, EnumValues: EnumStrings(MachOHeaderCpuSubtypesARM));
474 break;
475 case MachO::CPU_TYPE_POWERPC:
476 W.printEnum(Label: "CpuSubType", Value: subtype, EnumValues: EnumStrings(MachOHeaderCpuSubtypesPPC));
477 break;
478 case MachO::CPU_TYPE_SPARC:
479 W.printEnum(Label: "CpuSubType", Value: subtype,
480 EnumValues: EnumStrings(MachOHeaderCpuSubtypesSPARC));
481 break;
482 case MachO::CPU_TYPE_ARM64:
483 W.printEnum(Label: "CpuSubType", Value: subtype,
484 EnumValues: EnumStrings(MachOHeaderCpuSubtypesARM64));
485 break;
486 case MachO::CPU_TYPE_ARM64_32:
487 W.printEnum(Label: "CpuSubType", Value: subtype,
488 EnumValues: EnumStrings(MachOHeaderCpuSubtypesARM64_32));
489 break;
490 case MachO::CPU_TYPE_POWERPC64:
491 default:
492 W.printHex(Label: "CpuSubType", Value: subtype);
493 }
494 W.printEnum("FileType", Header.filetype, EnumStrings(MachOHeaderFileTypes));
495 W.printNumber("NumOfLoadCommands", Header.ncmds);
496 W.printNumber("SizeOfLoadCommands", Header.sizeofcmds);
497 W.printFlags("Flags", Header.flags, EnumStrings(MachOHeaderFlags));
498}
499
500void MachODumper::printSectionHeaders() { return printSectionHeaders(Obj); }
501
502void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {
503 ListScope Group(W, "Sections");
504
505 int SectionIndex = -1;
506 for (const SectionRef &Section : Obj->sections()) {
507 ++SectionIndex;
508
509 MachOSection MOSection;
510 getSection(Obj, Sec: Section.getRawDataRefImpl(), Section&: MOSection);
511 DataRefImpl DR = Section.getRawDataRefImpl();
512 StringRef Name = unwrapOrError(Input: Obj->getFileName(), EO: Section.getName());
513 ArrayRef<char> RawName = Obj->getSectionRawName(Sec: DR);
514 StringRef SegmentName = Obj->getSectionFinalSegmentName(Sec: DR);
515 ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(Sec: DR);
516
517 DictScope SectionD(W, "Section");
518 W.printNumber(Label: "Index", Value: SectionIndex);
519 W.printBinary(Label: "Name", Str: Name, Value: RawName);
520 W.printBinary(Label: "Segment", Str: SegmentName, Value: RawSegmentName);
521 W.printHex(Label: "Address", Value: MOSection.Address);
522 W.printHex(Label: "Size", Value: MOSection.Size);
523 W.printNumber(Label: "Offset", Value: MOSection.Offset);
524 W.printNumber(Label: "Alignment", Value: MOSection.Alignment);
525 W.printHex(Label: "RelocationOffset", Value: MOSection.RelocationTableOffset);
526 W.printNumber(Label: "RelocationCount", Value: MOSection.NumRelocationTableEntries);
527 W.printEnum(Label: "Type", Value: MOSection.Flags & 0xFF, EnumValues: EnumStrings(MachOSectionTypes));
528 W.printFlags(Label: "Attributes", Value: MOSection.Flags >> 8,
529 Flags: EnumStrings(MachOSectionAttributes));
530 W.printHex(Label: "Reserved1", Value: MOSection.Reserved1);
531 W.printHex(Label: "Reserved2", Value: MOSection.Reserved2);
532 if (Obj->is64Bit())
533 W.printHex(Label: "Reserved3", Value: MOSection.Reserved3);
534
535 if (opts::SectionRelocations) {
536 ListScope D(W, "Relocations");
537 for (const RelocationRef &Reloc : Section.relocations())
538 printRelocation(Reloc);
539 }
540
541 if (opts::SectionSymbols) {
542 ListScope D(W, "Symbols");
543 for (const SymbolRef &Symbol : Obj->symbols()) {
544 if (!Section.containsSymbol(S: Symbol))
545 continue;
546
547 printSymbol(Symbol);
548 }
549 }
550
551 if (opts::SectionData && !Section.isBSS())
552 W.printBinaryBlock(Label: "SectionData", Value: unwrapOrError(Input: Obj->getFileName(),
553 EO: Section.getContents()));
554 }
555}
556
557void MachODumper::printRelocations() {
558 ListScope D(W, "Relocations");
559
560 std::error_code EC;
561 for (const SectionRef &Section : Obj->sections()) {
562 StringRef Name = unwrapOrError(Input: Obj->getFileName(), EO: Section.getName());
563 bool PrintedGroup = false;
564 for (const RelocationRef &Reloc : Section.relocations()) {
565 if (!PrintedGroup) {
566 W.startLine() << "Section " << Name << " {\n";
567 W.indent();
568 PrintedGroup = true;
569 }
570
571 printRelocation(Reloc);
572 }
573
574 if (PrintedGroup) {
575 W.unindent();
576 W.startLine() << "}\n";
577 }
578 }
579}
580
581void MachODumper::printRelocation(const RelocationRef &Reloc) {
582 return printRelocation(Obj, Reloc);
583}
584
585void MachODumper::printRelocation(const MachOObjectFile *Obj,
586 const RelocationRef &Reloc) {
587 uint64_t Offset = Reloc.getOffset();
588 SmallString<32> RelocName;
589 Reloc.getTypeName(Result&: RelocName);
590
591 DataRefImpl DR = Reloc.getRawDataRefImpl();
592 MachO::any_relocation_info RE = Obj->getRelocation(Rel: DR);
593 bool IsScattered = Obj->isRelocationScattered(RE);
594 bool IsExtern = !IsScattered && Obj->getPlainRelocationExternal(RE);
595
596 StringRef TargetName;
597 if (IsExtern) {
598 symbol_iterator Symbol = Reloc.getSymbol();
599 if (Symbol != Obj->symbol_end()) {
600 TargetName = getSymbolName(Symbol: *Symbol);
601 }
602 } else if (!IsScattered) {
603 section_iterator SecI = Obj->getRelocationSection(Rel: DR);
604 if (SecI != Obj->section_end())
605 TargetName = unwrapOrError(Input: Obj->getFileName(), EO: SecI->getName());
606 }
607 if (TargetName.empty())
608 TargetName = "-";
609
610 if (opts::ExpandRelocs) {
611 DictScope Group(W, "Relocation");
612 W.printHex(Label: "Offset", Value: Offset);
613 W.printNumber(Label: "PCRel", Value: Obj->getAnyRelocationPCRel(RE));
614 W.printNumber(Label: "Length", Value: Obj->getAnyRelocationLength(RE));
615 W.printNumber(Label: "Type", Str: RelocName, Value: Obj->getAnyRelocationType(RE));
616 if (IsScattered) {
617 W.printHex(Label: "Value", Value: Obj->getScatteredRelocationValue(RE));
618 } else {
619 const char *Kind = IsExtern ? "Symbol" : "Section";
620 W.printNumber(Label: Kind, Str: TargetName, Value: Obj->getPlainRelocationSymbolNum(RE));
621 }
622 } else {
623 SmallString<32> SymbolNameOrOffset("0x");
624 if (IsScattered) {
625 // Scattered relocations don't really have an associated symbol for some
626 // reason, even if one exists in the symtab at the correct address.
627 SymbolNameOrOffset += utohexstr(X: Obj->getScatteredRelocationValue(RE));
628 } else {
629 SymbolNameOrOffset = TargetName;
630 }
631
632 raw_ostream& OS = W.startLine();
633 OS << W.hex(Value: Offset)
634 << " " << Obj->getAnyRelocationPCRel(RE)
635 << " " << Obj->getAnyRelocationLength(RE);
636 if (IsScattered)
637 OS << " n/a";
638 else
639 OS << " " << Obj->getPlainRelocationExternal(RE);
640 OS << " " << RelocName
641 << " " << IsScattered
642 << " " << SymbolNameOrOffset
643 << "\n";
644 }
645}
646
647StringRef MachODumper::getSymbolName(const SymbolRef &Symbol) const {
648 Expected<StringRef> SymbolNameOrErr = Symbol.getName();
649 if (!SymbolNameOrErr) {
650 reportError(Err: SymbolNameOrErr.takeError(), Input: Obj->getFileName());
651 }
652 return *SymbolNameOrErr;
653}
654
655uint8_t MachODumper::getSymbolType(const SymbolRef &Symbol) const {
656 return Obj->is64Bit()
657 ? Obj->getSymbol64TableEntry(DRI: Symbol.getRawDataRefImpl()).n_type
658 : Obj->getSymbolTableEntry(DRI: Symbol.getRawDataRefImpl()).n_type;
659}
660
661bool MachODumper::compareSymbolsByName(SymbolRef LHS, SymbolRef RHS) const {
662 return getSymbolName(Symbol: LHS).str().compare(str: getSymbolName(Symbol: RHS).str()) < 0;
663}
664
665bool MachODumper::compareSymbolsByType(SymbolRef LHS, SymbolRef RHS) const {
666 return getSymbolType(Symbol: LHS) < getSymbolType(Symbol: RHS);
667}
668
669void MachODumper::printSymbols(bool /*ExtraSymInfo*/) {
670 printSymbols(SymComp: std::nullopt);
671}
672
673void MachODumper::printSymbols(std::optional<SymbolComparator> SymComp) {
674 ListScope Group(W, "Symbols");
675 if (SymComp) {
676 auto SymbolRange = Obj->symbols();
677 std::vector<SymbolRef> SortedSymbols(SymbolRange.begin(),
678 SymbolRange.end());
679 llvm::stable_sort(Range&: SortedSymbols, C: *SymComp);
680 for (SymbolRef Symbol : SortedSymbols)
681 printSymbol(Symbol);
682 } else {
683 for (const SymbolRef &Symbol : Obj->symbols()) {
684 printSymbol(Symbol);
685 }
686 }
687}
688
689void MachODumper::printDynamicSymbols() {
690 ListScope Group(W, "DynamicSymbols");
691}
692void MachODumper::printDynamicSymbols(std::optional<SymbolComparator> SymComp) {
693 ListScope Group(W, "DynamicSymbols");
694}
695
696void MachODumper::printSymbol(const SymbolRef &Symbol) {
697 printSymbol(Symbol, W);
698}
699
700void MachODumper::printSymbol(const SymbolRef &Symbol, ScopedPrinter &W) {
701 StringRef SymbolName = getSymbolName(Symbol);
702
703 MachOSymbol MOSymbol;
704 getSymbol(Obj, DRI: Symbol.getRawDataRefImpl(), Symbol&: MOSymbol);
705
706 StringRef SectionName = "";
707 // Don't ask a Mach-O STABS symbol for its section unless we know that
708 // STAB symbol's section field refers to a valid section index. Otherwise
709 // the symbol may error trying to load a section that does not exist.
710 // TODO: Add a whitelist of STABS symbol types that contain valid section
711 // indices.
712 if (!(MOSymbol.Type & MachO::N_STAB)) {
713 Expected<section_iterator> SecIOrErr = Symbol.getSection();
714 if (!SecIOrErr)
715 reportError(Err: SecIOrErr.takeError(), Input: Obj->getFileName());
716
717 section_iterator SecI = *SecIOrErr;
718 if (SecI != Obj->section_end())
719 SectionName = unwrapOrError(Input: Obj->getFileName(), EO: SecI->getName());
720 }
721
722 DictScope D(W, "Symbol");
723 W.printNumber(Label: "Name", Str: SymbolName, Value: MOSymbol.StringIndex);
724 if (MOSymbol.Type & MachO::N_STAB) {
725 W.printHex(Label: "Type", Str: "SymDebugTable", Value: MOSymbol.Type);
726 } else {
727 if (MOSymbol.Type & MachO::N_PEXT)
728 W.startLine() << "PrivateExtern\n";
729 if (MOSymbol.Type & MachO::N_EXT)
730 W.startLine() << "Extern\n";
731 W.printEnum(Label: "Type", Value: uint8_t(MOSymbol.Type & MachO::N_TYPE),
732 EnumValues: EnumStrings(MachOSymbolTypes));
733 }
734 W.printHex(Label: "Section", Str: SectionName, Value: MOSymbol.SectionIndex);
735 W.printEnum(Label: "RefType", Value: static_cast<uint16_t>(MOSymbol.Flags & 0x7),
736 EnumValues: EnumStrings(MachOSymbolRefTypes));
737 W.printFlags(Label: "Flags", Value: static_cast<uint16_t>(MOSymbol.Flags & ~0x7),
738 Flags: EnumStrings(MachOSymbolFlags));
739 W.printHex(Label: "Value", Value: MOSymbol.Value);
740}
741
742void MachODumper::printUnwindInfo() {
743 W.startLine() << "UnwindInfo not implemented.\n";
744}
745
746void MachODumper::printStackMap() const {
747 object::SectionRef StackMapSection;
748 for (auto Sec : Obj->sections()) {
749 StringRef Name;
750 if (Expected<StringRef> NameOrErr = Sec.getName())
751 Name = *NameOrErr;
752 else
753 consumeError(Err: NameOrErr.takeError());
754
755 if (Name == "__llvm_stackmaps") {
756 StackMapSection = Sec;
757 break;
758 }
759 }
760
761 if (StackMapSection == object::SectionRef())
762 return;
763
764 StringRef StackMapContents =
765 unwrapOrError(Input: Obj->getFileName(), EO: StackMapSection.getContents());
766 ArrayRef<uint8_t> StackMapContentsArray =
767 arrayRefFromStringRef(Input: StackMapContents);
768
769 if (Obj->isLittleEndian())
770 prettyPrintStackMap(
771 W, SMP: StackMapParser<llvm::endianness::little>(StackMapContentsArray));
772 else
773 prettyPrintStackMap(
774 W, SMP: StackMapParser<llvm::endianness::big>(StackMapContentsArray));
775}
776
777void MachODumper::printCGProfile() {
778 object::SectionRef CGProfileSection;
779 for (auto Sec : Obj->sections()) {
780 StringRef Name;
781 if (Expected<StringRef> NameOrErr = Sec.getName())
782 Name = *NameOrErr;
783 else
784 consumeError(Err: NameOrErr.takeError());
785
786 if (Name == "__cg_profile") {
787 CGProfileSection = Sec;
788 break;
789 }
790 }
791 if (CGProfileSection == object::SectionRef())
792 return;
793
794 StringRef CGProfileContents =
795 unwrapOrError(Input: Obj->getFileName(), EO: CGProfileSection.getContents());
796 BinaryStreamReader Reader(CGProfileContents, Obj->isLittleEndian()
797 ? llvm::endianness::little
798 : llvm::endianness::big);
799
800 ListScope L(W, "CGProfile");
801 while (!Reader.empty()) {
802 uint32_t FromIndex, ToIndex;
803 uint64_t Count;
804 if (Error Err = Reader.readInteger(Dest&: FromIndex))
805 reportError(Err: std::move(Err), Input: Obj->getFileName());
806 if (Error Err = Reader.readInteger(Dest&: ToIndex))
807 reportError(Err: std::move(Err), Input: Obj->getFileName());
808 if (Error Err = Reader.readInteger(Dest&: Count))
809 reportError(Err: std::move(Err), Input: Obj->getFileName());
810 DictScope D(W, "CGProfileEntry");
811 W.printNumber(Label: "From", Str: getSymbolName(Symbol: *Obj->getSymbolByIndex(Index: FromIndex)),
812 Value: FromIndex);
813 W.printNumber(Label: "To", Str: getSymbolName(Symbol: *Obj->getSymbolByIndex(Index: ToIndex)),
814 Value: ToIndex);
815 W.printNumber(Label: "Weight", Value: Count);
816 }
817}
818
819void MachODumper::printNeededLibraries() {
820 ListScope D(W, "NeededLibraries");
821
822 using LibsTy = std::vector<StringRef>;
823 LibsTy Libs;
824
825 for (const auto &Command : Obj->load_commands()) {
826 if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
827 Command.C.cmd == MachO::LC_ID_DYLIB ||
828 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
829 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
830 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
831 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
832 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(L: Command);
833 if (Dl.dylib.name < Dl.cmdsize) {
834 auto *P = static_cast<const char*>(Command.Ptr) + Dl.dylib.name;
835 Libs.push_back(x: P);
836 }
837 }
838 }
839
840 llvm::stable_sort(Range&: Libs);
841
842 for (const auto &L : Libs) {
843 W.startLine() << L << "\n";
844 }
845}
846
847void MachODumper::printMachODataInCode() {
848 for (const auto &Load : Obj->load_commands()) {
849 if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {
850 MachO::linkedit_data_command LLC = Obj->getLinkeditDataLoadCommand(L: Load);
851 DictScope Group(W, "DataInCode");
852 W.printNumber(Label: "Data offset", Value: LLC.dataoff);
853 W.printNumber(Label: "Data size", Value: LLC.datasize);
854 ListScope D(W, "Data entries");
855 unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry);
856 for (unsigned i = 0; i < NumRegions; ++i) {
857 MachO::data_in_code_entry DICE = Obj->getDataInCodeTableEntry(
858 DataOffset: LLC.dataoff, Index: i);
859 DictScope Group(W, "Entry");
860 W.printNumber(Label: "Index", Value: i);
861 W.printNumber(Label: "Offset", Value: DICE.offset);
862 W.printNumber(Label: "Length", Value: DICE.length);
863 W.printNumber(Label: "Kind", Value: DICE.kind);
864 }
865 }
866 }
867}
868
869void MachODumper::printMachOVersionMin() {
870 for (const auto &Load : Obj->load_commands()) {
871 StringRef Cmd;
872 switch (Load.C.cmd) {
873 case MachO::LC_VERSION_MIN_MACOSX:
874 Cmd = "LC_VERSION_MIN_MACOSX";
875 break;
876 case MachO::LC_VERSION_MIN_IPHONEOS:
877 Cmd = "LC_VERSION_MIN_IPHONEOS";
878 break;
879 case MachO::LC_VERSION_MIN_TVOS:
880 Cmd = "LC_VERSION_MIN_TVOS";
881 break;
882 case MachO::LC_VERSION_MIN_WATCHOS:
883 Cmd = "LC_VERSION_MIN_WATCHOS";
884 break;
885 case MachO::LC_BUILD_VERSION:
886 Cmd = "LC_BUILD_VERSION";
887 break;
888 default:
889 continue;
890 }
891
892 DictScope Group(W, "MinVersion");
893 // Handle LC_BUILD_VERSION.
894 if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
895 MachO::build_version_command BVC = Obj->getBuildVersionLoadCommand(L: Load);
896 W.printString(Label: "Cmd", Value: Cmd);
897 W.printNumber(Label: "Size", Value: BVC.cmdsize);
898 W.printString(Label: "Platform",
899 Value: MachOObjectFile::getBuildPlatform(platform: BVC.platform));
900 W.printString(Label: "Version", Value: MachOObjectFile::getVersionString(version: BVC.minos));
901 if (BVC.sdk)
902 W.printString(Label: "SDK", Value: MachOObjectFile::getVersionString(version: BVC.sdk));
903 else
904 W.printString(Label: "SDK", Value: StringRef("n/a"));
905 continue;
906 }
907
908 MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(L: Load);
909 W.printString(Label: "Cmd", Value: Cmd);
910 W.printNumber(Label: "Size", Value: VMC.cmdsize);
911 SmallString<32> Version;
912 Version = utostr(X: MachOObjectFile::getVersionMinMajor(C&: VMC, SDK: false)) + "." +
913 utostr(X: MachOObjectFile::getVersionMinMinor(C&: VMC, SDK: false));
914 uint32_t Update = MachOObjectFile::getVersionMinUpdate(C&: VMC, SDK: false);
915 if (Update != 0)
916 Version += "." + utostr(X: MachOObjectFile::getVersionMinUpdate(C&: VMC, SDK: false));
917 W.printString(Label: "Version", Value: Version);
918 SmallString<32> SDK;
919 if (VMC.sdk == 0)
920 SDK = "n/a";
921 else {
922 SDK = utostr(X: MachOObjectFile::getVersionMinMajor(C&: VMC, SDK: true)) + "." +
923 utostr(X: MachOObjectFile::getVersionMinMinor(C&: VMC, SDK: true));
924 uint32_t Update = MachOObjectFile::getVersionMinUpdate(C&: VMC, SDK: true);
925 if (Update != 0)
926 SDK += "." + utostr(X: MachOObjectFile::getVersionMinUpdate(C&: VMC, SDK: true));
927 }
928 W.printString(Label: "SDK", Value: SDK);
929 }
930}
931
932void MachODumper::printMachOTargetTriple() {
933 for (const auto &Load : Obj->load_commands()) {
934 if (Load.C.cmd == MachO::LC_TARGET_TRIPLE) {
935 DictScope Group(W, "TargetTriple");
936 MachO::target_triple_command TTC = Obj->getTargetTripleLoadCommand(L: Load);
937 W.printString(Label: "Cmd", Value: "LC_TARGET_TRIPLE");
938 W.printNumber(Label: "Size", Value: TTC.cmdsize);
939 if (TTC.triple < TTC.cmdsize)
940 W.printString(Label: "Triple", Value: Load.Ptr + TTC.triple);
941 else
942 W.printNumber(Label: "Triple ?(bad offset)", Value: TTC.triple);
943 }
944 }
945}
946
947void MachODumper::printMachODysymtab() {
948 for (const auto &Load : Obj->load_commands()) {
949 if (Load.C.cmd == MachO::LC_DYSYMTAB) {
950 MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand();
951 DictScope Group(W, "Dysymtab");
952 W.printNumber(Label: "ilocalsym", Value: DLC.ilocalsym);
953 W.printNumber(Label: "nlocalsym", Value: DLC.nlocalsym);
954 W.printNumber(Label: "iextdefsym", Value: DLC.iextdefsym);
955 W.printNumber(Label: "nextdefsym", Value: DLC.nextdefsym);
956 W.printNumber(Label: "iundefsym", Value: DLC.iundefsym);
957 W.printNumber(Label: "nundefsym", Value: DLC.nundefsym);
958 W.printNumber(Label: "tocoff", Value: DLC.tocoff);
959 W.printNumber(Label: "ntoc", Value: DLC.ntoc);
960 W.printNumber(Label: "modtaboff", Value: DLC.modtaboff);
961 W.printNumber(Label: "nmodtab", Value: DLC.nmodtab);
962 W.printNumber(Label: "extrefsymoff", Value: DLC.extrefsymoff);
963 W.printNumber(Label: "nextrefsyms", Value: DLC.nextrefsyms);
964 W.printNumber(Label: "indirectsymoff", Value: DLC.indirectsymoff);
965 W.printNumber(Label: "nindirectsyms", Value: DLC.nindirectsyms);
966 W.printNumber(Label: "extreloff", Value: DLC.extreloff);
967 W.printNumber(Label: "nextrel", Value: DLC.nextrel);
968 W.printNumber(Label: "locreloff", Value: DLC.locreloff);
969 W.printNumber(Label: "nlocrel", Value: DLC.nlocrel);
970 }
971 }
972}
973
974void MachODumper::printMachOSegment() {
975 for (const auto &Load : Obj->load_commands()) {
976 if (Load.C.cmd == MachO::LC_SEGMENT || Load.C.cmd == MachO::LC_SEGMENT_64) {
977 MachOSegment MOSegment;
978 getSegment(Obj, L: Load, Segment&: MOSegment);
979 DictScope Group(W, "Segment");
980 W.printString(Label: "Cmd", Value: MOSegment.CmdName);
981 W.printString(Label: "Name", Value: MOSegment.SegName);
982 W.printNumber(Label: "Size", Value: MOSegment.cmdsize);
983 W.printHex(Label: "vmaddr", Value: MOSegment.vmaddr);
984 W.printHex(Label: "vmsize", Value: MOSegment.vmsize);
985 W.printNumber(Label: "fileoff", Value: MOSegment.fileoff);
986 W.printNumber(Label: "filesize", Value: MOSegment.filesize);
987 W.printString(Label: "maxprot", Value: getMask(prot: MOSegment.maxprot));
988 W.printString(Label: "initprot", Value: getMask(prot: MOSegment.initprot));
989 W.printNumber(Label: "nsects", Value: MOSegment.nsects);
990 W.printHex(Label: "flags", Value: MOSegment.flags);
991 }
992 }
993}
994
995void MachODumper::printMachOIndirectSymbols() {
996 for (const auto &Load : Obj->load_commands()) {
997 if (Load.C.cmd == MachO::LC_DYSYMTAB) {
998 MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand();
999 DictScope Group(W, "Indirect Symbols");
1000 W.printNumber(Label: "Number", Value: DLC.nindirectsyms);
1001 ListScope D(W, "Symbols");
1002 for (unsigned i = 0; i < DLC.nindirectsyms; ++i) {
1003 DictScope Group(W, "Entry");
1004 W.printNumber(Label: "Entry Index", Value: i);
1005 W.printHex(Label: "Symbol Index", Value: Obj->getIndirectSymbolTableEntry(DLC, Index: i));
1006 }
1007 }
1008 }
1009}
1010
1011void MachODumper::printMachOLinkerOptions() {
1012 for (const auto &Load : Obj->load_commands()) {
1013 if (Load.C.cmd == MachO::LC_LINKER_OPTION) {
1014 MachO::linker_option_command LOLC = Obj->getLinkerOptionLoadCommand(L: Load);
1015 DictScope Group(W, "Linker Options");
1016 W.printNumber(Label: "Size", Value: LOLC.cmdsize);
1017 ListScope D(W, "Strings");
1018 uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command);
1019 const char *P = Load.Ptr + sizeof(MachO::linker_option_command);
1020 StringRef Data(P, DataSize);
1021 for (unsigned i = 0; i < LOLC.count; ++i) {
1022 std::pair<StringRef,StringRef> Split = Data.split(Separator: '\0');
1023 W.printString(Label: "Value", Value: Split.first);
1024 Data = Split.second;
1025 }
1026 }
1027 }
1028}
1029