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