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