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