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