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