Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp
35231 views
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
using namespace llvm;
57
using namespace llvm::object;
58
using namespace llvm::objdump;
59
60
bool objdump::FirstPrivateHeader;
61
bool objdump::ExportsTrie;
62
bool objdump::Rebase;
63
bool objdump::Rpaths;
64
bool objdump::Bind;
65
bool objdump::LazyBind;
66
bool objdump::WeakBind;
67
static bool UseDbg;
68
static std::string DSYMFile;
69
bool objdump::FullLeadingAddr;
70
bool objdump::LeadingHeaders;
71
bool objdump::UniversalHeaders;
72
static bool ArchiveMemberOffsets;
73
bool objdump::IndirectSymbols;
74
bool objdump::DataInCode;
75
FunctionStartsMode objdump::FunctionStartsType =
76
objdump::FunctionStartsMode::None;
77
bool objdump::LinkOptHints;
78
bool objdump::InfoPlist;
79
bool objdump::ChainedFixups;
80
bool objdump::DyldInfo;
81
bool objdump::DylibsUsed;
82
bool objdump::DylibId;
83
bool objdump::Verbose;
84
bool objdump::ObjcMetaData;
85
std::string objdump::DisSymName;
86
bool objdump::SymbolicOperands;
87
static std::vector<std::string> ArchFlags;
88
89
static bool ArchAll = false;
90
static std::string ThumbTripleName;
91
92
static StringRef ordinalName(const object::MachOObjectFile *, int);
93
94
void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
95
FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);
96
ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);
97
Rebase = InputArgs.hasArg(OBJDUMP_rebase);
98
Rpaths = InputArgs.hasArg(OBJDUMP_rpaths);
99
Bind = InputArgs.hasArg(OBJDUMP_bind);
100
LazyBind = InputArgs.hasArg(OBJDUMP_lazy_bind);
101
WeakBind = InputArgs.hasArg(OBJDUMP_weak_bind);
102
UseDbg = InputArgs.hasArg(OBJDUMP_g);
103
DSYMFile = InputArgs.getLastArgValue(OBJDUMP_dsym_EQ).str();
104
FullLeadingAddr = InputArgs.hasArg(OBJDUMP_full_leading_addr);
105
LeadingHeaders = !InputArgs.hasArg(OBJDUMP_no_leading_headers);
106
UniversalHeaders = InputArgs.hasArg(OBJDUMP_universal_headers);
107
ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);
108
IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);
109
DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);
110
if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {
111
FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
112
.Case("addrs", FunctionStartsMode::Addrs)
113
.Case("names", FunctionStartsMode::Names)
114
.Case("both", FunctionStartsMode::Both)
115
.Default(FunctionStartsMode::None);
116
if (FunctionStartsType == FunctionStartsMode::None)
117
invalidArgValue(A);
118
}
119
LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
120
InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
121
ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
122
DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);
123
DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);
124
DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);
125
Verbose = !InputArgs.hasArg(OBJDUMP_non_verbose);
126
ObjcMetaData = InputArgs.hasArg(OBJDUMP_objc_meta_data);
127
DisSymName = InputArgs.getLastArgValue(OBJDUMP_dis_symname).str();
128
SymbolicOperands = !InputArgs.hasArg(OBJDUMP_no_symbolic_operands);
129
ArchFlags = InputArgs.getAllArgValues(OBJDUMP_arch_EQ);
130
}
131
132
static const Target *GetTarget(const MachOObjectFile *MachOObj,
133
const char **McpuDefault,
134
const Target **ThumbTarget) {
135
// Figure out the target triple.
136
Triple TT(TripleName);
137
if (TripleName.empty()) {
138
TT = MachOObj->getArchTriple(McpuDefault);
139
TripleName = TT.str();
140
}
141
142
if (TT.getArch() == Triple::arm) {
143
// We've inferred a 32-bit ARM target from the object file. All MachO CPUs
144
// that support ARM are also capable of Thumb mode.
145
Triple ThumbTriple = TT;
146
std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();
147
ThumbTriple.setArchName(ThumbName);
148
ThumbTripleName = ThumbTriple.str();
149
}
150
151
// Get the target specific parser.
152
std::string Error;
153
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
154
if (TheTarget && ThumbTripleName.empty())
155
return TheTarget;
156
157
*ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
158
if (*ThumbTarget)
159
return TheTarget;
160
161
WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";
162
if (!TheTarget)
163
errs() << TripleName;
164
else
165
errs() << ThumbTripleName;
166
errs() << "', see --version and --triple.\n";
167
return nullptr;
168
}
169
170
namespace {
171
struct SymbolSorter {
172
bool operator()(const SymbolRef &A, const SymbolRef &B) {
173
Expected<SymbolRef::Type> ATypeOrErr = A.getType();
174
if (!ATypeOrErr)
175
reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());
176
SymbolRef::Type AType = *ATypeOrErr;
177
Expected<SymbolRef::Type> BTypeOrErr = B.getType();
178
if (!BTypeOrErr)
179
reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());
180
SymbolRef::Type BType = *BTypeOrErr;
181
uint64_t AAddr =
182
(AType != SymbolRef::ST_Function) ? 0 : cantFail(A.getValue());
183
uint64_t BAddr =
184
(BType != SymbolRef::ST_Function) ? 0 : cantFail(B.getValue());
185
return AAddr < BAddr;
186
}
187
};
188
189
class MachODumper : public Dumper {
190
const object::MachOObjectFile &Obj;
191
192
public:
193
MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {}
194
void printPrivateHeaders() override;
195
};
196
} // namespace
197
198
std::unique_ptr<Dumper>
199
objdump::createMachODumper(const object::MachOObjectFile &Obj) {
200
return std::make_unique<MachODumper>(Obj);
201
}
202
203
// Types for the storted data in code table that is built before disassembly
204
// and the predicate function to sort them.
205
typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
206
typedef std::vector<DiceTableEntry> DiceTable;
207
typedef DiceTable::iterator dice_table_iterator;
208
209
// This is used to search for a data in code table entry for the PC being
210
// disassembled. The j parameter has the PC in j.first. A single data in code
211
// table entry can cover many bytes for each of its Kind's. So if the offset,
212
// aka the i.first value, of the data in code table entry plus its Length
213
// covers the PC being searched for this will return true. If not it will
214
// return false.
215
static bool compareDiceTableEntries(const DiceTableEntry &i,
216
const DiceTableEntry &j) {
217
uint16_t Length;
218
i.second.getLength(Length);
219
220
return j.first >= i.first && j.first < i.first + Length;
221
}
222
223
static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
224
unsigned short Kind) {
225
uint32_t Value, Size = 1;
226
227
switch (Kind) {
228
default:
229
case MachO::DICE_KIND_DATA:
230
if (Length >= 4) {
231
if (ShowRawInsn)
232
dumpBytes(ArrayRef(bytes, 4), outs());
233
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
234
outs() << "\t.long " << Value;
235
Size = 4;
236
} else if (Length >= 2) {
237
if (ShowRawInsn)
238
dumpBytes(ArrayRef(bytes, 2), outs());
239
Value = bytes[1] << 8 | bytes[0];
240
outs() << "\t.short " << Value;
241
Size = 2;
242
} else {
243
if (ShowRawInsn)
244
dumpBytes(ArrayRef(bytes, 2), outs());
245
Value = bytes[0];
246
outs() << "\t.byte " << Value;
247
Size = 1;
248
}
249
if (Kind == MachO::DICE_KIND_DATA)
250
outs() << "\t@ KIND_DATA\n";
251
else
252
outs() << "\t@ data in code kind = " << Kind << "\n";
253
break;
254
case MachO::DICE_KIND_JUMP_TABLE8:
255
if (ShowRawInsn)
256
dumpBytes(ArrayRef(bytes, 1), outs());
257
Value = bytes[0];
258
outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
259
Size = 1;
260
break;
261
case MachO::DICE_KIND_JUMP_TABLE16:
262
if (ShowRawInsn)
263
dumpBytes(ArrayRef(bytes, 2), outs());
264
Value = bytes[1] << 8 | bytes[0];
265
outs() << "\t.short " << format("%5u", Value & 0xffff)
266
<< "\t@ KIND_JUMP_TABLE16\n";
267
Size = 2;
268
break;
269
case MachO::DICE_KIND_JUMP_TABLE32:
270
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
271
if (ShowRawInsn)
272
dumpBytes(ArrayRef(bytes, 4), outs());
273
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
274
outs() << "\t.long " << Value;
275
if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
276
outs() << "\t@ KIND_JUMP_TABLE32\n";
277
else
278
outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
279
Size = 4;
280
break;
281
}
282
return Size;
283
}
284
285
static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
286
std::vector<SectionRef> &Sections,
287
std::vector<SymbolRef> &Symbols,
288
SmallVectorImpl<uint64_t> &FoundFns,
289
uint64_t &BaseSegmentAddress) {
290
const StringRef FileName = MachOObj->getFileName();
291
for (const SymbolRef &Symbol : MachOObj->symbols()) {
292
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
293
if (!SymName.starts_with("ltmp"))
294
Symbols.push_back(Symbol);
295
}
296
297
append_range(Sections, MachOObj->sections());
298
299
bool BaseSegmentAddressSet = false;
300
for (const auto &Command : MachOObj->load_commands()) {
301
if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
302
// We found a function starts segment, parse the addresses for later
303
// consumption.
304
MachO::linkedit_data_command LLC =
305
MachOObj->getLinkeditDataLoadCommand(Command);
306
307
MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
308
} else if (Command.C.cmd == MachO::LC_SEGMENT) {
309
MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
310
StringRef SegName = SLC.segname;
311
if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
312
BaseSegmentAddressSet = true;
313
BaseSegmentAddress = SLC.vmaddr;
314
}
315
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
316
MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command);
317
StringRef SegName = SLC.segname;
318
if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
319
BaseSegmentAddressSet = true;
320
BaseSegmentAddress = SLC.vmaddr;
321
}
322
}
323
}
324
}
325
326
static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes,
327
DiceTable &Dices, uint64_t &InstSize) {
328
// Check the data in code table here to see if this is data not an
329
// instruction to be disassembled.
330
DiceTable Dice;
331
Dice.push_back(std::make_pair(PC, DiceRef()));
332
dice_table_iterator DTI =
333
std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),
334
compareDiceTableEntries);
335
if (DTI != Dices.end()) {
336
uint16_t Length;
337
DTI->second.getLength(Length);
338
uint16_t Kind;
339
DTI->second.getKind(Kind);
340
InstSize = DumpDataInCode(bytes, Length, Kind);
341
if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
342
(PC == (DTI->first + Length - 1)) && (Length & 1))
343
InstSize++;
344
return true;
345
}
346
return false;
347
}
348
349
static void printRelocationTargetName(const MachOObjectFile *O,
350
const MachO::any_relocation_info &RE,
351
raw_string_ostream &Fmt) {
352
// Target of a scattered relocation is an address. In the interest of
353
// generating pretty output, scan through the symbol table looking for a
354
// symbol that aligns with that address. If we find one, print it.
355
// Otherwise, we just print the hex address of the target.
356
const StringRef FileName = O->getFileName();
357
if (O->isRelocationScattered(RE)) {
358
uint32_t Val = O->getPlainRelocationSymbolNum(RE);
359
360
for (const SymbolRef &Symbol : O->symbols()) {
361
uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
362
if (Addr != Val)
363
continue;
364
Fmt << unwrapOrError(Symbol.getName(), FileName);
365
return;
366
}
367
368
// If we couldn't find a symbol that this relocation refers to, try
369
// to find a section beginning instead.
370
for (const SectionRef &Section : ToolSectionFilter(*O)) {
371
uint64_t Addr = Section.getAddress();
372
if (Addr != Val)
373
continue;
374
StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName());
375
Fmt << NameOrErr;
376
return;
377
}
378
379
Fmt << format("0x%x", Val);
380
return;
381
}
382
383
StringRef S;
384
bool isExtern = O->getPlainRelocationExternal(RE);
385
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
386
387
if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND &&
388
(O->getArch() == Triple::aarch64 || O->getArch() == Triple::aarch64_be)) {
389
Fmt << format("0x%0" PRIx64, Val);
390
return;
391
}
392
393
if (isExtern) {
394
symbol_iterator SI = O->symbol_begin();
395
std::advance(SI, Val);
396
S = unwrapOrError(SI->getName(), FileName);
397
} else {
398
section_iterator SI = O->section_begin();
399
// Adjust for the fact that sections are 1-indexed.
400
if (Val == 0) {
401
Fmt << "0 (?,?)";
402
return;
403
}
404
uint32_t I = Val - 1;
405
while (I != 0 && SI != O->section_end()) {
406
--I;
407
std::advance(SI, 1);
408
}
409
if (SI == O->section_end()) {
410
Fmt << Val << " (?,?)";
411
} else {
412
if (Expected<StringRef> NameOrErr = SI->getName())
413
S = *NameOrErr;
414
else
415
consumeError(NameOrErr.takeError());
416
}
417
}
418
419
Fmt << S;
420
}
421
422
Error objdump::getMachORelocationValueString(const MachOObjectFile *Obj,
423
const RelocationRef &RelRef,
424
SmallVectorImpl<char> &Result) {
425
DataRefImpl Rel = RelRef.getRawDataRefImpl();
426
MachO::any_relocation_info RE = Obj->getRelocation(Rel);
427
428
unsigned Arch = Obj->getArch();
429
430
std::string FmtBuf;
431
raw_string_ostream Fmt(FmtBuf);
432
unsigned Type = Obj->getAnyRelocationType(RE);
433
bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
434
435
// Determine any addends that should be displayed with the relocation.
436
// These require decoding the relocation type, which is triple-specific.
437
438
// X86_64 has entirely custom relocation types.
439
if (Arch == Triple::x86_64) {
440
switch (Type) {
441
case MachO::X86_64_RELOC_GOT_LOAD:
442
case MachO::X86_64_RELOC_GOT: {
443
printRelocationTargetName(Obj, RE, Fmt);
444
Fmt << "@GOT";
445
if (IsPCRel)
446
Fmt << "PCREL";
447
break;
448
}
449
case MachO::X86_64_RELOC_SUBTRACTOR: {
450
DataRefImpl RelNext = Rel;
451
Obj->moveRelocationNext(RelNext);
452
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
453
454
// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
455
// X86_64_RELOC_UNSIGNED.
456
// NOTE: Scattered relocations don't exist on x86_64.
457
unsigned RType = Obj->getAnyRelocationType(RENext);
458
if (RType != MachO::X86_64_RELOC_UNSIGNED)
459
reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
460
"X86_64_RELOC_SUBTRACTOR.");
461
462
// The X86_64_RELOC_UNSIGNED contains the minuend symbol;
463
// X86_64_RELOC_SUBTRACTOR contains the subtrahend.
464
printRelocationTargetName(Obj, RENext, Fmt);
465
Fmt << "-";
466
printRelocationTargetName(Obj, RE, Fmt);
467
break;
468
}
469
case MachO::X86_64_RELOC_TLV:
470
printRelocationTargetName(Obj, RE, Fmt);
471
Fmt << "@TLV";
472
if (IsPCRel)
473
Fmt << "P";
474
break;
475
case MachO::X86_64_RELOC_SIGNED_1:
476
printRelocationTargetName(Obj, RE, Fmt);
477
Fmt << "-1";
478
break;
479
case MachO::X86_64_RELOC_SIGNED_2:
480
printRelocationTargetName(Obj, RE, Fmt);
481
Fmt << "-2";
482
break;
483
case MachO::X86_64_RELOC_SIGNED_4:
484
printRelocationTargetName(Obj, RE, Fmt);
485
Fmt << "-4";
486
break;
487
default:
488
printRelocationTargetName(Obj, RE, Fmt);
489
break;
490
}
491
// X86 and ARM share some relocation types in common.
492
} else if (Arch == Triple::x86 || Arch == Triple::arm ||
493
Arch == Triple::ppc) {
494
// Generic relocation types...
495
switch (Type) {
496
case MachO::GENERIC_RELOC_PAIR: // prints no info
497
return Error::success();
498
case MachO::GENERIC_RELOC_SECTDIFF: {
499
DataRefImpl RelNext = Rel;
500
Obj->moveRelocationNext(RelNext);
501
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
502
503
// X86 sect diff's must be followed by a relocation of type
504
// GENERIC_RELOC_PAIR.
505
unsigned RType = Obj->getAnyRelocationType(RENext);
506
507
if (RType != MachO::GENERIC_RELOC_PAIR)
508
reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
509
"GENERIC_RELOC_SECTDIFF.");
510
511
printRelocationTargetName(Obj, RE, Fmt);
512
Fmt << "-";
513
printRelocationTargetName(Obj, RENext, Fmt);
514
break;
515
}
516
}
517
518
if (Arch == Triple::x86 || Arch == Triple::ppc) {
519
switch (Type) {
520
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
521
DataRefImpl RelNext = Rel;
522
Obj->moveRelocationNext(RelNext);
523
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
524
525
// X86 sect diff's must be followed by a relocation of type
526
// GENERIC_RELOC_PAIR.
527
unsigned RType = Obj->getAnyRelocationType(RENext);
528
if (RType != MachO::GENERIC_RELOC_PAIR)
529
reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
530
"GENERIC_RELOC_LOCAL_SECTDIFF.");
531
532
printRelocationTargetName(Obj, RE, Fmt);
533
Fmt << "-";
534
printRelocationTargetName(Obj, RENext, Fmt);
535
break;
536
}
537
case MachO::GENERIC_RELOC_TLV: {
538
printRelocationTargetName(Obj, RE, Fmt);
539
Fmt << "@TLV";
540
if (IsPCRel)
541
Fmt << "P";
542
break;
543
}
544
default:
545
printRelocationTargetName(Obj, RE, Fmt);
546
}
547
} else { // ARM-specific relocations
548
switch (Type) {
549
case MachO::ARM_RELOC_HALF:
550
case MachO::ARM_RELOC_HALF_SECTDIFF: {
551
// Half relocations steal a bit from the length field to encode
552
// whether this is an upper16 or a lower16 relocation.
553
bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
554
555
if (isUpper)
556
Fmt << ":upper16:(";
557
else
558
Fmt << ":lower16:(";
559
printRelocationTargetName(Obj, RE, Fmt);
560
561
DataRefImpl RelNext = Rel;
562
Obj->moveRelocationNext(RelNext);
563
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
564
565
// ARM half relocs must be followed by a relocation of type
566
// ARM_RELOC_PAIR.
567
unsigned RType = Obj->getAnyRelocationType(RENext);
568
if (RType != MachO::ARM_RELOC_PAIR)
569
reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
570
"ARM_RELOC_HALF");
571
572
// NOTE: The half of the target virtual address is stashed in the
573
// address field of the secondary relocation, but we can't reverse
574
// engineer the constant offset from it without decoding the movw/movt
575
// instruction to find the other half in its immediate field.
576
577
// ARM_RELOC_HALF_SECTDIFF encodes the second section in the
578
// symbol/section pointer of the follow-on relocation.
579
if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
580
Fmt << "-";
581
printRelocationTargetName(Obj, RENext, Fmt);
582
}
583
584
Fmt << ")";
585
break;
586
}
587
default: {
588
printRelocationTargetName(Obj, RE, Fmt);
589
}
590
}
591
}
592
} else
593
printRelocationTargetName(Obj, RE, Fmt);
594
595
Fmt.flush();
596
Result.append(FmtBuf.begin(), FmtBuf.end());
597
return Error::success();
598
}
599
600
static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
601
uint32_t n, uint32_t count,
602
uint32_t stride, uint64_t addr) {
603
MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
604
uint32_t nindirectsyms = Dysymtab.nindirectsyms;
605
if (n > nindirectsyms)
606
outs() << " (entries start past the end of the indirect symbol "
607
"table) (reserved1 field greater than the table size)";
608
else if (n + count > nindirectsyms)
609
outs() << " (entries extends past the end of the indirect symbol "
610
"table)";
611
outs() << "\n";
612
uint32_t cputype = O->getHeader().cputype;
613
if (cputype & MachO::CPU_ARCH_ABI64)
614
outs() << "address index";
615
else
616
outs() << "address index";
617
if (verbose)
618
outs() << " name\n";
619
else
620
outs() << "\n";
621
for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
622
if (cputype & MachO::CPU_ARCH_ABI64)
623
outs() << format("0x%016" PRIx64, addr + j * stride) << " ";
624
else
625
outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";
626
MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
627
uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
628
if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
629
outs() << "LOCAL\n";
630
continue;
631
}
632
if (indirect_symbol ==
633
(MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
634
outs() << "LOCAL ABSOLUTE\n";
635
continue;
636
}
637
if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
638
outs() << "ABSOLUTE\n";
639
continue;
640
}
641
outs() << format("%5u ", indirect_symbol);
642
if (verbose) {
643
MachO::symtab_command Symtab = O->getSymtabLoadCommand();
644
if (indirect_symbol < Symtab.nsyms) {
645
symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
646
SymbolRef Symbol = *Sym;
647
outs() << unwrapOrError(Symbol.getName(), O->getFileName());
648
} else {
649
outs() << "?";
650
}
651
}
652
outs() << "\n";
653
}
654
}
655
656
static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
657
for (const auto &Load : O->load_commands()) {
658
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
659
MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
660
for (unsigned J = 0; J < Seg.nsects; ++J) {
661
MachO::section_64 Sec = O->getSection64(Load, J);
662
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
663
if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
664
section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
665
section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
666
section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
667
section_type == MachO::S_SYMBOL_STUBS) {
668
uint32_t stride;
669
if (section_type == MachO::S_SYMBOL_STUBS)
670
stride = Sec.reserved2;
671
else
672
stride = 8;
673
if (stride == 0) {
674
outs() << "Can't print indirect symbols for (" << Sec.segname << ","
675
<< Sec.sectname << ") "
676
<< "(size of stubs in reserved2 field is zero)\n";
677
continue;
678
}
679
uint32_t count = Sec.size / stride;
680
outs() << "Indirect symbols for (" << Sec.segname << ","
681
<< Sec.sectname << ") " << count << " entries";
682
uint32_t n = Sec.reserved1;
683
PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
684
}
685
}
686
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
687
MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
688
for (unsigned J = 0; J < Seg.nsects; ++J) {
689
MachO::section Sec = O->getSection(Load, J);
690
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
691
if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
692
section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
693
section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
694
section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
695
section_type == MachO::S_SYMBOL_STUBS) {
696
uint32_t stride;
697
if (section_type == MachO::S_SYMBOL_STUBS)
698
stride = Sec.reserved2;
699
else
700
stride = 4;
701
if (stride == 0) {
702
outs() << "Can't print indirect symbols for (" << Sec.segname << ","
703
<< Sec.sectname << ") "
704
<< "(size of stubs in reserved2 field is zero)\n";
705
continue;
706
}
707
uint32_t count = Sec.size / stride;
708
outs() << "Indirect symbols for (" << Sec.segname << ","
709
<< Sec.sectname << ") " << count << " entries";
710
uint32_t n = Sec.reserved1;
711
PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
712
}
713
}
714
}
715
}
716
}
717
718
static void PrintRType(const uint64_t cputype, const unsigned r_type) {
719
static char const *generic_r_types[] = {
720
"VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
721
" 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
722
" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
723
};
724
static char const *x86_64_r_types[] = {
725
"UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
726
"SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
727
" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
728
};
729
static char const *arm_r_types[] = {
730
"VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
731
"BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
732
" 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
733
};
734
static char const *arm64_r_types[] = {
735
"UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
736
"GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
737
"ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
738
};
739
740
if (r_type > 0xf){
741
outs() << format("%-7u", r_type) << " ";
742
return;
743
}
744
switch (cputype) {
745
case MachO::CPU_TYPE_I386:
746
outs() << generic_r_types[r_type];
747
break;
748
case MachO::CPU_TYPE_X86_64:
749
outs() << x86_64_r_types[r_type];
750
break;
751
case MachO::CPU_TYPE_ARM:
752
outs() << arm_r_types[r_type];
753
break;
754
case MachO::CPU_TYPE_ARM64:
755
case MachO::CPU_TYPE_ARM64_32:
756
outs() << arm64_r_types[r_type];
757
break;
758
default:
759
outs() << format("%-7u ", r_type);
760
}
761
}
762
763
static void PrintRLength(const uint64_t cputype, const unsigned r_type,
764
const unsigned r_length, const bool previous_arm_half){
765
if (cputype == MachO::CPU_TYPE_ARM &&
766
(r_type == MachO::ARM_RELOC_HALF ||
767
r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {
768
if ((r_length & 0x1) == 0)
769
outs() << "lo/";
770
else
771
outs() << "hi/";
772
if ((r_length & 0x1) == 0)
773
outs() << "arm ";
774
else
775
outs() << "thm ";
776
} else {
777
switch (r_length) {
778
case 0:
779
outs() << "byte ";
780
break;
781
case 1:
782
outs() << "word ";
783
break;
784
case 2:
785
outs() << "long ";
786
break;
787
case 3:
788
if (cputype == MachO::CPU_TYPE_X86_64)
789
outs() << "quad ";
790
else
791
outs() << format("?(%2d) ", r_length);
792
break;
793
default:
794
outs() << format("?(%2d) ", r_length);
795
}
796
}
797
}
798
799
static void PrintRelocationEntries(const MachOObjectFile *O,
800
const relocation_iterator Begin,
801
const relocation_iterator End,
802
const uint64_t cputype,
803
const bool verbose) {
804
const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
805
bool previous_arm_half = false;
806
bool previous_sectdiff = false;
807
uint32_t sectdiff_r_type = 0;
808
809
for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
810
const DataRefImpl Rel = Reloc->getRawDataRefImpl();
811
const MachO::any_relocation_info RE = O->getRelocation(Rel);
812
const unsigned r_type = O->getAnyRelocationType(RE);
813
const bool r_scattered = O->isRelocationScattered(RE);
814
const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
815
const unsigned r_length = O->getAnyRelocationLength(RE);
816
const unsigned r_address = O->getAnyRelocationAddress(RE);
817
const bool r_extern = (r_scattered ? false :
818
O->getPlainRelocationExternal(RE));
819
const uint32_t r_value = (r_scattered ?
820
O->getScatteredRelocationValue(RE) : 0);
821
const unsigned r_symbolnum = (r_scattered ? 0 :
822
O->getPlainRelocationSymbolNum(RE));
823
824
if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
825
if (verbose) {
826
// scattered: address
827
if ((cputype == MachO::CPU_TYPE_I386 &&
828
r_type == MachO::GENERIC_RELOC_PAIR) ||
829
(cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))
830
outs() << " ";
831
else
832
outs() << format("%08x ", (unsigned int)r_address);
833
834
// scattered: pcrel
835
if (r_pcrel)
836
outs() << "True ";
837
else
838
outs() << "False ";
839
840
// scattered: length
841
PrintRLength(cputype, r_type, r_length, previous_arm_half);
842
843
// scattered: extern & type
844
outs() << "n/a ";
845
PrintRType(cputype, r_type);
846
847
// scattered: scattered & value
848
outs() << format("True 0x%08x", (unsigned int)r_value);
849
if (previous_sectdiff == false) {
850
if ((cputype == MachO::CPU_TYPE_ARM &&
851
r_type == MachO::ARM_RELOC_PAIR))
852
outs() << format(" half = 0x%04x ", (unsigned int)r_address);
853
} else if (cputype == MachO::CPU_TYPE_ARM &&
854
sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)
855
outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
856
if ((cputype == MachO::CPU_TYPE_I386 &&
857
(r_type == MachO::GENERIC_RELOC_SECTDIFF ||
858
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
859
(cputype == MachO::CPU_TYPE_ARM &&
860
(sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||
861
sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
862
sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {
863
previous_sectdiff = true;
864
sectdiff_r_type = r_type;
865
} else {
866
previous_sectdiff = false;
867
sectdiff_r_type = 0;
868
}
869
if (cputype == MachO::CPU_TYPE_ARM &&
870
(r_type == MachO::ARM_RELOC_HALF ||
871
r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
872
previous_arm_half = true;
873
else
874
previous_arm_half = false;
875
outs() << "\n";
876
}
877
else {
878
// scattered: address pcrel length extern type scattered value
879
outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",
880
(unsigned int)r_address, r_pcrel, r_length, r_type,
881
(unsigned int)r_value);
882
}
883
}
884
else {
885
if (verbose) {
886
// plain: address
887
if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
888
outs() << " ";
889
else
890
outs() << format("%08x ", (unsigned int)r_address);
891
892
// plain: pcrel
893
if (r_pcrel)
894
outs() << "True ";
895
else
896
outs() << "False ";
897
898
// plain: length
899
PrintRLength(cputype, r_type, r_length, previous_arm_half);
900
901
if (r_extern) {
902
// plain: extern & type & scattered
903
outs() << "True ";
904
PrintRType(cputype, r_type);
905
outs() << "False ";
906
907
// plain: symbolnum/value
908
if (r_symbolnum > Symtab.nsyms)
909
outs() << format("?(%d)\n", r_symbolnum);
910
else {
911
SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);
912
Expected<StringRef> SymNameNext = Symbol.getName();
913
const char *name = nullptr;
914
if (SymNameNext)
915
name = SymNameNext->data();
916
if (name == nullptr)
917
outs() << format("?(%d)\n", r_symbolnum);
918
else
919
outs() << name << "\n";
920
}
921
}
922
else {
923
// plain: extern & type & scattered
924
outs() << "False ";
925
PrintRType(cputype, r_type);
926
outs() << "False ";
927
928
// plain: symbolnum/value
929
if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
930
outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
931
else if ((cputype == MachO::CPU_TYPE_ARM64 ||
932
cputype == MachO::CPU_TYPE_ARM64_32) &&
933
r_type == MachO::ARM64_RELOC_ADDEND)
934
outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
935
else {
936
outs() << format("%d ", r_symbolnum);
937
if (r_symbolnum == MachO::R_ABS)
938
outs() << "R_ABS\n";
939
else {
940
// in this case, r_symbolnum is actually a 1-based section number
941
uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
942
if (r_symbolnum > 0 && r_symbolnum <= nsects) {
943
object::DataRefImpl DRI;
944
DRI.d.a = r_symbolnum-1;
945
StringRef SegName = O->getSectionFinalSegmentName(DRI);
946
if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
947
outs() << "(" << SegName << "," << *NameOrErr << ")\n";
948
else
949
outs() << "(?,?)\n";
950
}
951
else {
952
outs() << "(?,?)\n";
953
}
954
}
955
}
956
}
957
if (cputype == MachO::CPU_TYPE_ARM &&
958
(r_type == MachO::ARM_RELOC_HALF ||
959
r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
960
previous_arm_half = true;
961
else
962
previous_arm_half = false;
963
}
964
else {
965
// plain: address pcrel length extern type scattered symbolnum/section
966
outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",
967
(unsigned int)r_address, r_pcrel, r_length, r_extern,
968
r_type, r_symbolnum);
969
}
970
}
971
}
972
}
973
974
static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
975
const uint64_t cputype = O->getHeader().cputype;
976
const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
977
if (Dysymtab.nextrel != 0) {
978
outs() << "External relocation information " << Dysymtab.nextrel
979
<< " entries";
980
outs() << "\naddress pcrel length extern type scattered "
981
"symbolnum/value\n";
982
PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,
983
verbose);
984
}
985
if (Dysymtab.nlocrel != 0) {
986
outs() << format("Local relocation information %u entries",
987
Dysymtab.nlocrel);
988
outs() << "\naddress pcrel length extern type scattered "
989
"symbolnum/value\n";
990
PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,
991
verbose);
992
}
993
for (const auto &Load : O->load_commands()) {
994
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
995
const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
996
for (unsigned J = 0; J < Seg.nsects; ++J) {
997
const MachO::section_64 Sec = O->getSection64(Load, J);
998
if (Sec.nreloc != 0) {
999
DataRefImpl DRI;
1000
DRI.d.a = J;
1001
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
1002
if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
1003
outs() << "Relocation information (" << SegName << "," << *NameOrErr
1004
<< format(") %u entries", Sec.nreloc);
1005
else
1006
outs() << "Relocation information (" << SegName << ",?) "
1007
<< format("%u entries", Sec.nreloc);
1008
outs() << "\naddress pcrel length extern type scattered "
1009
"symbolnum/value\n";
1010
PrintRelocationEntries(O, O->section_rel_begin(DRI),
1011
O->section_rel_end(DRI), cputype, verbose);
1012
}
1013
}
1014
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
1015
const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
1016
for (unsigned J = 0; J < Seg.nsects; ++J) {
1017
const MachO::section Sec = O->getSection(Load, J);
1018
if (Sec.nreloc != 0) {
1019
DataRefImpl DRI;
1020
DRI.d.a = J;
1021
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
1022
if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
1023
outs() << "Relocation information (" << SegName << "," << *NameOrErr
1024
<< format(") %u entries", Sec.nreloc);
1025
else
1026
outs() << "Relocation information (" << SegName << ",?) "
1027
<< format("%u entries", Sec.nreloc);
1028
outs() << "\naddress pcrel length extern type scattered "
1029
"symbolnum/value\n";
1030
PrintRelocationEntries(O, O->section_rel_begin(DRI),
1031
O->section_rel_end(DRI), cputype, verbose);
1032
}
1033
}
1034
}
1035
}
1036
}
1037
1038
static void PrintFunctionStarts(MachOObjectFile *O) {
1039
uint64_t BaseSegmentAddress = 0;
1040
for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1041
if (Command.C.cmd == MachO::LC_SEGMENT) {
1042
MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
1043
if (StringRef(SLC.segname) == "__TEXT") {
1044
BaseSegmentAddress = SLC.vmaddr;
1045
break;
1046
}
1047
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1048
MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
1049
if (StringRef(SLC.segname) == "__TEXT") {
1050
BaseSegmentAddress = SLC.vmaddr;
1051
break;
1052
}
1053
}
1054
}
1055
1056
SmallVector<uint64_t, 8> FunctionStarts;
1057
for (const MachOObjectFile::LoadCommandInfo &LC : O->load_commands()) {
1058
if (LC.C.cmd == MachO::LC_FUNCTION_STARTS) {
1059
MachO::linkedit_data_command FunctionStartsLC =
1060
O->getLinkeditDataLoadCommand(LC);
1061
O->ReadULEB128s(FunctionStartsLC.dataoff, FunctionStarts);
1062
break;
1063
}
1064
}
1065
1066
DenseMap<uint64_t, StringRef> SymbolNames;
1067
if (FunctionStartsType == FunctionStartsMode::Names ||
1068
FunctionStartsType == FunctionStartsMode::Both) {
1069
for (SymbolRef Sym : O->symbols()) {
1070
if (Expected<uint64_t> Addr = Sym.getAddress()) {
1071
if (Expected<StringRef> Name = Sym.getName()) {
1072
SymbolNames[*Addr] = *Name;
1073
}
1074
}
1075
}
1076
}
1077
1078
for (uint64_t S : FunctionStarts) {
1079
uint64_t Addr = BaseSegmentAddress + S;
1080
if (FunctionStartsType == FunctionStartsMode::Names) {
1081
auto It = SymbolNames.find(Addr);
1082
if (It != SymbolNames.end())
1083
outs() << It->second << "\n";
1084
} else {
1085
if (O->is64Bit())
1086
outs() << format("%016" PRIx64, Addr);
1087
else
1088
outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));
1089
1090
if (FunctionStartsType == FunctionStartsMode::Both) {
1091
auto It = SymbolNames.find(Addr);
1092
if (It != SymbolNames.end())
1093
outs() << " " << It->second;
1094
else
1095
outs() << " ?";
1096
}
1097
outs() << "\n";
1098
}
1099
}
1100
}
1101
1102
static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
1103
MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
1104
uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
1105
outs() << "Data in code table (" << nentries << " entries)\n";
1106
outs() << "offset length kind\n";
1107
for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
1108
++DI) {
1109
uint32_t Offset;
1110
DI->getOffset(Offset);
1111
outs() << format("0x%08" PRIx32, Offset) << " ";
1112
uint16_t Length;
1113
DI->getLength(Length);
1114
outs() << format("%6u", Length) << " ";
1115
uint16_t Kind;
1116
DI->getKind(Kind);
1117
if (verbose) {
1118
switch (Kind) {
1119
case MachO::DICE_KIND_DATA:
1120
outs() << "DATA";
1121
break;
1122
case MachO::DICE_KIND_JUMP_TABLE8:
1123
outs() << "JUMP_TABLE8";
1124
break;
1125
case MachO::DICE_KIND_JUMP_TABLE16:
1126
outs() << "JUMP_TABLE16";
1127
break;
1128
case MachO::DICE_KIND_JUMP_TABLE32:
1129
outs() << "JUMP_TABLE32";
1130
break;
1131
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
1132
outs() << "ABS_JUMP_TABLE32";
1133
break;
1134
default:
1135
outs() << format("0x%04" PRIx32, Kind);
1136
break;
1137
}
1138
} else
1139
outs() << format("0x%04" PRIx32, Kind);
1140
outs() << "\n";
1141
}
1142
}
1143
1144
static void PrintLinkOptHints(MachOObjectFile *O) {
1145
MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
1146
const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
1147
uint32_t nloh = LohLC.datasize;
1148
outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
1149
for (uint32_t i = 0; i < nloh;) {
1150
unsigned n;
1151
uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
1152
i += n;
1153
outs() << " identifier " << identifier << " ";
1154
if (i >= nloh)
1155
return;
1156
switch (identifier) {
1157
case 1:
1158
outs() << "AdrpAdrp\n";
1159
break;
1160
case 2:
1161
outs() << "AdrpLdr\n";
1162
break;
1163
case 3:
1164
outs() << "AdrpAddLdr\n";
1165
break;
1166
case 4:
1167
outs() << "AdrpLdrGotLdr\n";
1168
break;
1169
case 5:
1170
outs() << "AdrpAddStr\n";
1171
break;
1172
case 6:
1173
outs() << "AdrpLdrGotStr\n";
1174
break;
1175
case 7:
1176
outs() << "AdrpAdd\n";
1177
break;
1178
case 8:
1179
outs() << "AdrpLdrGot\n";
1180
break;
1181
default:
1182
outs() << "Unknown identifier value\n";
1183
break;
1184
}
1185
uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
1186
i += n;
1187
outs() << " narguments " << narguments << "\n";
1188
if (i >= nloh)
1189
return;
1190
1191
for (uint32_t j = 0; j < narguments; j++) {
1192
uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
1193
i += n;
1194
outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";
1195
if (i >= nloh)
1196
return;
1197
}
1198
}
1199
}
1200
1201
static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
1202
SmallVector<std::string> Ret;
1203
for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
1204
if (Command.C.cmd == MachO::LC_SEGMENT) {
1205
MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
1206
Ret.push_back(SLC.segname);
1207
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1208
MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
1209
Ret.push_back(SLC.segname);
1210
}
1211
}
1212
return Ret;
1213
}
1214
1215
static void
1216
PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
1217
outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
1218
outs() << " fixups_version = " << H.fixups_version << '\n';
1219
outs() << " starts_offset = " << H.starts_offset << '\n';
1220
outs() << " imports_offset = " << H.imports_offset << '\n';
1221
outs() << " symbols_offset = " << H.symbols_offset << '\n';
1222
outs() << " imports_count = " << H.imports_count << '\n';
1223
1224
outs() << " imports_format = " << H.imports_format;
1225
switch (H.imports_format) {
1226
case llvm::MachO::DYLD_CHAINED_IMPORT:
1227
outs() << " (DYLD_CHAINED_IMPORT)";
1228
break;
1229
case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
1230
outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
1231
break;
1232
case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
1233
outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
1234
break;
1235
}
1236
outs() << '\n';
1237
1238
outs() << " symbols_format = " << H.symbols_format;
1239
if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
1240
outs() << " (zlib compressed)";
1241
outs() << '\n';
1242
}
1243
1244
static constexpr std::array<StringRef, 13> PointerFormats{
1245
"DYLD_CHAINED_PTR_ARM64E",
1246
"DYLD_CHAINED_PTR_64",
1247
"DYLD_CHAINED_PTR_32",
1248
"DYLD_CHAINED_PTR_32_CACHE",
1249
"DYLD_CHAINED_PTR_32_FIRMWARE",
1250
"DYLD_CHAINED_PTR_64_OFFSET",
1251
"DYLD_CHAINED_PTR_ARM64E_KERNEL",
1252
"DYLD_CHAINED_PTR_64_KERNEL_CACHE",
1253
"DYLD_CHAINED_PTR_ARM64E_USERLAND",
1254
"DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
1255
"DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
1256
"DYLD_CHAINED_PTR_ARM64E_USERLAND24",
1257
};
1258
1259
static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,
1260
StringRef SegName) {
1261
outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
1262
<< ")\n";
1263
outs() << " size = " << Segment.Header.size << '\n';
1264
outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)
1265
<< '\n';
1266
1267
outs() << " pointer_format = " << Segment.Header.pointer_format;
1268
if ((Segment.Header.pointer_format - 1) <
1269
MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
1270
outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
1271
outs() << '\n';
1272
1273
outs() << " segment_offset = "
1274
<< format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';
1275
outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
1276
<< '\n';
1277
outs() << " page_count = " << Segment.Header.page_count << '\n';
1278
for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {
1279
outs() << " page_start[" << Index << "] = " << PageStart;
1280
// FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
1281
if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
1282
outs() << " (DYLD_CHAINED_PTR_START_NONE)";
1283
outs() << '\n';
1284
}
1285
}
1286
1287
static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,
1288
int Format, MachOObjectFile *O) {
1289
if (Format == MachO::DYLD_CHAINED_IMPORT)
1290
outs() << "dyld chained import";
1291
else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
1292
outs() << "dyld chained import addend";
1293
else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
1294
outs() << "dyld chained import addend64";
1295
// FIXME: otool prints the encoded value as well.
1296
outs() << '[' << Idx << "]\n";
1297
1298
outs() << " lib_ordinal = " << Target.libOrdinal() << " ("
1299
<< ordinalName(O, Target.libOrdinal()) << ")\n";
1300
outs() << " weak_import = " << Target.weakImport() << '\n';
1301
outs() << " name_offset = " << Target.nameOffset() << " ("
1302
<< Target.symbolName() << ")\n";
1303
if (Format != MachO::DYLD_CHAINED_IMPORT)
1304
outs() << " addend = " << (int64_t)Target.addend() << '\n';
1305
}
1306
1307
static void PrintChainedFixups(MachOObjectFile *O) {
1308
// MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
1309
// FIXME: Support chained fixups in __TEXT,__chain_starts section too.
1310
auto ChainedFixupHeader =
1311
unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());
1312
if (!ChainedFixupHeader)
1313
return;
1314
1315
PrintChainedFixupsHeader(*ChainedFixupHeader);
1316
1317
auto [SegCount, Segments] =
1318
unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());
1319
1320
auto SegNames = GetSegmentNames(O);
1321
1322
size_t StartsIdx = 0;
1323
outs() << "chained starts in image\n";
1324
outs() << " seg_count = " << SegCount << '\n';
1325
for (size_t I = 0; I < SegCount; ++I) {
1326
uint64_t SegOffset = 0;
1327
if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
1328
SegOffset = Segments[StartsIdx].Offset;
1329
++StartsIdx;
1330
}
1331
1332
outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
1333
<< SegNames[I] << ")\n";
1334
}
1335
1336
for (const ChainedFixupsSegment &S : Segments)
1337
PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);
1338
1339
auto FixupTargets =
1340
unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());
1341
1342
uint32_t ImportsFormat = ChainedFixupHeader->imports_format;
1343
for (auto [Idx, Target] : enumerate(FixupTargets))
1344
PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);
1345
}
1346
1347
static void PrintDyldInfo(MachOObjectFile *O) {
1348
Error Err = Error::success();
1349
1350
size_t SegmentWidth = strlen("segment");
1351
size_t SectionWidth = strlen("section");
1352
size_t AddressWidth = strlen("address");
1353
size_t AddendWidth = strlen("addend");
1354
size_t DylibWidth = strlen("dylib");
1355
const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;
1356
1357
auto HexLength = [](uint64_t Num) {
1358
return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;
1359
};
1360
for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1361
SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());
1362
SectionWidth = std::max(SectionWidth, Entry.sectionName().size());
1363
AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);
1364
if (Entry.isBind()) {
1365
AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);
1366
DylibWidth = std::max(DylibWidth, Entry.symbolName().size());
1367
}
1368
}
1369
// Errors will be handled when printing the table.
1370
if (Err)
1371
consumeError(std::move(Err));
1372
1373
outs() << "dyld information:\n";
1374
outs() << left_justify("segment", SegmentWidth) << ' '
1375
<< left_justify("section", SectionWidth) << ' '
1376
<< left_justify("address", AddressWidth) << ' '
1377
<< left_justify("pointer", PointerWidth) << " type "
1378
<< left_justify("addend", AddendWidth) << ' '
1379
<< left_justify("dylib", DylibWidth) << " symbol/vm address\n";
1380
for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
1381
outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '
1382
<< left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"
1383
<< left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '
1384
<< format_hex(Entry.rawValue(), PointerWidth, true) << ' ';
1385
if (Entry.isBind()) {
1386
outs() << "bind "
1387
<< "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)
1388
<< ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)
1389
<< ' ' << Entry.symbolName();
1390
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
1391
outs() << " (weak import)";
1392
outs() << '\n';
1393
} else {
1394
assert(Entry.isRebase());
1395
outs() << "rebase";
1396
outs().indent(AddendWidth + DylibWidth + 2);
1397
outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';
1398
}
1399
}
1400
if (Err)
1401
reportError(std::move(Err), O->getFileName());
1402
1403
// TODO: Print opcode-based fixups if the object uses those.
1404
}
1405
1406
static void PrintDylibs(MachOObjectFile *O, bool JustId) {
1407
unsigned Index = 0;
1408
for (const auto &Load : O->load_commands()) {
1409
if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
1410
(!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
1411
Load.C.cmd == MachO::LC_LOAD_DYLIB ||
1412
Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
1413
Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
1414
Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
1415
Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
1416
MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
1417
if (dl.dylib.name < dl.cmdsize) {
1418
const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
1419
if (JustId)
1420
outs() << p << "\n";
1421
else {
1422
outs() << "\t" << p;
1423
outs() << " (compatibility version "
1424
<< ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
1425
<< ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
1426
<< (dl.dylib.compatibility_version & 0xff) << ",";
1427
outs() << " current version "
1428
<< ((dl.dylib.current_version >> 16) & 0xffff) << "."
1429
<< ((dl.dylib.current_version >> 8) & 0xff) << "."
1430
<< (dl.dylib.current_version & 0xff);
1431
if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1432
outs() << ", weak";
1433
if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1434
outs() << ", reexport";
1435
if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1436
outs() << ", upward";
1437
if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1438
outs() << ", lazy";
1439
outs() << ")\n";
1440
}
1441
} else {
1442
outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
1443
if (Load.C.cmd == MachO::LC_ID_DYLIB)
1444
outs() << "LC_ID_DYLIB ";
1445
else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
1446
outs() << "LC_LOAD_DYLIB ";
1447
else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1448
outs() << "LC_LOAD_WEAK_DYLIB ";
1449
else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1450
outs() << "LC_LAZY_LOAD_DYLIB ";
1451
else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1452
outs() << "LC_REEXPORT_DYLIB ";
1453
else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1454
outs() << "LC_LOAD_UPWARD_DYLIB ";
1455
else
1456
outs() << "LC_??? ";
1457
outs() << "command " << Index++ << "\n";
1458
}
1459
}
1460
}
1461
}
1462
1463
static void printRpaths(MachOObjectFile *O) {
1464
for (const auto &Command : O->load_commands()) {
1465
if (Command.C.cmd == MachO::LC_RPATH) {
1466
auto Rpath = O->getRpathCommand(Command);
1467
const char *P = (const char *)(Command.Ptr) + Rpath.path;
1468
outs() << P << "\n";
1469
}
1470
}
1471
}
1472
1473
typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
1474
1475
static void CreateSymbolAddressMap(MachOObjectFile *O,
1476
SymbolAddressMap *AddrMap) {
1477
// Create a map of symbol addresses to symbol names.
1478
const StringRef FileName = O->getFileName();
1479
for (const SymbolRef &Symbol : O->symbols()) {
1480
SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);
1481
if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
1482
ST == SymbolRef::ST_Other) {
1483
uint64_t Address = cantFail(Symbol.getValue());
1484
StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
1485
if (!SymName.starts_with(".objc"))
1486
(*AddrMap)[Address] = SymName;
1487
}
1488
}
1489
}
1490
1491
// GuessSymbolName is passed the address of what might be a symbol and a
1492
// pointer to the SymbolAddressMap. It returns the name of a symbol
1493
// with that address or nullptr if no symbol is found with that address.
1494
static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
1495
const char *SymbolName = nullptr;
1496
// A DenseMap can't lookup up some values.
1497
if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
1498
StringRef name = AddrMap->lookup(value);
1499
if (!name.empty())
1500
SymbolName = name.data();
1501
}
1502
return SymbolName;
1503
}
1504
1505
static void DumpCstringChar(const char c) {
1506
char p[2];
1507
p[0] = c;
1508
p[1] = '\0';
1509
outs().write_escaped(p);
1510
}
1511
1512
static void DumpCstringSection(MachOObjectFile *O, const char *sect,
1513
uint32_t sect_size, uint64_t sect_addr,
1514
bool print_addresses) {
1515
for (uint32_t i = 0; i < sect_size; i++) {
1516
if (print_addresses) {
1517
if (O->is64Bit())
1518
outs() << format("%016" PRIx64, sect_addr + i) << " ";
1519
else
1520
outs() << format("%08" PRIx64, sect_addr + i) << " ";
1521
}
1522
for (; i < sect_size && sect[i] != '\0'; i++)
1523
DumpCstringChar(sect[i]);
1524
if (i < sect_size && sect[i] == '\0')
1525
outs() << "\n";
1526
}
1527
}
1528
1529
static void DumpLiteral4(uint32_t l, float f) {
1530
outs() << format("0x%08" PRIx32, l);
1531
if ((l & 0x7f800000) != 0x7f800000)
1532
outs() << format(" (%.16e)\n", f);
1533
else {
1534
if (l == 0x7f800000)
1535
outs() << " (+Infinity)\n";
1536
else if (l == 0xff800000)
1537
outs() << " (-Infinity)\n";
1538
else if ((l & 0x00400000) == 0x00400000)
1539
outs() << " (non-signaling Not-a-Number)\n";
1540
else
1541
outs() << " (signaling Not-a-Number)\n";
1542
}
1543
}
1544
1545
static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
1546
uint32_t sect_size, uint64_t sect_addr,
1547
bool print_addresses) {
1548
for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
1549
if (print_addresses) {
1550
if (O->is64Bit())
1551
outs() << format("%016" PRIx64, sect_addr + i) << " ";
1552
else
1553
outs() << format("%08" PRIx64, sect_addr + i) << " ";
1554
}
1555
float f;
1556
memcpy(&f, sect + i, sizeof(float));
1557
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1558
sys::swapByteOrder(f);
1559
uint32_t l;
1560
memcpy(&l, sect + i, sizeof(uint32_t));
1561
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1562
sys::swapByteOrder(l);
1563
DumpLiteral4(l, f);
1564
}
1565
}
1566
1567
static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
1568
double d) {
1569
outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
1570
uint32_t Hi, Lo;
1571
Hi = (O->isLittleEndian()) ? l1 : l0;
1572
Lo = (O->isLittleEndian()) ? l0 : l1;
1573
1574
// Hi is the high word, so this is equivalent to if(isfinite(d))
1575
if ((Hi & 0x7ff00000) != 0x7ff00000)
1576
outs() << format(" (%.16e)\n", d);
1577
else {
1578
if (Hi == 0x7ff00000 && Lo == 0)
1579
outs() << " (+Infinity)\n";
1580
else if (Hi == 0xfff00000 && Lo == 0)
1581
outs() << " (-Infinity)\n";
1582
else if ((Hi & 0x00080000) == 0x00080000)
1583
outs() << " (non-signaling Not-a-Number)\n";
1584
else
1585
outs() << " (signaling Not-a-Number)\n";
1586
}
1587
}
1588
1589
static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
1590
uint32_t sect_size, uint64_t sect_addr,
1591
bool print_addresses) {
1592
for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
1593
if (print_addresses) {
1594
if (O->is64Bit())
1595
outs() << format("%016" PRIx64, sect_addr + i) << " ";
1596
else
1597
outs() << format("%08" PRIx64, sect_addr + i) << " ";
1598
}
1599
double d;
1600
memcpy(&d, sect + i, sizeof(double));
1601
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1602
sys::swapByteOrder(d);
1603
uint32_t l0, l1;
1604
memcpy(&l0, sect + i, sizeof(uint32_t));
1605
memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1606
if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1607
sys::swapByteOrder(l0);
1608
sys::swapByteOrder(l1);
1609
}
1610
DumpLiteral8(O, l0, l1, d);
1611
}
1612
}
1613
1614
static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
1615
outs() << format("0x%08" PRIx32, l0) << " ";
1616
outs() << format("0x%08" PRIx32, l1) << " ";
1617
outs() << format("0x%08" PRIx32, l2) << " ";
1618
outs() << format("0x%08" PRIx32, l3) << "\n";
1619
}
1620
1621
static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
1622
uint32_t sect_size, uint64_t sect_addr,
1623
bool print_addresses) {
1624
for (uint32_t i = 0; i < sect_size; i += 16) {
1625
if (print_addresses) {
1626
if (O->is64Bit())
1627
outs() << format("%016" PRIx64, sect_addr + i) << " ";
1628
else
1629
outs() << format("%08" PRIx64, sect_addr + i) << " ";
1630
}
1631
uint32_t l0, l1, l2, l3;
1632
memcpy(&l0, sect + i, sizeof(uint32_t));
1633
memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1634
memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
1635
memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
1636
if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1637
sys::swapByteOrder(l0);
1638
sys::swapByteOrder(l1);
1639
sys::swapByteOrder(l2);
1640
sys::swapByteOrder(l3);
1641
}
1642
DumpLiteral16(l0, l1, l2, l3);
1643
}
1644
}
1645
1646
static void DumpLiteralPointerSection(MachOObjectFile *O,
1647
const SectionRef &Section,
1648
const char *sect, uint32_t sect_size,
1649
uint64_t sect_addr,
1650
bool print_addresses) {
1651
// Collect the literal sections in this Mach-O file.
1652
std::vector<SectionRef> LiteralSections;
1653
for (const SectionRef &Section : O->sections()) {
1654
DataRefImpl Ref = Section.getRawDataRefImpl();
1655
uint32_t section_type;
1656
if (O->is64Bit()) {
1657
const MachO::section_64 Sec = O->getSection64(Ref);
1658
section_type = Sec.flags & MachO::SECTION_TYPE;
1659
} else {
1660
const MachO::section Sec = O->getSection(Ref);
1661
section_type = Sec.flags & MachO::SECTION_TYPE;
1662
}
1663
if (section_type == MachO::S_CSTRING_LITERALS ||
1664
section_type == MachO::S_4BYTE_LITERALS ||
1665
section_type == MachO::S_8BYTE_LITERALS ||
1666
section_type == MachO::S_16BYTE_LITERALS)
1667
LiteralSections.push_back(Section);
1668
}
1669
1670
// Set the size of the literal pointer.
1671
uint32_t lp_size = O->is64Bit() ? 8 : 4;
1672
1673
// Collect the external relocation symbols for the literal pointers.
1674
std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1675
for (const RelocationRef &Reloc : Section.relocations()) {
1676
DataRefImpl Rel;
1677
MachO::any_relocation_info RE;
1678
bool isExtern = false;
1679
Rel = Reloc.getRawDataRefImpl();
1680
RE = O->getRelocation(Rel);
1681
isExtern = O->getPlainRelocationExternal(RE);
1682
if (isExtern) {
1683
uint64_t RelocOffset = Reloc.getOffset();
1684
symbol_iterator RelocSym = Reloc.getSymbol();
1685
Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1686
}
1687
}
1688
array_pod_sort(Relocs.begin(), Relocs.end());
1689
1690
// Dump each literal pointer.
1691
for (uint32_t i = 0; i < sect_size; i += lp_size) {
1692
if (print_addresses) {
1693
if (O->is64Bit())
1694
outs() << format("%016" PRIx64, sect_addr + i) << " ";
1695
else
1696
outs() << format("%08" PRIx64, sect_addr + i) << " ";
1697
}
1698
uint64_t lp;
1699
if (O->is64Bit()) {
1700
memcpy(&lp, sect + i, sizeof(uint64_t));
1701
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1702
sys::swapByteOrder(lp);
1703
} else {
1704
uint32_t li;
1705
memcpy(&li, sect + i, sizeof(uint32_t));
1706
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1707
sys::swapByteOrder(li);
1708
lp = li;
1709
}
1710
1711
// First look for an external relocation entry for this literal pointer.
1712
auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1713
return P.first == i;
1714
});
1715
if (Reloc != Relocs.end()) {
1716
symbol_iterator RelocSym = Reloc->second;
1717
StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());
1718
outs() << "external relocation entry for symbol:" << SymName << "\n";
1719
continue;
1720
}
1721
1722
// For local references see what the section the literal pointer points to.
1723
auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {
1724
return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();
1725
});
1726
if (Sect == LiteralSections.end()) {
1727
outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
1728
continue;
1729
}
1730
1731
uint64_t SectAddress = Sect->getAddress();
1732
uint64_t SectSize = Sect->getSize();
1733
1734
StringRef SectName;
1735
Expected<StringRef> SectNameOrErr = Sect->getName();
1736
if (SectNameOrErr)
1737
SectName = *SectNameOrErr;
1738
else
1739
consumeError(SectNameOrErr.takeError());
1740
1741
DataRefImpl Ref = Sect->getRawDataRefImpl();
1742
StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
1743
outs() << SegmentName << ":" << SectName << ":";
1744
1745
uint32_t section_type;
1746
if (O->is64Bit()) {
1747
const MachO::section_64 Sec = O->getSection64(Ref);
1748
section_type = Sec.flags & MachO::SECTION_TYPE;
1749
} else {
1750
const MachO::section Sec = O->getSection(Ref);
1751
section_type = Sec.flags & MachO::SECTION_TYPE;
1752
}
1753
1754
StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());
1755
1756
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
1757
1758
switch (section_type) {
1759
case MachO::S_CSTRING_LITERALS:
1760
for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
1761
i++) {
1762
DumpCstringChar(Contents[i]);
1763
}
1764
outs() << "\n";
1765
break;
1766
case MachO::S_4BYTE_LITERALS:
1767
float f;
1768
memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
1769
uint32_t l;
1770
memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
1771
if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1772
sys::swapByteOrder(f);
1773
sys::swapByteOrder(l);
1774
}
1775
DumpLiteral4(l, f);
1776
break;
1777
case MachO::S_8BYTE_LITERALS: {
1778
double d;
1779
memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
1780
uint32_t l0, l1;
1781
memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1782
memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1783
sizeof(uint32_t));
1784
if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1785
sys::swapByteOrder(f);
1786
sys::swapByteOrder(l0);
1787
sys::swapByteOrder(l1);
1788
}
1789
DumpLiteral8(O, l0, l1, d);
1790
break;
1791
}
1792
case MachO::S_16BYTE_LITERALS: {
1793
uint32_t l0, l1, l2, l3;
1794
memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1795
memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1796
sizeof(uint32_t));
1797
memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
1798
sizeof(uint32_t));
1799
memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
1800
sizeof(uint32_t));
1801
if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1802
sys::swapByteOrder(l0);
1803
sys::swapByteOrder(l1);
1804
sys::swapByteOrder(l2);
1805
sys::swapByteOrder(l3);
1806
}
1807
DumpLiteral16(l0, l1, l2, l3);
1808
break;
1809
}
1810
}
1811
}
1812
}
1813
1814
static void DumpInitTermPointerSection(MachOObjectFile *O,
1815
const SectionRef &Section,
1816
const char *sect,
1817
uint32_t sect_size, uint64_t sect_addr,
1818
SymbolAddressMap *AddrMap,
1819
bool verbose) {
1820
uint32_t stride;
1821
stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
1822
1823
// Collect the external relocation symbols for the pointers.
1824
std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1825
for (const RelocationRef &Reloc : Section.relocations()) {
1826
DataRefImpl Rel;
1827
MachO::any_relocation_info RE;
1828
bool isExtern = false;
1829
Rel = Reloc.getRawDataRefImpl();
1830
RE = O->getRelocation(Rel);
1831
isExtern = O->getPlainRelocationExternal(RE);
1832
if (isExtern) {
1833
uint64_t RelocOffset = Reloc.getOffset();
1834
symbol_iterator RelocSym = Reloc.getSymbol();
1835
Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1836
}
1837
}
1838
array_pod_sort(Relocs.begin(), Relocs.end());
1839
1840
for (uint32_t i = 0; i < sect_size; i += stride) {
1841
const char *SymbolName = nullptr;
1842
uint64_t p;
1843
if (O->is64Bit()) {
1844
outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
1845
uint64_t pointer_value;
1846
memcpy(&pointer_value, sect + i, stride);
1847
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1848
sys::swapByteOrder(pointer_value);
1849
outs() << format("0x%016" PRIx64, pointer_value);
1850
p = pointer_value;
1851
} else {
1852
outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
1853
uint32_t pointer_value;
1854
memcpy(&pointer_value, sect + i, stride);
1855
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1856
sys::swapByteOrder(pointer_value);
1857
outs() << format("0x%08" PRIx32, pointer_value);
1858
p = pointer_value;
1859
}
1860
if (verbose) {
1861
// First look for an external relocation entry for this pointer.
1862
auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1863
return P.first == i;
1864
});
1865
if (Reloc != Relocs.end()) {
1866
symbol_iterator RelocSym = Reloc->second;
1867
outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());
1868
} else {
1869
SymbolName = GuessSymbolName(p, AddrMap);
1870
if (SymbolName)
1871
outs() << " " << SymbolName;
1872
}
1873
}
1874
outs() << "\n";
1875
}
1876
}
1877
1878
static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
1879
uint32_t size, uint64_t addr) {
1880
uint32_t cputype = O->getHeader().cputype;
1881
if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
1882
uint32_t j;
1883
for (uint32_t i = 0; i < size; i += j, addr += j) {
1884
if (O->is64Bit())
1885
outs() << format("%016" PRIx64, addr) << "\t";
1886
else
1887
outs() << format("%08" PRIx64, addr) << "\t";
1888
for (j = 0; j < 16 && i + j < size; j++) {
1889
uint8_t byte_word = *(sect + i + j);
1890
outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1891
}
1892
outs() << "\n";
1893
}
1894
} else {
1895
uint32_t j;
1896
for (uint32_t i = 0; i < size; i += j, addr += j) {
1897
if (O->is64Bit())
1898
outs() << format("%016" PRIx64, addr) << "\t";
1899
else
1900
outs() << format("%08" PRIx64, addr) << "\t";
1901
for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
1902
j += sizeof(int32_t)) {
1903
if (i + j + sizeof(int32_t) <= size) {
1904
uint32_t long_word;
1905
memcpy(&long_word, sect + i + j, sizeof(int32_t));
1906
if (O->isLittleEndian() != sys::IsLittleEndianHost)
1907
sys::swapByteOrder(long_word);
1908
outs() << format("%08" PRIx32, long_word) << " ";
1909
} else {
1910
for (uint32_t k = 0; i + j + k < size; k++) {
1911
uint8_t byte_word = *(sect + i + j + k);
1912
outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1913
}
1914
}
1915
}
1916
outs() << "\n";
1917
}
1918
}
1919
}
1920
1921
static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
1922
StringRef DisSegName, StringRef DisSectName);
1923
static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1924
uint32_t size, uint32_t addr);
1925
static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1926
bool verbose) {
1927
SymbolAddressMap AddrMap;
1928
if (verbose)
1929
CreateSymbolAddressMap(O, &AddrMap);
1930
1931
for (unsigned i = 0; i < FilterSections.size(); ++i) {
1932
StringRef DumpSection = FilterSections[i];
1933
std::pair<StringRef, StringRef> DumpSegSectName;
1934
DumpSegSectName = DumpSection.split(',');
1935
StringRef DumpSegName, DumpSectName;
1936
if (!DumpSegSectName.second.empty()) {
1937
DumpSegName = DumpSegSectName.first;
1938
DumpSectName = DumpSegSectName.second;
1939
} else {
1940
DumpSegName = "";
1941
DumpSectName = DumpSegSectName.first;
1942
}
1943
for (const SectionRef &Section : O->sections()) {
1944
StringRef SectName;
1945
Expected<StringRef> SecNameOrErr = Section.getName();
1946
if (SecNameOrErr)
1947
SectName = *SecNameOrErr;
1948
else
1949
consumeError(SecNameOrErr.takeError());
1950
1951
if (!DumpSection.empty())
1952
FoundSectionSet.insert(DumpSection);
1953
1954
DataRefImpl Ref = Section.getRawDataRefImpl();
1955
StringRef SegName = O->getSectionFinalSegmentName(Ref);
1956
if ((DumpSegName.empty() || SegName == DumpSegName) &&
1957
(SectName == DumpSectName)) {
1958
1959
uint32_t section_flags;
1960
if (O->is64Bit()) {
1961
const MachO::section_64 Sec = O->getSection64(Ref);
1962
section_flags = Sec.flags;
1963
1964
} else {
1965
const MachO::section Sec = O->getSection(Ref);
1966
section_flags = Sec.flags;
1967
}
1968
uint32_t section_type = section_flags & MachO::SECTION_TYPE;
1969
1970
StringRef BytesStr =
1971
unwrapOrError(Section.getContents(), O->getFileName());
1972
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1973
uint32_t sect_size = BytesStr.size();
1974
uint64_t sect_addr = Section.getAddress();
1975
1976
if (LeadingHeaders)
1977
outs() << "Contents of (" << SegName << "," << SectName
1978
<< ") section\n";
1979
1980
if (verbose) {
1981
if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1982
(section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1983
DisassembleMachO(Filename, O, SegName, SectName);
1984
continue;
1985
}
1986
if (SegName == "__TEXT" && SectName == "__info_plist") {
1987
outs() << sect;
1988
continue;
1989
}
1990
if (SegName == "__OBJC" && SectName == "__protocol") {
1991
DumpProtocolSection(O, sect, sect_size, sect_addr);
1992
continue;
1993
}
1994
switch (section_type) {
1995
case MachO::S_REGULAR:
1996
DumpRawSectionContents(O, sect, sect_size, sect_addr);
1997
break;
1998
case MachO::S_ZEROFILL:
1999
outs() << "zerofill section and has no contents in the file\n";
2000
break;
2001
case MachO::S_CSTRING_LITERALS:
2002
DumpCstringSection(O, sect, sect_size, sect_addr, LeadingAddr);
2003
break;
2004
case MachO::S_4BYTE_LITERALS:
2005
DumpLiteral4Section(O, sect, sect_size, sect_addr, LeadingAddr);
2006
break;
2007
case MachO::S_8BYTE_LITERALS:
2008
DumpLiteral8Section(O, sect, sect_size, sect_addr, LeadingAddr);
2009
break;
2010
case MachO::S_16BYTE_LITERALS:
2011
DumpLiteral16Section(O, sect, sect_size, sect_addr, LeadingAddr);
2012
break;
2013
case MachO::S_LITERAL_POINTERS:
2014
DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
2015
LeadingAddr);
2016
break;
2017
case MachO::S_MOD_INIT_FUNC_POINTERS:
2018
case MachO::S_MOD_TERM_FUNC_POINTERS:
2019
DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,
2020
&AddrMap, verbose);
2021
break;
2022
default:
2023
outs() << "Unknown section type ("
2024
<< format("0x%08" PRIx32, section_type) << ")\n";
2025
DumpRawSectionContents(O, sect, sect_size, sect_addr);
2026
break;
2027
}
2028
} else {
2029
if (section_type == MachO::S_ZEROFILL)
2030
outs() << "zerofill section and has no contents in the file\n";
2031
else
2032
DumpRawSectionContents(O, sect, sect_size, sect_addr);
2033
}
2034
}
2035
}
2036
}
2037
}
2038
2039
static void DumpInfoPlistSectionContents(StringRef Filename,
2040
MachOObjectFile *O) {
2041
for (const SectionRef &Section : O->sections()) {
2042
StringRef SectName;
2043
Expected<StringRef> SecNameOrErr = Section.getName();
2044
if (SecNameOrErr)
2045
SectName = *SecNameOrErr;
2046
else
2047
consumeError(SecNameOrErr.takeError());
2048
2049
DataRefImpl Ref = Section.getRawDataRefImpl();
2050
StringRef SegName = O->getSectionFinalSegmentName(Ref);
2051
if (SegName == "__TEXT" && SectName == "__info_plist") {
2052
if (LeadingHeaders)
2053
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
2054
StringRef BytesStr =
2055
unwrapOrError(Section.getContents(), O->getFileName());
2056
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
2057
outs() << format("%.*s", BytesStr.size(), sect) << "\n";
2058
return;
2059
}
2060
}
2061
}
2062
2063
// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
2064
// and if it is and there is a list of architecture flags is specified then
2065
// check to make sure this Mach-O file is one of those architectures or all
2066
// architectures were specified. If not then an error is generated and this
2067
// routine returns false. Else it returns true.
2068
static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
2069
auto *MachO = dyn_cast<MachOObjectFile>(O);
2070
2071
if (!MachO || ArchAll || ArchFlags.empty())
2072
return true;
2073
2074
MachO::mach_header H;
2075
MachO::mach_header_64 H_64;
2076
Triple T;
2077
const char *McpuDefault, *ArchFlag;
2078
if (MachO->is64Bit()) {
2079
H_64 = MachO->MachOObjectFile::getHeader64();
2080
T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
2081
&McpuDefault, &ArchFlag);
2082
} else {
2083
H = MachO->MachOObjectFile::getHeader();
2084
T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
2085
&McpuDefault, &ArchFlag);
2086
}
2087
const std::string ArchFlagName(ArchFlag);
2088
if (!llvm::is_contained(ArchFlags, ArchFlagName)) {
2089
WithColor::error(errs(), "llvm-objdump")
2090
<< Filename << ": no architecture specified.\n";
2091
return false;
2092
}
2093
return true;
2094
}
2095
2096
static void printObjcMetaData(MachOObjectFile *O, bool verbose);
2097
2098
// ProcessMachO() is passed a single opened Mach-O file, which may be an
2099
// archive member and or in a slice of a universal file. It prints the
2100
// the file name and header info and then processes it according to the
2101
// command line options.
2102
static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
2103
StringRef ArchiveMemberName = StringRef(),
2104
StringRef ArchitectureName = StringRef()) {
2105
std::unique_ptr<Dumper> D = createMachODumper(*MachOOF);
2106
2107
// If we are doing some processing here on the Mach-O file print the header
2108
// info. And don't print it otherwise like in the case of printing the
2109
// UniversalHeaders or ArchiveHeaders.
2110
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
2111
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
2112
DataInCode || FunctionStartsType != FunctionStartsMode::None ||
2113
LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
2114
Rpaths || ObjcMetaData || (!FilterSections.empty())) {
2115
if (LeadingHeaders) {
2116
outs() << Name;
2117
if (!ArchiveMemberName.empty())
2118
outs() << '(' << ArchiveMemberName << ')';
2119
if (!ArchitectureName.empty())
2120
outs() << " (architecture " << ArchitectureName << ")";
2121
outs() << ":\n";
2122
}
2123
}
2124
// To use the report_error() form with an ArchiveName and FileName set
2125
// these up based on what is passed for Name and ArchiveMemberName.
2126
StringRef ArchiveName;
2127
StringRef FileName;
2128
if (!ArchiveMemberName.empty()) {
2129
ArchiveName = Name;
2130
FileName = ArchiveMemberName;
2131
} else {
2132
ArchiveName = StringRef();
2133
FileName = Name;
2134
}
2135
2136
// If we need the symbol table to do the operation then check it here to
2137
// produce a good error message as to where the Mach-O file comes from in
2138
// the error message.
2139
if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)
2140
if (Error Err = MachOOF->checkSymbolTable())
2141
reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);
2142
2143
if (DisassembleAll) {
2144
for (const SectionRef &Section : MachOOF->sections()) {
2145
StringRef SectName;
2146
if (Expected<StringRef> NameOrErr = Section.getName())
2147
SectName = *NameOrErr;
2148
else
2149
consumeError(NameOrErr.takeError());
2150
2151
if (SectName == "__text") {
2152
DataRefImpl Ref = Section.getRawDataRefImpl();
2153
StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);
2154
DisassembleMachO(FileName, MachOOF, SegName, SectName);
2155
}
2156
}
2157
}
2158
else if (Disassemble) {
2159
if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
2160
MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
2161
DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
2162
else
2163
DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
2164
}
2165
if (IndirectSymbols)
2166
PrintIndirectSymbols(MachOOF, Verbose);
2167
if (DataInCode)
2168
PrintDataInCodeTable(MachOOF, Verbose);
2169
if (FunctionStartsType != FunctionStartsMode::None)
2170
PrintFunctionStarts(MachOOF);
2171
if (LinkOptHints)
2172
PrintLinkOptHints(MachOOF);
2173
if (Relocations)
2174
PrintRelocations(MachOOF, Verbose);
2175
if (SectionHeaders)
2176
printSectionHeaders(*MachOOF);
2177
if (SectionContents)
2178
printSectionContents(MachOOF);
2179
if (!FilterSections.empty())
2180
DumpSectionContents(FileName, MachOOF, Verbose);
2181
if (InfoPlist)
2182
DumpInfoPlistSectionContents(FileName, MachOOF);
2183
if (DyldInfo)
2184
PrintDyldInfo(MachOOF);
2185
if (ChainedFixups)
2186
PrintChainedFixups(MachOOF);
2187
if (DylibsUsed)
2188
PrintDylibs(MachOOF, false);
2189
if (DylibId)
2190
PrintDylibs(MachOOF, true);
2191
if (SymbolTable)
2192
D->printSymbolTable(ArchiveName, ArchitectureName);
2193
if (UnwindInfo)
2194
printMachOUnwindInfo(MachOOF);
2195
if (PrivateHeaders) {
2196
printMachOFileHeader(MachOOF);
2197
printMachOLoadCommands(MachOOF);
2198
}
2199
if (FirstPrivateHeader)
2200
printMachOFileHeader(MachOOF);
2201
if (ObjcMetaData)
2202
printObjcMetaData(MachOOF, Verbose);
2203
if (ExportsTrie)
2204
printExportsTrie(MachOOF);
2205
if (Rebase)
2206
printRebaseTable(MachOOF);
2207
if (Rpaths)
2208
printRpaths(MachOOF);
2209
if (Bind)
2210
printBindTable(MachOOF);
2211
if (LazyBind)
2212
printLazyBindTable(MachOOF);
2213
if (WeakBind)
2214
printWeakBindTable(MachOOF);
2215
2216
if (DwarfDumpType != DIDT_Null) {
2217
std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);
2218
// Dump the complete DWARF structure.
2219
DIDumpOptions DumpOpts;
2220
DumpOpts.DumpType = DwarfDumpType;
2221
DICtx->dump(outs(), DumpOpts);
2222
}
2223
}
2224
2225
// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
2226
static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
2227
outs() << " cputype (" << cputype << ")\n";
2228
outs() << " cpusubtype (" << cpusubtype << ")\n";
2229
}
2230
2231
// printCPUType() helps print_fat_headers by printing the cputype and
2232
// pusubtype (symbolically for the one's it knows about).
2233
static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
2234
switch (cputype) {
2235
case MachO::CPU_TYPE_I386:
2236
switch (cpusubtype) {
2237
case MachO::CPU_SUBTYPE_I386_ALL:
2238
outs() << " cputype CPU_TYPE_I386\n";
2239
outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
2240
break;
2241
default:
2242
printUnknownCPUType(cputype, cpusubtype);
2243
break;
2244
}
2245
break;
2246
case MachO::CPU_TYPE_X86_64:
2247
switch (cpusubtype) {
2248
case MachO::CPU_SUBTYPE_X86_64_ALL:
2249
outs() << " cputype CPU_TYPE_X86_64\n";
2250
outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
2251
break;
2252
case MachO::CPU_SUBTYPE_X86_64_H:
2253
outs() << " cputype CPU_TYPE_X86_64\n";
2254
outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
2255
break;
2256
default:
2257
printUnknownCPUType(cputype, cpusubtype);
2258
break;
2259
}
2260
break;
2261
case MachO::CPU_TYPE_ARM:
2262
switch (cpusubtype) {
2263
case MachO::CPU_SUBTYPE_ARM_ALL:
2264
outs() << " cputype CPU_TYPE_ARM\n";
2265
outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
2266
break;
2267
case MachO::CPU_SUBTYPE_ARM_V4T:
2268
outs() << " cputype CPU_TYPE_ARM\n";
2269
outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
2270
break;
2271
case MachO::CPU_SUBTYPE_ARM_V5TEJ:
2272
outs() << " cputype CPU_TYPE_ARM\n";
2273
outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
2274
break;
2275
case MachO::CPU_SUBTYPE_ARM_XSCALE:
2276
outs() << " cputype CPU_TYPE_ARM\n";
2277
outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
2278
break;
2279
case MachO::CPU_SUBTYPE_ARM_V6:
2280
outs() << " cputype CPU_TYPE_ARM\n";
2281
outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
2282
break;
2283
case MachO::CPU_SUBTYPE_ARM_V6M:
2284
outs() << " cputype CPU_TYPE_ARM\n";
2285
outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
2286
break;
2287
case MachO::CPU_SUBTYPE_ARM_V7:
2288
outs() << " cputype CPU_TYPE_ARM\n";
2289
outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
2290
break;
2291
case MachO::CPU_SUBTYPE_ARM_V7EM:
2292
outs() << " cputype CPU_TYPE_ARM\n";
2293
outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
2294
break;
2295
case MachO::CPU_SUBTYPE_ARM_V7K:
2296
outs() << " cputype CPU_TYPE_ARM\n";
2297
outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
2298
break;
2299
case MachO::CPU_SUBTYPE_ARM_V7M:
2300
outs() << " cputype CPU_TYPE_ARM\n";
2301
outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
2302
break;
2303
case MachO::CPU_SUBTYPE_ARM_V7S:
2304
outs() << " cputype CPU_TYPE_ARM\n";
2305
outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
2306
break;
2307
default:
2308
printUnknownCPUType(cputype, cpusubtype);
2309
break;
2310
}
2311
break;
2312
case MachO::CPU_TYPE_ARM64:
2313
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2314
case MachO::CPU_SUBTYPE_ARM64_ALL:
2315
outs() << " cputype CPU_TYPE_ARM64\n";
2316
outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
2317
break;
2318
case MachO::CPU_SUBTYPE_ARM64_V8:
2319
outs() << " cputype CPU_TYPE_ARM64\n";
2320
outs() << " cpusubtype CPU_SUBTYPE_ARM64_V8\n";
2321
break;
2322
case MachO::CPU_SUBTYPE_ARM64E:
2323
outs() << " cputype CPU_TYPE_ARM64\n";
2324
outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";
2325
break;
2326
default:
2327
printUnknownCPUType(cputype, cpusubtype);
2328
break;
2329
}
2330
break;
2331
case MachO::CPU_TYPE_ARM64_32:
2332
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2333
case MachO::CPU_SUBTYPE_ARM64_32_V8:
2334
outs() << " cputype CPU_TYPE_ARM64_32\n";
2335
outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";
2336
break;
2337
default:
2338
printUnknownCPUType(cputype, cpusubtype);
2339
break;
2340
}
2341
break;
2342
default:
2343
printUnknownCPUType(cputype, cpusubtype);
2344
break;
2345
}
2346
}
2347
2348
static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
2349
bool verbose) {
2350
outs() << "Fat headers\n";
2351
if (verbose) {
2352
if (UB->getMagic() == MachO::FAT_MAGIC)
2353
outs() << "fat_magic FAT_MAGIC\n";
2354
else // UB->getMagic() == MachO::FAT_MAGIC_64
2355
outs() << "fat_magic FAT_MAGIC_64\n";
2356
} else
2357
outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";
2358
2359
uint32_t nfat_arch = UB->getNumberOfObjects();
2360
StringRef Buf = UB->getData();
2361
uint64_t size = Buf.size();
2362
uint64_t big_size = sizeof(struct MachO::fat_header) +
2363
nfat_arch * sizeof(struct MachO::fat_arch);
2364
outs() << "nfat_arch " << UB->getNumberOfObjects();
2365
if (nfat_arch == 0)
2366
outs() << " (malformed, contains zero architecture types)\n";
2367
else if (big_size > size)
2368
outs() << " (malformed, architectures past end of file)\n";
2369
else
2370
outs() << "\n";
2371
2372
for (uint32_t i = 0; i < nfat_arch; ++i) {
2373
MachOUniversalBinary::ObjectForArch OFA(UB, i);
2374
uint32_t cputype = OFA.getCPUType();
2375
uint32_t cpusubtype = OFA.getCPUSubType();
2376
outs() << "architecture ";
2377
for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
2378
MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
2379
uint32_t other_cputype = other_OFA.getCPUType();
2380
uint32_t other_cpusubtype = other_OFA.getCPUSubType();
2381
if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
2382
(cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
2383
(other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
2384
outs() << "(illegal duplicate architecture) ";
2385
break;
2386
}
2387
}
2388
if (verbose) {
2389
outs() << OFA.getArchFlagName() << "\n";
2390
printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
2391
} else {
2392
outs() << i << "\n";
2393
outs() << " cputype " << cputype << "\n";
2394
outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
2395
<< "\n";
2396
}
2397
if (verbose &&
2398
(cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
2399
outs() << " capabilities CPU_SUBTYPE_LIB64\n";
2400
else
2401
outs() << " capabilities "
2402
<< format("0x%" PRIx32,
2403
(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
2404
outs() << " offset " << OFA.getOffset();
2405
if (OFA.getOffset() > size)
2406
outs() << " (past end of file)";
2407
if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)
2408
outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
2409
outs() << "\n";
2410
outs() << " size " << OFA.getSize();
2411
big_size = OFA.getOffset() + OFA.getSize();
2412
if (big_size > size)
2413
outs() << " (past end of file)";
2414
outs() << "\n";
2415
outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
2416
<< ")\n";
2417
}
2418
}
2419
2420
static void printArchiveChild(StringRef Filename, const Archive::Child &C,
2421
size_t ChildIndex, bool verbose,
2422
bool print_offset,
2423
StringRef ArchitectureName = StringRef()) {
2424
if (print_offset)
2425
outs() << C.getChildOffset() << "\t";
2426
sys::fs::perms Mode =
2427
unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex),
2428
Filename, ArchitectureName);
2429
if (verbose) {
2430
// FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
2431
// But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
2432
outs() << "-";
2433
outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
2434
outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
2435
outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
2436
outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
2437
outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
2438
outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
2439
outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
2440
outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
2441
outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
2442
} else {
2443
outs() << format("0%o ", Mode);
2444
}
2445
2446
outs() << format("%3d/%-3d %5" PRId64 " ",
2447
unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex),
2448
Filename, ArchitectureName),
2449
unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex),
2450
Filename, ArchitectureName),
2451
unwrapOrError(C.getRawSize(),
2452
getFileNameForError(C, ChildIndex), Filename,
2453
ArchitectureName));
2454
2455
StringRef RawLastModified = C.getRawLastModified();
2456
if (verbose) {
2457
unsigned Seconds;
2458
if (RawLastModified.getAsInteger(10, Seconds))
2459
outs() << "(date: \"" << RawLastModified
2460
<< "\" contains non-decimal chars) ";
2461
else {
2462
// Since cime(3) returns a 26 character string of the form:
2463
// "Sun Sep 16 01:03:52 1973\n\0"
2464
// just print 24 characters.
2465
time_t t = Seconds;
2466
outs() << format("%.24s ", ctime(&t));
2467
}
2468
} else {
2469
outs() << RawLastModified << " ";
2470
}
2471
2472
if (verbose) {
2473
Expected<StringRef> NameOrErr = C.getName();
2474
if (!NameOrErr) {
2475
consumeError(NameOrErr.takeError());
2476
outs() << unwrapOrError(C.getRawName(),
2477
getFileNameForError(C, ChildIndex), Filename,
2478
ArchitectureName)
2479
<< "\n";
2480
} else {
2481
StringRef Name = NameOrErr.get();
2482
outs() << Name << "\n";
2483
}
2484
} else {
2485
outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex),
2486
Filename, ArchitectureName)
2487
<< "\n";
2488
}
2489
}
2490
2491
static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
2492
bool print_offset,
2493
StringRef ArchitectureName = StringRef()) {
2494
Error Err = Error::success();
2495
size_t I = 0;
2496
for (const auto &C : A->children(Err, false))
2497
printArchiveChild(Filename, C, I++, verbose, print_offset,
2498
ArchitectureName);
2499
2500
if (Err)
2501
reportError(std::move(Err), Filename, "", ArchitectureName);
2502
}
2503
2504
static bool ValidateArchFlags() {
2505
// Check for -arch all and verifiy the -arch flags are valid.
2506
for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2507
if (ArchFlags[i] == "all") {
2508
ArchAll = true;
2509
} else {
2510
if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
2511
WithColor::error(errs(), "llvm-objdump")
2512
<< "unknown architecture named '" + ArchFlags[i] +
2513
"'for the -arch option\n";
2514
return false;
2515
}
2516
}
2517
}
2518
return true;
2519
}
2520
2521
// ParseInputMachO() parses the named Mach-O file in Filename and handles the
2522
// -arch flags selecting just those slices as specified by them and also parses
2523
// archive files. Then for each individual Mach-O file ProcessMachO() is
2524
// called to process the file based on the command line options.
2525
void objdump::parseInputMachO(StringRef Filename) {
2526
if (!ValidateArchFlags())
2527
return;
2528
2529
// Attempt to open the binary.
2530
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
2531
if (!BinaryOrErr) {
2532
if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
2533
reportError(std::move(E), Filename);
2534
else
2535
outs() << Filename << ": is not an object file\n";
2536
return;
2537
}
2538
Binary &Bin = *BinaryOrErr.get().getBinary();
2539
2540
if (Archive *A = dyn_cast<Archive>(&Bin)) {
2541
outs() << "Archive : " << Filename << "\n";
2542
if (ArchiveHeaders)
2543
printArchiveHeaders(Filename, A, Verbose, ArchiveMemberOffsets);
2544
2545
Error Err = Error::success();
2546
unsigned I = -1;
2547
for (auto &C : A->children(Err)) {
2548
++I;
2549
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2550
if (!ChildOrErr) {
2551
if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2552
reportError(std::move(E), getFileNameForError(C, I), Filename);
2553
continue;
2554
}
2555
if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2556
if (!checkMachOAndArchFlags(O, Filename))
2557
return;
2558
ProcessMachO(Filename, O, O->getFileName());
2559
}
2560
}
2561
if (Err)
2562
reportError(std::move(Err), Filename);
2563
return;
2564
}
2565
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
2566
parseInputMachO(UB);
2567
return;
2568
}
2569
if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
2570
if (!checkMachOAndArchFlags(O, Filename))
2571
return;
2572
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))
2573
ProcessMachO(Filename, MachOOF);
2574
else
2575
WithColor::error(errs(), "llvm-objdump")
2576
<< Filename << "': "
2577
<< "object is not a Mach-O file type.\n";
2578
return;
2579
}
2580
llvm_unreachable("Input object can't be invalid at this point");
2581
}
2582
2583
void objdump::parseInputMachO(MachOUniversalBinary *UB) {
2584
if (!ValidateArchFlags())
2585
return;
2586
2587
auto Filename = UB->getFileName();
2588
2589
if (UniversalHeaders)
2590
printMachOUniversalHeaders(UB, Verbose);
2591
2592
// If we have a list of architecture flags specified dump only those.
2593
if (!ArchAll && !ArchFlags.empty()) {
2594
// Look for a slice in the universal binary that matches each ArchFlag.
2595
bool ArchFound;
2596
for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2597
ArchFound = false;
2598
for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2599
E = UB->end_objects();
2600
I != E; ++I) {
2601
if (ArchFlags[i] == I->getArchFlagName()) {
2602
ArchFound = true;
2603
Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2604
I->getAsObjectFile();
2605
std::string ArchitectureName;
2606
if (ArchFlags.size() > 1)
2607
ArchitectureName = I->getArchFlagName();
2608
if (ObjOrErr) {
2609
ObjectFile &O = *ObjOrErr.get();
2610
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2611
ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2612
} else if (Error E = isNotObjectErrorInvalidFileType(
2613
ObjOrErr.takeError())) {
2614
reportError(std::move(E), "", Filename, ArchitectureName);
2615
continue;
2616
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
2617
I->getAsArchive()) {
2618
std::unique_ptr<Archive> &A = *AOrErr;
2619
outs() << "Archive : " << Filename;
2620
if (!ArchitectureName.empty())
2621
outs() << " (architecture " << ArchitectureName << ")";
2622
outs() << "\n";
2623
if (ArchiveHeaders)
2624
printArchiveHeaders(Filename, A.get(), Verbose,
2625
ArchiveMemberOffsets, ArchitectureName);
2626
Error Err = Error::success();
2627
unsigned I = -1;
2628
for (auto &C : A->children(Err)) {
2629
++I;
2630
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2631
if (!ChildOrErr) {
2632
if (Error E =
2633
isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2634
reportError(std::move(E), getFileNameForError(C, I), Filename,
2635
ArchitectureName);
2636
continue;
2637
}
2638
if (MachOObjectFile *O =
2639
dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2640
ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
2641
}
2642
if (Err)
2643
reportError(std::move(Err), Filename);
2644
} else {
2645
consumeError(AOrErr.takeError());
2646
reportError(Filename,
2647
"Mach-O universal file for architecture " +
2648
StringRef(I->getArchFlagName()) +
2649
" is not a Mach-O file or an archive file");
2650
}
2651
}
2652
}
2653
if (!ArchFound) {
2654
WithColor::error(errs(), "llvm-objdump")
2655
<< "file: " + Filename + " does not contain "
2656
<< "architecture: " + ArchFlags[i] + "\n";
2657
return;
2658
}
2659
}
2660
return;
2661
}
2662
// No architecture flags were specified so if this contains a slice that
2663
// matches the host architecture dump only that.
2664
if (!ArchAll) {
2665
for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2666
E = UB->end_objects();
2667
I != E; ++I) {
2668
if (MachOObjectFile::getHostArch().getArchName() ==
2669
I->getArchFlagName()) {
2670
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2671
std::string ArchiveName;
2672
ArchiveName.clear();
2673
if (ObjOrErr) {
2674
ObjectFile &O = *ObjOrErr.get();
2675
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2676
ProcessMachO(Filename, MachOOF);
2677
} else if (Error E =
2678
isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2679
reportError(std::move(E), Filename);
2680
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
2681
I->getAsArchive()) {
2682
std::unique_ptr<Archive> &A = *AOrErr;
2683
outs() << "Archive : " << Filename << "\n";
2684
if (ArchiveHeaders)
2685
printArchiveHeaders(Filename, A.get(), Verbose,
2686
ArchiveMemberOffsets);
2687
Error Err = Error::success();
2688
unsigned I = -1;
2689
for (auto &C : A->children(Err)) {
2690
++I;
2691
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2692
if (!ChildOrErr) {
2693
if (Error E =
2694
isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2695
reportError(std::move(E), getFileNameForError(C, I), Filename);
2696
continue;
2697
}
2698
if (MachOObjectFile *O =
2699
dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2700
ProcessMachO(Filename, O, O->getFileName());
2701
}
2702
if (Err)
2703
reportError(std::move(Err), Filename);
2704
} else {
2705
consumeError(AOrErr.takeError());
2706
reportError(Filename, "Mach-O universal file for architecture " +
2707
StringRef(I->getArchFlagName()) +
2708
" is not a Mach-O file or an archive file");
2709
}
2710
return;
2711
}
2712
}
2713
}
2714
// Either all architectures have been specified or none have been specified
2715
// and this does not contain the host architecture so dump all the slices.
2716
bool moreThanOneArch = UB->getNumberOfObjects() > 1;
2717
for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2718
E = UB->end_objects();
2719
I != E; ++I) {
2720
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2721
std::string ArchitectureName;
2722
if (moreThanOneArch)
2723
ArchitectureName = I->getArchFlagName();
2724
if (ObjOrErr) {
2725
ObjectFile &Obj = *ObjOrErr.get();
2726
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
2727
ProcessMachO(Filename, MachOOF, "", ArchitectureName);
2728
} else if (Error E =
2729
isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2730
reportError(std::move(E), Filename, "", ArchitectureName);
2731
} else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
2732
std::unique_ptr<Archive> &A = *AOrErr;
2733
outs() << "Archive : " << Filename;
2734
if (!ArchitectureName.empty())
2735
outs() << " (architecture " << ArchitectureName << ")";
2736
outs() << "\n";
2737
if (ArchiveHeaders)
2738
printArchiveHeaders(Filename, A.get(), Verbose, ArchiveMemberOffsets,
2739
ArchitectureName);
2740
Error Err = Error::success();
2741
unsigned I = -1;
2742
for (auto &C : A->children(Err)) {
2743
++I;
2744
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2745
if (!ChildOrErr) {
2746
if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2747
reportError(std::move(E), getFileNameForError(C, I), Filename,
2748
ArchitectureName);
2749
continue;
2750
}
2751
if (MachOObjectFile *O =
2752
dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2753
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
2754
ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
2755
ArchitectureName);
2756
}
2757
}
2758
if (Err)
2759
reportError(std::move(Err), Filename);
2760
} else {
2761
consumeError(AOrErr.takeError());
2762
reportError(Filename, "Mach-O universal file for architecture " +
2763
StringRef(I->getArchFlagName()) +
2764
" is not a Mach-O file or an archive file");
2765
}
2766
}
2767
}
2768
2769
namespace {
2770
// The block of info used by the Symbolizer call backs.
2771
struct DisassembleInfo {
2772
DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2773
std::vector<SectionRef> *Sections, bool verbose)
2774
: verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
2775
bool verbose;
2776
MachOObjectFile *O;
2777
SectionRef S;
2778
SymbolAddressMap *AddrMap;
2779
std::vector<SectionRef> *Sections;
2780
const char *class_name = nullptr;
2781
const char *selector_name = nullptr;
2782
std::unique_ptr<char[]> method = nullptr;
2783
char *demangled_name = nullptr;
2784
uint64_t adrp_addr = 0;
2785
uint32_t adrp_inst = 0;
2786
std::unique_ptr<SymbolAddressMap> bindtable;
2787
uint32_t depth = 0;
2788
};
2789
} // namespace
2790
2791
// SymbolizerGetOpInfo() is the operand information call back function.
2792
// This is called to get the symbolic information for operand(s) of an
2793
// instruction when it is being done. This routine does this from
2794
// the relocation information, symbol table, etc. That block of information
2795
// is a pointer to the struct DisassembleInfo that was passed when the
2796
// disassembler context was created and passed to back to here when
2797
// called back by the disassembler for instruction operands that could have
2798
// relocation information. The address of the instruction containing operand is
2799
// at the Pc parameter. The immediate value the operand has is passed in
2800
// op_info->Value and is at Offset past the start of the instruction and has a
2801
// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2802
// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2803
// names and addends of the symbolic expression to add for the operand. The
2804
// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2805
// information is returned then this function returns 1 else it returns 0.
2806
static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2807
uint64_t OpSize, uint64_t InstSize, int TagType,
2808
void *TagBuf) {
2809
struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2810
struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
2811
uint64_t value = op_info->Value;
2812
2813
// Make sure all fields returned are zero if we don't set them.
2814
memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
2815
op_info->Value = value;
2816
2817
// If the TagType is not the value 1 which it code knows about or if no
2818
// verbose symbolic information is wanted then just return 0, indicating no
2819
// information is being returned.
2820
if (TagType != 1 || !info->verbose)
2821
return 0;
2822
2823
unsigned int Arch = info->O->getArch();
2824
if (Arch == Triple::x86) {
2825
if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2826
return 0;
2827
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2828
// TODO:
2829
// Search the external relocation entries of a fully linked image
2830
// (if any) for an entry that matches this segment offset.
2831
// uint32_t seg_offset = (Pc + Offset);
2832
return 0;
2833
}
2834
// In MH_OBJECT filetypes search the section's relocation entries (if any)
2835
// for an entry for this section offset.
2836
uint32_t sect_addr = info->S.getAddress();
2837
uint32_t sect_offset = (Pc + Offset) - sect_addr;
2838
bool reloc_found = false;
2839
DataRefImpl Rel;
2840
MachO::any_relocation_info RE;
2841
bool isExtern = false;
2842
SymbolRef Symbol;
2843
bool r_scattered = false;
2844
uint32_t r_value, pair_r_value, r_type;
2845
for (const RelocationRef &Reloc : info->S.relocations()) {
2846
uint64_t RelocOffset = Reloc.getOffset();
2847
if (RelocOffset == sect_offset) {
2848
Rel = Reloc.getRawDataRefImpl();
2849
RE = info->O->getRelocation(Rel);
2850
r_type = info->O->getAnyRelocationType(RE);
2851
r_scattered = info->O->isRelocationScattered(RE);
2852
if (r_scattered) {
2853
r_value = info->O->getScatteredRelocationValue(RE);
2854
if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2855
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2856
DataRefImpl RelNext = Rel;
2857
info->O->moveRelocationNext(RelNext);
2858
MachO::any_relocation_info RENext;
2859
RENext = info->O->getRelocation(RelNext);
2860
if (info->O->isRelocationScattered(RENext))
2861
pair_r_value = info->O->getScatteredRelocationValue(RENext);
2862
else
2863
return 0;
2864
}
2865
} else {
2866
isExtern = info->O->getPlainRelocationExternal(RE);
2867
if (isExtern) {
2868
symbol_iterator RelocSym = Reloc.getSymbol();
2869
Symbol = *RelocSym;
2870
}
2871
}
2872
reloc_found = true;
2873
break;
2874
}
2875
}
2876
if (reloc_found && isExtern) {
2877
op_info->AddSymbol.Present = 1;
2878
op_info->AddSymbol.Name =
2879
unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2880
// For i386 extern relocation entries the value in the instruction is
2881
// the offset from the symbol, and value is already set in op_info->Value.
2882
return 1;
2883
}
2884
if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2885
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
2886
const char *add = GuessSymbolName(r_value, info->AddrMap);
2887
const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
2888
uint32_t offset = value - (r_value - pair_r_value);
2889
op_info->AddSymbol.Present = 1;
2890
if (add != nullptr)
2891
op_info->AddSymbol.Name = add;
2892
else
2893
op_info->AddSymbol.Value = r_value;
2894
op_info->SubtractSymbol.Present = 1;
2895
if (sub != nullptr)
2896
op_info->SubtractSymbol.Name = sub;
2897
else
2898
op_info->SubtractSymbol.Value = pair_r_value;
2899
op_info->Value = offset;
2900
return 1;
2901
}
2902
return 0;
2903
}
2904
if (Arch == Triple::x86_64) {
2905
if (OpSize != 1 && OpSize != 2 && OpSize != 4 && OpSize != 0)
2906
return 0;
2907
// For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2908
// relocation entries of a linked image (if any) for an entry that matches
2909
// this segment offset.
2910
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2911
uint64_t seg_offset = Pc + Offset;
2912
bool reloc_found = false;
2913
DataRefImpl Rel;
2914
MachO::any_relocation_info RE;
2915
bool isExtern = false;
2916
SymbolRef Symbol;
2917
for (const RelocationRef &Reloc : info->O->external_relocations()) {
2918
uint64_t RelocOffset = Reloc.getOffset();
2919
if (RelocOffset == seg_offset) {
2920
Rel = Reloc.getRawDataRefImpl();
2921
RE = info->O->getRelocation(Rel);
2922
// external relocation entries should always be external.
2923
isExtern = info->O->getPlainRelocationExternal(RE);
2924
if (isExtern) {
2925
symbol_iterator RelocSym = Reloc.getSymbol();
2926
Symbol = *RelocSym;
2927
}
2928
reloc_found = true;
2929
break;
2930
}
2931
}
2932
if (reloc_found && isExtern) {
2933
// The Value passed in will be adjusted by the Pc if the instruction
2934
// adds the Pc. But for x86_64 external relocation entries the Value
2935
// is the offset from the external symbol.
2936
if (info->O->getAnyRelocationPCRel(RE))
2937
op_info->Value -= Pc + InstSize;
2938
const char *name =
2939
unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2940
op_info->AddSymbol.Present = 1;
2941
op_info->AddSymbol.Name = name;
2942
return 1;
2943
}
2944
return 0;
2945
}
2946
// In MH_OBJECT filetypes search the section's relocation entries (if any)
2947
// for an entry for this section offset.
2948
uint64_t sect_addr = info->S.getAddress();
2949
uint64_t sect_offset = (Pc + Offset) - sect_addr;
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->S.relocations()) {
2956
uint64_t RelocOffset = Reloc.getOffset();
2957
if (RelocOffset == sect_offset) {
2958
Rel = Reloc.getRawDataRefImpl();
2959
RE = info->O->getRelocation(Rel);
2960
// NOTE: Scattered relocations don't exist on x86_64.
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
unsigned Type = info->O->getAnyRelocationType(RE);
2979
if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2980
DataRefImpl RelNext = Rel;
2981
info->O->moveRelocationNext(RelNext);
2982
MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2983
unsigned TypeNext = info->O->getAnyRelocationType(RENext);
2984
bool isExternNext = info->O->getPlainRelocationExternal(RENext);
2985
unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
2986
if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
2987
op_info->SubtractSymbol.Present = 1;
2988
op_info->SubtractSymbol.Name = name;
2989
symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
2990
Symbol = *RelocSymNext;
2991
name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
2992
}
2993
}
2994
// TODO: add the VariantKinds to op_info->VariantKind for relocation types
2995
// like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
2996
op_info->AddSymbol.Present = 1;
2997
op_info->AddSymbol.Name = name;
2998
return 1;
2999
}
3000
return 0;
3001
}
3002
if (Arch == Triple::arm) {
3003
if (Offset != 0 || (InstSize != 4 && InstSize != 2))
3004
return 0;
3005
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3006
// TODO:
3007
// Search the external relocation entries of a fully linked image
3008
// (if any) for an entry that matches this segment offset.
3009
// uint32_t seg_offset = (Pc + Offset);
3010
return 0;
3011
}
3012
// In MH_OBJECT filetypes search the section's relocation entries (if any)
3013
// for an entry for this section offset.
3014
uint32_t sect_addr = info->S.getAddress();
3015
uint32_t sect_offset = (Pc + Offset) - sect_addr;
3016
DataRefImpl Rel;
3017
MachO::any_relocation_info RE;
3018
bool isExtern = false;
3019
SymbolRef Symbol;
3020
bool r_scattered = false;
3021
uint32_t r_value, pair_r_value, r_type, r_length, other_half;
3022
auto Reloc =
3023
find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
3024
uint64_t RelocOffset = Reloc.getOffset();
3025
return RelocOffset == sect_offset;
3026
});
3027
3028
if (Reloc == info->S.relocations().end())
3029
return 0;
3030
3031
Rel = Reloc->getRawDataRefImpl();
3032
RE = info->O->getRelocation(Rel);
3033
r_length = info->O->getAnyRelocationLength(RE);
3034
r_scattered = info->O->isRelocationScattered(RE);
3035
if (r_scattered) {
3036
r_value = info->O->getScatteredRelocationValue(RE);
3037
r_type = info->O->getScatteredRelocationType(RE);
3038
} else {
3039
r_type = info->O->getAnyRelocationType(RE);
3040
isExtern = info->O->getPlainRelocationExternal(RE);
3041
if (isExtern) {
3042
symbol_iterator RelocSym = Reloc->getSymbol();
3043
Symbol = *RelocSym;
3044
}
3045
}
3046
if (r_type == MachO::ARM_RELOC_HALF ||
3047
r_type == MachO::ARM_RELOC_SECTDIFF ||
3048
r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
3049
r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3050
DataRefImpl RelNext = Rel;
3051
info->O->moveRelocationNext(RelNext);
3052
MachO::any_relocation_info RENext;
3053
RENext = info->O->getRelocation(RelNext);
3054
other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
3055
if (info->O->isRelocationScattered(RENext))
3056
pair_r_value = info->O->getScatteredRelocationValue(RENext);
3057
}
3058
3059
if (isExtern) {
3060
const char *name =
3061
unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
3062
op_info->AddSymbol.Present = 1;
3063
op_info->AddSymbol.Name = name;
3064
switch (r_type) {
3065
case MachO::ARM_RELOC_HALF:
3066
if ((r_length & 0x1) == 1) {
3067
op_info->Value = value << 16 | other_half;
3068
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3069
} else {
3070
op_info->Value = other_half << 16 | value;
3071
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3072
}
3073
break;
3074
default:
3075
break;
3076
}
3077
return 1;
3078
}
3079
// If we have a branch that is not an external relocation entry then
3080
// return 0 so the code in tryAddingSymbolicOperand() can use the
3081
// SymbolLookUp call back with the branch target address to look up the
3082
// symbol and possibility add an annotation for a symbol stub.
3083
if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
3084
r_type == MachO::ARM_THUMB_RELOC_BR22))
3085
return 0;
3086
3087
uint32_t offset = 0;
3088
if (r_type == MachO::ARM_RELOC_HALF ||
3089
r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3090
if ((r_length & 0x1) == 1)
3091
value = value << 16 | other_half;
3092
else
3093
value = other_half << 16 | value;
3094
}
3095
if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
3096
r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
3097
offset = value - r_value;
3098
value = r_value;
3099
}
3100
3101
if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
3102
if ((r_length & 0x1) == 1)
3103
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3104
else
3105
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3106
const char *add = GuessSymbolName(r_value, info->AddrMap);
3107
const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
3108
int32_t offset = value - (r_value - pair_r_value);
3109
op_info->AddSymbol.Present = 1;
3110
if (add != nullptr)
3111
op_info->AddSymbol.Name = add;
3112
else
3113
op_info->AddSymbol.Value = r_value;
3114
op_info->SubtractSymbol.Present = 1;
3115
if (sub != nullptr)
3116
op_info->SubtractSymbol.Name = sub;
3117
else
3118
op_info->SubtractSymbol.Value = pair_r_value;
3119
op_info->Value = offset;
3120
return 1;
3121
}
3122
3123
op_info->AddSymbol.Present = 1;
3124
op_info->Value = offset;
3125
if (r_type == MachO::ARM_RELOC_HALF) {
3126
if ((r_length & 0x1) == 1)
3127
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
3128
else
3129
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
3130
}
3131
const char *add = GuessSymbolName(value, info->AddrMap);
3132
if (add != nullptr) {
3133
op_info->AddSymbol.Name = add;
3134
return 1;
3135
}
3136
op_info->AddSymbol.Value = value;
3137
return 1;
3138
}
3139
if (Arch == Triple::aarch64) {
3140
if (Offset != 0 || InstSize != 4)
3141
return 0;
3142
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
3143
// TODO:
3144
// Search the external relocation entries of a fully linked image
3145
// (if any) for an entry that matches this segment offset.
3146
// uint64_t seg_offset = (Pc + Offset);
3147
return 0;
3148
}
3149
// In MH_OBJECT filetypes search the section's relocation entries (if any)
3150
// for an entry for this section offset.
3151
uint64_t sect_addr = info->S.getAddress();
3152
uint64_t sect_offset = (Pc + Offset) - sect_addr;
3153
auto Reloc =
3154
find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
3155
uint64_t RelocOffset = Reloc.getOffset();
3156
return RelocOffset == sect_offset;
3157
});
3158
3159
if (Reloc == info->S.relocations().end())
3160
return 0;
3161
3162
DataRefImpl Rel = Reloc->getRawDataRefImpl();
3163
MachO::any_relocation_info RE = info->O->getRelocation(Rel);
3164
uint32_t r_type = info->O->getAnyRelocationType(RE);
3165
if (r_type == MachO::ARM64_RELOC_ADDEND) {
3166
DataRefImpl RelNext = Rel;
3167
info->O->moveRelocationNext(RelNext);
3168
MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
3169
if (value == 0) {
3170
value = info->O->getPlainRelocationSymbolNum(RENext);
3171
op_info->Value = value;
3172
}
3173
}
3174
// NOTE: Scattered relocations don't exist on arm64.
3175
if (!info->O->getPlainRelocationExternal(RE))
3176
return 0;
3177
const char *name =
3178
unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())
3179
.data();
3180
op_info->AddSymbol.Present = 1;
3181
op_info->AddSymbol.Name = name;
3182
3183
switch (r_type) {
3184
case MachO::ARM64_RELOC_PAGE21:
3185
/* @page */
3186
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
3187
break;
3188
case MachO::ARM64_RELOC_PAGEOFF12:
3189
/* @pageoff */
3190
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
3191
break;
3192
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
3193
/* @gotpage */
3194
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
3195
break;
3196
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
3197
/* @gotpageoff */
3198
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
3199
break;
3200
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
3201
/* @tvlppage is not implemented in llvm-mc */
3202
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
3203
break;
3204
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
3205
/* @tvlppageoff is not implemented in llvm-mc */
3206
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
3207
break;
3208
default:
3209
case MachO::ARM64_RELOC_BRANCH26:
3210
op_info->VariantKind = LLVMDisassembler_VariantKind_None;
3211
break;
3212
}
3213
return 1;
3214
}
3215
return 0;
3216
}
3217
3218
// GuessCstringPointer is passed the address of what might be a pointer to a
3219
// literal string in a cstring section. If that address is in a cstring section
3220
// it returns a pointer to that string. Else it returns nullptr.
3221
static const char *GuessCstringPointer(uint64_t ReferenceValue,
3222
struct DisassembleInfo *info) {
3223
for (const auto &Load : info->O->load_commands()) {
3224
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3225
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3226
for (unsigned J = 0; J < Seg.nsects; ++J) {
3227
MachO::section_64 Sec = info->O->getSection64(Load, J);
3228
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3229
if (section_type == MachO::S_CSTRING_LITERALS &&
3230
ReferenceValue >= Sec.addr &&
3231
ReferenceValue < Sec.addr + Sec.size) {
3232
uint64_t sect_offset = ReferenceValue - Sec.addr;
3233
uint64_t object_offset = Sec.offset + sect_offset;
3234
StringRef MachOContents = info->O->getData();
3235
uint64_t object_size = MachOContents.size();
3236
const char *object_addr = (const char *)MachOContents.data();
3237
if (object_offset < object_size) {
3238
const char *name = object_addr + object_offset;
3239
return name;
3240
} else {
3241
return nullptr;
3242
}
3243
}
3244
}
3245
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
3246
MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
3247
for (unsigned J = 0; J < Seg.nsects; ++J) {
3248
MachO::section Sec = info->O->getSection(Load, J);
3249
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3250
if (section_type == MachO::S_CSTRING_LITERALS &&
3251
ReferenceValue >= Sec.addr &&
3252
ReferenceValue < Sec.addr + Sec.size) {
3253
uint64_t sect_offset = ReferenceValue - Sec.addr;
3254
uint64_t object_offset = Sec.offset + sect_offset;
3255
StringRef MachOContents = info->O->getData();
3256
uint64_t object_size = MachOContents.size();
3257
const char *object_addr = (const char *)MachOContents.data();
3258
if (object_offset < object_size) {
3259
const char *name = object_addr + object_offset;
3260
return name;
3261
} else {
3262
return nullptr;
3263
}
3264
}
3265
}
3266
}
3267
}
3268
return nullptr;
3269
}
3270
3271
// GuessIndirectSymbol returns the name of the indirect symbol for the
3272
// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
3273
// an address of a symbol stub or a lazy or non-lazy pointer to associate the
3274
// symbol name being referenced by the stub or pointer.
3275
static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
3276
struct DisassembleInfo *info) {
3277
MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
3278
MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
3279
for (const auto &Load : info->O->load_commands()) {
3280
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3281
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3282
for (unsigned J = 0; J < Seg.nsects; ++J) {
3283
MachO::section_64 Sec = info->O->getSection64(Load, J);
3284
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3285
if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3286
section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3287
section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3288
section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3289
section_type == MachO::S_SYMBOL_STUBS) &&
3290
ReferenceValue >= Sec.addr &&
3291
ReferenceValue < Sec.addr + Sec.size) {
3292
uint32_t stride;
3293
if (section_type == MachO::S_SYMBOL_STUBS)
3294
stride = Sec.reserved2;
3295
else
3296
stride = 8;
3297
if (stride == 0)
3298
return nullptr;
3299
uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3300
if (index < Dysymtab.nindirectsyms) {
3301
uint32_t indirect_symbol =
3302
info->O->getIndirectSymbolTableEntry(Dysymtab, index);
3303
if (indirect_symbol < Symtab.nsyms) {
3304
symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
3305
return unwrapOrError(Sym->getName(), info->O->getFileName())
3306
.data();
3307
}
3308
}
3309
}
3310
}
3311
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
3312
MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
3313
for (unsigned J = 0; J < Seg.nsects; ++J) {
3314
MachO::section Sec = info->O->getSection(Load, J);
3315
uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
3316
if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
3317
section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
3318
section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
3319
section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
3320
section_type == MachO::S_SYMBOL_STUBS) &&
3321
ReferenceValue >= Sec.addr &&
3322
ReferenceValue < Sec.addr + Sec.size) {
3323
uint32_t stride;
3324
if (section_type == MachO::S_SYMBOL_STUBS)
3325
stride = Sec.reserved2;
3326
else
3327
stride = 4;
3328
if (stride == 0)
3329
return nullptr;
3330
uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
3331
if (index < Dysymtab.nindirectsyms) {
3332
uint32_t indirect_symbol =
3333
info->O->getIndirectSymbolTableEntry(Dysymtab, index);
3334
if (indirect_symbol < Symtab.nsyms) {
3335
symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
3336
return unwrapOrError(Sym->getName(), info->O->getFileName())
3337
.data();
3338
}
3339
}
3340
}
3341
}
3342
}
3343
}
3344
return nullptr;
3345
}
3346
3347
// method_reference() is called passing it the ReferenceName that might be
3348
// a reference it to an Objective-C method call. If so then it allocates and
3349
// assembles a method call string with the values last seen and saved in
3350
// the DisassembleInfo's class_name and selector_name fields. This is saved
3351
// into the method field of the info and any previous string is free'ed.
3352
// Then the class_name field in the info is set to nullptr. The method call
3353
// string is set into ReferenceName and ReferenceType is set to
3354
// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
3355
// then both ReferenceType and ReferenceName are left unchanged.
3356
static void method_reference(struct DisassembleInfo *info,
3357
uint64_t *ReferenceType,
3358
const char **ReferenceName) {
3359
unsigned int Arch = info->O->getArch();
3360
if (*ReferenceName != nullptr) {
3361
if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
3362
if (info->selector_name != nullptr) {
3363
if (info->class_name != nullptr) {
3364
info->method = std::make_unique<char[]>(
3365
5 + strlen(info->class_name) + strlen(info->selector_name));
3366
char *method = info->method.get();
3367
if (method != nullptr) {
3368
strcpy(method, "+[");
3369
strcat(method, info->class_name);
3370
strcat(method, " ");
3371
strcat(method, info->selector_name);
3372
strcat(method, "]");
3373
*ReferenceName = method;
3374
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3375
}
3376
} else {
3377
info->method =
3378
std::make_unique<char[]>(9 + strlen(info->selector_name));
3379
char *method = info->method.get();
3380
if (method != nullptr) {
3381
if (Arch == Triple::x86_64)
3382
strcpy(method, "-[%rdi ");
3383
else if (Arch == Triple::aarch64)
3384
strcpy(method, "-[x0 ");
3385
else
3386
strcpy(method, "-[r? ");
3387
strcat(method, info->selector_name);
3388
strcat(method, "]");
3389
*ReferenceName = method;
3390
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3391
}
3392
}
3393
info->class_name = nullptr;
3394
}
3395
} else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
3396
if (info->selector_name != nullptr) {
3397
info->method =
3398
std::make_unique<char[]>(17 + strlen(info->selector_name));
3399
char *method = info->method.get();
3400
if (method != nullptr) {
3401
if (Arch == Triple::x86_64)
3402
strcpy(method, "-[[%rdi super] ");
3403
else if (Arch == Triple::aarch64)
3404
strcpy(method, "-[[x0 super] ");
3405
else
3406
strcpy(method, "-[[r? super] ");
3407
strcat(method, info->selector_name);
3408
strcat(method, "]");
3409
*ReferenceName = method;
3410
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3411
}
3412
info->class_name = nullptr;
3413
}
3414
}
3415
}
3416
}
3417
3418
// GuessPointerPointer() is passed the address of what might be a pointer to
3419
// a reference to an Objective-C class, selector, message ref or cfstring.
3420
// If so the value of the pointer is returned and one of the booleans are set
3421
// to true. If not zero is returned and all the booleans are set to false.
3422
static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
3423
struct DisassembleInfo *info,
3424
bool &classref, bool &selref, bool &msgref,
3425
bool &cfstring) {
3426
classref = false;
3427
selref = false;
3428
msgref = false;
3429
cfstring = false;
3430
for (const auto &Load : info->O->load_commands()) {
3431
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3432
MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3433
for (unsigned J = 0; J < Seg.nsects; ++J) {
3434
MachO::section_64 Sec = info->O->getSection64(Load, J);
3435
if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
3436
strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3437
strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
3438
strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
3439
strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
3440
ReferenceValue >= Sec.addr &&
3441
ReferenceValue < Sec.addr + Sec.size) {
3442
uint64_t sect_offset = ReferenceValue - Sec.addr;
3443
uint64_t object_offset = Sec.offset + sect_offset;
3444
StringRef MachOContents = info->O->getData();
3445
uint64_t object_size = MachOContents.size();
3446
const char *object_addr = (const char *)MachOContents.data();
3447
if (object_offset < object_size) {
3448
uint64_t pointer_value;
3449
memcpy(&pointer_value, object_addr + object_offset,
3450
sizeof(uint64_t));
3451
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3452
sys::swapByteOrder(pointer_value);
3453
if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
3454
selref = true;
3455
else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3456
strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
3457
classref = true;
3458
else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
3459
ReferenceValue + 8 < Sec.addr + Sec.size) {
3460
msgref = true;
3461
memcpy(&pointer_value, object_addr + object_offset + 8,
3462
sizeof(uint64_t));
3463
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3464
sys::swapByteOrder(pointer_value);
3465
} else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
3466
cfstring = true;
3467
return pointer_value;
3468
} else {
3469
return 0;
3470
}
3471
}
3472
}
3473
}
3474
// TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
3475
}
3476
return 0;
3477
}
3478
3479
// get_pointer_64 returns a pointer to the bytes in the object file at the
3480
// Address from a section in the Mach-O file. And indirectly returns the
3481
// offset into the section, number of bytes left in the section past the offset
3482
// and which section is was being referenced. If the Address is not in a
3483
// section nullptr is returned.
3484
static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
3485
uint32_t &left, SectionRef &S,
3486
DisassembleInfo *info,
3487
bool objc_only = false) {
3488
offset = 0;
3489
left = 0;
3490
S = SectionRef();
3491
for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
3492
uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
3493
uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
3494
if (SectSize == 0)
3495
continue;
3496
if (objc_only) {
3497
StringRef SectName;
3498
Expected<StringRef> SecNameOrErr =
3499
((*(info->Sections))[SectIdx]).getName();
3500
if (SecNameOrErr)
3501
SectName = *SecNameOrErr;
3502
else
3503
consumeError(SecNameOrErr.takeError());
3504
3505
DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
3506
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
3507
if (SegName != "__OBJC" && SectName != "__cstring")
3508
continue;
3509
}
3510
if (Address >= SectAddress && Address < SectAddress + SectSize) {
3511
S = (*(info->Sections))[SectIdx];
3512
offset = Address - SectAddress;
3513
left = SectSize - offset;
3514
StringRef SectContents = unwrapOrError(
3515
((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());
3516
return SectContents.data() + offset;
3517
}
3518
}
3519
return nullptr;
3520
}
3521
3522
static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
3523
uint32_t &left, SectionRef &S,
3524
DisassembleInfo *info,
3525
bool objc_only = false) {
3526
return get_pointer_64(Address, offset, left, S, info, objc_only);
3527
}
3528
3529
// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
3530
// the symbol indirectly through n_value. Based on the relocation information
3531
// for the specified section offset in the specified section reference.
3532
// If no relocation information is found and a non-zero ReferenceValue for the
3533
// symbol is passed, look up that address in the info's AddrMap.
3534
static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
3535
DisassembleInfo *info, uint64_t &n_value,
3536
uint64_t ReferenceValue = 0) {
3537
n_value = 0;
3538
if (!info->verbose)
3539
return nullptr;
3540
3541
// See if there is an external relocation entry at the sect_offset.
3542
bool reloc_found = false;
3543
DataRefImpl Rel;
3544
MachO::any_relocation_info RE;
3545
bool isExtern = false;
3546
SymbolRef Symbol;
3547
for (const RelocationRef &Reloc : S.relocations()) {
3548
uint64_t RelocOffset = Reloc.getOffset();
3549
if (RelocOffset == sect_offset) {
3550
Rel = Reloc.getRawDataRefImpl();
3551
RE = info->O->getRelocation(Rel);
3552
if (info->O->isRelocationScattered(RE))
3553
continue;
3554
isExtern = info->O->getPlainRelocationExternal(RE);
3555
if (isExtern) {
3556
symbol_iterator RelocSym = Reloc.getSymbol();
3557
Symbol = *RelocSym;
3558
}
3559
reloc_found = true;
3560
break;
3561
}
3562
}
3563
// If there is an external relocation entry for a symbol in this section
3564
// at this section_offset then use that symbol's value for the n_value
3565
// and return its name.
3566
const char *SymbolName = nullptr;
3567
if (reloc_found && isExtern) {
3568
n_value = cantFail(Symbol.getValue());
3569
StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());
3570
if (!Name.empty()) {
3571
SymbolName = Name.data();
3572
return SymbolName;
3573
}
3574
}
3575
3576
// TODO: For fully linked images, look through the external relocation
3577
// entries off the dynamic symtab command. For these the r_offset is from the
3578
// start of the first writeable segment in the Mach-O file. So the offset
3579
// to this section from that segment is passed to this routine by the caller,
3580
// as the database_offset. Which is the difference of the section's starting
3581
// address and the first writable segment.
3582
//
3583
// NOTE: need add passing the database_offset to this routine.
3584
3585
// We did not find an external relocation entry so look up the ReferenceValue
3586
// as an address of a symbol and if found return that symbol's name.
3587
SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
3588
3589
return SymbolName;
3590
}
3591
3592
static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3593
DisassembleInfo *info,
3594
uint32_t ReferenceValue) {
3595
uint64_t n_value64;
3596
return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
3597
}
3598
3599
namespace {
3600
3601
// These are structs in the Objective-C meta data and read to produce the
3602
// comments for disassembly. While these are part of the ABI they are no
3603
// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
3604
// .
3605
3606
// The cfstring object in a 64-bit Mach-O file.
3607
struct cfstring64_t {
3608
uint64_t isa; // class64_t * (64-bit pointer)
3609
uint64_t flags; // flag bits
3610
uint64_t characters; // char * (64-bit pointer)
3611
uint64_t length; // number of non-NULL characters in above
3612
};
3613
3614
// The class object in a 64-bit Mach-O file.
3615
struct class64_t {
3616
uint64_t isa; // class64_t * (64-bit pointer)
3617
uint64_t superclass; // class64_t * (64-bit pointer)
3618
uint64_t cache; // Cache (64-bit pointer)
3619
uint64_t vtable; // IMP * (64-bit pointer)
3620
uint64_t data; // class_ro64_t * (64-bit pointer)
3621
};
3622
3623
struct class32_t {
3624
uint32_t isa; /* class32_t * (32-bit pointer) */
3625
uint32_t superclass; /* class32_t * (32-bit pointer) */
3626
uint32_t cache; /* Cache (32-bit pointer) */
3627
uint32_t vtable; /* IMP * (32-bit pointer) */
3628
uint32_t data; /* class_ro32_t * (32-bit pointer) */
3629
};
3630
3631
struct class_ro64_t {
3632
uint32_t flags;
3633
uint32_t instanceStart;
3634
uint32_t instanceSize;
3635
uint32_t reserved;
3636
uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3637
uint64_t name; // const char * (64-bit pointer)
3638
uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3639
uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3640
uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3641
uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3642
uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3643
};
3644
3645
struct class_ro32_t {
3646
uint32_t flags;
3647
uint32_t instanceStart;
3648
uint32_t instanceSize;
3649
uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3650
uint32_t name; /* const char * (32-bit pointer) */
3651
uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3652
uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3653
uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3654
uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3655
uint32_t baseProperties; /* const struct objc_property_list *
3656
(32-bit pointer) */
3657
};
3658
3659
/* Values for class_ro{64,32}_t->flags */
3660
#define RO_META (1 << 0)
3661
#define RO_ROOT (1 << 1)
3662
#define RO_HAS_CXX_STRUCTORS (1 << 2)
3663
3664
/* Values for method_list{64,32}_t->entsize */
3665
#define ML_HAS_RELATIVE_PTRS (1 << 31)
3666
#define ML_ENTSIZE_MASK 0xFFFF
3667
3668
struct method_list64_t {
3669
uint32_t entsize;
3670
uint32_t count;
3671
/* struct method64_t first; These structures follow inline */
3672
};
3673
3674
struct method_list32_t {
3675
uint32_t entsize;
3676
uint32_t count;
3677
/* struct method32_t first; These structures follow inline */
3678
};
3679
3680
struct method64_t {
3681
uint64_t name; /* SEL (64-bit pointer) */
3682
uint64_t types; /* const char * (64-bit pointer) */
3683
uint64_t imp; /* IMP (64-bit pointer) */
3684
};
3685
3686
struct method32_t {
3687
uint32_t name; /* SEL (32-bit pointer) */
3688
uint32_t types; /* const char * (32-bit pointer) */
3689
uint32_t imp; /* IMP (32-bit pointer) */
3690
};
3691
3692
struct method_relative_t {
3693
int32_t name; /* SEL (32-bit relative) */
3694
int32_t types; /* const char * (32-bit relative) */
3695
int32_t imp; /* IMP (32-bit relative) */
3696
};
3697
3698
struct protocol_list64_t {
3699
uint64_t count; /* uintptr_t (a 64-bit value) */
3700
/* struct protocol64_t * list[0]; These pointers follow inline */
3701
};
3702
3703
struct protocol_list32_t {
3704
uint32_t count; /* uintptr_t (a 32-bit value) */
3705
/* struct protocol32_t * list[0]; These pointers follow inline */
3706
};
3707
3708
struct protocol64_t {
3709
uint64_t isa; /* id * (64-bit pointer) */
3710
uint64_t name; /* const char * (64-bit pointer) */
3711
uint64_t protocols; /* struct protocol_list64_t *
3712
(64-bit pointer) */
3713
uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3714
uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3715
uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3716
uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3717
uint64_t instanceProperties; /* struct objc_property_list *
3718
(64-bit pointer) */
3719
};
3720
3721
struct protocol32_t {
3722
uint32_t isa; /* id * (32-bit pointer) */
3723
uint32_t name; /* const char * (32-bit pointer) */
3724
uint32_t protocols; /* struct protocol_list_t *
3725
(32-bit pointer) */
3726
uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3727
uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3728
uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3729
uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3730
uint32_t instanceProperties; /* struct objc_property_list *
3731
(32-bit pointer) */
3732
};
3733
3734
struct ivar_list64_t {
3735
uint32_t entsize;
3736
uint32_t count;
3737
/* struct ivar64_t first; These structures follow inline */
3738
};
3739
3740
struct ivar_list32_t {
3741
uint32_t entsize;
3742
uint32_t count;
3743
/* struct ivar32_t first; These structures follow inline */
3744
};
3745
3746
struct ivar64_t {
3747
uint64_t offset; /* uintptr_t * (64-bit pointer) */
3748
uint64_t name; /* const char * (64-bit pointer) */
3749
uint64_t type; /* const char * (64-bit pointer) */
3750
uint32_t alignment;
3751
uint32_t size;
3752
};
3753
3754
struct ivar32_t {
3755
uint32_t offset; /* uintptr_t * (32-bit pointer) */
3756
uint32_t name; /* const char * (32-bit pointer) */
3757
uint32_t type; /* const char * (32-bit pointer) */
3758
uint32_t alignment;
3759
uint32_t size;
3760
};
3761
3762
struct objc_property_list64 {
3763
uint32_t entsize;
3764
uint32_t count;
3765
/* struct objc_property64 first; These structures follow inline */
3766
};
3767
3768
struct objc_property_list32 {
3769
uint32_t entsize;
3770
uint32_t count;
3771
/* struct objc_property32 first; These structures follow inline */
3772
};
3773
3774
struct objc_property64 {
3775
uint64_t name; /* const char * (64-bit pointer) */
3776
uint64_t attributes; /* const char * (64-bit pointer) */
3777
};
3778
3779
struct objc_property32 {
3780
uint32_t name; /* const char * (32-bit pointer) */
3781
uint32_t attributes; /* const char * (32-bit pointer) */
3782
};
3783
3784
struct category64_t {
3785
uint64_t name; /* const char * (64-bit pointer) */
3786
uint64_t cls; /* struct class_t * (64-bit pointer) */
3787
uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3788
uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3789
uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3790
uint64_t instanceProperties; /* struct objc_property_list *
3791
(64-bit pointer) */
3792
};
3793
3794
struct category32_t {
3795
uint32_t name; /* const char * (32-bit pointer) */
3796
uint32_t cls; /* struct class_t * (32-bit pointer) */
3797
uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3798
uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3799
uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3800
uint32_t instanceProperties; /* struct objc_property_list *
3801
(32-bit pointer) */
3802
};
3803
3804
struct objc_image_info64 {
3805
uint32_t version;
3806
uint32_t flags;
3807
};
3808
struct objc_image_info32 {
3809
uint32_t version;
3810
uint32_t flags;
3811
};
3812
struct imageInfo_t {
3813
uint32_t version;
3814
uint32_t flags;
3815
};
3816
/* masks for objc_image_info.flags */
3817
#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
3818
#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
3819
#define OBJC_IMAGE_IS_SIMULATED (1 << 5)
3820
#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)
3821
3822
struct message_ref64 {
3823
uint64_t imp; /* IMP (64-bit pointer) */
3824
uint64_t sel; /* SEL (64-bit pointer) */
3825
};
3826
3827
struct message_ref32 {
3828
uint32_t imp; /* IMP (32-bit pointer) */
3829
uint32_t sel; /* SEL (32-bit pointer) */
3830
};
3831
3832
// Objective-C 1 (32-bit only) meta data structs.
3833
3834
struct objc_module_t {
3835
uint32_t version;
3836
uint32_t size;
3837
uint32_t name; /* char * (32-bit pointer) */
3838
uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3839
};
3840
3841
struct objc_symtab_t {
3842
uint32_t sel_ref_cnt;
3843
uint32_t refs; /* SEL * (32-bit pointer) */
3844
uint16_t cls_def_cnt;
3845
uint16_t cat_def_cnt;
3846
// uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3847
};
3848
3849
struct objc_class_t {
3850
uint32_t isa; /* struct objc_class * (32-bit pointer) */
3851
uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3852
uint32_t name; /* const char * (32-bit pointer) */
3853
int32_t version;
3854
int32_t info;
3855
int32_t instance_size;
3856
uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3857
uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3858
uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3859
uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3860
};
3861
3862
#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
3863
// class is not a metaclass
3864
#define CLS_CLASS 0x1
3865
// class is a metaclass
3866
#define CLS_META 0x2
3867
3868
struct objc_category_t {
3869
uint32_t category_name; /* char * (32-bit pointer) */
3870
uint32_t class_name; /* char * (32-bit pointer) */
3871
uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3872
uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3873
uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3874
};
3875
3876
struct objc_ivar_t {
3877
uint32_t ivar_name; /* char * (32-bit pointer) */
3878
uint32_t ivar_type; /* char * (32-bit pointer) */
3879
int32_t ivar_offset;
3880
};
3881
3882
struct objc_ivar_list_t {
3883
int32_t ivar_count;
3884
// struct objc_ivar_t ivar_list[1]; /* variable length structure */
3885
};
3886
3887
struct objc_method_list_t {
3888
uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3889
int32_t method_count;
3890
// struct objc_method_t method_list[1]; /* variable length structure */
3891
};
3892
3893
struct objc_method_t {
3894
uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3895
uint32_t method_types; /* char * (32-bit pointer) */
3896
uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3897
(32-bit pointer) */
3898
};
3899
3900
struct objc_protocol_list_t {
3901
uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3902
int32_t count;
3903
// uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3904
// (32-bit pointer) */
3905
};
3906
3907
struct objc_protocol_t {
3908
uint32_t isa; /* struct objc_class * (32-bit pointer) */
3909
uint32_t protocol_name; /* char * (32-bit pointer) */
3910
uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3911
uint32_t instance_methods; /* struct objc_method_description_list *
3912
(32-bit pointer) */
3913
uint32_t class_methods; /* struct objc_method_description_list *
3914
(32-bit pointer) */
3915
};
3916
3917
struct objc_method_description_list_t {
3918
int32_t count;
3919
// struct objc_method_description_t list[1];
3920
};
3921
3922
struct objc_method_description_t {
3923
uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3924
uint32_t types; /* char * (32-bit pointer) */
3925
};
3926
3927
inline void swapStruct(struct cfstring64_t &cfs) {
3928
sys::swapByteOrder(cfs.isa);
3929
sys::swapByteOrder(cfs.flags);
3930
sys::swapByteOrder(cfs.characters);
3931
sys::swapByteOrder(cfs.length);
3932
}
3933
3934
inline void swapStruct(struct class64_t &c) {
3935
sys::swapByteOrder(c.isa);
3936
sys::swapByteOrder(c.superclass);
3937
sys::swapByteOrder(c.cache);
3938
sys::swapByteOrder(c.vtable);
3939
sys::swapByteOrder(c.data);
3940
}
3941
3942
inline void swapStruct(struct class32_t &c) {
3943
sys::swapByteOrder(c.isa);
3944
sys::swapByteOrder(c.superclass);
3945
sys::swapByteOrder(c.cache);
3946
sys::swapByteOrder(c.vtable);
3947
sys::swapByteOrder(c.data);
3948
}
3949
3950
inline void swapStruct(struct class_ro64_t &cro) {
3951
sys::swapByteOrder(cro.flags);
3952
sys::swapByteOrder(cro.instanceStart);
3953
sys::swapByteOrder(cro.instanceSize);
3954
sys::swapByteOrder(cro.reserved);
3955
sys::swapByteOrder(cro.ivarLayout);
3956
sys::swapByteOrder(cro.name);
3957
sys::swapByteOrder(cro.baseMethods);
3958
sys::swapByteOrder(cro.baseProtocols);
3959
sys::swapByteOrder(cro.ivars);
3960
sys::swapByteOrder(cro.weakIvarLayout);
3961
sys::swapByteOrder(cro.baseProperties);
3962
}
3963
3964
inline void swapStruct(struct class_ro32_t &cro) {
3965
sys::swapByteOrder(cro.flags);
3966
sys::swapByteOrder(cro.instanceStart);
3967
sys::swapByteOrder(cro.instanceSize);
3968
sys::swapByteOrder(cro.ivarLayout);
3969
sys::swapByteOrder(cro.name);
3970
sys::swapByteOrder(cro.baseMethods);
3971
sys::swapByteOrder(cro.baseProtocols);
3972
sys::swapByteOrder(cro.ivars);
3973
sys::swapByteOrder(cro.weakIvarLayout);
3974
sys::swapByteOrder(cro.baseProperties);
3975
}
3976
3977
inline void swapStruct(struct method_list64_t &ml) {
3978
sys::swapByteOrder(ml.entsize);
3979
sys::swapByteOrder(ml.count);
3980
}
3981
3982
inline void swapStruct(struct method_list32_t &ml) {
3983
sys::swapByteOrder(ml.entsize);
3984
sys::swapByteOrder(ml.count);
3985
}
3986
3987
inline void swapStruct(struct method64_t &m) {
3988
sys::swapByteOrder(m.name);
3989
sys::swapByteOrder(m.types);
3990
sys::swapByteOrder(m.imp);
3991
}
3992
3993
inline void swapStruct(struct method32_t &m) {
3994
sys::swapByteOrder(m.name);
3995
sys::swapByteOrder(m.types);
3996
sys::swapByteOrder(m.imp);
3997
}
3998
3999
inline void swapStruct(struct method_relative_t &m) {
4000
sys::swapByteOrder(m.name);
4001
sys::swapByteOrder(m.types);
4002
sys::swapByteOrder(m.imp);
4003
}
4004
4005
inline void swapStruct(struct protocol_list64_t &pl) {
4006
sys::swapByteOrder(pl.count);
4007
}
4008
4009
inline void swapStruct(struct protocol_list32_t &pl) {
4010
sys::swapByteOrder(pl.count);
4011
}
4012
4013
inline void swapStruct(struct protocol64_t &p) {
4014
sys::swapByteOrder(p.isa);
4015
sys::swapByteOrder(p.name);
4016
sys::swapByteOrder(p.protocols);
4017
sys::swapByteOrder(p.instanceMethods);
4018
sys::swapByteOrder(p.classMethods);
4019
sys::swapByteOrder(p.optionalInstanceMethods);
4020
sys::swapByteOrder(p.optionalClassMethods);
4021
sys::swapByteOrder(p.instanceProperties);
4022
}
4023
4024
inline void swapStruct(struct protocol32_t &p) {
4025
sys::swapByteOrder(p.isa);
4026
sys::swapByteOrder(p.name);
4027
sys::swapByteOrder(p.protocols);
4028
sys::swapByteOrder(p.instanceMethods);
4029
sys::swapByteOrder(p.classMethods);
4030
sys::swapByteOrder(p.optionalInstanceMethods);
4031
sys::swapByteOrder(p.optionalClassMethods);
4032
sys::swapByteOrder(p.instanceProperties);
4033
}
4034
4035
inline void swapStruct(struct ivar_list64_t &il) {
4036
sys::swapByteOrder(il.entsize);
4037
sys::swapByteOrder(il.count);
4038
}
4039
4040
inline void swapStruct(struct ivar_list32_t &il) {
4041
sys::swapByteOrder(il.entsize);
4042
sys::swapByteOrder(il.count);
4043
}
4044
4045
inline void swapStruct(struct ivar64_t &i) {
4046
sys::swapByteOrder(i.offset);
4047
sys::swapByteOrder(i.name);
4048
sys::swapByteOrder(i.type);
4049
sys::swapByteOrder(i.alignment);
4050
sys::swapByteOrder(i.size);
4051
}
4052
4053
inline void swapStruct(struct ivar32_t &i) {
4054
sys::swapByteOrder(i.offset);
4055
sys::swapByteOrder(i.name);
4056
sys::swapByteOrder(i.type);
4057
sys::swapByteOrder(i.alignment);
4058
sys::swapByteOrder(i.size);
4059
}
4060
4061
inline void swapStruct(struct objc_property_list64 &pl) {
4062
sys::swapByteOrder(pl.entsize);
4063
sys::swapByteOrder(pl.count);
4064
}
4065
4066
inline void swapStruct(struct objc_property_list32 &pl) {
4067
sys::swapByteOrder(pl.entsize);
4068
sys::swapByteOrder(pl.count);
4069
}
4070
4071
inline void swapStruct(struct objc_property64 &op) {
4072
sys::swapByteOrder(op.name);
4073
sys::swapByteOrder(op.attributes);
4074
}
4075
4076
inline void swapStruct(struct objc_property32 &op) {
4077
sys::swapByteOrder(op.name);
4078
sys::swapByteOrder(op.attributes);
4079
}
4080
4081
inline void swapStruct(struct category64_t &c) {
4082
sys::swapByteOrder(c.name);
4083
sys::swapByteOrder(c.cls);
4084
sys::swapByteOrder(c.instanceMethods);
4085
sys::swapByteOrder(c.classMethods);
4086
sys::swapByteOrder(c.protocols);
4087
sys::swapByteOrder(c.instanceProperties);
4088
}
4089
4090
inline void swapStruct(struct category32_t &c) {
4091
sys::swapByteOrder(c.name);
4092
sys::swapByteOrder(c.cls);
4093
sys::swapByteOrder(c.instanceMethods);
4094
sys::swapByteOrder(c.classMethods);
4095
sys::swapByteOrder(c.protocols);
4096
sys::swapByteOrder(c.instanceProperties);
4097
}
4098
4099
inline void swapStruct(struct objc_image_info64 &o) {
4100
sys::swapByteOrder(o.version);
4101
sys::swapByteOrder(o.flags);
4102
}
4103
4104
inline void swapStruct(struct objc_image_info32 &o) {
4105
sys::swapByteOrder(o.version);
4106
sys::swapByteOrder(o.flags);
4107
}
4108
4109
inline void swapStruct(struct imageInfo_t &o) {
4110
sys::swapByteOrder(o.version);
4111
sys::swapByteOrder(o.flags);
4112
}
4113
4114
inline void swapStruct(struct message_ref64 &mr) {
4115
sys::swapByteOrder(mr.imp);
4116
sys::swapByteOrder(mr.sel);
4117
}
4118
4119
inline void swapStruct(struct message_ref32 &mr) {
4120
sys::swapByteOrder(mr.imp);
4121
sys::swapByteOrder(mr.sel);
4122
}
4123
4124
inline void swapStruct(struct objc_module_t &module) {
4125
sys::swapByteOrder(module.version);
4126
sys::swapByteOrder(module.size);
4127
sys::swapByteOrder(module.name);
4128
sys::swapByteOrder(module.symtab);
4129
}
4130
4131
inline void swapStruct(struct objc_symtab_t &symtab) {
4132
sys::swapByteOrder(symtab.sel_ref_cnt);
4133
sys::swapByteOrder(symtab.refs);
4134
sys::swapByteOrder(symtab.cls_def_cnt);
4135
sys::swapByteOrder(symtab.cat_def_cnt);
4136
}
4137
4138
inline void swapStruct(struct objc_class_t &objc_class) {
4139
sys::swapByteOrder(objc_class.isa);
4140
sys::swapByteOrder(objc_class.super_class);
4141
sys::swapByteOrder(objc_class.name);
4142
sys::swapByteOrder(objc_class.version);
4143
sys::swapByteOrder(objc_class.info);
4144
sys::swapByteOrder(objc_class.instance_size);
4145
sys::swapByteOrder(objc_class.ivars);
4146
sys::swapByteOrder(objc_class.methodLists);
4147
sys::swapByteOrder(objc_class.cache);
4148
sys::swapByteOrder(objc_class.protocols);
4149
}
4150
4151
inline void swapStruct(struct objc_category_t &objc_category) {
4152
sys::swapByteOrder(objc_category.category_name);
4153
sys::swapByteOrder(objc_category.class_name);
4154
sys::swapByteOrder(objc_category.instance_methods);
4155
sys::swapByteOrder(objc_category.class_methods);
4156
sys::swapByteOrder(objc_category.protocols);
4157
}
4158
4159
inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
4160
sys::swapByteOrder(objc_ivar_list.ivar_count);
4161
}
4162
4163
inline void swapStruct(struct objc_ivar_t &objc_ivar) {
4164
sys::swapByteOrder(objc_ivar.ivar_name);
4165
sys::swapByteOrder(objc_ivar.ivar_type);
4166
sys::swapByteOrder(objc_ivar.ivar_offset);
4167
}
4168
4169
inline void swapStruct(struct objc_method_list_t &method_list) {
4170
sys::swapByteOrder(method_list.obsolete);
4171
sys::swapByteOrder(method_list.method_count);
4172
}
4173
4174
inline void swapStruct(struct objc_method_t &method) {
4175
sys::swapByteOrder(method.method_name);
4176
sys::swapByteOrder(method.method_types);
4177
sys::swapByteOrder(method.method_imp);
4178
}
4179
4180
inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
4181
sys::swapByteOrder(protocol_list.next);
4182
sys::swapByteOrder(protocol_list.count);
4183
}
4184
4185
inline void swapStruct(struct objc_protocol_t &protocol) {
4186
sys::swapByteOrder(protocol.isa);
4187
sys::swapByteOrder(protocol.protocol_name);
4188
sys::swapByteOrder(protocol.protocol_list);
4189
sys::swapByteOrder(protocol.instance_methods);
4190
sys::swapByteOrder(protocol.class_methods);
4191
}
4192
4193
inline void swapStruct(struct objc_method_description_list_t &mdl) {
4194
sys::swapByteOrder(mdl.count);
4195
}
4196
4197
inline void swapStruct(struct objc_method_description_t &md) {
4198
sys::swapByteOrder(md.name);
4199
sys::swapByteOrder(md.types);
4200
}
4201
4202
} // namespace
4203
4204
static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
4205
struct DisassembleInfo *info);
4206
4207
// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
4208
// to an Objective-C class and returns the class name. It is also passed the
4209
// address of the pointer, so when the pointer is zero as it can be in an .o
4210
// file, that is used to look for an external relocation entry with a symbol
4211
// name.
4212
static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
4213
uint64_t ReferenceValue,
4214
struct DisassembleInfo *info) {
4215
const char *r;
4216
uint32_t offset, left;
4217
SectionRef S;
4218
4219
// The pointer_value can be 0 in an object file and have a relocation
4220
// entry for the class symbol at the ReferenceValue (the address of the
4221
// pointer).
4222
if (pointer_value == 0) {
4223
r = get_pointer_64(ReferenceValue, offset, left, S, info);
4224
if (r == nullptr || left < sizeof(uint64_t))
4225
return nullptr;
4226
uint64_t n_value;
4227
const char *symbol_name = get_symbol_64(offset, S, info, n_value);
4228
if (symbol_name == nullptr)
4229
return nullptr;
4230
const char *class_name = strrchr(symbol_name, '$');
4231
if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
4232
return class_name + 2;
4233
else
4234
return nullptr;
4235
}
4236
4237
// The case were the pointer_value is non-zero and points to a class defined
4238
// in this Mach-O file.
4239
r = get_pointer_64(pointer_value, offset, left, S, info);
4240
if (r == nullptr || left < sizeof(struct class64_t))
4241
return nullptr;
4242
struct class64_t c;
4243
memcpy(&c, r, sizeof(struct class64_t));
4244
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4245
swapStruct(c);
4246
if (c.data == 0)
4247
return nullptr;
4248
r = get_pointer_64(c.data, offset, left, S, info);
4249
if (r == nullptr || left < sizeof(struct class_ro64_t))
4250
return nullptr;
4251
struct class_ro64_t cro;
4252
memcpy(&cro, r, sizeof(struct class_ro64_t));
4253
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4254
swapStruct(cro);
4255
if (cro.name == 0)
4256
return nullptr;
4257
const char *name = get_pointer_64(cro.name, offset, left, S, info);
4258
return name;
4259
}
4260
4261
// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
4262
// pointer to a cfstring and returns its name or nullptr.
4263
static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
4264
struct DisassembleInfo *info) {
4265
const char *r, *name;
4266
uint32_t offset, left;
4267
SectionRef S;
4268
struct cfstring64_t cfs;
4269
uint64_t cfs_characters;
4270
4271
r = get_pointer_64(ReferenceValue, offset, left, S, info);
4272
if (r == nullptr || left < sizeof(struct cfstring64_t))
4273
return nullptr;
4274
memcpy(&cfs, r, sizeof(struct cfstring64_t));
4275
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4276
swapStruct(cfs);
4277
if (cfs.characters == 0) {
4278
uint64_t n_value;
4279
const char *symbol_name = get_symbol_64(
4280
offset + offsetof(struct cfstring64_t, characters), S, info, n_value);
4281
if (symbol_name == nullptr)
4282
return nullptr;
4283
cfs_characters = n_value;
4284
} else
4285
cfs_characters = cfs.characters;
4286
name = get_pointer_64(cfs_characters, offset, left, S, info);
4287
4288
return name;
4289
}
4290
4291
// get_objc2_64bit_selref() is used for disassembly and is passed a the address
4292
// of a pointer to an Objective-C selector reference when the pointer value is
4293
// zero as in a .o file and is likely to have a external relocation entry with
4294
// who's symbol's n_value is the real pointer to the selector name. If that is
4295
// the case the real pointer to the selector name is returned else 0 is
4296
// returned
4297
static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
4298
struct DisassembleInfo *info) {
4299
uint32_t offset, left;
4300
SectionRef S;
4301
4302
const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
4303
if (r == nullptr || left < sizeof(uint64_t))
4304
return 0;
4305
uint64_t n_value;
4306
const char *symbol_name = get_symbol_64(offset, S, info, n_value);
4307
if (symbol_name == nullptr)
4308
return 0;
4309
return n_value;
4310
}
4311
4312
static const SectionRef get_section(MachOObjectFile *O, const char *segname,
4313
const char *sectname) {
4314
for (const SectionRef &Section : O->sections()) {
4315
StringRef SectName;
4316
Expected<StringRef> SecNameOrErr = Section.getName();
4317
if (SecNameOrErr)
4318
SectName = *SecNameOrErr;
4319
else
4320
consumeError(SecNameOrErr.takeError());
4321
4322
DataRefImpl Ref = Section.getRawDataRefImpl();
4323
StringRef SegName = O->getSectionFinalSegmentName(Ref);
4324
if (SegName == segname && SectName == sectname)
4325
return Section;
4326
}
4327
return SectionRef();
4328
}
4329
4330
static void
4331
walk_pointer_list_64(const char *listname, const SectionRef S,
4332
MachOObjectFile *O, struct DisassembleInfo *info,
4333
void (*func)(uint64_t, struct DisassembleInfo *info)) {
4334
if (S == SectionRef())
4335
return;
4336
4337
StringRef SectName;
4338
Expected<StringRef> SecNameOrErr = S.getName();
4339
if (SecNameOrErr)
4340
SectName = *SecNameOrErr;
4341
else
4342
consumeError(SecNameOrErr.takeError());
4343
4344
DataRefImpl Ref = S.getRawDataRefImpl();
4345
StringRef SegName = O->getSectionFinalSegmentName(Ref);
4346
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4347
4348
StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
4349
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
4350
4351
for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
4352
uint32_t left = S.getSize() - i;
4353
uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
4354
uint64_t p = 0;
4355
memcpy(&p, Contents + i, size);
4356
if (i + sizeof(uint64_t) > S.getSize())
4357
outs() << listname << " list pointer extends past end of (" << SegName
4358
<< "," << SectName << ") section\n";
4359
outs() << format("%016" PRIx64, S.getAddress() + i) << " ";
4360
4361
if (O->isLittleEndian() != sys::IsLittleEndianHost)
4362
sys::swapByteOrder(p);
4363
4364
uint64_t n_value = 0;
4365
const char *name = get_symbol_64(i, S, info, n_value, p);
4366
if (name == nullptr)
4367
name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
4368
4369
if (n_value != 0) {
4370
outs() << format("0x%" PRIx64, n_value);
4371
if (p != 0)
4372
outs() << " + " << format("0x%" PRIx64, p);
4373
} else
4374
outs() << format("0x%" PRIx64, p);
4375
if (name != nullptr)
4376
outs() << " " << name;
4377
outs() << "\n";
4378
4379
p += n_value;
4380
if (func)
4381
func(p, info);
4382
}
4383
}
4384
4385
static void
4386
walk_pointer_list_32(const char *listname, const SectionRef S,
4387
MachOObjectFile *O, struct DisassembleInfo *info,
4388
void (*func)(uint32_t, struct DisassembleInfo *info)) {
4389
if (S == SectionRef())
4390
return;
4391
4392
StringRef SectName = unwrapOrError(S.getName(), O->getFileName());
4393
DataRefImpl Ref = S.getRawDataRefImpl();
4394
StringRef SegName = O->getSectionFinalSegmentName(Ref);
4395
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4396
4397
StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
4398
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
4399
4400
for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
4401
uint32_t left = S.getSize() - i;
4402
uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
4403
uint32_t p = 0;
4404
memcpy(&p, Contents + i, size);
4405
if (i + sizeof(uint32_t) > S.getSize())
4406
outs() << listname << " list pointer extends past end of (" << SegName
4407
<< "," << SectName << ") section\n";
4408
uint32_t Address = S.getAddress() + i;
4409
outs() << format("%08" PRIx32, Address) << " ";
4410
4411
if (O->isLittleEndian() != sys::IsLittleEndianHost)
4412
sys::swapByteOrder(p);
4413
outs() << format("0x%" PRIx32, p);
4414
4415
const char *name = get_symbol_32(i, S, info, p);
4416
if (name != nullptr)
4417
outs() << " " << name;
4418
outs() << "\n";
4419
4420
if (func)
4421
func(p, info);
4422
}
4423
}
4424
4425
static void print_layout_map(const char *layout_map, uint32_t left) {
4426
if (layout_map == nullptr)
4427
return;
4428
outs() << " layout map: ";
4429
do {
4430
outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";
4431
left--;
4432
layout_map++;
4433
} while (*layout_map != '\0' && left != 0);
4434
outs() << "\n";
4435
}
4436
4437
static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
4438
uint32_t offset, left;
4439
SectionRef S;
4440
const char *layout_map;
4441
4442
if (p == 0)
4443
return;
4444
layout_map = get_pointer_64(p, offset, left, S, info);
4445
print_layout_map(layout_map, left);
4446
}
4447
4448
static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
4449
uint32_t offset, left;
4450
SectionRef S;
4451
const char *layout_map;
4452
4453
if (p == 0)
4454
return;
4455
layout_map = get_pointer_32(p, offset, left, S, info);
4456
print_layout_map(layout_map, left);
4457
}
4458
4459
static void print_relative_method_list(uint32_t structSizeAndFlags,
4460
uint32_t structCount, uint64_t p,
4461
struct DisassembleInfo *info,
4462
const char *indent,
4463
uint32_t pointerBits) {
4464
struct method_relative_t m;
4465
const char *r, *name;
4466
uint32_t offset, xoffset, left, i;
4467
SectionRef S, xS;
4468
4469
assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&
4470
"expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");
4471
4472
outs() << indent << "\t\t entsize "
4473
<< (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";
4474
outs() << indent << "\t\t count " << structCount << "\n";
4475
4476
for (i = 0; i < structCount; i++) {
4477
r = get_pointer_64(p, offset, left, S, info);
4478
memset(&m, '\0', sizeof(struct method_relative_t));
4479
if (left < sizeof(struct method_relative_t)) {
4480
memcpy(&m, r, left);
4481
outs() << indent << " (method_t extends past the end of the section)\n";
4482
} else
4483
memcpy(&m, r, sizeof(struct method_relative_t));
4484
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4485
swapStruct(m);
4486
4487
outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4488
uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);
4489
uint64_t absNameRefVA = relNameRefVA + m.name;
4490
outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
4491
4492
// since this is a relative list, absNameRefVA is the address of the
4493
// __objc_selrefs entry, so a pointer, not the actual name
4494
const char *nameRefPtr =
4495
get_pointer_64(absNameRefVA, xoffset, left, xS, info);
4496
if (nameRefPtr) {
4497
uint32_t pointerSize = pointerBits / CHAR_BIT;
4498
if (left < pointerSize)
4499
outs() << indent << " (nameRefPtr extends past the end of the section)";
4500
else {
4501
if (pointerSize == 64) {
4502
uint64_t nameOff_64 = *reinterpret_cast<const uint64_t *>(nameRefPtr);
4503
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4504
sys::swapByteOrder(nameOff_64);
4505
name = get_pointer_64(nameOff_64, xoffset, left, xS, info);
4506
} else {
4507
uint32_t nameOff_32 = *reinterpret_cast<const uint32_t *>(nameRefPtr);
4508
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4509
sys::swapByteOrder(nameOff_32);
4510
name = get_pointer_32(nameOff_32, xoffset, left, xS, info);
4511
}
4512
if (name != nullptr)
4513
outs() << format(" %.*s", left, name);
4514
}
4515
}
4516
outs() << "\n";
4517
4518
outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4519
uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);
4520
uint64_t absTypesVA = relTypesVA + m.types;
4521
outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
4522
name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
4523
if (name != nullptr)
4524
outs() << format(" %.*s", left, name);
4525
outs() << "\n";
4526
4527
outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4528
uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);
4529
uint64_t absImpVA = relImpVA + m.imp;
4530
outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
4531
name = GuessSymbolName(absImpVA, info->AddrMap);
4532
if (name != nullptr)
4533
outs() << " " << name;
4534
outs() << "\n";
4535
4536
p += sizeof(struct method_relative_t);
4537
offset += sizeof(struct method_relative_t);
4538
}
4539
}
4540
4541
static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
4542
const char *indent) {
4543
struct method_list64_t ml;
4544
struct method64_t m;
4545
const char *r;
4546
uint32_t offset, xoffset, left, i;
4547
SectionRef S, xS;
4548
const char *name, *sym_name;
4549
uint64_t n_value;
4550
4551
r = get_pointer_64(p, offset, left, S, info);
4552
if (r == nullptr)
4553
return;
4554
memset(&ml, '\0', sizeof(struct method_list64_t));
4555
if (left < sizeof(struct method_list64_t)) {
4556
memcpy(&ml, r, left);
4557
outs() << " (method_list_t entends past the end of the section)\n";
4558
} else
4559
memcpy(&ml, r, sizeof(struct method_list64_t));
4560
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4561
swapStruct(ml);
4562
p += sizeof(struct method_list64_t);
4563
4564
if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4565
print_relative_method_list(ml.entsize, ml.count, p, info, indent,
4566
/*pointerBits=*/64);
4567
return;
4568
}
4569
4570
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4571
outs() << indent << "\t\t count " << ml.count << "\n";
4572
4573
offset += sizeof(struct method_list64_t);
4574
for (i = 0; i < ml.count; i++) {
4575
r = get_pointer_64(p, offset, left, S, info);
4576
if (r == nullptr)
4577
return;
4578
memset(&m, '\0', sizeof(struct method64_t));
4579
if (left < sizeof(struct method64_t)) {
4580
memcpy(&m, r, left);
4581
outs() << indent << " (method_t extends past the end of the section)\n";
4582
} else
4583
memcpy(&m, r, sizeof(struct method64_t));
4584
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4585
swapStruct(m);
4586
4587
outs() << indent << "\t\t name ";
4588
sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,
4589
info, n_value, m.name);
4590
if (n_value != 0) {
4591
if (info->verbose && sym_name != nullptr)
4592
outs() << sym_name;
4593
else
4594
outs() << format("0x%" PRIx64, n_value);
4595
if (m.name != 0)
4596
outs() << " + " << format("0x%" PRIx64, m.name);
4597
} else
4598
outs() << format("0x%" PRIx64, m.name);
4599
name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
4600
if (name != nullptr)
4601
outs() << format(" %.*s", left, name);
4602
outs() << "\n";
4603
4604
outs() << indent << "\t\t types ";
4605
sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,
4606
info, n_value, m.types);
4607
if (n_value != 0) {
4608
if (info->verbose && sym_name != nullptr)
4609
outs() << sym_name;
4610
else
4611
outs() << format("0x%" PRIx64, n_value);
4612
if (m.types != 0)
4613
outs() << " + " << format("0x%" PRIx64, m.types);
4614
} else
4615
outs() << format("0x%" PRIx64, m.types);
4616
name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
4617
if (name != nullptr)
4618
outs() << format(" %.*s", left, name);
4619
outs() << "\n";
4620
4621
outs() << indent << "\t\t imp ";
4622
name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,
4623
n_value, m.imp);
4624
if (info->verbose && name == nullptr) {
4625
if (n_value != 0) {
4626
outs() << format("0x%" PRIx64, n_value) << " ";
4627
if (m.imp != 0)
4628
outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";
4629
} else
4630
outs() << format("0x%" PRIx64, m.imp) << " ";
4631
}
4632
if (name != nullptr)
4633
outs() << name;
4634
outs() << "\n";
4635
4636
p += sizeof(struct method64_t);
4637
offset += sizeof(struct method64_t);
4638
}
4639
}
4640
4641
static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
4642
const char *indent) {
4643
struct method_list32_t ml;
4644
struct method32_t m;
4645
const char *r, *name;
4646
uint32_t offset, xoffset, left, i;
4647
SectionRef S, xS;
4648
4649
r = get_pointer_32(p, offset, left, S, info);
4650
if (r == nullptr)
4651
return;
4652
memset(&ml, '\0', sizeof(struct method_list32_t));
4653
if (left < sizeof(struct method_list32_t)) {
4654
memcpy(&ml, r, left);
4655
outs() << " (method_list_t entends past the end of the section)\n";
4656
} else
4657
memcpy(&ml, r, sizeof(struct method_list32_t));
4658
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4659
swapStruct(ml);
4660
p += sizeof(struct method_list32_t);
4661
4662
if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
4663
print_relative_method_list(ml.entsize, ml.count, p, info, indent,
4664
/*pointerBits=*/32);
4665
return;
4666
}
4667
4668
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4669
outs() << indent << "\t\t count " << ml.count << "\n";
4670
4671
offset += sizeof(struct method_list32_t);
4672
for (i = 0; i < ml.count; i++) {
4673
r = get_pointer_32(p, offset, left, S, info);
4674
if (r == nullptr)
4675
return;
4676
memset(&m, '\0', sizeof(struct method32_t));
4677
if (left < sizeof(struct method32_t)) {
4678
memcpy(&ml, r, left);
4679
outs() << indent << " (method_t entends past the end of the section)\n";
4680
} else
4681
memcpy(&m, r, sizeof(struct method32_t));
4682
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4683
swapStruct(m);
4684
4685
outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4686
name = get_pointer_32(m.name, xoffset, left, xS, info);
4687
if (name != nullptr)
4688
outs() << format(" %.*s", left, name);
4689
outs() << "\n";
4690
4691
outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4692
name = get_pointer_32(m.types, xoffset, left, xS, info);
4693
if (name != nullptr)
4694
outs() << format(" %.*s", left, name);
4695
outs() << "\n";
4696
4697
outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4698
name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,
4699
m.imp);
4700
if (name != nullptr)
4701
outs() << " " << name;
4702
outs() << "\n";
4703
4704
p += sizeof(struct method32_t);
4705
offset += sizeof(struct method32_t);
4706
}
4707
}
4708
4709
static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4710
uint32_t offset, left, xleft;
4711
SectionRef S;
4712
struct objc_method_list_t method_list;
4713
struct objc_method_t method;
4714
const char *r, *methods, *name, *SymbolName;
4715
int32_t i;
4716
4717
r = get_pointer_32(p, offset, left, S, info, true);
4718
if (r == nullptr)
4719
return true;
4720
4721
outs() << "\n";
4722
if (left > sizeof(struct objc_method_list_t)) {
4723
memcpy(&method_list, r, sizeof(struct objc_method_list_t));
4724
} else {
4725
outs() << "\t\t objc_method_list extends past end of the section\n";
4726
memset(&method_list, '\0', sizeof(struct objc_method_list_t));
4727
memcpy(&method_list, r, left);
4728
}
4729
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4730
swapStruct(method_list);
4731
4732
outs() << "\t\t obsolete "
4733
<< format("0x%08" PRIx32, method_list.obsolete) << "\n";
4734
outs() << "\t\t method_count " << method_list.method_count << "\n";
4735
4736
methods = r + sizeof(struct objc_method_list_t);
4737
for (i = 0; i < method_list.method_count; i++) {
4738
if ((i + 1) * sizeof(struct objc_method_t) > left) {
4739
outs() << "\t\t remaining method's extend past the of the section\n";
4740
break;
4741
}
4742
memcpy(&method, methods + i * sizeof(struct objc_method_t),
4743
sizeof(struct objc_method_t));
4744
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4745
swapStruct(method);
4746
4747
outs() << "\t\t method_name "
4748
<< format("0x%08" PRIx32, method.method_name);
4749
if (info->verbose) {
4750
name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
4751
if (name != nullptr)
4752
outs() << format(" %.*s", xleft, name);
4753
else
4754
outs() << " (not in an __OBJC section)";
4755
}
4756
outs() << "\n";
4757
4758
outs() << "\t\t method_types "
4759
<< format("0x%08" PRIx32, method.method_types);
4760
if (info->verbose) {
4761
name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
4762
if (name != nullptr)
4763
outs() << format(" %.*s", xleft, name);
4764
else
4765
outs() << " (not in an __OBJC section)";
4766
}
4767
outs() << "\n";
4768
4769
outs() << "\t\t method_imp "
4770
<< format("0x%08" PRIx32, method.method_imp) << " ";
4771
if (info->verbose) {
4772
SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
4773
if (SymbolName != nullptr)
4774
outs() << SymbolName;
4775
}
4776
outs() << "\n";
4777
}
4778
return false;
4779
}
4780
4781
static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4782
struct protocol_list64_t pl;
4783
uint64_t q, n_value;
4784
struct protocol64_t pc;
4785
const char *r;
4786
uint32_t offset, xoffset, left, i;
4787
SectionRef S, xS;
4788
const char *name, *sym_name;
4789
4790
r = get_pointer_64(p, offset, left, S, info);
4791
if (r == nullptr)
4792
return;
4793
memset(&pl, '\0', sizeof(struct protocol_list64_t));
4794
if (left < sizeof(struct protocol_list64_t)) {
4795
memcpy(&pl, r, left);
4796
outs() << " (protocol_list_t entends past the end of the section)\n";
4797
} else
4798
memcpy(&pl, r, sizeof(struct protocol_list64_t));
4799
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4800
swapStruct(pl);
4801
outs() << " count " << pl.count << "\n";
4802
4803
p += sizeof(struct protocol_list64_t);
4804
offset += sizeof(struct protocol_list64_t);
4805
for (i = 0; i < pl.count; i++) {
4806
r = get_pointer_64(p, offset, left, S, info);
4807
if (r == nullptr)
4808
return;
4809
q = 0;
4810
if (left < sizeof(uint64_t)) {
4811
memcpy(&q, r, left);
4812
outs() << " (protocol_t * entends past the end of the section)\n";
4813
} else
4814
memcpy(&q, r, sizeof(uint64_t));
4815
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4816
sys::swapByteOrder(q);
4817
4818
outs() << "\t\t list[" << i << "] ";
4819
sym_name = get_symbol_64(offset, S, info, n_value, q);
4820
if (n_value != 0) {
4821
if (info->verbose && sym_name != nullptr)
4822
outs() << sym_name;
4823
else
4824
outs() << format("0x%" PRIx64, n_value);
4825
if (q != 0)
4826
outs() << " + " << format("0x%" PRIx64, q);
4827
} else
4828
outs() << format("0x%" PRIx64, q);
4829
outs() << " (struct protocol_t *)\n";
4830
4831
r = get_pointer_64(q + n_value, offset, left, S, info);
4832
if (r == nullptr)
4833
return;
4834
memset(&pc, '\0', sizeof(struct protocol64_t));
4835
if (left < sizeof(struct protocol64_t)) {
4836
memcpy(&pc, r, left);
4837
outs() << " (protocol_t entends past the end of the section)\n";
4838
} else
4839
memcpy(&pc, r, sizeof(struct protocol64_t));
4840
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4841
swapStruct(pc);
4842
4843
outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";
4844
4845
outs() << "\t\t\t name ";
4846
sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,
4847
info, n_value, pc.name);
4848
if (n_value != 0) {
4849
if (info->verbose && sym_name != nullptr)
4850
outs() << sym_name;
4851
else
4852
outs() << format("0x%" PRIx64, n_value);
4853
if (pc.name != 0)
4854
outs() << " + " << format("0x%" PRIx64, pc.name);
4855
} else
4856
outs() << format("0x%" PRIx64, pc.name);
4857
name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
4858
if (name != nullptr)
4859
outs() << format(" %.*s", left, name);
4860
outs() << "\n";
4861
4862
outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";
4863
4864
outs() << "\t\t instanceMethods ";
4865
sym_name =
4866
get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),
4867
S, info, n_value, pc.instanceMethods);
4868
if (n_value != 0) {
4869
if (info->verbose && sym_name != nullptr)
4870
outs() << sym_name;
4871
else
4872
outs() << format("0x%" PRIx64, n_value);
4873
if (pc.instanceMethods != 0)
4874
outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);
4875
} else
4876
outs() << format("0x%" PRIx64, pc.instanceMethods);
4877
outs() << " (struct method_list_t *)\n";
4878
if (pc.instanceMethods + n_value != 0)
4879
print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
4880
4881
outs() << "\t\t classMethods ";
4882
sym_name =
4883
get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,
4884
info, n_value, pc.classMethods);
4885
if (n_value != 0) {
4886
if (info->verbose && sym_name != nullptr)
4887
outs() << sym_name;
4888
else
4889
outs() << format("0x%" PRIx64, n_value);
4890
if (pc.classMethods != 0)
4891
outs() << " + " << format("0x%" PRIx64, pc.classMethods);
4892
} else
4893
outs() << format("0x%" PRIx64, pc.classMethods);
4894
outs() << " (struct method_list_t *)\n";
4895
if (pc.classMethods + n_value != 0)
4896
print_method_list64_t(pc.classMethods + n_value, info, "\t");
4897
4898
outs() << "\t optionalInstanceMethods "
4899
<< format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";
4900
outs() << "\t optionalClassMethods "
4901
<< format("0x%" PRIx64, pc.optionalClassMethods) << "\n";
4902
outs() << "\t instanceProperties "
4903
<< format("0x%" PRIx64, pc.instanceProperties) << "\n";
4904
4905
p += sizeof(uint64_t);
4906
offset += sizeof(uint64_t);
4907
}
4908
}
4909
4910
static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4911
struct protocol_list32_t pl;
4912
uint32_t q;
4913
struct protocol32_t pc;
4914
const char *r;
4915
uint32_t offset, xoffset, left, i;
4916
SectionRef S, xS;
4917
const char *name;
4918
4919
r = get_pointer_32(p, offset, left, S, info);
4920
if (r == nullptr)
4921
return;
4922
memset(&pl, '\0', sizeof(struct protocol_list32_t));
4923
if (left < sizeof(struct protocol_list32_t)) {
4924
memcpy(&pl, r, left);
4925
outs() << " (protocol_list_t entends past the end of the section)\n";
4926
} else
4927
memcpy(&pl, r, sizeof(struct protocol_list32_t));
4928
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4929
swapStruct(pl);
4930
outs() << " count " << pl.count << "\n";
4931
4932
p += sizeof(struct protocol_list32_t);
4933
offset += sizeof(struct protocol_list32_t);
4934
for (i = 0; i < pl.count; i++) {
4935
r = get_pointer_32(p, offset, left, S, info);
4936
if (r == nullptr)
4937
return;
4938
q = 0;
4939
if (left < sizeof(uint32_t)) {
4940
memcpy(&q, r, left);
4941
outs() << " (protocol_t * entends past the end of the section)\n";
4942
} else
4943
memcpy(&q, r, sizeof(uint32_t));
4944
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4945
sys::swapByteOrder(q);
4946
outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)
4947
<< " (struct protocol_t *)\n";
4948
r = get_pointer_32(q, offset, left, S, info);
4949
if (r == nullptr)
4950
return;
4951
memset(&pc, '\0', sizeof(struct protocol32_t));
4952
if (left < sizeof(struct protocol32_t)) {
4953
memcpy(&pc, r, left);
4954
outs() << " (protocol_t entends past the end of the section)\n";
4955
} else
4956
memcpy(&pc, r, sizeof(struct protocol32_t));
4957
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4958
swapStruct(pc);
4959
outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";
4960
outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);
4961
name = get_pointer_32(pc.name, xoffset, left, xS, info);
4962
if (name != nullptr)
4963
outs() << format(" %.*s", left, name);
4964
outs() << "\n";
4965
outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";
4966
outs() << "\t\t instanceMethods "
4967
<< format("0x%" PRIx32, pc.instanceMethods)
4968
<< " (struct method_list_t *)\n";
4969
if (pc.instanceMethods != 0)
4970
print_method_list32_t(pc.instanceMethods, info, "\t");
4971
outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)
4972
<< " (struct method_list_t *)\n";
4973
if (pc.classMethods != 0)
4974
print_method_list32_t(pc.classMethods, info, "\t");
4975
outs() << "\t optionalInstanceMethods "
4976
<< format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";
4977
outs() << "\t optionalClassMethods "
4978
<< format("0x%" PRIx32, pc.optionalClassMethods) << "\n";
4979
outs() << "\t instanceProperties "
4980
<< format("0x%" PRIx32, pc.instanceProperties) << "\n";
4981
p += sizeof(uint32_t);
4982
offset += sizeof(uint32_t);
4983
}
4984
}
4985
4986
static void print_indent(uint32_t indent) {
4987
for (uint32_t i = 0; i < indent;) {
4988
if (indent - i >= 8) {
4989
outs() << "\t";
4990
i += 8;
4991
} else {
4992
for (uint32_t j = i; j < indent; j++)
4993
outs() << " ";
4994
return;
4995
}
4996
}
4997
}
4998
4999
static bool print_method_description_list(uint32_t p, uint32_t indent,
5000
struct DisassembleInfo *info) {
5001
uint32_t offset, left, xleft;
5002
SectionRef S;
5003
struct objc_method_description_list_t mdl;
5004
struct objc_method_description_t md;
5005
const char *r, *list, *name;
5006
int32_t i;
5007
5008
r = get_pointer_32(p, offset, left, S, info, true);
5009
if (r == nullptr)
5010
return true;
5011
5012
outs() << "\n";
5013
if (left > sizeof(struct objc_method_description_list_t)) {
5014
memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
5015
} else {
5016
print_indent(indent);
5017
outs() << " objc_method_description_list extends past end of the section\n";
5018
memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
5019
memcpy(&mdl, r, left);
5020
}
5021
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5022
swapStruct(mdl);
5023
5024
print_indent(indent);
5025
outs() << " count " << mdl.count << "\n";
5026
5027
list = r + sizeof(struct objc_method_description_list_t);
5028
for (i = 0; i < mdl.count; i++) {
5029
if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
5030
print_indent(indent);
5031
outs() << " remaining list entries extend past the of the section\n";
5032
break;
5033
}
5034
print_indent(indent);
5035
outs() << " list[" << i << "]\n";
5036
memcpy(&md, list + i * sizeof(struct objc_method_description_t),
5037
sizeof(struct objc_method_description_t));
5038
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5039
swapStruct(md);
5040
5041
print_indent(indent);
5042
outs() << " name " << format("0x%08" PRIx32, md.name);
5043
if (info->verbose) {
5044
name = get_pointer_32(md.name, offset, xleft, S, info, true);
5045
if (name != nullptr)
5046
outs() << format(" %.*s", xleft, name);
5047
else
5048
outs() << " (not in an __OBJC section)";
5049
}
5050
outs() << "\n";
5051
5052
print_indent(indent);
5053
outs() << " types " << format("0x%08" PRIx32, md.types);
5054
if (info->verbose) {
5055
name = get_pointer_32(md.types, offset, xleft, S, info, true);
5056
if (name != nullptr)
5057
outs() << format(" %.*s", xleft, name);
5058
else
5059
outs() << " (not in an __OBJC section)";
5060
}
5061
outs() << "\n";
5062
}
5063
return false;
5064
}
5065
5066
static bool print_protocol_list(uint32_t p, uint32_t indent,
5067
struct DisassembleInfo *info);
5068
5069
static bool print_protocol(uint32_t p, uint32_t indent,
5070
struct DisassembleInfo *info) {
5071
uint32_t offset, left;
5072
SectionRef S;
5073
struct objc_protocol_t protocol;
5074
const char *r, *name;
5075
5076
r = get_pointer_32(p, offset, left, S, info, true);
5077
if (r == nullptr)
5078
return true;
5079
5080
outs() << "\n";
5081
if (left >= sizeof(struct objc_protocol_t)) {
5082
memcpy(&protocol, r, sizeof(struct objc_protocol_t));
5083
} else {
5084
print_indent(indent);
5085
outs() << " Protocol extends past end of the section\n";
5086
memset(&protocol, '\0', sizeof(struct objc_protocol_t));
5087
memcpy(&protocol, r, left);
5088
}
5089
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5090
swapStruct(protocol);
5091
5092
print_indent(indent);
5093
outs() << " isa " << format("0x%08" PRIx32, protocol.isa)
5094
<< "\n";
5095
5096
print_indent(indent);
5097
outs() << " protocol_name "
5098
<< format("0x%08" PRIx32, protocol.protocol_name);
5099
if (info->verbose) {
5100
name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
5101
if (name != nullptr)
5102
outs() << format(" %.*s", left, name);
5103
else
5104
outs() << " (not in an __OBJC section)";
5105
}
5106
outs() << "\n";
5107
5108
print_indent(indent);
5109
outs() << " protocol_list "
5110
<< format("0x%08" PRIx32, protocol.protocol_list);
5111
if (print_protocol_list(protocol.protocol_list, indent + 4, info))
5112
outs() << " (not in an __OBJC section)\n";
5113
5114
print_indent(indent);
5115
outs() << " instance_methods "
5116
<< format("0x%08" PRIx32, protocol.instance_methods);
5117
if (print_method_description_list(protocol.instance_methods, indent, info))
5118
outs() << " (not in an __OBJC section)\n";
5119
5120
print_indent(indent);
5121
outs() << " class_methods "
5122
<< format("0x%08" PRIx32, protocol.class_methods);
5123
if (print_method_description_list(protocol.class_methods, indent, info))
5124
outs() << " (not in an __OBJC section)\n";
5125
5126
return false;
5127
}
5128
5129
static bool print_protocol_list(uint32_t p, uint32_t indent,
5130
struct DisassembleInfo *info) {
5131
uint32_t offset, left, l;
5132
SectionRef S;
5133
struct objc_protocol_list_t protocol_list;
5134
const char *r, *list;
5135
int32_t i;
5136
5137
r = get_pointer_32(p, offset, left, S, info, true);
5138
if (r == nullptr)
5139
return true;
5140
5141
outs() << "\n";
5142
if (left > sizeof(struct objc_protocol_list_t)) {
5143
memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
5144
} else {
5145
outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
5146
memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
5147
memcpy(&protocol_list, r, left);
5148
}
5149
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5150
swapStruct(protocol_list);
5151
5152
print_indent(indent);
5153
outs() << " next " << format("0x%08" PRIx32, protocol_list.next)
5154
<< "\n";
5155
print_indent(indent);
5156
outs() << " count " << protocol_list.count << "\n";
5157
5158
list = r + sizeof(struct objc_protocol_list_t);
5159
for (i = 0; i < protocol_list.count; i++) {
5160
if ((i + 1) * sizeof(uint32_t) > left) {
5161
outs() << "\t\t remaining list entries extend past the of the section\n";
5162
break;
5163
}
5164
memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
5165
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5166
sys::swapByteOrder(l);
5167
5168
print_indent(indent);
5169
outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);
5170
if (print_protocol(l, indent, info))
5171
outs() << "(not in an __OBJC section)\n";
5172
}
5173
return false;
5174
}
5175
5176
static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
5177
struct ivar_list64_t il;
5178
struct ivar64_t i;
5179
const char *r;
5180
uint32_t offset, xoffset, left, j;
5181
SectionRef S, xS;
5182
const char *name, *sym_name, *ivar_offset_p;
5183
uint64_t ivar_offset, n_value;
5184
5185
r = get_pointer_64(p, offset, left, S, info);
5186
if (r == nullptr)
5187
return;
5188
memset(&il, '\0', sizeof(struct ivar_list64_t));
5189
if (left < sizeof(struct ivar_list64_t)) {
5190
memcpy(&il, r, left);
5191
outs() << " (ivar_list_t entends past the end of the section)\n";
5192
} else
5193
memcpy(&il, r, sizeof(struct ivar_list64_t));
5194
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5195
swapStruct(il);
5196
outs() << " entsize " << il.entsize << "\n";
5197
outs() << " count " << il.count << "\n";
5198
5199
p += sizeof(struct ivar_list64_t);
5200
offset += sizeof(struct ivar_list64_t);
5201
for (j = 0; j < il.count; j++) {
5202
r = get_pointer_64(p, offset, left, S, info);
5203
if (r == nullptr)
5204
return;
5205
memset(&i, '\0', sizeof(struct ivar64_t));
5206
if (left < sizeof(struct ivar64_t)) {
5207
memcpy(&i, r, left);
5208
outs() << " (ivar_t entends past the end of the section)\n";
5209
} else
5210
memcpy(&i, r, sizeof(struct ivar64_t));
5211
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5212
swapStruct(i);
5213
5214
outs() << "\t\t\t offset ";
5215
sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,
5216
info, n_value, i.offset);
5217
if (n_value != 0) {
5218
if (info->verbose && sym_name != nullptr)
5219
outs() << sym_name;
5220
else
5221
outs() << format("0x%" PRIx64, n_value);
5222
if (i.offset != 0)
5223
outs() << " + " << format("0x%" PRIx64, i.offset);
5224
} else
5225
outs() << format("0x%" PRIx64, i.offset);
5226
ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
5227
if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5228
memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
5229
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5230
sys::swapByteOrder(ivar_offset);
5231
outs() << " " << ivar_offset << "\n";
5232
} else
5233
outs() << "\n";
5234
5235
outs() << "\t\t\t name ";
5236
sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,
5237
n_value, i.name);
5238
if (n_value != 0) {
5239
if (info->verbose && sym_name != nullptr)
5240
outs() << sym_name;
5241
else
5242
outs() << format("0x%" PRIx64, n_value);
5243
if (i.name != 0)
5244
outs() << " + " << format("0x%" PRIx64, i.name);
5245
} else
5246
outs() << format("0x%" PRIx64, i.name);
5247
name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
5248
if (name != nullptr)
5249
outs() << format(" %.*s", left, name);
5250
outs() << "\n";
5251
5252
outs() << "\t\t\t type ";
5253
sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,
5254
n_value, i.name);
5255
name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
5256
if (n_value != 0) {
5257
if (info->verbose && sym_name != nullptr)
5258
outs() << sym_name;
5259
else
5260
outs() << format("0x%" PRIx64, n_value);
5261
if (i.type != 0)
5262
outs() << " + " << format("0x%" PRIx64, i.type);
5263
} else
5264
outs() << format("0x%" PRIx64, i.type);
5265
if (name != nullptr)
5266
outs() << format(" %.*s", left, name);
5267
outs() << "\n";
5268
5269
outs() << "\t\t\talignment " << i.alignment << "\n";
5270
outs() << "\t\t\t size " << i.size << "\n";
5271
5272
p += sizeof(struct ivar64_t);
5273
offset += sizeof(struct ivar64_t);
5274
}
5275
}
5276
5277
static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
5278
struct ivar_list32_t il;
5279
struct ivar32_t i;
5280
const char *r;
5281
uint32_t offset, xoffset, left, j;
5282
SectionRef S, xS;
5283
const char *name, *ivar_offset_p;
5284
uint32_t ivar_offset;
5285
5286
r = get_pointer_32(p, offset, left, S, info);
5287
if (r == nullptr)
5288
return;
5289
memset(&il, '\0', sizeof(struct ivar_list32_t));
5290
if (left < sizeof(struct ivar_list32_t)) {
5291
memcpy(&il, r, left);
5292
outs() << " (ivar_list_t entends past the end of the section)\n";
5293
} else
5294
memcpy(&il, r, sizeof(struct ivar_list32_t));
5295
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5296
swapStruct(il);
5297
outs() << " entsize " << il.entsize << "\n";
5298
outs() << " count " << il.count << "\n";
5299
5300
p += sizeof(struct ivar_list32_t);
5301
offset += sizeof(struct ivar_list32_t);
5302
for (j = 0; j < il.count; j++) {
5303
r = get_pointer_32(p, offset, left, S, info);
5304
if (r == nullptr)
5305
return;
5306
memset(&i, '\0', sizeof(struct ivar32_t));
5307
if (left < sizeof(struct ivar32_t)) {
5308
memcpy(&i, r, left);
5309
outs() << " (ivar_t entends past the end of the section)\n";
5310
} else
5311
memcpy(&i, r, sizeof(struct ivar32_t));
5312
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5313
swapStruct(i);
5314
5315
outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);
5316
ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
5317
if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
5318
memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
5319
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5320
sys::swapByteOrder(ivar_offset);
5321
outs() << " " << ivar_offset << "\n";
5322
} else
5323
outs() << "\n";
5324
5325
outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);
5326
name = get_pointer_32(i.name, xoffset, left, xS, info);
5327
if (name != nullptr)
5328
outs() << format(" %.*s", left, name);
5329
outs() << "\n";
5330
5331
outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);
5332
name = get_pointer_32(i.type, xoffset, left, xS, info);
5333
if (name != nullptr)
5334
outs() << format(" %.*s", left, name);
5335
outs() << "\n";
5336
5337
outs() << "\t\t\talignment " << i.alignment << "\n";
5338
outs() << "\t\t\t size " << i.size << "\n";
5339
5340
p += sizeof(struct ivar32_t);
5341
offset += sizeof(struct ivar32_t);
5342
}
5343
}
5344
5345
static void print_objc_property_list64(uint64_t p,
5346
struct DisassembleInfo *info) {
5347
struct objc_property_list64 opl;
5348
struct objc_property64 op;
5349
const char *r;
5350
uint32_t offset, xoffset, left, j;
5351
SectionRef S, xS;
5352
const char *name, *sym_name;
5353
uint64_t n_value;
5354
5355
r = get_pointer_64(p, offset, left, S, info);
5356
if (r == nullptr)
5357
return;
5358
memset(&opl, '\0', sizeof(struct objc_property_list64));
5359
if (left < sizeof(struct objc_property_list64)) {
5360
memcpy(&opl, r, left);
5361
outs() << " (objc_property_list entends past the end of the section)\n";
5362
} else
5363
memcpy(&opl, r, sizeof(struct objc_property_list64));
5364
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5365
swapStruct(opl);
5366
outs() << " entsize " << opl.entsize << "\n";
5367
outs() << " count " << opl.count << "\n";
5368
5369
p += sizeof(struct objc_property_list64);
5370
offset += sizeof(struct objc_property_list64);
5371
for (j = 0; j < opl.count; j++) {
5372
r = get_pointer_64(p, offset, left, S, info);
5373
if (r == nullptr)
5374
return;
5375
memset(&op, '\0', sizeof(struct objc_property64));
5376
if (left < sizeof(struct objc_property64)) {
5377
memcpy(&op, r, left);
5378
outs() << " (objc_property entends past the end of the section)\n";
5379
} else
5380
memcpy(&op, r, sizeof(struct objc_property64));
5381
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5382
swapStruct(op);
5383
5384
outs() << "\t\t\t name ";
5385
sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,
5386
info, n_value, op.name);
5387
if (n_value != 0) {
5388
if (info->verbose && sym_name != nullptr)
5389
outs() << sym_name;
5390
else
5391
outs() << format("0x%" PRIx64, n_value);
5392
if (op.name != 0)
5393
outs() << " + " << format("0x%" PRIx64, op.name);
5394
} else
5395
outs() << format("0x%" PRIx64, op.name);
5396
name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
5397
if (name != nullptr)
5398
outs() << format(" %.*s", left, name);
5399
outs() << "\n";
5400
5401
outs() << "\t\t\tattributes ";
5402
sym_name =
5403
get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,
5404
info, n_value, op.attributes);
5405
if (n_value != 0) {
5406
if (info->verbose && sym_name != nullptr)
5407
outs() << sym_name;
5408
else
5409
outs() << format("0x%" PRIx64, n_value);
5410
if (op.attributes != 0)
5411
outs() << " + " << format("0x%" PRIx64, op.attributes);
5412
} else
5413
outs() << format("0x%" PRIx64, op.attributes);
5414
name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
5415
if (name != nullptr)
5416
outs() << format(" %.*s", left, name);
5417
outs() << "\n";
5418
5419
p += sizeof(struct objc_property64);
5420
offset += sizeof(struct objc_property64);
5421
}
5422
}
5423
5424
static void print_objc_property_list32(uint32_t p,
5425
struct DisassembleInfo *info) {
5426
struct objc_property_list32 opl;
5427
struct objc_property32 op;
5428
const char *r;
5429
uint32_t offset, xoffset, left, j;
5430
SectionRef S, xS;
5431
const char *name;
5432
5433
r = get_pointer_32(p, offset, left, S, info);
5434
if (r == nullptr)
5435
return;
5436
memset(&opl, '\0', sizeof(struct objc_property_list32));
5437
if (left < sizeof(struct objc_property_list32)) {
5438
memcpy(&opl, r, left);
5439
outs() << " (objc_property_list entends past the end of the section)\n";
5440
} else
5441
memcpy(&opl, r, sizeof(struct objc_property_list32));
5442
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5443
swapStruct(opl);
5444
outs() << " entsize " << opl.entsize << "\n";
5445
outs() << " count " << opl.count << "\n";
5446
5447
p += sizeof(struct objc_property_list32);
5448
offset += sizeof(struct objc_property_list32);
5449
for (j = 0; j < opl.count; j++) {
5450
r = get_pointer_32(p, offset, left, S, info);
5451
if (r == nullptr)
5452
return;
5453
memset(&op, '\0', sizeof(struct objc_property32));
5454
if (left < sizeof(struct objc_property32)) {
5455
memcpy(&op, r, left);
5456
outs() << " (objc_property entends past the end of the section)\n";
5457
} else
5458
memcpy(&op, r, sizeof(struct objc_property32));
5459
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5460
swapStruct(op);
5461
5462
outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);
5463
name = get_pointer_32(op.name, xoffset, left, xS, info);
5464
if (name != nullptr)
5465
outs() << format(" %.*s", left, name);
5466
outs() << "\n";
5467
5468
outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);
5469
name = get_pointer_32(op.attributes, xoffset, left, xS, info);
5470
if (name != nullptr)
5471
outs() << format(" %.*s", left, name);
5472
outs() << "\n";
5473
5474
p += sizeof(struct objc_property32);
5475
offset += sizeof(struct objc_property32);
5476
}
5477
}
5478
5479
static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
5480
bool &is_meta_class) {
5481
struct class_ro64_t cro;
5482
const char *r;
5483
uint32_t offset, xoffset, left;
5484
SectionRef S, xS;
5485
const char *name, *sym_name;
5486
uint64_t n_value;
5487
5488
r = get_pointer_64(p, offset, left, S, info);
5489
if (r == nullptr || left < sizeof(struct class_ro64_t))
5490
return false;
5491
memcpy(&cro, r, sizeof(struct class_ro64_t));
5492
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5493
swapStruct(cro);
5494
outs() << " flags " << format("0x%" PRIx32, cro.flags);
5495
if (cro.flags & RO_META)
5496
outs() << " RO_META";
5497
if (cro.flags & RO_ROOT)
5498
outs() << " RO_ROOT";
5499
if (cro.flags & RO_HAS_CXX_STRUCTORS)
5500
outs() << " RO_HAS_CXX_STRUCTORS";
5501
outs() << "\n";
5502
outs() << " instanceStart " << cro.instanceStart << "\n";
5503
outs() << " instanceSize " << cro.instanceSize << "\n";
5504
outs() << " reserved " << format("0x%" PRIx32, cro.reserved)
5505
<< "\n";
5506
outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)
5507
<< "\n";
5508
print_layout_map64(cro.ivarLayout, info);
5509
5510
outs() << " name ";
5511
sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,
5512
info, n_value, cro.name);
5513
if (n_value != 0) {
5514
if (info->verbose && sym_name != nullptr)
5515
outs() << sym_name;
5516
else
5517
outs() << format("0x%" PRIx64, n_value);
5518
if (cro.name != 0)
5519
outs() << " + " << format("0x%" PRIx64, cro.name);
5520
} else
5521
outs() << format("0x%" PRIx64, cro.name);
5522
name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
5523
if (name != nullptr)
5524
outs() << format(" %.*s", left, name);
5525
outs() << "\n";
5526
5527
outs() << " baseMethods ";
5528
sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),
5529
S, info, n_value, cro.baseMethods);
5530
if (n_value != 0) {
5531
if (info->verbose && sym_name != nullptr)
5532
outs() << sym_name;
5533
else
5534
outs() << format("0x%" PRIx64, n_value);
5535
if (cro.baseMethods != 0)
5536
outs() << " + " << format("0x%" PRIx64, cro.baseMethods);
5537
} else
5538
outs() << format("0x%" PRIx64, cro.baseMethods);
5539
outs() << " (struct method_list_t *)\n";
5540
if (cro.baseMethods + n_value != 0)
5541
print_method_list64_t(cro.baseMethods + n_value, info, "");
5542
5543
outs() << " baseProtocols ";
5544
sym_name =
5545
get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,
5546
info, n_value, cro.baseProtocols);
5547
if (n_value != 0) {
5548
if (info->verbose && sym_name != nullptr)
5549
outs() << sym_name;
5550
else
5551
outs() << format("0x%" PRIx64, n_value);
5552
if (cro.baseProtocols != 0)
5553
outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);
5554
} else
5555
outs() << format("0x%" PRIx64, cro.baseProtocols);
5556
outs() << "\n";
5557
if (cro.baseProtocols + n_value != 0)
5558
print_protocol_list64_t(cro.baseProtocols + n_value, info);
5559
5560
outs() << " ivars ";
5561
sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,
5562
info, n_value, cro.ivars);
5563
if (n_value != 0) {
5564
if (info->verbose && sym_name != nullptr)
5565
outs() << sym_name;
5566
else
5567
outs() << format("0x%" PRIx64, n_value);
5568
if (cro.ivars != 0)
5569
outs() << " + " << format("0x%" PRIx64, cro.ivars);
5570
} else
5571
outs() << format("0x%" PRIx64, cro.ivars);
5572
outs() << "\n";
5573
if (cro.ivars + n_value != 0)
5574
print_ivar_list64_t(cro.ivars + n_value, info);
5575
5576
outs() << " weakIvarLayout ";
5577
sym_name =
5578
get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,
5579
info, n_value, cro.weakIvarLayout);
5580
if (n_value != 0) {
5581
if (info->verbose && sym_name != nullptr)
5582
outs() << sym_name;
5583
else
5584
outs() << format("0x%" PRIx64, n_value);
5585
if (cro.weakIvarLayout != 0)
5586
outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);
5587
} else
5588
outs() << format("0x%" PRIx64, cro.weakIvarLayout);
5589
outs() << "\n";
5590
print_layout_map64(cro.weakIvarLayout + n_value, info);
5591
5592
outs() << " baseProperties ";
5593
sym_name =
5594
get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,
5595
info, n_value, cro.baseProperties);
5596
if (n_value != 0) {
5597
if (info->verbose && sym_name != nullptr)
5598
outs() << sym_name;
5599
else
5600
outs() << format("0x%" PRIx64, n_value);
5601
if (cro.baseProperties != 0)
5602
outs() << " + " << format("0x%" PRIx64, cro.baseProperties);
5603
} else
5604
outs() << format("0x%" PRIx64, cro.baseProperties);
5605
outs() << "\n";
5606
if (cro.baseProperties + n_value != 0)
5607
print_objc_property_list64(cro.baseProperties + n_value, info);
5608
5609
is_meta_class = (cro.flags & RO_META) != 0;
5610
return true;
5611
}
5612
5613
static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
5614
bool &is_meta_class) {
5615
struct class_ro32_t cro;
5616
const char *r;
5617
uint32_t offset, xoffset, left;
5618
SectionRef S, xS;
5619
const char *name;
5620
5621
r = get_pointer_32(p, offset, left, S, info);
5622
if (r == nullptr)
5623
return false;
5624
memset(&cro, '\0', sizeof(struct class_ro32_t));
5625
if (left < sizeof(struct class_ro32_t)) {
5626
memcpy(&cro, r, left);
5627
outs() << " (class_ro_t entends past the end of the section)\n";
5628
} else
5629
memcpy(&cro, r, sizeof(struct class_ro32_t));
5630
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5631
swapStruct(cro);
5632
outs() << " flags " << format("0x%" PRIx32, cro.flags);
5633
if (cro.flags & RO_META)
5634
outs() << " RO_META";
5635
if (cro.flags & RO_ROOT)
5636
outs() << " RO_ROOT";
5637
if (cro.flags & RO_HAS_CXX_STRUCTORS)
5638
outs() << " RO_HAS_CXX_STRUCTORS";
5639
outs() << "\n";
5640
outs() << " instanceStart " << cro.instanceStart << "\n";
5641
outs() << " instanceSize " << cro.instanceSize << "\n";
5642
outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)
5643
<< "\n";
5644
print_layout_map32(cro.ivarLayout, info);
5645
5646
outs() << " name " << format("0x%" PRIx32, cro.name);
5647
name = get_pointer_32(cro.name, xoffset, left, xS, info);
5648
if (name != nullptr)
5649
outs() << format(" %.*s", left, name);
5650
outs() << "\n";
5651
5652
outs() << " baseMethods "
5653
<< format("0x%" PRIx32, cro.baseMethods)
5654
<< " (struct method_list_t *)\n";
5655
if (cro.baseMethods != 0)
5656
print_method_list32_t(cro.baseMethods, info, "");
5657
5658
outs() << " baseProtocols "
5659
<< format("0x%" PRIx32, cro.baseProtocols) << "\n";
5660
if (cro.baseProtocols != 0)
5661
print_protocol_list32_t(cro.baseProtocols, info);
5662
outs() << " ivars " << format("0x%" PRIx32, cro.ivars)
5663
<< "\n";
5664
if (cro.ivars != 0)
5665
print_ivar_list32_t(cro.ivars, info);
5666
outs() << " weakIvarLayout "
5667
<< format("0x%" PRIx32, cro.weakIvarLayout) << "\n";
5668
print_layout_map32(cro.weakIvarLayout, info);
5669
outs() << " baseProperties "
5670
<< format("0x%" PRIx32, cro.baseProperties) << "\n";
5671
if (cro.baseProperties != 0)
5672
print_objc_property_list32(cro.baseProperties, info);
5673
is_meta_class = (cro.flags & RO_META) != 0;
5674
return true;
5675
}
5676
5677
static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
5678
struct class64_t c;
5679
const char *r;
5680
uint32_t offset, left;
5681
SectionRef S;
5682
const char *name;
5683
uint64_t isa_n_value, n_value;
5684
5685
r = get_pointer_64(p, offset, left, S, info);
5686
if (r == nullptr || left < sizeof(struct class64_t))
5687
return;
5688
memcpy(&c, r, sizeof(struct class64_t));
5689
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5690
swapStruct(c);
5691
5692
outs() << " isa " << format("0x%" PRIx64, c.isa);
5693
name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,
5694
isa_n_value, c.isa);
5695
if (name != nullptr)
5696
outs() << " " << name;
5697
outs() << "\n";
5698
5699
outs() << " superclass " << format("0x%" PRIx64, c.superclass);
5700
name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,
5701
n_value, c.superclass);
5702
if (name != nullptr)
5703
outs() << " " << name;
5704
else {
5705
name = get_dyld_bind_info_symbolname(S.getAddress() +
5706
offset + offsetof(struct class64_t, superclass), info);
5707
if (name != nullptr)
5708
outs() << " " << name;
5709
}
5710
outs() << "\n";
5711
5712
outs() << " cache " << format("0x%" PRIx64, c.cache);
5713
name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,
5714
n_value, c.cache);
5715
if (name != nullptr)
5716
outs() << " " << name;
5717
outs() << "\n";
5718
5719
outs() << " vtable " << format("0x%" PRIx64, c.vtable);
5720
name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,
5721
n_value, c.vtable);
5722
if (name != nullptr)
5723
outs() << " " << name;
5724
outs() << "\n";
5725
5726
name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,
5727
n_value, c.data);
5728
outs() << " data ";
5729
if (n_value != 0) {
5730
if (info->verbose && name != nullptr)
5731
outs() << name;
5732
else
5733
outs() << format("0x%" PRIx64, n_value);
5734
if (c.data != 0)
5735
outs() << " + " << format("0x%" PRIx64, c.data);
5736
} else
5737
outs() << format("0x%" PRIx64, c.data);
5738
outs() << " (struct class_ro_t *)";
5739
5740
// This is a Swift class if some of the low bits of the pointer are set.
5741
if ((c.data + n_value) & 0x7)
5742
outs() << " Swift class";
5743
outs() << "\n";
5744
bool is_meta_class;
5745
if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
5746
return;
5747
5748
if (!is_meta_class &&
5749
c.isa + isa_n_value != p &&
5750
c.isa + isa_n_value != 0 &&
5751
info->depth < 100) {
5752
info->depth++;
5753
outs() << "Meta Class\n";
5754
print_class64_t(c.isa + isa_n_value, info);
5755
}
5756
}
5757
5758
static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5759
struct class32_t c;
5760
const char *r;
5761
uint32_t offset, left;
5762
SectionRef S;
5763
const char *name;
5764
5765
r = get_pointer_32(p, offset, left, S, info);
5766
if (r == nullptr)
5767
return;
5768
memset(&c, '\0', sizeof(struct class32_t));
5769
if (left < sizeof(struct class32_t)) {
5770
memcpy(&c, r, left);
5771
outs() << " (class_t entends past the end of the section)\n";
5772
} else
5773
memcpy(&c, r, sizeof(struct class32_t));
5774
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5775
swapStruct(c);
5776
5777
outs() << " isa " << format("0x%" PRIx32, c.isa);
5778
name =
5779
get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);
5780
if (name != nullptr)
5781
outs() << " " << name;
5782
outs() << "\n";
5783
5784
outs() << " superclass " << format("0x%" PRIx32, c.superclass);
5785
name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,
5786
c.superclass);
5787
if (name != nullptr)
5788
outs() << " " << name;
5789
outs() << "\n";
5790
5791
outs() << " cache " << format("0x%" PRIx32, c.cache);
5792
name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,
5793
c.cache);
5794
if (name != nullptr)
5795
outs() << " " << name;
5796
outs() << "\n";
5797
5798
outs() << " vtable " << format("0x%" PRIx32, c.vtable);
5799
name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,
5800
c.vtable);
5801
if (name != nullptr)
5802
outs() << " " << name;
5803
outs() << "\n";
5804
5805
name =
5806
get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);
5807
outs() << " data " << format("0x%" PRIx32, c.data)
5808
<< " (struct class_ro_t *)";
5809
5810
// This is a Swift class if some of the low bits of the pointer are set.
5811
if (c.data & 0x3)
5812
outs() << " Swift class";
5813
outs() << "\n";
5814
bool is_meta_class;
5815
if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
5816
return;
5817
5818
if (!is_meta_class) {
5819
outs() << "Meta Class\n";
5820
print_class32_t(c.isa, info);
5821
}
5822
}
5823
5824
static void print_objc_class_t(struct objc_class_t *objc_class,
5825
struct DisassembleInfo *info) {
5826
uint32_t offset, left, xleft;
5827
const char *name, *p, *ivar_list;
5828
SectionRef S;
5829
int32_t i;
5830
struct objc_ivar_list_t objc_ivar_list;
5831
struct objc_ivar_t ivar;
5832
5833
outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);
5834
if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {
5835
name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
5836
if (name != nullptr)
5837
outs() << format(" %.*s", left, name);
5838
else
5839
outs() << " (not in an __OBJC section)";
5840
}
5841
outs() << "\n";
5842
5843
outs() << "\t super_class "
5844
<< format("0x%08" PRIx32, objc_class->super_class);
5845
if (info->verbose) {
5846
name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
5847
if (name != nullptr)
5848
outs() << format(" %.*s", left, name);
5849
else
5850
outs() << " (not in an __OBJC section)";
5851
}
5852
outs() << "\n";
5853
5854
outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);
5855
if (info->verbose) {
5856
name = get_pointer_32(objc_class->name, offset, left, S, info, true);
5857
if (name != nullptr)
5858
outs() << format(" %.*s", left, name);
5859
else
5860
outs() << " (not in an __OBJC section)";
5861
}
5862
outs() << "\n";
5863
5864
outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)
5865
<< "\n";
5866
5867
outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);
5868
if (info->verbose) {
5869
if (CLS_GETINFO(objc_class, CLS_CLASS))
5870
outs() << " CLS_CLASS";
5871
else if (CLS_GETINFO(objc_class, CLS_META))
5872
outs() << " CLS_META";
5873
}
5874
outs() << "\n";
5875
5876
outs() << "\t instance_size "
5877
<< format("0x%08" PRIx32, objc_class->instance_size) << "\n";
5878
5879
p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
5880
outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);
5881
if (p != nullptr) {
5882
if (left > sizeof(struct objc_ivar_list_t)) {
5883
outs() << "\n";
5884
memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
5885
} else {
5886
outs() << " (entends past the end of the section)\n";
5887
memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
5888
memcpy(&objc_ivar_list, p, left);
5889
}
5890
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5891
swapStruct(objc_ivar_list);
5892
outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5893
ivar_list = p + sizeof(struct objc_ivar_list_t);
5894
for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5895
if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5896
outs() << "\t\t remaining ivar's extend past the of the section\n";
5897
break;
5898
}
5899
memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
5900
sizeof(struct objc_ivar_t));
5901
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5902
swapStruct(ivar);
5903
5904
outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);
5905
if (info->verbose) {
5906
name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
5907
if (name != nullptr)
5908
outs() << format(" %.*s", xleft, name);
5909
else
5910
outs() << " (not in an __OBJC section)";
5911
}
5912
outs() << "\n";
5913
5914
outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);
5915
if (info->verbose) {
5916
name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
5917
if (name != nullptr)
5918
outs() << format(" %.*s", xleft, name);
5919
else
5920
outs() << " (not in an __OBJC section)";
5921
}
5922
outs() << "\n";
5923
5924
outs() << "\t\t ivar_offset "
5925
<< format("0x%08" PRIx32, ivar.ivar_offset) << "\n";
5926
}
5927
} else {
5928
outs() << " (not in an __OBJC section)\n";
5929
}
5930
5931
outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);
5932
if (print_method_list(objc_class->methodLists, info))
5933
outs() << " (not in an __OBJC section)\n";
5934
5935
outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)
5936
<< "\n";
5937
5938
outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);
5939
if (print_protocol_list(objc_class->protocols, 16, info))
5940
outs() << " (not in an __OBJC section)\n";
5941
}
5942
5943
static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5944
struct DisassembleInfo *info) {
5945
uint32_t offset, left;
5946
const char *name;
5947
SectionRef S;
5948
5949
outs() << "\t category name "
5950
<< format("0x%08" PRIx32, objc_category->category_name);
5951
if (info->verbose) {
5952
name = get_pointer_32(objc_category->category_name, offset, left, S, info,
5953
true);
5954
if (name != nullptr)
5955
outs() << format(" %.*s", left, name);
5956
else
5957
outs() << " (not in an __OBJC section)";
5958
}
5959
outs() << "\n";
5960
5961
outs() << "\t\t class name "
5962
<< format("0x%08" PRIx32, objc_category->class_name);
5963
if (info->verbose) {
5964
name =
5965
get_pointer_32(objc_category->class_name, offset, left, S, info, true);
5966
if (name != nullptr)
5967
outs() << format(" %.*s", left, name);
5968
else
5969
outs() << " (not in an __OBJC section)";
5970
}
5971
outs() << "\n";
5972
5973
outs() << "\t instance methods "
5974
<< format("0x%08" PRIx32, objc_category->instance_methods);
5975
if (print_method_list(objc_category->instance_methods, info))
5976
outs() << " (not in an __OBJC section)\n";
5977
5978
outs() << "\t class methods "
5979
<< format("0x%08" PRIx32, objc_category->class_methods);
5980
if (print_method_list(objc_category->class_methods, info))
5981
outs() << " (not in an __OBJC section)\n";
5982
}
5983
5984
static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
5985
struct category64_t c;
5986
const char *r;
5987
uint32_t offset, xoffset, left;
5988
SectionRef S, xS;
5989
const char *name, *sym_name;
5990
uint64_t n_value;
5991
5992
r = get_pointer_64(p, offset, left, S, info);
5993
if (r == nullptr)
5994
return;
5995
memset(&c, '\0', sizeof(struct category64_t));
5996
if (left < sizeof(struct category64_t)) {
5997
memcpy(&c, r, left);
5998
outs() << " (category_t entends past the end of the section)\n";
5999
} else
6000
memcpy(&c, r, sizeof(struct category64_t));
6001
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6002
swapStruct(c);
6003
6004
outs() << " name ";
6005
sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,
6006
info, n_value, c.name);
6007
if (n_value != 0) {
6008
if (info->verbose && sym_name != nullptr)
6009
outs() << sym_name;
6010
else
6011
outs() << format("0x%" PRIx64, n_value);
6012
if (c.name != 0)
6013
outs() << " + " << format("0x%" PRIx64, c.name);
6014
} else
6015
outs() << format("0x%" PRIx64, c.name);
6016
name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
6017
if (name != nullptr)
6018
outs() << format(" %.*s", left, name);
6019
outs() << "\n";
6020
6021
outs() << " cls ";
6022
sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,
6023
n_value, c.cls);
6024
if (n_value != 0) {
6025
if (info->verbose && sym_name != nullptr)
6026
outs() << sym_name;
6027
else
6028
outs() << format("0x%" PRIx64, n_value);
6029
if (c.cls != 0)
6030
outs() << " + " << format("0x%" PRIx64, c.cls);
6031
} else
6032
outs() << format("0x%" PRIx64, c.cls);
6033
outs() << "\n";
6034
if (c.cls + n_value != 0)
6035
print_class64_t(c.cls + n_value, info);
6036
6037
outs() << " instanceMethods ";
6038
sym_name =
6039
get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,
6040
info, n_value, c.instanceMethods);
6041
if (n_value != 0) {
6042
if (info->verbose && sym_name != nullptr)
6043
outs() << sym_name;
6044
else
6045
outs() << format("0x%" PRIx64, n_value);
6046
if (c.instanceMethods != 0)
6047
outs() << " + " << format("0x%" PRIx64, c.instanceMethods);
6048
} else
6049
outs() << format("0x%" PRIx64, c.instanceMethods);
6050
outs() << "\n";
6051
if (c.instanceMethods + n_value != 0)
6052
print_method_list64_t(c.instanceMethods + n_value, info, "");
6053
6054
outs() << " classMethods ";
6055
sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),
6056
S, info, n_value, c.classMethods);
6057
if (n_value != 0) {
6058
if (info->verbose && sym_name != nullptr)
6059
outs() << sym_name;
6060
else
6061
outs() << format("0x%" PRIx64, n_value);
6062
if (c.classMethods != 0)
6063
outs() << " + " << format("0x%" PRIx64, c.classMethods);
6064
} else
6065
outs() << format("0x%" PRIx64, c.classMethods);
6066
outs() << "\n";
6067
if (c.classMethods + n_value != 0)
6068
print_method_list64_t(c.classMethods + n_value, info, "");
6069
6070
outs() << " protocols ";
6071
sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,
6072
info, n_value, c.protocols);
6073
if (n_value != 0) {
6074
if (info->verbose && sym_name != nullptr)
6075
outs() << sym_name;
6076
else
6077
outs() << format("0x%" PRIx64, n_value);
6078
if (c.protocols != 0)
6079
outs() << " + " << format("0x%" PRIx64, c.protocols);
6080
} else
6081
outs() << format("0x%" PRIx64, c.protocols);
6082
outs() << "\n";
6083
if (c.protocols + n_value != 0)
6084
print_protocol_list64_t(c.protocols + n_value, info);
6085
6086
outs() << "instanceProperties ";
6087
sym_name =
6088
get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),
6089
S, info, n_value, c.instanceProperties);
6090
if (n_value != 0) {
6091
if (info->verbose && sym_name != nullptr)
6092
outs() << sym_name;
6093
else
6094
outs() << format("0x%" PRIx64, n_value);
6095
if (c.instanceProperties != 0)
6096
outs() << " + " << format("0x%" PRIx64, c.instanceProperties);
6097
} else
6098
outs() << format("0x%" PRIx64, c.instanceProperties);
6099
outs() << "\n";
6100
if (c.instanceProperties + n_value != 0)
6101
print_objc_property_list64(c.instanceProperties + n_value, info);
6102
}
6103
6104
static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
6105
struct category32_t c;
6106
const char *r;
6107
uint32_t offset, left;
6108
SectionRef S, xS;
6109
const char *name;
6110
6111
r = get_pointer_32(p, offset, left, S, info);
6112
if (r == nullptr)
6113
return;
6114
memset(&c, '\0', sizeof(struct category32_t));
6115
if (left < sizeof(struct category32_t)) {
6116
memcpy(&c, r, left);
6117
outs() << " (category_t entends past the end of the section)\n";
6118
} else
6119
memcpy(&c, r, sizeof(struct category32_t));
6120
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6121
swapStruct(c);
6122
6123
outs() << " name " << format("0x%" PRIx32, c.name);
6124
name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,
6125
c.name);
6126
if (name)
6127
outs() << " " << name;
6128
outs() << "\n";
6129
6130
outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";
6131
if (c.cls != 0)
6132
print_class32_t(c.cls, info);
6133
outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)
6134
<< "\n";
6135
if (c.instanceMethods != 0)
6136
print_method_list32_t(c.instanceMethods, info, "");
6137
outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)
6138
<< "\n";
6139
if (c.classMethods != 0)
6140
print_method_list32_t(c.classMethods, info, "");
6141
outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";
6142
if (c.protocols != 0)
6143
print_protocol_list32_t(c.protocols, info);
6144
outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)
6145
<< "\n";
6146
if (c.instanceProperties != 0)
6147
print_objc_property_list32(c.instanceProperties, info);
6148
}
6149
6150
static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
6151
uint32_t i, left, offset, xoffset;
6152
uint64_t p, n_value;
6153
struct message_ref64 mr;
6154
const char *name, *sym_name;
6155
const char *r;
6156
SectionRef xS;
6157
6158
if (S == SectionRef())
6159
return;
6160
6161
StringRef SectName;
6162
Expected<StringRef> SecNameOrErr = S.getName();
6163
if (SecNameOrErr)
6164
SectName = *SecNameOrErr;
6165
else
6166
consumeError(SecNameOrErr.takeError());
6167
6168
DataRefImpl Ref = S.getRawDataRefImpl();
6169
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6170
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6171
offset = 0;
6172
for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6173
p = S.getAddress() + i;
6174
r = get_pointer_64(p, offset, left, S, info);
6175
if (r == nullptr)
6176
return;
6177
memset(&mr, '\0', sizeof(struct message_ref64));
6178
if (left < sizeof(struct message_ref64)) {
6179
memcpy(&mr, r, left);
6180
outs() << " (message_ref entends past the end of the section)\n";
6181
} else
6182
memcpy(&mr, r, sizeof(struct message_ref64));
6183
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6184
swapStruct(mr);
6185
6186
outs() << " imp ";
6187
name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,
6188
n_value, mr.imp);
6189
if (n_value != 0) {
6190
outs() << format("0x%" PRIx64, n_value) << " ";
6191
if (mr.imp != 0)
6192
outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";
6193
} else
6194
outs() << format("0x%" PRIx64, mr.imp) << " ";
6195
if (name != nullptr)
6196
outs() << " " << name;
6197
outs() << "\n";
6198
6199
outs() << " sel ";
6200
sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,
6201
info, n_value, mr.sel);
6202
if (n_value != 0) {
6203
if (info->verbose && sym_name != nullptr)
6204
outs() << sym_name;
6205
else
6206
outs() << format("0x%" PRIx64, n_value);
6207
if (mr.sel != 0)
6208
outs() << " + " << format("0x%" PRIx64, mr.sel);
6209
} else
6210
outs() << format("0x%" PRIx64, mr.sel);
6211
name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
6212
if (name != nullptr)
6213
outs() << format(" %.*s", left, name);
6214
outs() << "\n";
6215
6216
offset += sizeof(struct message_ref64);
6217
}
6218
}
6219
6220
static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
6221
uint32_t i, left, offset, xoffset, p;
6222
struct message_ref32 mr;
6223
const char *name, *r;
6224
SectionRef xS;
6225
6226
if (S == SectionRef())
6227
return;
6228
6229
StringRef SectName;
6230
Expected<StringRef> SecNameOrErr = S.getName();
6231
if (SecNameOrErr)
6232
SectName = *SecNameOrErr;
6233
else
6234
consumeError(SecNameOrErr.takeError());
6235
6236
DataRefImpl Ref = S.getRawDataRefImpl();
6237
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6238
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6239
offset = 0;
6240
for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
6241
p = S.getAddress() + i;
6242
r = get_pointer_32(p, offset, left, S, info);
6243
if (r == nullptr)
6244
return;
6245
memset(&mr, '\0', sizeof(struct message_ref32));
6246
if (left < sizeof(struct message_ref32)) {
6247
memcpy(&mr, r, left);
6248
outs() << " (message_ref entends past the end of the section)\n";
6249
} else
6250
memcpy(&mr, r, sizeof(struct message_ref32));
6251
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6252
swapStruct(mr);
6253
6254
outs() << " imp " << format("0x%" PRIx32, mr.imp);
6255
name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,
6256
mr.imp);
6257
if (name != nullptr)
6258
outs() << " " << name;
6259
outs() << "\n";
6260
6261
outs() << " sel " << format("0x%" PRIx32, mr.sel);
6262
name = get_pointer_32(mr.sel, xoffset, left, xS, info);
6263
if (name != nullptr)
6264
outs() << " " << name;
6265
outs() << "\n";
6266
6267
offset += sizeof(struct message_ref32);
6268
}
6269
}
6270
6271
static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
6272
uint32_t left, offset, swift_version;
6273
uint64_t p;
6274
struct objc_image_info64 o;
6275
const char *r;
6276
6277
if (S == SectionRef())
6278
return;
6279
6280
StringRef SectName;
6281
Expected<StringRef> SecNameOrErr = S.getName();
6282
if (SecNameOrErr)
6283
SectName = *SecNameOrErr;
6284
else
6285
consumeError(SecNameOrErr.takeError());
6286
6287
DataRefImpl Ref = S.getRawDataRefImpl();
6288
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6289
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6290
p = S.getAddress();
6291
r = get_pointer_64(p, offset, left, S, info);
6292
if (r == nullptr)
6293
return;
6294
memset(&o, '\0', sizeof(struct objc_image_info64));
6295
if (left < sizeof(struct objc_image_info64)) {
6296
memcpy(&o, r, left);
6297
outs() << " (objc_image_info entends past the end of the section)\n";
6298
} else
6299
memcpy(&o, r, sizeof(struct objc_image_info64));
6300
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6301
swapStruct(o);
6302
outs() << " version " << o.version << "\n";
6303
outs() << " flags " << format("0x%" PRIx32, o.flags);
6304
if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6305
outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6306
if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6307
outs() << " OBJC_IMAGE_SUPPORTS_GC";
6308
if (o.flags & OBJC_IMAGE_IS_SIMULATED)
6309
outs() << " OBJC_IMAGE_IS_SIMULATED";
6310
if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)
6311
outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";
6312
swift_version = (o.flags >> 8) & 0xff;
6313
if (swift_version != 0) {
6314
if (swift_version == 1)
6315
outs() << " Swift 1.0";
6316
else if (swift_version == 2)
6317
outs() << " Swift 1.1";
6318
else if(swift_version == 3)
6319
outs() << " Swift 2.0";
6320
else if(swift_version == 4)
6321
outs() << " Swift 3.0";
6322
else if(swift_version == 5)
6323
outs() << " Swift 4.0";
6324
else if(swift_version == 6)
6325
outs() << " Swift 4.1/Swift 4.2";
6326
else if(swift_version == 7)
6327
outs() << " Swift 5 or later";
6328
else
6329
outs() << " unknown future Swift version (" << swift_version << ")";
6330
}
6331
outs() << "\n";
6332
}
6333
6334
static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
6335
uint32_t left, offset, swift_version, p;
6336
struct objc_image_info32 o;
6337
const char *r;
6338
6339
if (S == SectionRef())
6340
return;
6341
6342
StringRef SectName;
6343
Expected<StringRef> SecNameOrErr = S.getName();
6344
if (SecNameOrErr)
6345
SectName = *SecNameOrErr;
6346
else
6347
consumeError(SecNameOrErr.takeError());
6348
6349
DataRefImpl Ref = S.getRawDataRefImpl();
6350
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6351
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6352
p = S.getAddress();
6353
r = get_pointer_32(p, offset, left, S, info);
6354
if (r == nullptr)
6355
return;
6356
memset(&o, '\0', sizeof(struct objc_image_info32));
6357
if (left < sizeof(struct objc_image_info32)) {
6358
memcpy(&o, r, left);
6359
outs() << " (objc_image_info entends past the end of the section)\n";
6360
} else
6361
memcpy(&o, r, sizeof(struct objc_image_info32));
6362
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6363
swapStruct(o);
6364
outs() << " version " << o.version << "\n";
6365
outs() << " flags " << format("0x%" PRIx32, o.flags);
6366
if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
6367
outs() << " OBJC_IMAGE_IS_REPLACEMENT";
6368
if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
6369
outs() << " OBJC_IMAGE_SUPPORTS_GC";
6370
swift_version = (o.flags >> 8) & 0xff;
6371
if (swift_version != 0) {
6372
if (swift_version == 1)
6373
outs() << " Swift 1.0";
6374
else if (swift_version == 2)
6375
outs() << " Swift 1.1";
6376
else if(swift_version == 3)
6377
outs() << " Swift 2.0";
6378
else if(swift_version == 4)
6379
outs() << " Swift 3.0";
6380
else if(swift_version == 5)
6381
outs() << " Swift 4.0";
6382
else if(swift_version == 6)
6383
outs() << " Swift 4.1/Swift 4.2";
6384
else if(swift_version == 7)
6385
outs() << " Swift 5 or later";
6386
else
6387
outs() << " unknown future Swift version (" << swift_version << ")";
6388
}
6389
outs() << "\n";
6390
}
6391
6392
static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
6393
uint32_t left, offset, p;
6394
struct imageInfo_t o;
6395
const char *r;
6396
6397
StringRef SectName;
6398
Expected<StringRef> SecNameOrErr = S.getName();
6399
if (SecNameOrErr)
6400
SectName = *SecNameOrErr;
6401
else
6402
consumeError(SecNameOrErr.takeError());
6403
6404
DataRefImpl Ref = S.getRawDataRefImpl();
6405
StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
6406
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
6407
p = S.getAddress();
6408
r = get_pointer_32(p, offset, left, S, info);
6409
if (r == nullptr)
6410
return;
6411
memset(&o, '\0', sizeof(struct imageInfo_t));
6412
if (left < sizeof(struct imageInfo_t)) {
6413
memcpy(&o, r, left);
6414
outs() << " (imageInfo entends past the end of the section)\n";
6415
} else
6416
memcpy(&o, r, sizeof(struct imageInfo_t));
6417
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
6418
swapStruct(o);
6419
outs() << " version " << o.version << "\n";
6420
outs() << " flags " << format("0x%" PRIx32, o.flags);
6421
if (o.flags & 0x1)
6422
outs() << " F&C";
6423
if (o.flags & 0x2)
6424
outs() << " GC";
6425
if (o.flags & 0x4)
6426
outs() << " GC-only";
6427
else
6428
outs() << " RR";
6429
outs() << "\n";
6430
}
6431
6432
static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
6433
SymbolAddressMap AddrMap;
6434
if (verbose)
6435
CreateSymbolAddressMap(O, &AddrMap);
6436
6437
std::vector<SectionRef> Sections;
6438
append_range(Sections, O->sections());
6439
6440
struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6441
6442
SectionRef CL = get_section(O, "__OBJC2", "__class_list");
6443
if (CL == SectionRef())
6444
CL = get_section(O, "__DATA", "__objc_classlist");
6445
if (CL == SectionRef())
6446
CL = get_section(O, "__DATA_CONST", "__objc_classlist");
6447
if (CL == SectionRef())
6448
CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
6449
info.S = CL;
6450
walk_pointer_list_64("class", CL, O, &info, print_class64_t);
6451
6452
SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
6453
if (CR == SectionRef())
6454
CR = get_section(O, "__DATA", "__objc_classrefs");
6455
if (CR == SectionRef())
6456
CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
6457
if (CR == SectionRef())
6458
CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
6459
info.S = CR;
6460
walk_pointer_list_64("class refs", CR, O, &info, nullptr);
6461
6462
SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
6463
if (SR == SectionRef())
6464
SR = get_section(O, "__DATA", "__objc_superrefs");
6465
if (SR == SectionRef())
6466
SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
6467
if (SR == SectionRef())
6468
SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
6469
info.S = SR;
6470
walk_pointer_list_64("super refs", SR, O, &info, nullptr);
6471
6472
SectionRef CA = get_section(O, "__OBJC2", "__category_list");
6473
if (CA == SectionRef())
6474
CA = get_section(O, "__DATA", "__objc_catlist");
6475
if (CA == SectionRef())
6476
CA = get_section(O, "__DATA_CONST", "__objc_catlist");
6477
if (CA == SectionRef())
6478
CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
6479
info.S = CA;
6480
walk_pointer_list_64("category", CA, O, &info, print_category64_t);
6481
6482
SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
6483
if (PL == SectionRef())
6484
PL = get_section(O, "__DATA", "__objc_protolist");
6485
if (PL == SectionRef())
6486
PL = get_section(O, "__DATA_CONST", "__objc_protolist");
6487
if (PL == SectionRef())
6488
PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
6489
info.S = PL;
6490
walk_pointer_list_64("protocol", PL, O, &info, nullptr);
6491
6492
SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
6493
if (MR == SectionRef())
6494
MR = get_section(O, "__DATA", "__objc_msgrefs");
6495
if (MR == SectionRef())
6496
MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
6497
if (MR == SectionRef())
6498
MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
6499
info.S = MR;
6500
print_message_refs64(MR, &info);
6501
6502
SectionRef II = get_section(O, "__OBJC2", "__image_info");
6503
if (II == SectionRef())
6504
II = get_section(O, "__DATA", "__objc_imageinfo");
6505
if (II == SectionRef())
6506
II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6507
if (II == SectionRef())
6508
II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
6509
info.S = II;
6510
print_image_info64(II, &info);
6511
}
6512
6513
static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6514
SymbolAddressMap AddrMap;
6515
if (verbose)
6516
CreateSymbolAddressMap(O, &AddrMap);
6517
6518
std::vector<SectionRef> Sections;
6519
append_range(Sections, O->sections());
6520
6521
struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6522
6523
SectionRef CL = get_section(O, "__OBJC2", "__class_list");
6524
if (CL == SectionRef())
6525
CL = get_section(O, "__DATA", "__objc_classlist");
6526
if (CL == SectionRef())
6527
CL = get_section(O, "__DATA_CONST", "__objc_classlist");
6528
if (CL == SectionRef())
6529
CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
6530
info.S = CL;
6531
walk_pointer_list_32("class", CL, O, &info, print_class32_t);
6532
6533
SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
6534
if (CR == SectionRef())
6535
CR = get_section(O, "__DATA", "__objc_classrefs");
6536
if (CR == SectionRef())
6537
CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
6538
if (CR == SectionRef())
6539
CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
6540
info.S = CR;
6541
walk_pointer_list_32("class refs", CR, O, &info, nullptr);
6542
6543
SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
6544
if (SR == SectionRef())
6545
SR = get_section(O, "__DATA", "__objc_superrefs");
6546
if (SR == SectionRef())
6547
SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
6548
if (SR == SectionRef())
6549
SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
6550
info.S = SR;
6551
walk_pointer_list_32("super refs", SR, O, &info, nullptr);
6552
6553
SectionRef CA = get_section(O, "__OBJC2", "__category_list");
6554
if (CA == SectionRef())
6555
CA = get_section(O, "__DATA", "__objc_catlist");
6556
if (CA == SectionRef())
6557
CA = get_section(O, "__DATA_CONST", "__objc_catlist");
6558
if (CA == SectionRef())
6559
CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
6560
info.S = CA;
6561
walk_pointer_list_32("category", CA, O, &info, print_category32_t);
6562
6563
SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
6564
if (PL == SectionRef())
6565
PL = get_section(O, "__DATA", "__objc_protolist");
6566
if (PL == SectionRef())
6567
PL = get_section(O, "__DATA_CONST", "__objc_protolist");
6568
if (PL == SectionRef())
6569
PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
6570
info.S = PL;
6571
walk_pointer_list_32("protocol", PL, O, &info, nullptr);
6572
6573
SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
6574
if (MR == SectionRef())
6575
MR = get_section(O, "__DATA", "__objc_msgrefs");
6576
if (MR == SectionRef())
6577
MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
6578
if (MR == SectionRef())
6579
MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
6580
info.S = MR;
6581
print_message_refs32(MR, &info);
6582
6583
SectionRef II = get_section(O, "__OBJC2", "__image_info");
6584
if (II == SectionRef())
6585
II = get_section(O, "__DATA", "__objc_imageinfo");
6586
if (II == SectionRef())
6587
II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6588
if (II == SectionRef())
6589
II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
6590
info.S = II;
6591
print_image_info32(II, &info);
6592
}
6593
6594
static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
6595
uint32_t i, j, p, offset, xoffset, left, defs_left, def;
6596
const char *r, *name, *defs;
6597
struct objc_module_t module;
6598
SectionRef S, xS;
6599
struct objc_symtab_t symtab;
6600
struct objc_class_t objc_class;
6601
struct objc_category_t objc_category;
6602
6603
outs() << "Objective-C segment\n";
6604
S = get_section(O, "__OBJC", "__module_info");
6605
if (S == SectionRef())
6606
return false;
6607
6608
SymbolAddressMap AddrMap;
6609
if (verbose)
6610
CreateSymbolAddressMap(O, &AddrMap);
6611
6612
std::vector<SectionRef> Sections;
6613
append_range(Sections, O->sections());
6614
6615
struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
6616
6617
for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
6618
p = S.getAddress() + i;
6619
r = get_pointer_32(p, offset, left, S, &info, true);
6620
if (r == nullptr)
6621
return true;
6622
memset(&module, '\0', sizeof(struct objc_module_t));
6623
if (left < sizeof(struct objc_module_t)) {
6624
memcpy(&module, r, left);
6625
outs() << " (module extends past end of __module_info section)\n";
6626
} else
6627
memcpy(&module, r, sizeof(struct objc_module_t));
6628
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6629
swapStruct(module);
6630
6631
outs() << "Module " << format("0x%" PRIx32, p) << "\n";
6632
outs() << " version " << module.version << "\n";
6633
outs() << " size " << module.size << "\n";
6634
outs() << " name ";
6635
name = get_pointer_32(module.name, xoffset, left, xS, &info, true);
6636
if (name != nullptr)
6637
outs() << format("%.*s", left, name);
6638
else
6639
outs() << format("0x%08" PRIx32, module.name)
6640
<< "(not in an __OBJC section)";
6641
outs() << "\n";
6642
6643
r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);
6644
if (module.symtab == 0 || r == nullptr) {
6645
outs() << " symtab " << format("0x%08" PRIx32, module.symtab)
6646
<< " (not in an __OBJC section)\n";
6647
continue;
6648
}
6649
outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";
6650
memset(&symtab, '\0', sizeof(struct objc_symtab_t));
6651
defs_left = 0;
6652
defs = nullptr;
6653
if (left < sizeof(struct objc_symtab_t)) {
6654
memcpy(&symtab, r, left);
6655
outs() << "\tsymtab extends past end of an __OBJC section)\n";
6656
} else {
6657
memcpy(&symtab, r, sizeof(struct objc_symtab_t));
6658
if (left > sizeof(struct objc_symtab_t)) {
6659
defs_left = left - sizeof(struct objc_symtab_t);
6660
defs = r + sizeof(struct objc_symtab_t);
6661
}
6662
}
6663
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6664
swapStruct(symtab);
6665
6666
outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
6667
r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);
6668
outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);
6669
if (r == nullptr)
6670
outs() << " (not in an __OBJC section)";
6671
outs() << "\n";
6672
outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
6673
outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
6674
if (symtab.cls_def_cnt > 0)
6675
outs() << "\tClass Definitions\n";
6676
for (j = 0; j < symtab.cls_def_cnt; j++) {
6677
if ((j + 1) * sizeof(uint32_t) > defs_left) {
6678
outs() << "\t(remaining class defs entries entends past the end of the "
6679
<< "section)\n";
6680
break;
6681
}
6682
memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));
6683
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6684
sys::swapByteOrder(def);
6685
6686
r = get_pointer_32(def, xoffset, left, xS, &info, true);
6687
outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);
6688
if (r != nullptr) {
6689
if (left > sizeof(struct objc_class_t)) {
6690
outs() << "\n";
6691
memcpy(&objc_class, r, sizeof(struct objc_class_t));
6692
} else {
6693
outs() << " (entends past the end of the section)\n";
6694
memset(&objc_class, '\0', sizeof(struct objc_class_t));
6695
memcpy(&objc_class, r, left);
6696
}
6697
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6698
swapStruct(objc_class);
6699
print_objc_class_t(&objc_class, &info);
6700
} else {
6701
outs() << "(not in an __OBJC section)\n";
6702
}
6703
6704
if (CLS_GETINFO(&objc_class, CLS_CLASS)) {
6705
outs() << "\tMeta Class";
6706
r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);
6707
if (r != nullptr) {
6708
if (left > sizeof(struct objc_class_t)) {
6709
outs() << "\n";
6710
memcpy(&objc_class, r, sizeof(struct objc_class_t));
6711
} else {
6712
outs() << " (entends past the end of the section)\n";
6713
memset(&objc_class, '\0', sizeof(struct objc_class_t));
6714
memcpy(&objc_class, r, left);
6715
}
6716
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6717
swapStruct(objc_class);
6718
print_objc_class_t(&objc_class, &info);
6719
} else {
6720
outs() << "(not in an __OBJC section)\n";
6721
}
6722
}
6723
}
6724
if (symtab.cat_def_cnt > 0)
6725
outs() << "\tCategory Definitions\n";
6726
for (j = 0; j < symtab.cat_def_cnt; j++) {
6727
if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
6728
outs() << "\t(remaining category defs entries entends past the end of "
6729
<< "the section)\n";
6730
break;
6731
}
6732
memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
6733
sizeof(uint32_t));
6734
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6735
sys::swapByteOrder(def);
6736
6737
r = get_pointer_32(def, xoffset, left, xS, &info, true);
6738
outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
6739
<< format("0x%08" PRIx32, def);
6740
if (r != nullptr) {
6741
if (left > sizeof(struct objc_category_t)) {
6742
outs() << "\n";
6743
memcpy(&objc_category, r, sizeof(struct objc_category_t));
6744
} else {
6745
outs() << " (entends past the end of the section)\n";
6746
memset(&objc_category, '\0', sizeof(struct objc_category_t));
6747
memcpy(&objc_category, r, left);
6748
}
6749
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6750
swapStruct(objc_category);
6751
print_objc_objc_category_t(&objc_category, &info);
6752
} else {
6753
outs() << "(not in an __OBJC section)\n";
6754
}
6755
}
6756
}
6757
const SectionRef II = get_section(O, "__OBJC", "__image_info");
6758
if (II != SectionRef())
6759
print_image_info(II, &info);
6760
6761
return true;
6762
}
6763
6764
static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
6765
uint32_t size, uint32_t addr) {
6766
SymbolAddressMap AddrMap;
6767
CreateSymbolAddressMap(O, &AddrMap);
6768
6769
std::vector<SectionRef> Sections;
6770
append_range(Sections, O->sections());
6771
6772
struct DisassembleInfo info(O, &AddrMap, &Sections, true);
6773
6774
const char *p;
6775
struct objc_protocol_t protocol;
6776
uint32_t left, paddr;
6777
for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
6778
memset(&protocol, '\0', sizeof(struct objc_protocol_t));
6779
left = size - (p - sect);
6780
if (left < sizeof(struct objc_protocol_t)) {
6781
outs() << "Protocol extends past end of __protocol section\n";
6782
memcpy(&protocol, p, left);
6783
} else
6784
memcpy(&protocol, p, sizeof(struct objc_protocol_t));
6785
if (O->isLittleEndian() != sys::IsLittleEndianHost)
6786
swapStruct(protocol);
6787
paddr = addr + (p - sect);
6788
outs() << "Protocol " << format("0x%" PRIx32, paddr);
6789
if (print_protocol(paddr, 0, &info))
6790
outs() << "(not in an __OBJC section)\n";
6791
}
6792
}
6793
6794
static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
6795
if (O->is64Bit())
6796
printObjc2_64bit_MetaData(O, verbose);
6797
else {
6798
MachO::mach_header H;
6799
H = O->getHeader();
6800
if (H.cputype == MachO::CPU_TYPE_ARM)
6801
printObjc2_32bit_MetaData(O, verbose);
6802
else {
6803
// This is the 32-bit non-arm cputype case. Which is normally
6804
// the first Objective-C ABI. But it may be the case of a
6805
// binary for the iOS simulator which is the second Objective-C
6806
// ABI. In that case printObjc1_32bit_MetaData() will determine that
6807
// and return false.
6808
if (!printObjc1_32bit_MetaData(O, verbose))
6809
printObjc2_32bit_MetaData(O, verbose);
6810
}
6811
}
6812
}
6813
6814
// GuessLiteralPointer returns a string which for the item in the Mach-O file
6815
// for the address passed in as ReferenceValue for printing as a comment with
6816
// the instruction and also returns the corresponding type of that item
6817
// indirectly through ReferenceType.
6818
//
6819
// If ReferenceValue is an address of literal cstring then a pointer to the
6820
// cstring is returned and ReferenceType is set to
6821
// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
6822
//
6823
// If ReferenceValue is an address of an Objective-C CFString, Selector ref or
6824
// Class ref that name is returned and the ReferenceType is set accordingly.
6825
//
6826
// Lastly, literals which are Symbol address in a literal pool are looked for
6827
// and if found the symbol name is returned and ReferenceType is set to
6828
// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
6829
//
6830
// If there is no item in the Mach-O file for the address passed in as
6831
// ReferenceValue nullptr is returned and ReferenceType is unchanged.
6832
static const char *GuessLiteralPointer(uint64_t ReferenceValue,
6833
uint64_t ReferencePC,
6834
uint64_t *ReferenceType,
6835
struct DisassembleInfo *info) {
6836
// First see if there is an external relocation entry at the ReferencePC.
6837
if (info->O->getHeader().filetype == MachO::MH_OBJECT) {
6838
uint64_t sect_addr = info->S.getAddress();
6839
uint64_t sect_offset = ReferencePC - sect_addr;
6840
bool reloc_found = false;
6841
DataRefImpl Rel;
6842
MachO::any_relocation_info RE;
6843
bool isExtern = false;
6844
SymbolRef Symbol;
6845
for (const RelocationRef &Reloc : info->S.relocations()) {
6846
uint64_t RelocOffset = Reloc.getOffset();
6847
if (RelocOffset == sect_offset) {
6848
Rel = Reloc.getRawDataRefImpl();
6849
RE = info->O->getRelocation(Rel);
6850
if (info->O->isRelocationScattered(RE))
6851
continue;
6852
isExtern = info->O->getPlainRelocationExternal(RE);
6853
if (isExtern) {
6854
symbol_iterator RelocSym = Reloc.getSymbol();
6855
Symbol = *RelocSym;
6856
}
6857
reloc_found = true;
6858
break;
6859
}
6860
}
6861
// If there is an external relocation entry for a symbol in a section
6862
// then used that symbol's value for the value of the reference.
6863
if (reloc_found && isExtern) {
6864
if (info->O->getAnyRelocationPCRel(RE)) {
6865
unsigned Type = info->O->getAnyRelocationType(RE);
6866
if (Type == MachO::X86_64_RELOC_SIGNED) {
6867
ReferenceValue = cantFail(Symbol.getValue());
6868
}
6869
}
6870
}
6871
}
6872
6873
// Look for literals such as Objective-C CFStrings refs, Selector refs,
6874
// Message refs and Class refs.
6875
bool classref, selref, msgref, cfstring;
6876
uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
6877
selref, msgref, cfstring);
6878
if (classref && pointer_value == 0) {
6879
// Note the ReferenceValue is a pointer into the __objc_classrefs section.
6880
// And the pointer_value in that section is typically zero as it will be
6881
// set by dyld as part of the "bind information".
6882
const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
6883
if (name != nullptr) {
6884
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6885
const char *class_name = strrchr(name, '$');
6886
if (class_name != nullptr && class_name[1] == '_' &&
6887
class_name[2] != '\0') {
6888
info->class_name = class_name + 2;
6889
return name;
6890
}
6891
}
6892
}
6893
6894
if (classref) {
6895
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6896
const char *name =
6897
get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
6898
if (name != nullptr)
6899
info->class_name = name;
6900
else
6901
name = "bad class ref";
6902
return name;
6903
}
6904
6905
if (cfstring) {
6906
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
6907
const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
6908
return name;
6909
}
6910
6911
if (selref && pointer_value == 0)
6912
pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
6913
6914
if (pointer_value != 0)
6915
ReferenceValue = pointer_value;
6916
6917
const char *name = GuessCstringPointer(ReferenceValue, info);
6918
if (name) {
6919
if (pointer_value != 0 && selref) {
6920
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
6921
info->selector_name = name;
6922
} else if (pointer_value != 0 && msgref) {
6923
info->class_name = nullptr;
6924
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
6925
info->selector_name = name;
6926
} else
6927
*ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;
6928
return name;
6929
}
6930
6931
// Lastly look for an indirect symbol with this ReferenceValue which is in
6932
// a literal pool. If found return that symbol name.
6933
name = GuessIndirectSymbol(ReferenceValue, info);
6934
if (name) {
6935
*ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
6936
return name;
6937
}
6938
6939
return nullptr;
6940
}
6941
6942
// SymbolizerSymbolLookUp is the symbol lookup function passed when creating
6943
// the Symbolizer. It looks up the ReferenceValue using the info passed via the
6944
// pointer to the struct DisassembleInfo that was passed when MCSymbolizer
6945
// is created and returns the symbol name that matches the ReferenceValue or
6946
// nullptr if none. The ReferenceType is passed in for the IN type of
6947
// reference the instruction is making from the values in defined in the header
6948
// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
6949
// Out type and the ReferenceName will also be set which is added as a comment
6950
// to the disassembled instruction.
6951
//
6952
// If the symbol name is a C++ mangled name then the demangled name is
6953
// returned through ReferenceName and ReferenceType is set to
6954
// LLVMDisassembler_ReferenceType_DeMangled_Name .
6955
//
6956
// When this is called to get a symbol name for a branch target then the
6957
// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
6958
// SymbolValue will be looked for in the indirect symbol table to determine if
6959
// it is an address for a symbol stub. If so then the symbol name for that
6960
// stub is returned indirectly through ReferenceName and then ReferenceType is
6961
// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
6962
//
6963
// When this is called with an value loaded via a PC relative load then
6964
// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
6965
// SymbolValue is checked to be an address of literal pointer, symbol pointer,
6966
// or an Objective-C meta data reference. If so the output ReferenceType is
6967
// set to correspond to that as well as setting the ReferenceName.
6968
static const char *SymbolizerSymbolLookUp(void *DisInfo,
6969
uint64_t ReferenceValue,
6970
uint64_t *ReferenceType,
6971
uint64_t ReferencePC,
6972
const char **ReferenceName) {
6973
struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
6974
// If no verbose symbolic information is wanted then just return nullptr.
6975
if (!info->verbose) {
6976
*ReferenceName = nullptr;
6977
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6978
return nullptr;
6979
}
6980
6981
const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
6982
6983
if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
6984
*ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
6985
if (*ReferenceName != nullptr) {
6986
method_reference(info, ReferenceType, ReferenceName);
6987
if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
6988
*ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
6989
} else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
6990
if (info->demangled_name != nullptr)
6991
free(info->demangled_name);
6992
info->demangled_name = itaniumDemangle(SymbolName + 1);
6993
if (info->demangled_name != nullptr) {
6994
*ReferenceName = info->demangled_name;
6995
*ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
6996
} else
6997
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6998
} else
6999
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7000
} else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
7001
*ReferenceName =
7002
GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7003
if (*ReferenceName)
7004
method_reference(info, ReferenceType, ReferenceName);
7005
else
7006
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7007
// If this is arm64 and the reference is an adrp instruction save the
7008
// instruction, passed in ReferenceValue and the address of the instruction
7009
// for use later if we see and add immediate instruction.
7010
} else if (info->O->getArch() == Triple::aarch64 &&
7011
*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
7012
info->adrp_inst = ReferenceValue;
7013
info->adrp_addr = ReferencePC;
7014
SymbolName = nullptr;
7015
*ReferenceName = nullptr;
7016
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7017
// If this is arm64 and reference is an add immediate instruction and we
7018
// have
7019
// seen an adrp instruction just before it and the adrp's Xd register
7020
// matches
7021
// this add's Xn register reconstruct the value being referenced and look to
7022
// see if it is a literal pointer. Note the add immediate instruction is
7023
// passed in ReferenceValue.
7024
} else if (info->O->getArch() == Triple::aarch64 &&
7025
*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
7026
ReferencePC - 4 == info->adrp_addr &&
7027
(info->adrp_inst & 0x9f000000) == 0x90000000 &&
7028
(info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7029
uint32_t addxri_inst;
7030
uint64_t adrp_imm, addxri_imm;
7031
7032
adrp_imm =
7033
((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7034
if (info->adrp_inst & 0x0200000)
7035
adrp_imm |= 0xfffffffffc000000LL;
7036
7037
addxri_inst = ReferenceValue;
7038
addxri_imm = (addxri_inst >> 10) & 0xfff;
7039
if (((addxri_inst >> 22) & 0x3) == 1)
7040
addxri_imm <<= 12;
7041
7042
ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7043
(adrp_imm << 12) + addxri_imm;
7044
7045
*ReferenceName =
7046
GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7047
if (*ReferenceName == nullptr)
7048
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7049
// If this is arm64 and the reference is a load register instruction and we
7050
// have seen an adrp instruction just before it and the adrp's Xd register
7051
// matches this add's Xn register reconstruct the value being referenced and
7052
// look to see if it is a literal pointer. Note the load register
7053
// instruction is passed in ReferenceValue.
7054
} else if (info->O->getArch() == Triple::aarch64 &&
7055
*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&
7056
ReferencePC - 4 == info->adrp_addr &&
7057
(info->adrp_inst & 0x9f000000) == 0x90000000 &&
7058
(info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
7059
uint32_t ldrxui_inst;
7060
uint64_t adrp_imm, ldrxui_imm;
7061
7062
adrp_imm =
7063
((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
7064
if (info->adrp_inst & 0x0200000)
7065
adrp_imm |= 0xfffffffffc000000LL;
7066
7067
ldrxui_inst = ReferenceValue;
7068
ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
7069
7070
ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
7071
(adrp_imm << 12) + (ldrxui_imm << 3);
7072
7073
*ReferenceName =
7074
GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7075
if (*ReferenceName == nullptr)
7076
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7077
}
7078
// If this arm64 and is an load register (PC-relative) instruction the
7079
// ReferenceValue is the PC plus the immediate value.
7080
else if (info->O->getArch() == Triple::aarch64 &&
7081
(*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||
7082
*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {
7083
*ReferenceName =
7084
GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
7085
if (*ReferenceName == nullptr)
7086
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7087
} else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
7088
if (info->demangled_name != nullptr)
7089
free(info->demangled_name);
7090
info->demangled_name = itaniumDemangle(SymbolName + 1);
7091
if (info->demangled_name != nullptr) {
7092
*ReferenceName = info->demangled_name;
7093
*ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
7094
}
7095
}
7096
else {
7097
*ReferenceName = nullptr;
7098
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
7099
}
7100
7101
return SymbolName;
7102
}
7103
7104
/// Emits the comments that are stored in the CommentStream.
7105
/// Each comment in the CommentStream must end with a newline.
7106
static void emitComments(raw_svector_ostream &CommentStream,
7107
SmallString<128> &CommentsToEmit,
7108
formatted_raw_ostream &FormattedOS,
7109
const MCAsmInfo &MAI) {
7110
// Flush the stream before taking its content.
7111
StringRef Comments = CommentsToEmit.str();
7112
// Get the default information for printing a comment.
7113
StringRef CommentBegin = MAI.getCommentString();
7114
unsigned CommentColumn = MAI.getCommentColumn();
7115
ListSeparator LS("\n");
7116
while (!Comments.empty()) {
7117
FormattedOS << LS;
7118
// Emit a line of comments.
7119
FormattedOS.PadToColumn(CommentColumn);
7120
size_t Position = Comments.find('\n');
7121
FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
7122
// Move after the newline character.
7123
Comments = Comments.substr(Position + 1);
7124
}
7125
FormattedOS.flush();
7126
7127
// Tell the comment stream that the vector changed underneath it.
7128
CommentsToEmit.clear();
7129
}
7130
7131
const MachOObjectFile *
7132
objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,
7133
std::unique_ptr<Binary> &DSYMBinary,
7134
std::unique_ptr<MemoryBuffer> &DSYMBuf) {
7135
const MachOObjectFile *DbgObj = MachOOF;
7136
std::string DSYMPath;
7137
7138
// Auto-detect w/o --dsym.
7139
if (DSYMFile.empty()) {
7140
sys::fs::file_status DSYMStatus;
7141
Twine FilenameDSYM = Filename + ".dSYM";
7142
if (!status(FilenameDSYM, DSYMStatus)) {
7143
if (sys::fs::is_directory(DSYMStatus)) {
7144
SmallString<1024> Path;
7145
FilenameDSYM.toVector(Path);
7146
sys::path::append(Path, "Contents", "Resources", "DWARF",
7147
sys::path::filename(Filename));
7148
DSYMPath = std::string(Path);
7149
} else if (sys::fs::is_regular_file(DSYMStatus)) {
7150
DSYMPath = FilenameDSYM.str();
7151
}
7152
}
7153
}
7154
7155
if (DSYMPath.empty() && !DSYMFile.empty()) {
7156
// If DSYMPath is a .dSYM directory, append the Mach-O file.
7157
if (sys::fs::is_directory(DSYMFile) &&
7158
sys::path::extension(DSYMFile) == ".dSYM") {
7159
SmallString<128> ShortName(sys::path::filename(DSYMFile));
7160
sys::path::replace_extension(ShortName, "");
7161
SmallString<1024> FullPath(DSYMFile);
7162
sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);
7163
DSYMPath = FullPath.str();
7164
} else {
7165
DSYMPath = DSYMFile;
7166
}
7167
}
7168
7169
if (!DSYMPath.empty()) {
7170
// Load the file.
7171
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
7172
MemoryBuffer::getFileOrSTDIN(DSYMPath);
7173
if (std::error_code EC = BufOrErr.getError()) {
7174
reportError(errorCodeToError(EC), DSYMPath);
7175
return nullptr;
7176
}
7177
7178
// We need to keep the file alive, because we're replacing DbgObj with it.
7179
DSYMBuf = std::move(BufOrErr.get());
7180
7181
Expected<std::unique_ptr<Binary>> BinaryOrErr =
7182
createBinary(DSYMBuf->getMemBufferRef());
7183
if (!BinaryOrErr) {
7184
reportError(BinaryOrErr.takeError(), DSYMPath);
7185
return nullptr;
7186
}
7187
7188
// We need to keep the Binary alive with the buffer
7189
DSYMBinary = std::move(BinaryOrErr.get());
7190
if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
7191
// this is a Mach-O object file, use it
7192
if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
7193
DbgObj = MachDSYM;
7194
} else {
7195
WithColor::error(errs(), "llvm-objdump")
7196
<< DSYMPath << " is not a Mach-O file type.\n";
7197
return nullptr;
7198
}
7199
} else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {
7200
// this is a Universal Binary, find a Mach-O for this architecture
7201
uint32_t CPUType, CPUSubType;
7202
const char *ArchFlag;
7203
if (MachOOF->is64Bit()) {
7204
const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
7205
CPUType = H_64.cputype;
7206
CPUSubType = H_64.cpusubtype;
7207
} else {
7208
const MachO::mach_header H = MachOOF->getHeader();
7209
CPUType = H.cputype;
7210
CPUSubType = H.cpusubtype;
7211
}
7212
Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
7213
&ArchFlag);
7214
Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
7215
UB->getMachOObjectForArch(ArchFlag);
7216
if (!MachDSYM) {
7217
reportError(MachDSYM.takeError(), DSYMPath);
7218
return nullptr;
7219
}
7220
7221
// We need to keep the Binary alive with the buffer
7222
DbgObj = &*MachDSYM.get();
7223
DSYMBinary = std::move(*MachDSYM);
7224
} else {
7225
WithColor::error(errs(), "llvm-objdump")
7226
<< DSYMPath << " is not a Mach-O or Universal file type.\n";
7227
return nullptr;
7228
}
7229
}
7230
return DbgObj;
7231
}
7232
7233
static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
7234
StringRef DisSegName, StringRef DisSectName) {
7235
const char *McpuDefault = nullptr;
7236
const Target *ThumbTarget = nullptr;
7237
const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
7238
if (!TheTarget) {
7239
// GetTarget prints out stuff.
7240
return;
7241
}
7242
std::string MachOMCPU;
7243
if (MCPU.empty() && McpuDefault)
7244
MachOMCPU = McpuDefault;
7245
else
7246
MachOMCPU = MCPU;
7247
7248
#define CHECK_TARGET_INFO_CREATION(NAME) \
7249
do { \
7250
if (!NAME) { \
7251
WithColor::error(errs(), "llvm-objdump") \
7252
<< "couldn't initialize disassembler for target " << TripleName \
7253
<< '\n'; \
7254
return; \
7255
} \
7256
} while (false)
7257
#define CHECK_THUMB_TARGET_INFO_CREATION(NAME) \
7258
do { \
7259
if (!NAME) { \
7260
WithColor::error(errs(), "llvm-objdump") \
7261
<< "couldn't initialize disassembler for target " << ThumbTripleName \
7262
<< '\n'; \
7263
return; \
7264
} \
7265
} while (false)
7266
7267
std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
7268
CHECK_TARGET_INFO_CREATION(InstrInfo);
7269
std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
7270
if (ThumbTarget) {
7271
ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());
7272
CHECK_THUMB_TARGET_INFO_CREATION(ThumbInstrInfo);
7273
}
7274
7275
// Package up features to be passed to target/subtarget
7276
std::string FeaturesStr;
7277
if (!MAttrs.empty()) {
7278
SubtargetFeatures Features;
7279
for (unsigned i = 0; i != MAttrs.size(); ++i)
7280
Features.AddFeature(MAttrs[i]);
7281
FeaturesStr = Features.getString();
7282
}
7283
7284
MCTargetOptions MCOptions;
7285
// Set up disassembler.
7286
std::unique_ptr<const MCRegisterInfo> MRI(
7287
TheTarget->createMCRegInfo(TripleName));
7288
CHECK_TARGET_INFO_CREATION(MRI);
7289
std::unique_ptr<const MCAsmInfo> AsmInfo(
7290
TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
7291
CHECK_TARGET_INFO_CREATION(AsmInfo);
7292
std::unique_ptr<const MCSubtargetInfo> STI(
7293
TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr));
7294
CHECK_TARGET_INFO_CREATION(STI);
7295
MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
7296
std::unique_ptr<MCDisassembler> DisAsm(
7297
TheTarget->createMCDisassembler(*STI, Ctx));
7298
CHECK_TARGET_INFO_CREATION(DisAsm);
7299
std::unique_ptr<MCSymbolizer> Symbolizer;
7300
struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);
7301
std::unique_ptr<MCRelocationInfo> RelInfo(
7302
TheTarget->createMCRelocationInfo(TripleName, Ctx));
7303
if (RelInfo) {
7304
Symbolizer.reset(TheTarget->createMCSymbolizer(
7305
TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
7306
&SymbolizerInfo, &Ctx, std::move(RelInfo)));
7307
DisAsm->setSymbolizer(std::move(Symbolizer));
7308
}
7309
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
7310
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
7311
Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));
7312
CHECK_TARGET_INFO_CREATION(IP);
7313
// Set the display preference for hex vs. decimal immediates.
7314
IP->setPrintImmHex(PrintImmHex);
7315
// Comment stream and backing vector.
7316
SmallString<128> CommentsToEmit;
7317
raw_svector_ostream CommentStream(CommentsToEmit);
7318
// FIXME: Setting the CommentStream in the InstPrinter is problematic in that
7319
// if it is done then arm64 comments for string literals don't get printed
7320
// and some constant get printed instead and not setting it causes intel
7321
// (32-bit and 64-bit) comments printed with different spacing before the
7322
// comment causing different diffs with the 'C' disassembler library API.
7323
// IP->setCommentStream(CommentStream);
7324
7325
// Set up separate thumb disassembler if needed.
7326
std::unique_ptr<const MCRegisterInfo> ThumbMRI;
7327
std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
7328
std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
7329
std::unique_ptr<MCDisassembler> ThumbDisAsm;
7330
std::unique_ptr<MCInstPrinter> ThumbIP;
7331
std::unique_ptr<MCContext> ThumbCtx;
7332
std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
7333
struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);
7334
std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
7335
if (ThumbTarget) {
7336
ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
7337
CHECK_THUMB_TARGET_INFO_CREATION(ThumbMRI);
7338
ThumbAsmInfo.reset(
7339
ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName, MCOptions));
7340
CHECK_THUMB_TARGET_INFO_CREATION(ThumbAsmInfo);
7341
ThumbSTI.reset(
7342
ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU,
7343
FeaturesStr));
7344
CHECK_THUMB_TARGET_INFO_CREATION(ThumbSTI);
7345
ThumbCtx.reset(new MCContext(Triple(ThumbTripleName), ThumbAsmInfo.get(),
7346
ThumbMRI.get(), ThumbSTI.get()));
7347
ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
7348
CHECK_THUMB_TARGET_INFO_CREATION(ThumbDisAsm);
7349
MCContext *PtrThumbCtx = ThumbCtx.get();
7350
ThumbRelInfo.reset(
7351
ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));
7352
if (ThumbRelInfo) {
7353
ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
7354
ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
7355
&ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
7356
ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
7357
}
7358
int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
7359
ThumbIP.reset(ThumbTarget->createMCInstPrinter(
7360
Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,
7361
*ThumbInstrInfo, *ThumbMRI));
7362
CHECK_THUMB_TARGET_INFO_CREATION(ThumbIP);
7363
// Set the display preference for hex vs. decimal immediates.
7364
ThumbIP->setPrintImmHex(PrintImmHex);
7365
}
7366
7367
#undef CHECK_TARGET_INFO_CREATION
7368
#undef CHECK_THUMB_TARGET_INFO_CREATION
7369
7370
MachO::mach_header Header = MachOOF->getHeader();
7371
7372
// FIXME: Using the -cfg command line option, this code used to be able to
7373
// annotate relocations with the referenced symbol's name, and if this was
7374
// inside a __[cf]string section, the data it points to. This is now replaced
7375
// by the upcoming MCSymbolizer, which needs the appropriate setup done above.
7376
std::vector<SectionRef> Sections;
7377
std::vector<SymbolRef> Symbols;
7378
SmallVector<uint64_t, 8> FoundFns;
7379
uint64_t BaseSegmentAddress = 0;
7380
7381
getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,
7382
BaseSegmentAddress);
7383
7384
// Sort the symbols by address, just in case they didn't come in that way.
7385
llvm::stable_sort(Symbols, SymbolSorter());
7386
7387
// Build a data in code table that is sorted on by the address of each entry.
7388
uint64_t BaseAddress = 0;
7389
if (Header.filetype == MachO::MH_OBJECT)
7390
BaseAddress = Sections[0].getAddress();
7391
else
7392
BaseAddress = BaseSegmentAddress;
7393
DiceTable Dices;
7394
for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
7395
DI != DE; ++DI) {
7396
uint32_t Offset;
7397
DI->getOffset(Offset);
7398
Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
7399
}
7400
array_pod_sort(Dices.begin(), Dices.end());
7401
7402
// Try to find debug info and set up the DIContext for it.
7403
std::unique_ptr<DIContext> diContext;
7404
std::unique_ptr<Binary> DSYMBinary;
7405
std::unique_ptr<MemoryBuffer> DSYMBuf;
7406
if (UseDbg) {
7407
// If separate DSym file path was specified, parse it as a macho file,
7408
// get the sections and supply it to the section name parsing machinery.
7409
if (const ObjectFile *DbgObj =
7410
getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf)) {
7411
// Setup the DIContext
7412
diContext = DWARFContext::create(*DbgObj);
7413
} else {
7414
return;
7415
}
7416
}
7417
7418
if (FilterSections.empty())
7419
outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
7420
7421
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
7422
Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName();
7423
if (!SecNameOrErr) {
7424
consumeError(SecNameOrErr.takeError());
7425
continue;
7426
}
7427
if (*SecNameOrErr != DisSectName)
7428
continue;
7429
7430
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
7431
7432
StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
7433
if (SegmentName != DisSegName)
7434
continue;
7435
7436
StringRef BytesStr =
7437
unwrapOrError(Sections[SectIdx].getContents(), Filename);
7438
ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);
7439
uint64_t SectAddress = Sections[SectIdx].getAddress();
7440
7441
bool symbolTableWorked = false;
7442
7443
// Create a map of symbol addresses to symbol names for use by
7444
// the SymbolizerSymbolLookUp() routine.
7445
SymbolAddressMap AddrMap;
7446
bool DisSymNameFound = false;
7447
for (const SymbolRef &Symbol : MachOOF->symbols()) {
7448
SymbolRef::Type ST =
7449
unwrapOrError(Symbol.getType(), MachOOF->getFileName());
7450
if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
7451
ST == SymbolRef::ST_Other) {
7452
uint64_t Address = cantFail(Symbol.getValue());
7453
StringRef SymName =
7454
unwrapOrError(Symbol.getName(), MachOOF->getFileName());
7455
AddrMap[Address] = SymName;
7456
if (!DisSymName.empty() && DisSymName == SymName)
7457
DisSymNameFound = true;
7458
}
7459
}
7460
if (!DisSymName.empty() && !DisSymNameFound) {
7461
outs() << "Can't find -dis-symname: " << DisSymName << "\n";
7462
return;
7463
}
7464
// Set up the block of info used by the Symbolizer call backs.
7465
SymbolizerInfo.verbose = SymbolicOperands;
7466
SymbolizerInfo.O = MachOOF;
7467
SymbolizerInfo.S = Sections[SectIdx];
7468
SymbolizerInfo.AddrMap = &AddrMap;
7469
SymbolizerInfo.Sections = &Sections;
7470
// Same for the ThumbSymbolizer
7471
ThumbSymbolizerInfo.verbose = SymbolicOperands;
7472
ThumbSymbolizerInfo.O = MachOOF;
7473
ThumbSymbolizerInfo.S = Sections[SectIdx];
7474
ThumbSymbolizerInfo.AddrMap = &AddrMap;
7475
ThumbSymbolizerInfo.Sections = &Sections;
7476
7477
unsigned int Arch = MachOOF->getArch();
7478
7479
// Skip all symbols if this is a stubs file.
7480
if (Bytes.empty())
7481
return;
7482
7483
// If the section has symbols but no symbol at the start of the section
7484
// these are used to make sure the bytes before the first symbol are
7485
// disassembled.
7486
bool FirstSymbol = true;
7487
bool FirstSymbolAtSectionStart = true;
7488
7489
// Disassemble symbol by symbol.
7490
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
7491
StringRef SymName =
7492
unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());
7493
SymbolRef::Type ST =
7494
unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());
7495
if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
7496
continue;
7497
7498
// Make sure the symbol is defined in this section.
7499
bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);
7500
if (!containsSym) {
7501
if (!DisSymName.empty() && DisSymName == SymName) {
7502
outs() << "-dis-symname: " << DisSymName << " not in the section\n";
7503
return;
7504
}
7505
continue;
7506
}
7507
// The __mh_execute_header is special and we need to deal with that fact
7508
// this symbol is before the start of the (__TEXT,__text) section and at the
7509
// address of the start of the __TEXT segment. This is because this symbol
7510
// is an N_SECT symbol in the (__TEXT,__text) but its address is before the
7511
// start of the section in a standard MH_EXECUTE filetype.
7512
if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {
7513
outs() << "-dis-symname: __mh_execute_header not in any section\n";
7514
return;
7515
}
7516
// When this code is trying to disassemble a symbol at a time and in the
7517
// case there is only the __mh_execute_header symbol left as in a stripped
7518
// executable, we need to deal with this by ignoring this symbol so the
7519
// whole section is disassembled and this symbol is then not displayed.
7520
if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||
7521
SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||
7522
SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")
7523
continue;
7524
7525
// If we are only disassembling one symbol see if this is that symbol.
7526
if (!DisSymName.empty() && DisSymName != SymName)
7527
continue;
7528
7529
// Start at the address of the symbol relative to the section's address.
7530
uint64_t SectSize = Sections[SectIdx].getSize();
7531
uint64_t Start = cantFail(Symbols[SymIdx].getValue());
7532
uint64_t SectionAddress = Sections[SectIdx].getAddress();
7533
Start -= SectionAddress;
7534
7535
if (Start > SectSize) {
7536
outs() << "section data ends, " << SymName
7537
<< " lies outside valid range\n";
7538
return;
7539
}
7540
7541
// Stop disassembling either at the beginning of the next symbol or at
7542
// the end of the section.
7543
bool containsNextSym = false;
7544
uint64_t NextSym = 0;
7545
uint64_t NextSymIdx = SymIdx + 1;
7546
while (Symbols.size() > NextSymIdx) {
7547
SymbolRef::Type NextSymType = unwrapOrError(
7548
Symbols[NextSymIdx].getType(), MachOOF->getFileName());
7549
if (NextSymType == SymbolRef::ST_Function) {
7550
containsNextSym =
7551
Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
7552
NextSym = cantFail(Symbols[NextSymIdx].getValue());
7553
NextSym -= SectionAddress;
7554
break;
7555
}
7556
++NextSymIdx;
7557
}
7558
7559
uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;
7560
uint64_t Size;
7561
7562
symbolTableWorked = true;
7563
7564
DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
7565
uint32_t SymbolFlags = cantFail(MachOOF->getSymbolFlags(Symb));
7566
bool IsThumb = SymbolFlags & SymbolRef::SF_Thumb;
7567
7568
// We only need the dedicated Thumb target if there's a real choice
7569
// (i.e. we're not targeting M-class) and the function is Thumb.
7570
bool UseThumbTarget = IsThumb && ThumbTarget;
7571
7572
// If we are not specifying a symbol to start disassembly with and this
7573
// is the first symbol in the section but not at the start of the section
7574
// then move the disassembly index to the start of the section and
7575
// don't print the symbol name just yet. This is so the bytes before the
7576
// first symbol are disassembled.
7577
uint64_t SymbolStart = Start;
7578
if (DisSymName.empty() && FirstSymbol && Start != 0) {
7579
FirstSymbolAtSectionStart = false;
7580
Start = 0;
7581
}
7582
else
7583
outs() << SymName << ":\n";
7584
7585
DILineInfo lastLine;
7586
for (uint64_t Index = Start; Index < End; Index += Size) {
7587
MCInst Inst;
7588
7589
// If this is the first symbol in the section and it was not at the
7590
// start of the section, see if we are at its Index now and if so print
7591
// the symbol name.
7592
if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
7593
outs() << SymName << ":\n";
7594
7595
uint64_t PC = SectAddress + Index;
7596
if (LeadingAddr) {
7597
if (FullLeadingAddr) {
7598
if (MachOOF->is64Bit())
7599
outs() << format("%016" PRIx64, PC);
7600
else
7601
outs() << format("%08" PRIx64, PC);
7602
} else {
7603
outs() << format("%8" PRIx64 ":", PC);
7604
}
7605
}
7606
if (ShowRawInsn || Arch == Triple::arm)
7607
outs() << "\t";
7608
7609
if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))
7610
continue;
7611
7612
SmallVector<char, 64> AnnotationsBytes;
7613
raw_svector_ostream Annotations(AnnotationsBytes);
7614
7615
bool gotInst;
7616
if (UseThumbTarget)
7617
gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
7618
PC, Annotations);
7619
else
7620
gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,
7621
Annotations);
7622
if (gotInst) {
7623
if (ShowRawInsn || Arch == Triple::arm) {
7624
dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());
7625
}
7626
formatted_raw_ostream FormattedOS(outs());
7627
StringRef AnnotationsStr = Annotations.str();
7628
if (UseThumbTarget)
7629
ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI,
7630
FormattedOS);
7631
else
7632
IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);
7633
emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
7634
7635
// Print debug info.
7636
if (diContext) {
7637
DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
7638
// Print valid line info if it changed.
7639
if (dli != lastLine && dli.Line != 0)
7640
outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
7641
<< dli.Column;
7642
lastLine = dli;
7643
}
7644
outs() << "\n";
7645
} else {
7646
if (MachOOF->getArchTriple().isX86()) {
7647
outs() << format("\t.byte 0x%02x #bad opcode\n",
7648
*(Bytes.data() + Index) & 0xff);
7649
Size = 1; // skip exactly one illegible byte and move on.
7650
} else if (Arch == Triple::aarch64 ||
7651
(Arch == Triple::arm && !IsThumb)) {
7652
uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7653
(*(Bytes.data() + Index + 1) & 0xff) << 8 |
7654
(*(Bytes.data() + Index + 2) & 0xff) << 16 |
7655
(*(Bytes.data() + Index + 3) & 0xff) << 24;
7656
outs() << format("\t.long\t0x%08x\n", opcode);
7657
Size = 4;
7658
} else if (Arch == Triple::arm) {
7659
assert(IsThumb && "ARM mode should have been dealt with above");
7660
uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7661
(*(Bytes.data() + Index + 1) & 0xff) << 8;
7662
outs() << format("\t.short\t0x%04x\n", opcode);
7663
Size = 2;
7664
} else{
7665
WithColor::warning(errs(), "llvm-objdump")
7666
<< "invalid instruction encoding\n";
7667
if (Size == 0)
7668
Size = 1; // skip illegible bytes
7669
}
7670
}
7671
}
7672
// Now that we are done disassembled the first symbol set the bool that
7673
// were doing this to false.
7674
FirstSymbol = false;
7675
}
7676
if (!symbolTableWorked) {
7677
// Reading the symbol table didn't work, disassemble the whole section.
7678
uint64_t SectAddress = Sections[SectIdx].getAddress();
7679
uint64_t SectSize = Sections[SectIdx].getSize();
7680
uint64_t InstSize;
7681
for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
7682
MCInst Inst;
7683
7684
uint64_t PC = SectAddress + Index;
7685
7686
if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize))
7687
continue;
7688
7689
SmallVector<char, 64> AnnotationsBytes;
7690
raw_svector_ostream Annotations(AnnotationsBytes);
7691
if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
7692
Annotations)) {
7693
if (LeadingAddr) {
7694
if (FullLeadingAddr) {
7695
if (MachOOF->is64Bit())
7696
outs() << format("%016" PRIx64, PC);
7697
else
7698
outs() << format("%08" PRIx64, PC);
7699
} else {
7700
outs() << format("%8" PRIx64 ":", PC);
7701
}
7702
}
7703
if (ShowRawInsn || Arch == Triple::arm) {
7704
outs() << "\t";
7705
dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());
7706
}
7707
StringRef AnnotationsStr = Annotations.str();
7708
IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());
7709
outs() << "\n";
7710
} else {
7711
if (MachOOF->getArchTriple().isX86()) {
7712
outs() << format("\t.byte 0x%02x #bad opcode\n",
7713
*(Bytes.data() + Index) & 0xff);
7714
InstSize = 1; // skip exactly one illegible byte and move on.
7715
} else {
7716
WithColor::warning(errs(), "llvm-objdump")
7717
<< "invalid instruction encoding\n";
7718
if (InstSize == 0)
7719
InstSize = 1; // skip illegible bytes
7720
}
7721
}
7722
}
7723
}
7724
// The TripleName's need to be reset if we are called again for a different
7725
// architecture.
7726
TripleName = "";
7727
ThumbTripleName = "";
7728
7729
if (SymbolizerInfo.demangled_name != nullptr)
7730
free(SymbolizerInfo.demangled_name);
7731
if (ThumbSymbolizerInfo.demangled_name != nullptr)
7732
free(ThumbSymbolizerInfo.demangled_name);
7733
}
7734
}
7735
7736
//===----------------------------------------------------------------------===//
7737
// __compact_unwind section dumping
7738
//===----------------------------------------------------------------------===//
7739
7740
namespace {
7741
7742
template <typename T>
7743
static uint64_t read(StringRef Contents, ptrdiff_t Offset) {
7744
if (Offset + sizeof(T) > Contents.size()) {
7745
outs() << "warning: attempt to read past end of buffer\n";
7746
return T();
7747
}
7748
7749
uint64_t Val = support::endian::read<T, llvm::endianness::little>(
7750
Contents.data() + Offset);
7751
return Val;
7752
}
7753
7754
template <typename T>
7755
static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {
7756
T Val = read<T>(Contents, Offset);
7757
Offset += sizeof(T);
7758
return Val;
7759
}
7760
7761
struct CompactUnwindEntry {
7762
uint32_t OffsetInSection;
7763
7764
uint64_t FunctionAddr;
7765
uint32_t Length;
7766
uint32_t CompactEncoding;
7767
uint64_t PersonalityAddr;
7768
uint64_t LSDAAddr;
7769
7770
RelocationRef FunctionReloc;
7771
RelocationRef PersonalityReloc;
7772
RelocationRef LSDAReloc;
7773
7774
CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
7775
: OffsetInSection(Offset) {
7776
if (Is64)
7777
read<uint64_t>(Contents, Offset);
7778
else
7779
read<uint32_t>(Contents, Offset);
7780
}
7781
7782
private:
7783
template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {
7784
FunctionAddr = readNext<UIntPtr>(Contents, Offset);
7785
Length = readNext<uint32_t>(Contents, Offset);
7786
CompactEncoding = readNext<uint32_t>(Contents, Offset);
7787
PersonalityAddr = readNext<UIntPtr>(Contents, Offset);
7788
LSDAAddr = readNext<UIntPtr>(Contents, Offset);
7789
}
7790
};
7791
}
7792
7793
/// Given a relocation from __compact_unwind, consisting of the RelocationRef
7794
/// and data being relocated, determine the best base Name and Addend to use for
7795
/// display purposes.
7796
///
7797
/// 1. An Extern relocation will directly reference a symbol (and the data is
7798
/// then already an addend), so use that.
7799
/// 2. Otherwise the data is an offset in the object file's layout; try to find
7800
// a symbol before it in the same section, and use the offset from there.
7801
/// 3. Finally, if all that fails, fall back to an offset from the start of the
7802
/// referenced section.
7803
static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
7804
std::map<uint64_t, SymbolRef> &Symbols,
7805
const RelocationRef &Reloc, uint64_t Addr,
7806
StringRef &Name, uint64_t &Addend) {
7807
if (Reloc.getSymbol() != Obj->symbol_end()) {
7808
Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());
7809
Addend = Addr;
7810
return;
7811
}
7812
7813
auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
7814
SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
7815
7816
uint64_t SectionAddr = RelocSection.getAddress();
7817
7818
auto Sym = Symbols.upper_bound(Addr);
7819
if (Sym == Symbols.begin()) {
7820
// The first symbol in the object is after this reference, the best we can
7821
// do is section-relative notation.
7822
if (Expected<StringRef> NameOrErr = RelocSection.getName())
7823
Name = *NameOrErr;
7824
else
7825
consumeError(NameOrErr.takeError());
7826
7827
Addend = Addr - SectionAddr;
7828
return;
7829
}
7830
7831
// Go back one so that SymbolAddress <= Addr.
7832
--Sym;
7833
7834
section_iterator SymSection =
7835
unwrapOrError(Sym->second.getSection(), Obj->getFileName());
7836
if (RelocSection == *SymSection) {
7837
// There's a valid symbol in the same section before this reference.
7838
Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());
7839
Addend = Addr - Sym->first;
7840
return;
7841
}
7842
7843
// There is a symbol before this reference, but it's in a different
7844
// section. Probably not helpful to mention it, so use the section name.
7845
if (Expected<StringRef> NameOrErr = RelocSection.getName())
7846
Name = *NameOrErr;
7847
else
7848
consumeError(NameOrErr.takeError());
7849
7850
Addend = Addr - SectionAddr;
7851
}
7852
7853
static void printUnwindRelocDest(const MachOObjectFile *Obj,
7854
std::map<uint64_t, SymbolRef> &Symbols,
7855
const RelocationRef &Reloc, uint64_t Addr) {
7856
StringRef Name;
7857
uint64_t Addend;
7858
7859
if (!Reloc.getObject())
7860
return;
7861
7862
findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
7863
7864
outs() << Name;
7865
if (Addend)
7866
outs() << " + " << format("0x%" PRIx64, Addend);
7867
}
7868
7869
static void
7870
printMachOCompactUnwindSection(const MachOObjectFile *Obj,
7871
std::map<uint64_t, SymbolRef> &Symbols,
7872
const SectionRef &CompactUnwind) {
7873
7874
if (!Obj->isLittleEndian()) {
7875
outs() << "Skipping big-endian __compact_unwind section\n";
7876
return;
7877
}
7878
7879
bool Is64 = Obj->is64Bit();
7880
uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
7881
uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
7882
7883
StringRef Contents =
7884
unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());
7885
SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
7886
7887
// First populate the initial raw offsets, encodings and so on from the entry.
7888
for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
7889
CompactUnwindEntry Entry(Contents, Offset, Is64);
7890
CompactUnwinds.push_back(Entry);
7891
}
7892
7893
// Next we need to look at the relocations to find out what objects are
7894
// actually being referred to.
7895
for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
7896
uint64_t RelocAddress = Reloc.getOffset();
7897
7898
uint32_t EntryIdx = RelocAddress / EntrySize;
7899
uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
7900
CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
7901
7902
if (OffsetInEntry == 0)
7903
Entry.FunctionReloc = Reloc;
7904
else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
7905
Entry.PersonalityReloc = Reloc;
7906
else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
7907
Entry.LSDAReloc = Reloc;
7908
else {
7909
outs() << "Invalid relocation in __compact_unwind section\n";
7910
return;
7911
}
7912
}
7913
7914
// Finally, we're ready to print the data we've gathered.
7915
outs() << "Contents of __compact_unwind section:\n";
7916
for (auto &Entry : CompactUnwinds) {
7917
outs() << " Entry at offset "
7918
<< format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";
7919
7920
// 1. Start of the region this entry applies to.
7921
outs() << " start: " << format("0x%" PRIx64,
7922
Entry.FunctionAddr) << ' ';
7923
printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);
7924
outs() << '\n';
7925
7926
// 2. Length of the region this entry applies to.
7927
outs() << " length: " << format("0x%" PRIx32, Entry.Length)
7928
<< '\n';
7929
// 3. The 32-bit compact encoding.
7930
outs() << " compact encoding: "
7931
<< format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';
7932
7933
// 4. The personality function, if present.
7934
if (Entry.PersonalityReloc.getObject()) {
7935
outs() << " personality function: "
7936
<< format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';
7937
printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
7938
Entry.PersonalityAddr);
7939
outs() << '\n';
7940
}
7941
7942
// 5. This entry's language-specific data area.
7943
if (Entry.LSDAReloc.getObject()) {
7944
outs() << " LSDA: " << format("0x%" PRIx64,
7945
Entry.LSDAAddr) << ' ';
7946
printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
7947
outs() << '\n';
7948
}
7949
}
7950
}
7951
7952
//===----------------------------------------------------------------------===//
7953
// __unwind_info section dumping
7954
//===----------------------------------------------------------------------===//
7955
7956
static void printRegularSecondLevelUnwindPage(StringRef PageData) {
7957
ptrdiff_t Pos = 0;
7958
uint32_t Kind = readNext<uint32_t>(PageData, Pos);
7959
(void)Kind;
7960
assert(Kind == 2 && "kind for a regular 2nd level index should be 2");
7961
7962
uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7963
uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
7964
7965
Pos = EntriesStart;
7966
for (unsigned i = 0; i < NumEntries; ++i) {
7967
uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);
7968
uint32_t Encoding = readNext<uint32_t>(PageData, Pos);
7969
7970
outs() << " [" << i << "]: "
7971
<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)
7972
<< ", "
7973
<< "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';
7974
}
7975
}
7976
7977
static void printCompressedSecondLevelUnwindPage(
7978
StringRef PageData, uint32_t FunctionBase,
7979
const SmallVectorImpl<uint32_t> &CommonEncodings) {
7980
ptrdiff_t Pos = 0;
7981
uint32_t Kind = readNext<uint32_t>(PageData, Pos);
7982
(void)Kind;
7983
assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");
7984
7985
uint32_t NumCommonEncodings = CommonEncodings.size();
7986
uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7987
uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
7988
7989
uint16_t PageEncodingsStart = readNext<uint16_t>(PageData, Pos);
7990
uint16_t NumPageEncodings = readNext<uint16_t>(PageData, Pos);
7991
SmallVector<uint32_t, 64> PageEncodings;
7992
if (NumPageEncodings) {
7993
outs() << " Page encodings: (count = " << NumPageEncodings << ")\n";
7994
Pos = PageEncodingsStart;
7995
for (unsigned i = 0; i < NumPageEncodings; ++i) {
7996
uint32_t Encoding = readNext<uint32_t>(PageData, Pos);
7997
PageEncodings.push_back(Encoding);
7998
outs() << " encoding[" << (i + NumCommonEncodings)
7999
<< "]: " << format("0x%08" PRIx32, Encoding) << '\n';
8000
}
8001
}
8002
8003
Pos = EntriesStart;
8004
for (unsigned i = 0; i < NumEntries; ++i) {
8005
uint32_t Entry = readNext<uint32_t>(PageData, Pos);
8006
uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
8007
uint32_t EncodingIdx = Entry >> 24;
8008
8009
uint32_t Encoding;
8010
if (EncodingIdx < NumCommonEncodings)
8011
Encoding = CommonEncodings[EncodingIdx];
8012
else
8013
Encoding = PageEncodings[EncodingIdx - NumCommonEncodings];
8014
8015
outs() << " [" << i << "]: "
8016
<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)
8017
<< ", "
8018
<< "encoding[" << EncodingIdx
8019
<< "]=" << format("0x%08" PRIx32, Encoding) << '\n';
8020
}
8021
}
8022
8023
static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
8024
std::map<uint64_t, SymbolRef> &Symbols,
8025
const SectionRef &UnwindInfo) {
8026
8027
if (!Obj->isLittleEndian()) {
8028
outs() << "Skipping big-endian __unwind_info section\n";
8029
return;
8030
}
8031
8032
outs() << "Contents of __unwind_info section:\n";
8033
8034
StringRef Contents =
8035
unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());
8036
ptrdiff_t Pos = 0;
8037
8038
//===----------------------------------
8039
// Section header
8040
//===----------------------------------
8041
8042
uint32_t Version = readNext<uint32_t>(Contents, Pos);
8043
outs() << " Version: "
8044
<< format("0x%" PRIx32, Version) << '\n';
8045
if (Version != 1) {
8046
outs() << " Skipping section with unknown version\n";
8047
return;
8048
}
8049
8050
uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);
8051
outs() << " Common encodings array section offset: "
8052
<< format("0x%" PRIx32, CommonEncodingsStart) << '\n';
8053
uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);
8054
outs() << " Number of common encodings in array: "
8055
<< format("0x%" PRIx32, NumCommonEncodings) << '\n';
8056
8057
uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);
8058
outs() << " Personality function array section offset: "
8059
<< format("0x%" PRIx32, PersonalitiesStart) << '\n';
8060
uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);
8061
outs() << " Number of personality functions in array: "
8062
<< format("0x%" PRIx32, NumPersonalities) << '\n';
8063
8064
uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);
8065
outs() << " Index array section offset: "
8066
<< format("0x%" PRIx32, IndicesStart) << '\n';
8067
uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);
8068
outs() << " Number of indices in array: "
8069
<< format("0x%" PRIx32, NumIndices) << '\n';
8070
8071
//===----------------------------------
8072
// A shared list of common encodings
8073
//===----------------------------------
8074
8075
// These occupy indices in the range [0, N] whenever an encoding is referenced
8076
// from a compressed 2nd level index table. In practice the linker only
8077
// creates ~128 of these, so that indices are available to embed encodings in
8078
// the 2nd level index.
8079
8080
SmallVector<uint32_t, 64> CommonEncodings;
8081
outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
8082
Pos = CommonEncodingsStart;
8083
for (unsigned i = 0; i < NumCommonEncodings; ++i) {
8084
uint32_t Encoding = readNext<uint32_t>(Contents, Pos);
8085
CommonEncodings.push_back(Encoding);
8086
8087
outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)
8088
<< '\n';
8089
}
8090
8091
//===----------------------------------
8092
// Personality functions used in this executable
8093
//===----------------------------------
8094
8095
// There should be only a handful of these (one per source language,
8096
// roughly). Particularly since they only get 2 bits in the compact encoding.
8097
8098
outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
8099
Pos = PersonalitiesStart;
8100
for (unsigned i = 0; i < NumPersonalities; ++i) {
8101
uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);
8102
outs() << " personality[" << i + 1
8103
<< "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';
8104
}
8105
8106
//===----------------------------------
8107
// The level 1 index entries
8108
//===----------------------------------
8109
8110
// These specify an approximate place to start searching for the more detailed
8111
// information, sorted by PC.
8112
8113
struct IndexEntry {
8114
uint32_t FunctionOffset;
8115
uint32_t SecondLevelPageStart;
8116
uint32_t LSDAStart;
8117
};
8118
8119
SmallVector<IndexEntry, 4> IndexEntries;
8120
8121
outs() << " Top level indices: (count = " << NumIndices << ")\n";
8122
Pos = IndicesStart;
8123
for (unsigned i = 0; i < NumIndices; ++i) {
8124
IndexEntry Entry;
8125
8126
Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);
8127
Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);
8128
Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);
8129
IndexEntries.push_back(Entry);
8130
8131
outs() << " [" << i << "]: "
8132
<< "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)
8133
<< ", "
8134
<< "2nd level page offset="
8135
<< format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "
8136
<< "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';
8137
}
8138
8139
//===----------------------------------
8140
// Next come the LSDA tables
8141
//===----------------------------------
8142
8143
// The LSDA layout is rather implicit: it's a contiguous array of entries from
8144
// the first top-level index's LSDAOffset to the last (sentinel).
8145
8146
outs() << " LSDA descriptors:\n";
8147
Pos = IndexEntries[0].LSDAStart;
8148
const uint32_t LSDASize = 2 * sizeof(uint32_t);
8149
int NumLSDAs =
8150
(IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;
8151
8152
for (int i = 0; i < NumLSDAs; ++i) {
8153
uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);
8154
uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);
8155
outs() << " [" << i << "]: "
8156
<< "function offset=" << format("0x%08" PRIx32, FunctionOffset)
8157
<< ", "
8158
<< "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';
8159
}
8160
8161
//===----------------------------------
8162
// Finally, the 2nd level indices
8163
//===----------------------------------
8164
8165
// Generally these are 4K in size, and have 2 possible forms:
8166
// + Regular stores up to 511 entries with disparate encodings
8167
// + Compressed stores up to 1021 entries if few enough compact encoding
8168
// values are used.
8169
outs() << " Second level indices:\n";
8170
for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
8171
// The final sentinel top-level index has no associated 2nd level page
8172
if (IndexEntries[i].SecondLevelPageStart == 0)
8173
break;
8174
8175
outs() << " Second level index[" << i << "]: "
8176
<< "offset in section="
8177
<< format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)
8178
<< ", "
8179
<< "base function offset="
8180
<< format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';
8181
8182
Pos = IndexEntries[i].SecondLevelPageStart;
8183
if (Pos + sizeof(uint32_t) > Contents.size()) {
8184
outs() << "warning: invalid offset for second level page: " << Pos << '\n';
8185
continue;
8186
}
8187
8188
uint32_t Kind =
8189
*reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);
8190
if (Kind == 2)
8191
printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));
8192
else if (Kind == 3)
8193
printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),
8194
IndexEntries[i].FunctionOffset,
8195
CommonEncodings);
8196
else
8197
outs() << " Skipping 2nd level page with unknown kind " << Kind
8198
<< '\n';
8199
}
8200
}
8201
8202
void objdump::printMachOUnwindInfo(const MachOObjectFile *Obj) {
8203
std::map<uint64_t, SymbolRef> Symbols;
8204
for (const SymbolRef &SymRef : Obj->symbols()) {
8205
// Discard any undefined or absolute symbols. They're not going to take part
8206
// in the convenience lookup for unwind info and just take up resources.
8207
auto SectOrErr = SymRef.getSection();
8208
if (!SectOrErr) {
8209
// TODO: Actually report errors helpfully.
8210
consumeError(SectOrErr.takeError());
8211
continue;
8212
}
8213
section_iterator Section = *SectOrErr;
8214
if (Section == Obj->section_end())
8215
continue;
8216
8217
uint64_t Addr = cantFail(SymRef.getValue());
8218
Symbols.insert(std::make_pair(Addr, SymRef));
8219
}
8220
8221
for (const SectionRef &Section : Obj->sections()) {
8222
StringRef SectName;
8223
if (Expected<StringRef> NameOrErr = Section.getName())
8224
SectName = *NameOrErr;
8225
else
8226
consumeError(NameOrErr.takeError());
8227
8228
if (SectName == "__compact_unwind")
8229
printMachOCompactUnwindSection(Obj, Symbols, Section);
8230
else if (SectName == "__unwind_info")
8231
printMachOUnwindInfoSection(Obj, Symbols, Section);
8232
}
8233
}
8234
8235
static void PrintMachHeader(uint32_t magic, uint32_t cputype,
8236
uint32_t cpusubtype, uint32_t filetype,
8237
uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
8238
bool verbose) {
8239
outs() << "Mach header\n";
8240
outs() << " magic cputype cpusubtype caps filetype ncmds "
8241
"sizeofcmds flags\n";
8242
if (verbose) {
8243
if (magic == MachO::MH_MAGIC)
8244
outs() << " MH_MAGIC";
8245
else if (magic == MachO::MH_MAGIC_64)
8246
outs() << "MH_MAGIC_64";
8247
else
8248
outs() << format(" 0x%08" PRIx32, magic);
8249
switch (cputype) {
8250
case MachO::CPU_TYPE_I386:
8251
outs() << " I386";
8252
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8253
case MachO::CPU_SUBTYPE_I386_ALL:
8254
outs() << " ALL";
8255
break;
8256
default:
8257
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8258
break;
8259
}
8260
break;
8261
case MachO::CPU_TYPE_X86_64:
8262
outs() << " X86_64";
8263
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8264
case MachO::CPU_SUBTYPE_X86_64_ALL:
8265
outs() << " ALL";
8266
break;
8267
case MachO::CPU_SUBTYPE_X86_64_H:
8268
outs() << " Haswell";
8269
break;
8270
default:
8271
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8272
break;
8273
}
8274
break;
8275
case MachO::CPU_TYPE_ARM:
8276
outs() << " ARM";
8277
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8278
case MachO::CPU_SUBTYPE_ARM_ALL:
8279
outs() << " ALL";
8280
break;
8281
case MachO::CPU_SUBTYPE_ARM_V4T:
8282
outs() << " V4T";
8283
break;
8284
case MachO::CPU_SUBTYPE_ARM_V5TEJ:
8285
outs() << " V5TEJ";
8286
break;
8287
case MachO::CPU_SUBTYPE_ARM_XSCALE:
8288
outs() << " XSCALE";
8289
break;
8290
case MachO::CPU_SUBTYPE_ARM_V6:
8291
outs() << " V6";
8292
break;
8293
case MachO::CPU_SUBTYPE_ARM_V6M:
8294
outs() << " V6M";
8295
break;
8296
case MachO::CPU_SUBTYPE_ARM_V7:
8297
outs() << " V7";
8298
break;
8299
case MachO::CPU_SUBTYPE_ARM_V7EM:
8300
outs() << " V7EM";
8301
break;
8302
case MachO::CPU_SUBTYPE_ARM_V7K:
8303
outs() << " V7K";
8304
break;
8305
case MachO::CPU_SUBTYPE_ARM_V7M:
8306
outs() << " V7M";
8307
break;
8308
case MachO::CPU_SUBTYPE_ARM_V7S:
8309
outs() << " V7S";
8310
break;
8311
default:
8312
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8313
break;
8314
}
8315
break;
8316
case MachO::CPU_TYPE_ARM64:
8317
outs() << " ARM64";
8318
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8319
case MachO::CPU_SUBTYPE_ARM64_ALL:
8320
outs() << " ALL";
8321
break;
8322
case MachO::CPU_SUBTYPE_ARM64_V8:
8323
outs() << " V8";
8324
break;
8325
case MachO::CPU_SUBTYPE_ARM64E:
8326
outs() << " E";
8327
break;
8328
default:
8329
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8330
break;
8331
}
8332
break;
8333
case MachO::CPU_TYPE_ARM64_32:
8334
outs() << " ARM64_32";
8335
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8336
case MachO::CPU_SUBTYPE_ARM64_32_V8:
8337
outs() << " V8";
8338
break;
8339
default:
8340
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8341
break;
8342
}
8343
break;
8344
case MachO::CPU_TYPE_POWERPC:
8345
outs() << " PPC";
8346
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8347
case MachO::CPU_SUBTYPE_POWERPC_ALL:
8348
outs() << " ALL";
8349
break;
8350
default:
8351
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8352
break;
8353
}
8354
break;
8355
case MachO::CPU_TYPE_POWERPC64:
8356
outs() << " PPC64";
8357
switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8358
case MachO::CPU_SUBTYPE_POWERPC_ALL:
8359
outs() << " ALL";
8360
break;
8361
default:
8362
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8363
break;
8364
}
8365
break;
8366
default:
8367
outs() << format(" %7d", cputype);
8368
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8369
break;
8370
}
8371
if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {
8372
outs() << " LIB64";
8373
} else {
8374
outs() << format(" 0x%02" PRIx32,
8375
(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8376
}
8377
switch (filetype) {
8378
case MachO::MH_OBJECT:
8379
outs() << " OBJECT";
8380
break;
8381
case MachO::MH_EXECUTE:
8382
outs() << " EXECUTE";
8383
break;
8384
case MachO::MH_FVMLIB:
8385
outs() << " FVMLIB";
8386
break;
8387
case MachO::MH_CORE:
8388
outs() << " CORE";
8389
break;
8390
case MachO::MH_PRELOAD:
8391
outs() << " PRELOAD";
8392
break;
8393
case MachO::MH_DYLIB:
8394
outs() << " DYLIB";
8395
break;
8396
case MachO::MH_DYLIB_STUB:
8397
outs() << " DYLIB_STUB";
8398
break;
8399
case MachO::MH_DYLINKER:
8400
outs() << " DYLINKER";
8401
break;
8402
case MachO::MH_BUNDLE:
8403
outs() << " BUNDLE";
8404
break;
8405
case MachO::MH_DSYM:
8406
outs() << " DSYM";
8407
break;
8408
case MachO::MH_KEXT_BUNDLE:
8409
outs() << " KEXTBUNDLE";
8410
break;
8411
case MachO::MH_FILESET:
8412
outs() << " FILESET";
8413
break;
8414
default:
8415
outs() << format(" %10u", filetype);
8416
break;
8417
}
8418
outs() << format(" %5u", ncmds);
8419
outs() << format(" %10u", sizeofcmds);
8420
uint32_t f = flags;
8421
if (f & MachO::MH_NOUNDEFS) {
8422
outs() << " NOUNDEFS";
8423
f &= ~MachO::MH_NOUNDEFS;
8424
}
8425
if (f & MachO::MH_INCRLINK) {
8426
outs() << " INCRLINK";
8427
f &= ~MachO::MH_INCRLINK;
8428
}
8429
if (f & MachO::MH_DYLDLINK) {
8430
outs() << " DYLDLINK";
8431
f &= ~MachO::MH_DYLDLINK;
8432
}
8433
if (f & MachO::MH_BINDATLOAD) {
8434
outs() << " BINDATLOAD";
8435
f &= ~MachO::MH_BINDATLOAD;
8436
}
8437
if (f & MachO::MH_PREBOUND) {
8438
outs() << " PREBOUND";
8439
f &= ~MachO::MH_PREBOUND;
8440
}
8441
if (f & MachO::MH_SPLIT_SEGS) {
8442
outs() << " SPLIT_SEGS";
8443
f &= ~MachO::MH_SPLIT_SEGS;
8444
}
8445
if (f & MachO::MH_LAZY_INIT) {
8446
outs() << " LAZY_INIT";
8447
f &= ~MachO::MH_LAZY_INIT;
8448
}
8449
if (f & MachO::MH_TWOLEVEL) {
8450
outs() << " TWOLEVEL";
8451
f &= ~MachO::MH_TWOLEVEL;
8452
}
8453
if (f & MachO::MH_FORCE_FLAT) {
8454
outs() << " FORCE_FLAT";
8455
f &= ~MachO::MH_FORCE_FLAT;
8456
}
8457
if (f & MachO::MH_NOMULTIDEFS) {
8458
outs() << " NOMULTIDEFS";
8459
f &= ~MachO::MH_NOMULTIDEFS;
8460
}
8461
if (f & MachO::MH_NOFIXPREBINDING) {
8462
outs() << " NOFIXPREBINDING";
8463
f &= ~MachO::MH_NOFIXPREBINDING;
8464
}
8465
if (f & MachO::MH_PREBINDABLE) {
8466
outs() << " PREBINDABLE";
8467
f &= ~MachO::MH_PREBINDABLE;
8468
}
8469
if (f & MachO::MH_ALLMODSBOUND) {
8470
outs() << " ALLMODSBOUND";
8471
f &= ~MachO::MH_ALLMODSBOUND;
8472
}
8473
if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
8474
outs() << " SUBSECTIONS_VIA_SYMBOLS";
8475
f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
8476
}
8477
if (f & MachO::MH_CANONICAL) {
8478
outs() << " CANONICAL";
8479
f &= ~MachO::MH_CANONICAL;
8480
}
8481
if (f & MachO::MH_WEAK_DEFINES) {
8482
outs() << " WEAK_DEFINES";
8483
f &= ~MachO::MH_WEAK_DEFINES;
8484
}
8485
if (f & MachO::MH_BINDS_TO_WEAK) {
8486
outs() << " BINDS_TO_WEAK";
8487
f &= ~MachO::MH_BINDS_TO_WEAK;
8488
}
8489
if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
8490
outs() << " ALLOW_STACK_EXECUTION";
8491
f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
8492
}
8493
if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
8494
outs() << " DEAD_STRIPPABLE_DYLIB";
8495
f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
8496
}
8497
if (f & MachO::MH_PIE) {
8498
outs() << " PIE";
8499
f &= ~MachO::MH_PIE;
8500
}
8501
if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
8502
outs() << " NO_REEXPORTED_DYLIBS";
8503
f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
8504
}
8505
if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
8506
outs() << " MH_HAS_TLV_DESCRIPTORS";
8507
f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
8508
}
8509
if (f & MachO::MH_NO_HEAP_EXECUTION) {
8510
outs() << " MH_NO_HEAP_EXECUTION";
8511
f &= ~MachO::MH_NO_HEAP_EXECUTION;
8512
}
8513
if (f & MachO::MH_APP_EXTENSION_SAFE) {
8514
outs() << " APP_EXTENSION_SAFE";
8515
f &= ~MachO::MH_APP_EXTENSION_SAFE;
8516
}
8517
if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
8518
outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
8519
f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
8520
}
8521
if (f != 0 || flags == 0)
8522
outs() << format(" 0x%08" PRIx32, f);
8523
} else {
8524
outs() << format(" 0x%08" PRIx32, magic);
8525
outs() << format(" %7d", cputype);
8526
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8527
outs() << format(" 0x%02" PRIx32,
8528
(cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8529
outs() << format(" %10u", filetype);
8530
outs() << format(" %5u", ncmds);
8531
outs() << format(" %10u", sizeofcmds);
8532
outs() << format(" 0x%08" PRIx32, flags);
8533
}
8534
outs() << "\n";
8535
}
8536
8537
static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
8538
StringRef SegName, uint64_t vmaddr,
8539
uint64_t vmsize, uint64_t fileoff,
8540
uint64_t filesize, uint32_t maxprot,
8541
uint32_t initprot, uint32_t nsects,
8542
uint32_t flags, uint32_t object_size,
8543
bool verbose) {
8544
uint64_t expected_cmdsize;
8545
if (cmd == MachO::LC_SEGMENT) {
8546
outs() << " cmd LC_SEGMENT\n";
8547
expected_cmdsize = nsects;
8548
expected_cmdsize *= sizeof(struct MachO::section);
8549
expected_cmdsize += sizeof(struct MachO::segment_command);
8550
} else {
8551
outs() << " cmd LC_SEGMENT_64\n";
8552
expected_cmdsize = nsects;
8553
expected_cmdsize *= sizeof(struct MachO::section_64);
8554
expected_cmdsize += sizeof(struct MachO::segment_command_64);
8555
}
8556
outs() << " cmdsize " << cmdsize;
8557
if (cmdsize != expected_cmdsize)
8558
outs() << " Inconsistent size\n";
8559
else
8560
outs() << "\n";
8561
outs() << " segname " << SegName << "\n";
8562
if (cmd == MachO::LC_SEGMENT_64) {
8563
outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";
8564
outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";
8565
} else {
8566
outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";
8567
outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";
8568
}
8569
outs() << " fileoff " << fileoff;
8570
if (fileoff > object_size)
8571
outs() << " (past end of file)\n";
8572
else
8573
outs() << "\n";
8574
outs() << " filesize " << filesize;
8575
if (fileoff + filesize > object_size)
8576
outs() << " (past end of file)\n";
8577
else
8578
outs() << "\n";
8579
if (verbose) {
8580
if ((maxprot &
8581
~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8582
MachO::VM_PROT_EXECUTE)) != 0)
8583
outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";
8584
else {
8585
outs() << " maxprot ";
8586
outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");
8587
outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8588
outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8589
}
8590
if ((initprot &
8591
~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8592
MachO::VM_PROT_EXECUTE)) != 0)
8593
outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";
8594
else {
8595
outs() << " initprot ";
8596
outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");
8597
outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8598
outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
8599
}
8600
} else {
8601
outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";
8602
outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";
8603
}
8604
outs() << " nsects " << nsects << "\n";
8605
if (verbose) {
8606
outs() << " flags";
8607
if (flags == 0)
8608
outs() << " (none)\n";
8609
else {
8610
if (flags & MachO::SG_HIGHVM) {
8611
outs() << " HIGHVM";
8612
flags &= ~MachO::SG_HIGHVM;
8613
}
8614
if (flags & MachO::SG_FVMLIB) {
8615
outs() << " FVMLIB";
8616
flags &= ~MachO::SG_FVMLIB;
8617
}
8618
if (flags & MachO::SG_NORELOC) {
8619
outs() << " NORELOC";
8620
flags &= ~MachO::SG_NORELOC;
8621
}
8622
if (flags & MachO::SG_PROTECTED_VERSION_1) {
8623
outs() << " PROTECTED_VERSION_1";
8624
flags &= ~MachO::SG_PROTECTED_VERSION_1;
8625
}
8626
if (flags & MachO::SG_READ_ONLY) {
8627
// Apple's otool prints the SG_ prefix for this flag, but not for the
8628
// others.
8629
outs() << " SG_READ_ONLY";
8630
flags &= ~MachO::SG_READ_ONLY;
8631
}
8632
if (flags)
8633
outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
8634
else
8635
outs() << "\n";
8636
}
8637
} else {
8638
outs() << " flags " << format("0x%" PRIx32, flags) << "\n";
8639
}
8640
}
8641
8642
static void PrintSection(const char *sectname, const char *segname,
8643
uint64_t addr, uint64_t size, uint32_t offset,
8644
uint32_t align, uint32_t reloff, uint32_t nreloc,
8645
uint32_t flags, uint32_t reserved1, uint32_t reserved2,
8646
uint32_t cmd, const char *sg_segname,
8647
uint32_t filetype, uint32_t object_size,
8648
bool verbose) {
8649
outs() << "Section\n";
8650
outs() << " sectname " << format("%.16s\n", sectname);
8651
outs() << " segname " << format("%.16s", segname);
8652
if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)
8653
outs() << " (does not match segment)\n";
8654
else
8655
outs() << "\n";
8656
if (cmd == MachO::LC_SEGMENT_64) {
8657
outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";
8658
outs() << " size " << format("0x%016" PRIx64, size);
8659
} else {
8660
outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";
8661
outs() << " size " << format("0x%08" PRIx64, size);
8662
}
8663
if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
8664
outs() << " (past end of file)\n";
8665
else
8666
outs() << "\n";
8667
outs() << " offset " << offset;
8668
if (offset > object_size)
8669
outs() << " (past end of file)\n";
8670
else
8671
outs() << "\n";
8672
uint32_t align_shifted = 1 << align;
8673
outs() << " align 2^" << align << " (" << align_shifted << ")\n";
8674
outs() << " reloff " << reloff;
8675
if (reloff > object_size)
8676
outs() << " (past end of file)\n";
8677
else
8678
outs() << "\n";
8679
outs() << " nreloc " << nreloc;
8680
if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
8681
outs() << " (past end of file)\n";
8682
else
8683
outs() << "\n";
8684
uint32_t section_type = flags & MachO::SECTION_TYPE;
8685
if (verbose) {
8686
outs() << " type";
8687
if (section_type == MachO::S_REGULAR)
8688
outs() << " S_REGULAR\n";
8689
else if (section_type == MachO::S_ZEROFILL)
8690
outs() << " S_ZEROFILL\n";
8691
else if (section_type == MachO::S_CSTRING_LITERALS)
8692
outs() << " S_CSTRING_LITERALS\n";
8693
else if (section_type == MachO::S_4BYTE_LITERALS)
8694
outs() << " S_4BYTE_LITERALS\n";
8695
else if (section_type == MachO::S_8BYTE_LITERALS)
8696
outs() << " S_8BYTE_LITERALS\n";
8697
else if (section_type == MachO::S_16BYTE_LITERALS)
8698
outs() << " S_16BYTE_LITERALS\n";
8699
else if (section_type == MachO::S_LITERAL_POINTERS)
8700
outs() << " S_LITERAL_POINTERS\n";
8701
else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
8702
outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
8703
else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
8704
outs() << " S_LAZY_SYMBOL_POINTERS\n";
8705
else if (section_type == MachO::S_SYMBOL_STUBS)
8706
outs() << " S_SYMBOL_STUBS\n";
8707
else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
8708
outs() << " S_MOD_INIT_FUNC_POINTERS\n";
8709
else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
8710
outs() << " S_MOD_TERM_FUNC_POINTERS\n";
8711
else if (section_type == MachO::S_COALESCED)
8712
outs() << " S_COALESCED\n";
8713
else if (section_type == MachO::S_INTERPOSING)
8714
outs() << " S_INTERPOSING\n";
8715
else if (section_type == MachO::S_DTRACE_DOF)
8716
outs() << " S_DTRACE_DOF\n";
8717
else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
8718
outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
8719
else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
8720
outs() << " S_THREAD_LOCAL_REGULAR\n";
8721
else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
8722
outs() << " S_THREAD_LOCAL_ZEROFILL\n";
8723
else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
8724
outs() << " S_THREAD_LOCAL_VARIABLES\n";
8725
else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8726
outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
8727
else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
8728
outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
8729
else if (section_type == MachO::S_INIT_FUNC_OFFSETS)
8730
outs() << " S_INIT_FUNC_OFFSETS\n";
8731
else
8732
outs() << format("0x%08" PRIx32, section_type) << "\n";
8733
outs() << "attributes";
8734
uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
8735
if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
8736
outs() << " PURE_INSTRUCTIONS";
8737
if (section_attributes & MachO::S_ATTR_NO_TOC)
8738
outs() << " NO_TOC";
8739
if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
8740
outs() << " STRIP_STATIC_SYMS";
8741
if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
8742
outs() << " NO_DEAD_STRIP";
8743
if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
8744
outs() << " LIVE_SUPPORT";
8745
if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
8746
outs() << " SELF_MODIFYING_CODE";
8747
if (section_attributes & MachO::S_ATTR_DEBUG)
8748
outs() << " DEBUG";
8749
if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
8750
outs() << " SOME_INSTRUCTIONS";
8751
if (section_attributes & MachO::S_ATTR_EXT_RELOC)
8752
outs() << " EXT_RELOC";
8753
if (section_attributes & MachO::S_ATTR_LOC_RELOC)
8754
outs() << " LOC_RELOC";
8755
if (section_attributes == 0)
8756
outs() << " (none)";
8757
outs() << "\n";
8758
} else
8759
outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";
8760
outs() << " reserved1 " << reserved1;
8761
if (section_type == MachO::S_SYMBOL_STUBS ||
8762
section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
8763
section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
8764
section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
8765
section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8766
outs() << " (index into indirect symbol table)\n";
8767
else
8768
outs() << "\n";
8769
outs() << " reserved2 " << reserved2;
8770
if (section_type == MachO::S_SYMBOL_STUBS)
8771
outs() << " (size of stubs)\n";
8772
else
8773
outs() << "\n";
8774
}
8775
8776
static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
8777
uint32_t object_size) {
8778
outs() << " cmd LC_SYMTAB\n";
8779
outs() << " cmdsize " << st.cmdsize;
8780
if (st.cmdsize != sizeof(struct MachO::symtab_command))
8781
outs() << " Incorrect size\n";
8782
else
8783
outs() << "\n";
8784
outs() << " symoff " << st.symoff;
8785
if (st.symoff > object_size)
8786
outs() << " (past end of file)\n";
8787
else
8788
outs() << "\n";
8789
outs() << " nsyms " << st.nsyms;
8790
uint64_t big_size;
8791
if (Is64Bit) {
8792
big_size = st.nsyms;
8793
big_size *= sizeof(struct MachO::nlist_64);
8794
big_size += st.symoff;
8795
if (big_size > object_size)
8796
outs() << " (past end of file)\n";
8797
else
8798
outs() << "\n";
8799
} else {
8800
big_size = st.nsyms;
8801
big_size *= sizeof(struct MachO::nlist);
8802
big_size += st.symoff;
8803
if (big_size > object_size)
8804
outs() << " (past end of file)\n";
8805
else
8806
outs() << "\n";
8807
}
8808
outs() << " stroff " << st.stroff;
8809
if (st.stroff > object_size)
8810
outs() << " (past end of file)\n";
8811
else
8812
outs() << "\n";
8813
outs() << " strsize " << st.strsize;
8814
big_size = st.stroff;
8815
big_size += st.strsize;
8816
if (big_size > object_size)
8817
outs() << " (past end of file)\n";
8818
else
8819
outs() << "\n";
8820
}
8821
8822
static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
8823
uint32_t nsyms, uint32_t object_size,
8824
bool Is64Bit) {
8825
outs() << " cmd LC_DYSYMTAB\n";
8826
outs() << " cmdsize " << dyst.cmdsize;
8827
if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
8828
outs() << " Incorrect size\n";
8829
else
8830
outs() << "\n";
8831
outs() << " ilocalsym " << dyst.ilocalsym;
8832
if (dyst.ilocalsym > nsyms)
8833
outs() << " (greater than the number of symbols)\n";
8834
else
8835
outs() << "\n";
8836
outs() << " nlocalsym " << dyst.nlocalsym;
8837
uint64_t big_size;
8838
big_size = dyst.ilocalsym;
8839
big_size += dyst.nlocalsym;
8840
if (big_size > nsyms)
8841
outs() << " (past the end of the symbol table)\n";
8842
else
8843
outs() << "\n";
8844
outs() << " iextdefsym " << dyst.iextdefsym;
8845
if (dyst.iextdefsym > nsyms)
8846
outs() << " (greater than the number of symbols)\n";
8847
else
8848
outs() << "\n";
8849
outs() << " nextdefsym " << dyst.nextdefsym;
8850
big_size = dyst.iextdefsym;
8851
big_size += dyst.nextdefsym;
8852
if (big_size > nsyms)
8853
outs() << " (past the end of the symbol table)\n";
8854
else
8855
outs() << "\n";
8856
outs() << " iundefsym " << dyst.iundefsym;
8857
if (dyst.iundefsym > nsyms)
8858
outs() << " (greater than the number of symbols)\n";
8859
else
8860
outs() << "\n";
8861
outs() << " nundefsym " << dyst.nundefsym;
8862
big_size = dyst.iundefsym;
8863
big_size += dyst.nundefsym;
8864
if (big_size > nsyms)
8865
outs() << " (past the end of the symbol table)\n";
8866
else
8867
outs() << "\n";
8868
outs() << " tocoff " << dyst.tocoff;
8869
if (dyst.tocoff > object_size)
8870
outs() << " (past end of file)\n";
8871
else
8872
outs() << "\n";
8873
outs() << " ntoc " << dyst.ntoc;
8874
big_size = dyst.ntoc;
8875
big_size *= sizeof(struct MachO::dylib_table_of_contents);
8876
big_size += dyst.tocoff;
8877
if (big_size > object_size)
8878
outs() << " (past end of file)\n";
8879
else
8880
outs() << "\n";
8881
outs() << " modtaboff " << dyst.modtaboff;
8882
if (dyst.modtaboff > object_size)
8883
outs() << " (past end of file)\n";
8884
else
8885
outs() << "\n";
8886
outs() << " nmodtab " << dyst.nmodtab;
8887
uint64_t modtabend;
8888
if (Is64Bit) {
8889
modtabend = dyst.nmodtab;
8890
modtabend *= sizeof(struct MachO::dylib_module_64);
8891
modtabend += dyst.modtaboff;
8892
} else {
8893
modtabend = dyst.nmodtab;
8894
modtabend *= sizeof(struct MachO::dylib_module);
8895
modtabend += dyst.modtaboff;
8896
}
8897
if (modtabend > object_size)
8898
outs() << " (past end of file)\n";
8899
else
8900
outs() << "\n";
8901
outs() << " extrefsymoff " << dyst.extrefsymoff;
8902
if (dyst.extrefsymoff > object_size)
8903
outs() << " (past end of file)\n";
8904
else
8905
outs() << "\n";
8906
outs() << " nextrefsyms " << dyst.nextrefsyms;
8907
big_size = dyst.nextrefsyms;
8908
big_size *= sizeof(struct MachO::dylib_reference);
8909
big_size += dyst.extrefsymoff;
8910
if (big_size > object_size)
8911
outs() << " (past end of file)\n";
8912
else
8913
outs() << "\n";
8914
outs() << " indirectsymoff " << dyst.indirectsymoff;
8915
if (dyst.indirectsymoff > object_size)
8916
outs() << " (past end of file)\n";
8917
else
8918
outs() << "\n";
8919
outs() << " nindirectsyms " << dyst.nindirectsyms;
8920
big_size = dyst.nindirectsyms;
8921
big_size *= sizeof(uint32_t);
8922
big_size += dyst.indirectsymoff;
8923
if (big_size > object_size)
8924
outs() << " (past end of file)\n";
8925
else
8926
outs() << "\n";
8927
outs() << " extreloff " << dyst.extreloff;
8928
if (dyst.extreloff > object_size)
8929
outs() << " (past end of file)\n";
8930
else
8931
outs() << "\n";
8932
outs() << " nextrel " << dyst.nextrel;
8933
big_size = dyst.nextrel;
8934
big_size *= sizeof(struct MachO::relocation_info);
8935
big_size += dyst.extreloff;
8936
if (big_size > object_size)
8937
outs() << " (past end of file)\n";
8938
else
8939
outs() << "\n";
8940
outs() << " locreloff " << dyst.locreloff;
8941
if (dyst.locreloff > object_size)
8942
outs() << " (past end of file)\n";
8943
else
8944
outs() << "\n";
8945
outs() << " nlocrel " << dyst.nlocrel;
8946
big_size = dyst.nlocrel;
8947
big_size *= sizeof(struct MachO::relocation_info);
8948
big_size += dyst.locreloff;
8949
if (big_size > object_size)
8950
outs() << " (past end of file)\n";
8951
else
8952
outs() << "\n";
8953
}
8954
8955
static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
8956
uint32_t object_size) {
8957
if (dc.cmd == MachO::LC_DYLD_INFO)
8958
outs() << " cmd LC_DYLD_INFO\n";
8959
else
8960
outs() << " cmd LC_DYLD_INFO_ONLY\n";
8961
outs() << " cmdsize " << dc.cmdsize;
8962
if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
8963
outs() << " Incorrect size\n";
8964
else
8965
outs() << "\n";
8966
outs() << " rebase_off " << dc.rebase_off;
8967
if (dc.rebase_off > object_size)
8968
outs() << " (past end of file)\n";
8969
else
8970
outs() << "\n";
8971
outs() << " rebase_size " << dc.rebase_size;
8972
uint64_t big_size;
8973
big_size = dc.rebase_off;
8974
big_size += dc.rebase_size;
8975
if (big_size > object_size)
8976
outs() << " (past end of file)\n";
8977
else
8978
outs() << "\n";
8979
outs() << " bind_off " << dc.bind_off;
8980
if (dc.bind_off > object_size)
8981
outs() << " (past end of file)\n";
8982
else
8983
outs() << "\n";
8984
outs() << " bind_size " << dc.bind_size;
8985
big_size = dc.bind_off;
8986
big_size += dc.bind_size;
8987
if (big_size > object_size)
8988
outs() << " (past end of file)\n";
8989
else
8990
outs() << "\n";
8991
outs() << " weak_bind_off " << dc.weak_bind_off;
8992
if (dc.weak_bind_off > object_size)
8993
outs() << " (past end of file)\n";
8994
else
8995
outs() << "\n";
8996
outs() << " weak_bind_size " << dc.weak_bind_size;
8997
big_size = dc.weak_bind_off;
8998
big_size += dc.weak_bind_size;
8999
if (big_size > object_size)
9000
outs() << " (past end of file)\n";
9001
else
9002
outs() << "\n";
9003
outs() << " lazy_bind_off " << dc.lazy_bind_off;
9004
if (dc.lazy_bind_off > object_size)
9005
outs() << " (past end of file)\n";
9006
else
9007
outs() << "\n";
9008
outs() << " lazy_bind_size " << dc.lazy_bind_size;
9009
big_size = dc.lazy_bind_off;
9010
big_size += dc.lazy_bind_size;
9011
if (big_size > object_size)
9012
outs() << " (past end of file)\n";
9013
else
9014
outs() << "\n";
9015
outs() << " export_off " << dc.export_off;
9016
if (dc.export_off > object_size)
9017
outs() << " (past end of file)\n";
9018
else
9019
outs() << "\n";
9020
outs() << " export_size " << dc.export_size;
9021
big_size = dc.export_off;
9022
big_size += dc.export_size;
9023
if (big_size > object_size)
9024
outs() << " (past end of file)\n";
9025
else
9026
outs() << "\n";
9027
}
9028
9029
static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
9030
const char *Ptr) {
9031
if (dyld.cmd == MachO::LC_ID_DYLINKER)
9032
outs() << " cmd LC_ID_DYLINKER\n";
9033
else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
9034
outs() << " cmd LC_LOAD_DYLINKER\n";
9035
else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
9036
outs() << " cmd LC_DYLD_ENVIRONMENT\n";
9037
else
9038
outs() << " cmd ?(" << dyld.cmd << ")\n";
9039
outs() << " cmdsize " << dyld.cmdsize;
9040
if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
9041
outs() << " Incorrect size\n";
9042
else
9043
outs() << "\n";
9044
if (dyld.name >= dyld.cmdsize)
9045
outs() << " name ?(bad offset " << dyld.name << ")\n";
9046
else {
9047
const char *P = (const char *)(Ptr) + dyld.name;
9048
outs() << " name " << P << " (offset " << dyld.name << ")\n";
9049
}
9050
}
9051
9052
static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
9053
outs() << " cmd LC_UUID\n";
9054
outs() << " cmdsize " << uuid.cmdsize;
9055
if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
9056
outs() << " Incorrect size\n";
9057
else
9058
outs() << "\n";
9059
outs() << " uuid ";
9060
for (int i = 0; i < 16; ++i) {
9061
outs() << format("%02" PRIX32, uuid.uuid[i]);
9062
if (i == 3 || i == 5 || i == 7 || i == 9)
9063
outs() << "-";
9064
}
9065
outs() << "\n";
9066
}
9067
9068
static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
9069
outs() << " cmd LC_RPATH\n";
9070
outs() << " cmdsize " << rpath.cmdsize;
9071
if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
9072
outs() << " Incorrect size\n";
9073
else
9074
outs() << "\n";
9075
if (rpath.path >= rpath.cmdsize)
9076
outs() << " path ?(bad offset " << rpath.path << ")\n";
9077
else {
9078
const char *P = (const char *)(Ptr) + rpath.path;
9079
outs() << " path " << P << " (offset " << rpath.path << ")\n";
9080
}
9081
}
9082
9083
static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
9084
StringRef LoadCmdName;
9085
switch (vd.cmd) {
9086
case MachO::LC_VERSION_MIN_MACOSX:
9087
LoadCmdName = "LC_VERSION_MIN_MACOSX";
9088
break;
9089
case MachO::LC_VERSION_MIN_IPHONEOS:
9090
LoadCmdName = "LC_VERSION_MIN_IPHONEOS";
9091
break;
9092
case MachO::LC_VERSION_MIN_TVOS:
9093
LoadCmdName = "LC_VERSION_MIN_TVOS";
9094
break;
9095
case MachO::LC_VERSION_MIN_WATCHOS:
9096
LoadCmdName = "LC_VERSION_MIN_WATCHOS";
9097
break;
9098
default:
9099
llvm_unreachable("Unknown version min load command");
9100
}
9101
9102
outs() << " cmd " << LoadCmdName << '\n';
9103
outs() << " cmdsize " << vd.cmdsize;
9104
if (vd.cmdsize != sizeof(struct MachO::version_min_command))
9105
outs() << " Incorrect size\n";
9106
else
9107
outs() << "\n";
9108
outs() << " version "
9109
<< MachOObjectFile::getVersionMinMajor(vd, false) << "."
9110
<< MachOObjectFile::getVersionMinMinor(vd, false);
9111
uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);
9112
if (Update != 0)
9113
outs() << "." << Update;
9114
outs() << "\n";
9115
if (vd.sdk == 0)
9116
outs() << " sdk n/a";
9117
else {
9118
outs() << " sdk "
9119
<< MachOObjectFile::getVersionMinMajor(vd, true) << "."
9120
<< MachOObjectFile::getVersionMinMinor(vd, true);
9121
}
9122
Update = MachOObjectFile::getVersionMinUpdate(vd, true);
9123
if (Update != 0)
9124
outs() << "." << Update;
9125
outs() << "\n";
9126
}
9127
9128
static void PrintNoteLoadCommand(MachO::note_command Nt) {
9129
outs() << " cmd LC_NOTE\n";
9130
outs() << " cmdsize " << Nt.cmdsize;
9131
if (Nt.cmdsize != sizeof(struct MachO::note_command))
9132
outs() << " Incorrect size\n";
9133
else
9134
outs() << "\n";
9135
const char *d = Nt.data_owner;
9136
outs() << "data_owner " << format("%.16s\n", d);
9137
outs() << " offset " << Nt.offset << "\n";
9138
outs() << " size " << Nt.size << "\n";
9139
}
9140
9141
static void PrintBuildToolVersion(MachO::build_tool_version bv, bool verbose) {
9142
outs() << " tool ";
9143
if (verbose)
9144
outs() << MachOObjectFile::getBuildTool(bv.tool);
9145
else
9146
outs() << bv.tool;
9147
outs() << "\n";
9148
outs() << " version " << MachOObjectFile::getVersionString(bv.version)
9149
<< "\n";
9150
}
9151
9152
static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
9153
MachO::build_version_command bd,
9154
bool verbose) {
9155
outs() << " cmd LC_BUILD_VERSION\n";
9156
outs() << " cmdsize " << bd.cmdsize;
9157
if (bd.cmdsize !=
9158
sizeof(struct MachO::build_version_command) +
9159
bd.ntools * sizeof(struct MachO::build_tool_version))
9160
outs() << " Incorrect size\n";
9161
else
9162
outs() << "\n";
9163
outs() << " platform ";
9164
if (verbose)
9165
outs() << MachOObjectFile::getBuildPlatform(bd.platform);
9166
else
9167
outs() << bd.platform;
9168
outs() << "\n";
9169
if (bd.sdk)
9170
outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
9171
<< "\n";
9172
else
9173
outs() << " sdk n/a\n";
9174
outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
9175
<< "\n";
9176
outs() << " ntools " << bd.ntools << "\n";
9177
for (unsigned i = 0; i < bd.ntools; ++i) {
9178
MachO::build_tool_version bv = obj->getBuildToolVersion(i);
9179
PrintBuildToolVersion(bv, verbose);
9180
}
9181
}
9182
9183
static void PrintSourceVersionCommand(MachO::source_version_command sd) {
9184
outs() << " cmd LC_SOURCE_VERSION\n";
9185
outs() << " cmdsize " << sd.cmdsize;
9186
if (sd.cmdsize != sizeof(struct MachO::source_version_command))
9187
outs() << " Incorrect size\n";
9188
else
9189
outs() << "\n";
9190
uint64_t a = (sd.version >> 40) & 0xffffff;
9191
uint64_t b = (sd.version >> 30) & 0x3ff;
9192
uint64_t c = (sd.version >> 20) & 0x3ff;
9193
uint64_t d = (sd.version >> 10) & 0x3ff;
9194
uint64_t e = sd.version & 0x3ff;
9195
outs() << " version " << a << "." << b;
9196
if (e != 0)
9197
outs() << "." << c << "." << d << "." << e;
9198
else if (d != 0)
9199
outs() << "." << c << "." << d;
9200
else if (c != 0)
9201
outs() << "." << c;
9202
outs() << "\n";
9203
}
9204
9205
static void PrintEntryPointCommand(MachO::entry_point_command ep) {
9206
outs() << " cmd LC_MAIN\n";
9207
outs() << " cmdsize " << ep.cmdsize;
9208
if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
9209
outs() << " Incorrect size\n";
9210
else
9211
outs() << "\n";
9212
outs() << " entryoff " << ep.entryoff << "\n";
9213
outs() << " stacksize " << ep.stacksize << "\n";
9214
}
9215
9216
static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
9217
uint32_t object_size) {
9218
outs() << " cmd LC_ENCRYPTION_INFO\n";
9219
outs() << " cmdsize " << ec.cmdsize;
9220
if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
9221
outs() << " Incorrect size\n";
9222
else
9223
outs() << "\n";
9224
outs() << " cryptoff " << ec.cryptoff;
9225
if (ec.cryptoff > object_size)
9226
outs() << " (past end of file)\n";
9227
else
9228
outs() << "\n";
9229
outs() << " cryptsize " << ec.cryptsize;
9230
if (ec.cryptsize > object_size)
9231
outs() << " (past end of file)\n";
9232
else
9233
outs() << "\n";
9234
outs() << " cryptid " << ec.cryptid << "\n";
9235
}
9236
9237
static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
9238
uint32_t object_size) {
9239
outs() << " cmd LC_ENCRYPTION_INFO_64\n";
9240
outs() << " cmdsize " << ec.cmdsize;
9241
if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
9242
outs() << " Incorrect size\n";
9243
else
9244
outs() << "\n";
9245
outs() << " cryptoff " << ec.cryptoff;
9246
if (ec.cryptoff > object_size)
9247
outs() << " (past end of file)\n";
9248
else
9249
outs() << "\n";
9250
outs() << " cryptsize " << ec.cryptsize;
9251
if (ec.cryptsize > object_size)
9252
outs() << " (past end of file)\n";
9253
else
9254
outs() << "\n";
9255
outs() << " cryptid " << ec.cryptid << "\n";
9256
outs() << " pad " << ec.pad << "\n";
9257
}
9258
9259
static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
9260
const char *Ptr) {
9261
outs() << " cmd LC_LINKER_OPTION\n";
9262
outs() << " cmdsize " << lo.cmdsize;
9263
if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
9264
outs() << " Incorrect size\n";
9265
else
9266
outs() << "\n";
9267
outs() << " count " << lo.count << "\n";
9268
const char *string = Ptr + sizeof(struct MachO::linker_option_command);
9269
uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
9270
uint32_t i = 0;
9271
while (left > 0) {
9272
while (*string == '\0' && left > 0) {
9273
string++;
9274
left--;
9275
}
9276
if (left > 0) {
9277
i++;
9278
outs() << " string #" << i << " " << format("%.*s\n", left, string);
9279
uint32_t NullPos = StringRef(string, left).find('\0');
9280
uint32_t len = std::min(NullPos, left) + 1;
9281
string += len;
9282
left -= len;
9283
}
9284
}
9285
if (lo.count != i)
9286
outs() << " count " << lo.count << " does not match number of strings "
9287
<< i << "\n";
9288
}
9289
9290
static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
9291
const char *Ptr) {
9292
outs() << " cmd LC_SUB_FRAMEWORK\n";
9293
outs() << " cmdsize " << sub.cmdsize;
9294
if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
9295
outs() << " Incorrect size\n";
9296
else
9297
outs() << "\n";
9298
if (sub.umbrella < sub.cmdsize) {
9299
const char *P = Ptr + sub.umbrella;
9300
outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
9301
} else {
9302
outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
9303
}
9304
}
9305
9306
static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
9307
const char *Ptr) {
9308
outs() << " cmd LC_SUB_UMBRELLA\n";
9309
outs() << " cmdsize " << sub.cmdsize;
9310
if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
9311
outs() << " Incorrect size\n";
9312
else
9313
outs() << "\n";
9314
if (sub.sub_umbrella < sub.cmdsize) {
9315
const char *P = Ptr + sub.sub_umbrella;
9316
outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
9317
} else {
9318
outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
9319
}
9320
}
9321
9322
static void PrintSubLibraryCommand(MachO::sub_library_command sub,
9323
const char *Ptr) {
9324
outs() << " cmd LC_SUB_LIBRARY\n";
9325
outs() << " cmdsize " << sub.cmdsize;
9326
if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
9327
outs() << " Incorrect size\n";
9328
else
9329
outs() << "\n";
9330
if (sub.sub_library < sub.cmdsize) {
9331
const char *P = Ptr + sub.sub_library;
9332
outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
9333
} else {
9334
outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
9335
}
9336
}
9337
9338
static void PrintSubClientCommand(MachO::sub_client_command sub,
9339
const char *Ptr) {
9340
outs() << " cmd LC_SUB_CLIENT\n";
9341
outs() << " cmdsize " << sub.cmdsize;
9342
if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
9343
outs() << " Incorrect size\n";
9344
else
9345
outs() << "\n";
9346
if (sub.client < sub.cmdsize) {
9347
const char *P = Ptr + sub.client;
9348
outs() << " client " << P << " (offset " << sub.client << ")\n";
9349
} else {
9350
outs() << " client ?(bad offset " << sub.client << ")\n";
9351
}
9352
}
9353
9354
static void PrintRoutinesCommand(MachO::routines_command r) {
9355
outs() << " cmd LC_ROUTINES\n";
9356
outs() << " cmdsize " << r.cmdsize;
9357
if (r.cmdsize != sizeof(struct MachO::routines_command))
9358
outs() << " Incorrect size\n";
9359
else
9360
outs() << "\n";
9361
outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";
9362
outs() << " init_module " << r.init_module << "\n";
9363
outs() << " reserved1 " << r.reserved1 << "\n";
9364
outs() << " reserved2 " << r.reserved2 << "\n";
9365
outs() << " reserved3 " << r.reserved3 << "\n";
9366
outs() << " reserved4 " << r.reserved4 << "\n";
9367
outs() << " reserved5 " << r.reserved5 << "\n";
9368
outs() << " reserved6 " << r.reserved6 << "\n";
9369
}
9370
9371
static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
9372
outs() << " cmd LC_ROUTINES_64\n";
9373
outs() << " cmdsize " << r.cmdsize;
9374
if (r.cmdsize != sizeof(struct MachO::routines_command_64))
9375
outs() << " Incorrect size\n";
9376
else
9377
outs() << "\n";
9378
outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";
9379
outs() << " init_module " << r.init_module << "\n";
9380
outs() << " reserved1 " << r.reserved1 << "\n";
9381
outs() << " reserved2 " << r.reserved2 << "\n";
9382
outs() << " reserved3 " << r.reserved3 << "\n";
9383
outs() << " reserved4 " << r.reserved4 << "\n";
9384
outs() << " reserved5 " << r.reserved5 << "\n";
9385
outs() << " reserved6 " << r.reserved6 << "\n";
9386
}
9387
9388
static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
9389
outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);
9390
outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);
9391
outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);
9392
outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";
9393
outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);
9394
outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);
9395
outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);
9396
outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";
9397
outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);
9398
outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);
9399
outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);
9400
outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";
9401
outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);
9402
outs() << " es " << format("0x%08" PRIx32, cpu32.es);
9403
outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);
9404
outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";
9405
}
9406
9407
static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
9408
outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
9409
outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
9410
outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";
9411
outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);
9412
outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);
9413
outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";
9414
outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);
9415
outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);
9416
outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";
9417
outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);
9418
outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);
9419
outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";
9420
outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);
9421
outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);
9422
outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";
9423
outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);
9424
outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";
9425
outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);
9426
outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);
9427
outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";
9428
outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";
9429
}
9430
9431
static void Print_mmst_reg(MachO::mmst_reg_t &r) {
9432
uint32_t f;
9433
outs() << "\t mmst_reg ";
9434
for (f = 0; f < 10; f++)
9435
outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";
9436
outs() << "\n";
9437
outs() << "\t mmst_rsrv ";
9438
for (f = 0; f < 6; f++)
9439
outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";
9440
outs() << "\n";
9441
}
9442
9443
static void Print_xmm_reg(MachO::xmm_reg_t &r) {
9444
uint32_t f;
9445
outs() << "\t xmm_reg ";
9446
for (f = 0; f < 16; f++)
9447
outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";
9448
outs() << "\n";
9449
}
9450
9451
static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
9452
outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
9453
outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
9454
outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
9455
outs() << " denorm " << fpu.fpu_fcw.denorm;
9456
outs() << " zdiv " << fpu.fpu_fcw.zdiv;
9457
outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
9458
outs() << " undfl " << fpu.fpu_fcw.undfl;
9459
outs() << " precis " << fpu.fpu_fcw.precis << "\n";
9460
outs() << "\t\t pc ";
9461
if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
9462
outs() << "FP_PREC_24B ";
9463
else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
9464
outs() << "FP_PREC_53B ";
9465
else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
9466
outs() << "FP_PREC_64B ";
9467
else
9468
outs() << fpu.fpu_fcw.pc << " ";
9469
outs() << "rc ";
9470
if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
9471
outs() << "FP_RND_NEAR ";
9472
else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
9473
outs() << "FP_RND_DOWN ";
9474
else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
9475
outs() << "FP_RND_UP ";
9476
else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
9477
outs() << "FP_CHOP ";
9478
outs() << "\n";
9479
outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
9480
outs() << " denorm " << fpu.fpu_fsw.denorm;
9481
outs() << " zdiv " << fpu.fpu_fsw.zdiv;
9482
outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
9483
outs() << " undfl " << fpu.fpu_fsw.undfl;
9484
outs() << " precis " << fpu.fpu_fsw.precis;
9485
outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
9486
outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
9487
outs() << " c0 " << fpu.fpu_fsw.c0;
9488
outs() << " c1 " << fpu.fpu_fsw.c1;
9489
outs() << " c2 " << fpu.fpu_fsw.c2;
9490
outs() << " tos " << fpu.fpu_fsw.tos;
9491
outs() << " c3 " << fpu.fpu_fsw.c3;
9492
outs() << " busy " << fpu.fpu_fsw.busy << "\n";
9493
outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);
9494
outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);
9495
outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);
9496
outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";
9497
outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);
9498
outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);
9499
outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);
9500
outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";
9501
outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);
9502
outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);
9503
outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);
9504
outs() << "\n";
9505
outs() << "\t fpu_stmm0:\n";
9506
Print_mmst_reg(fpu.fpu_stmm0);
9507
outs() << "\t fpu_stmm1:\n";
9508
Print_mmst_reg(fpu.fpu_stmm1);
9509
outs() << "\t fpu_stmm2:\n";
9510
Print_mmst_reg(fpu.fpu_stmm2);
9511
outs() << "\t fpu_stmm3:\n";
9512
Print_mmst_reg(fpu.fpu_stmm3);
9513
outs() << "\t fpu_stmm4:\n";
9514
Print_mmst_reg(fpu.fpu_stmm4);
9515
outs() << "\t fpu_stmm5:\n";
9516
Print_mmst_reg(fpu.fpu_stmm5);
9517
outs() << "\t fpu_stmm6:\n";
9518
Print_mmst_reg(fpu.fpu_stmm6);
9519
outs() << "\t fpu_stmm7:\n";
9520
Print_mmst_reg(fpu.fpu_stmm7);
9521
outs() << "\t fpu_xmm0:\n";
9522
Print_xmm_reg(fpu.fpu_xmm0);
9523
outs() << "\t fpu_xmm1:\n";
9524
Print_xmm_reg(fpu.fpu_xmm1);
9525
outs() << "\t fpu_xmm2:\n";
9526
Print_xmm_reg(fpu.fpu_xmm2);
9527
outs() << "\t fpu_xmm3:\n";
9528
Print_xmm_reg(fpu.fpu_xmm3);
9529
outs() << "\t fpu_xmm4:\n";
9530
Print_xmm_reg(fpu.fpu_xmm4);
9531
outs() << "\t fpu_xmm5:\n";
9532
Print_xmm_reg(fpu.fpu_xmm5);
9533
outs() << "\t fpu_xmm6:\n";
9534
Print_xmm_reg(fpu.fpu_xmm6);
9535
outs() << "\t fpu_xmm7:\n";
9536
Print_xmm_reg(fpu.fpu_xmm7);
9537
outs() << "\t fpu_xmm8:\n";
9538
Print_xmm_reg(fpu.fpu_xmm8);
9539
outs() << "\t fpu_xmm9:\n";
9540
Print_xmm_reg(fpu.fpu_xmm9);
9541
outs() << "\t fpu_xmm10:\n";
9542
Print_xmm_reg(fpu.fpu_xmm10);
9543
outs() << "\t fpu_xmm11:\n";
9544
Print_xmm_reg(fpu.fpu_xmm11);
9545
outs() << "\t fpu_xmm12:\n";
9546
Print_xmm_reg(fpu.fpu_xmm12);
9547
outs() << "\t fpu_xmm13:\n";
9548
Print_xmm_reg(fpu.fpu_xmm13);
9549
outs() << "\t fpu_xmm14:\n";
9550
Print_xmm_reg(fpu.fpu_xmm14);
9551
outs() << "\t fpu_xmm15:\n";
9552
Print_xmm_reg(fpu.fpu_xmm15);
9553
outs() << "\t fpu_rsrv4:\n";
9554
for (uint32_t f = 0; f < 6; f++) {
9555
outs() << "\t ";
9556
for (uint32_t g = 0; g < 16; g++)
9557
outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";
9558
outs() << "\n";
9559
}
9560
outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);
9561
outs() << "\n";
9562
}
9563
9564
static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
9565
outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);
9566
outs() << " err " << format("0x%08" PRIx32, exc64.err);
9567
outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";
9568
}
9569
9570
static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {
9571
outs() << "\t r0 " << format("0x%08" PRIx32, cpu32.r[0]);
9572
outs() << " r1 " << format("0x%08" PRIx32, cpu32.r[1]);
9573
outs() << " r2 " << format("0x%08" PRIx32, cpu32.r[2]);
9574
outs() << " r3 " << format("0x%08" PRIx32, cpu32.r[3]) << "\n";
9575
outs() << "\t r4 " << format("0x%08" PRIx32, cpu32.r[4]);
9576
outs() << " r5 " << format("0x%08" PRIx32, cpu32.r[5]);
9577
outs() << " r6 " << format("0x%08" PRIx32, cpu32.r[6]);
9578
outs() << " r7 " << format("0x%08" PRIx32, cpu32.r[7]) << "\n";
9579
outs() << "\t r8 " << format("0x%08" PRIx32, cpu32.r[8]);
9580
outs() << " r9 " << format("0x%08" PRIx32, cpu32.r[9]);
9581
outs() << " r10 " << format("0x%08" PRIx32, cpu32.r[10]);
9582
outs() << " r11 " << format("0x%08" PRIx32, cpu32.r[11]) << "\n";
9583
outs() << "\t r12 " << format("0x%08" PRIx32, cpu32.r[12]);
9584
outs() << " sp " << format("0x%08" PRIx32, cpu32.sp);
9585
outs() << " lr " << format("0x%08" PRIx32, cpu32.lr);
9586
outs() << " pc " << format("0x%08" PRIx32, cpu32.pc) << "\n";
9587
outs() << "\t cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";
9588
}
9589
9590
static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {
9591
outs() << "\t x0 " << format("0x%016" PRIx64, cpu64.x[0]);
9592
outs() << " x1 " << format("0x%016" PRIx64, cpu64.x[1]);
9593
outs() << " x2 " << format("0x%016" PRIx64, cpu64.x[2]) << "\n";
9594
outs() << "\t x3 " << format("0x%016" PRIx64, cpu64.x[3]);
9595
outs() << " x4 " << format("0x%016" PRIx64, cpu64.x[4]);
9596
outs() << " x5 " << format("0x%016" PRIx64, cpu64.x[5]) << "\n";
9597
outs() << "\t x6 " << format("0x%016" PRIx64, cpu64.x[6]);
9598
outs() << " x7 " << format("0x%016" PRIx64, cpu64.x[7]);
9599
outs() << " x8 " << format("0x%016" PRIx64, cpu64.x[8]) << "\n";
9600
outs() << "\t x9 " << format("0x%016" PRIx64, cpu64.x[9]);
9601
outs() << " x10 " << format("0x%016" PRIx64, cpu64.x[10]);
9602
outs() << " x11 " << format("0x%016" PRIx64, cpu64.x[11]) << "\n";
9603
outs() << "\t x12 " << format("0x%016" PRIx64, cpu64.x[12]);
9604
outs() << " x13 " << format("0x%016" PRIx64, cpu64.x[13]);
9605
outs() << " x14 " << format("0x%016" PRIx64, cpu64.x[14]) << "\n";
9606
outs() << "\t x15 " << format("0x%016" PRIx64, cpu64.x[15]);
9607
outs() << " x16 " << format("0x%016" PRIx64, cpu64.x[16]);
9608
outs() << " x17 " << format("0x%016" PRIx64, cpu64.x[17]) << "\n";
9609
outs() << "\t x18 " << format("0x%016" PRIx64, cpu64.x[18]);
9610
outs() << " x19 " << format("0x%016" PRIx64, cpu64.x[19]);
9611
outs() << " x20 " << format("0x%016" PRIx64, cpu64.x[20]) << "\n";
9612
outs() << "\t x21 " << format("0x%016" PRIx64, cpu64.x[21]);
9613
outs() << " x22 " << format("0x%016" PRIx64, cpu64.x[22]);
9614
outs() << " x23 " << format("0x%016" PRIx64, cpu64.x[23]) << "\n";
9615
outs() << "\t x24 " << format("0x%016" PRIx64, cpu64.x[24]);
9616
outs() << " x25 " << format("0x%016" PRIx64, cpu64.x[25]);
9617
outs() << " x26 " << format("0x%016" PRIx64, cpu64.x[26]) << "\n";
9618
outs() << "\t x27 " << format("0x%016" PRIx64, cpu64.x[27]);
9619
outs() << " x28 " << format("0x%016" PRIx64, cpu64.x[28]);
9620
outs() << " fp " << format("0x%016" PRIx64, cpu64.fp) << "\n";
9621
outs() << "\t lr " << format("0x%016" PRIx64, cpu64.lr);
9622
outs() << " sp " << format("0x%016" PRIx64, cpu64.sp);
9623
outs() << " pc " << format("0x%016" PRIx64, cpu64.pc) << "\n";
9624
outs() << "\t cpsr " << format("0x%08" PRIx32, cpu64.cpsr) << "\n";
9625
}
9626
9627
static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
9628
bool isLittleEndian, uint32_t cputype) {
9629
if (t.cmd == MachO::LC_THREAD)
9630
outs() << " cmd LC_THREAD\n";
9631
else if (t.cmd == MachO::LC_UNIXTHREAD)
9632
outs() << " cmd LC_UNIXTHREAD\n";
9633
else
9634
outs() << " cmd " << t.cmd << " (unknown)\n";
9635
outs() << " cmdsize " << t.cmdsize;
9636
if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
9637
outs() << " Incorrect size\n";
9638
else
9639
outs() << "\n";
9640
9641
const char *begin = Ptr + sizeof(struct MachO::thread_command);
9642
const char *end = Ptr + t.cmdsize;
9643
uint32_t flavor, count, left;
9644
if (cputype == MachO::CPU_TYPE_I386) {
9645
while (begin < end) {
9646
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9647
memcpy((char *)&flavor, begin, sizeof(uint32_t));
9648
begin += sizeof(uint32_t);
9649
} else {
9650
flavor = 0;
9651
begin = end;
9652
}
9653
if (isLittleEndian != sys::IsLittleEndianHost)
9654
sys::swapByteOrder(flavor);
9655
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9656
memcpy((char *)&count, begin, sizeof(uint32_t));
9657
begin += sizeof(uint32_t);
9658
} else {
9659
count = 0;
9660
begin = end;
9661
}
9662
if (isLittleEndian != sys::IsLittleEndianHost)
9663
sys::swapByteOrder(count);
9664
if (flavor == MachO::x86_THREAD_STATE32) {
9665
outs() << " flavor i386_THREAD_STATE\n";
9666
if (count == MachO::x86_THREAD_STATE32_COUNT)
9667
outs() << " count i386_THREAD_STATE_COUNT\n";
9668
else
9669
outs() << " count " << count
9670
<< " (not x86_THREAD_STATE32_COUNT)\n";
9671
MachO::x86_thread_state32_t cpu32;
9672
left = end - begin;
9673
if (left >= sizeof(MachO::x86_thread_state32_t)) {
9674
memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));
9675
begin += sizeof(MachO::x86_thread_state32_t);
9676
} else {
9677
memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));
9678
memcpy(&cpu32, begin, left);
9679
begin += left;
9680
}
9681
if (isLittleEndian != sys::IsLittleEndianHost)
9682
swapStruct(cpu32);
9683
Print_x86_thread_state32_t(cpu32);
9684
} else if (flavor == MachO::x86_THREAD_STATE) {
9685
outs() << " flavor x86_THREAD_STATE\n";
9686
if (count == MachO::x86_THREAD_STATE_COUNT)
9687
outs() << " count x86_THREAD_STATE_COUNT\n";
9688
else
9689
outs() << " count " << count
9690
<< " (not x86_THREAD_STATE_COUNT)\n";
9691
struct MachO::x86_thread_state_t ts;
9692
left = end - begin;
9693
if (left >= sizeof(MachO::x86_thread_state_t)) {
9694
memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9695
begin += sizeof(MachO::x86_thread_state_t);
9696
} else {
9697
memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9698
memcpy(&ts, begin, left);
9699
begin += left;
9700
}
9701
if (isLittleEndian != sys::IsLittleEndianHost)
9702
swapStruct(ts);
9703
if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
9704
outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
9705
if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
9706
outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
9707
else
9708
outs() << "tsh.count " << ts.tsh.count
9709
<< " (not x86_THREAD_STATE32_COUNT\n";
9710
Print_x86_thread_state32_t(ts.uts.ts32);
9711
} else {
9712
outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9713
<< ts.tsh.count << "\n";
9714
}
9715
} else {
9716
outs() << " flavor " << flavor << " (unknown)\n";
9717
outs() << " count " << count << "\n";
9718
outs() << " state (unknown)\n";
9719
begin += count * sizeof(uint32_t);
9720
}
9721
}
9722
} else if (cputype == MachO::CPU_TYPE_X86_64) {
9723
while (begin < end) {
9724
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9725
memcpy((char *)&flavor, begin, sizeof(uint32_t));
9726
begin += sizeof(uint32_t);
9727
} else {
9728
flavor = 0;
9729
begin = end;
9730
}
9731
if (isLittleEndian != sys::IsLittleEndianHost)
9732
sys::swapByteOrder(flavor);
9733
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9734
memcpy((char *)&count, begin, sizeof(uint32_t));
9735
begin += sizeof(uint32_t);
9736
} else {
9737
count = 0;
9738
begin = end;
9739
}
9740
if (isLittleEndian != sys::IsLittleEndianHost)
9741
sys::swapByteOrder(count);
9742
if (flavor == MachO::x86_THREAD_STATE64) {
9743
outs() << " flavor x86_THREAD_STATE64\n";
9744
if (count == MachO::x86_THREAD_STATE64_COUNT)
9745
outs() << " count x86_THREAD_STATE64_COUNT\n";
9746
else
9747
outs() << " count " << count
9748
<< " (not x86_THREAD_STATE64_COUNT)\n";
9749
MachO::x86_thread_state64_t cpu64;
9750
left = end - begin;
9751
if (left >= sizeof(MachO::x86_thread_state64_t)) {
9752
memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));
9753
begin += sizeof(MachO::x86_thread_state64_t);
9754
} else {
9755
memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));
9756
memcpy(&cpu64, begin, left);
9757
begin += left;
9758
}
9759
if (isLittleEndian != sys::IsLittleEndianHost)
9760
swapStruct(cpu64);
9761
Print_x86_thread_state64_t(cpu64);
9762
} else if (flavor == MachO::x86_THREAD_STATE) {
9763
outs() << " flavor x86_THREAD_STATE\n";
9764
if (count == MachO::x86_THREAD_STATE_COUNT)
9765
outs() << " count x86_THREAD_STATE_COUNT\n";
9766
else
9767
outs() << " count " << count
9768
<< " (not x86_THREAD_STATE_COUNT)\n";
9769
struct MachO::x86_thread_state_t ts;
9770
left = end - begin;
9771
if (left >= sizeof(MachO::x86_thread_state_t)) {
9772
memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9773
begin += sizeof(MachO::x86_thread_state_t);
9774
} else {
9775
memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9776
memcpy(&ts, begin, left);
9777
begin += left;
9778
}
9779
if (isLittleEndian != sys::IsLittleEndianHost)
9780
swapStruct(ts);
9781
if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
9782
outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
9783
if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
9784
outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
9785
else
9786
outs() << "tsh.count " << ts.tsh.count
9787
<< " (not x86_THREAD_STATE64_COUNT\n";
9788
Print_x86_thread_state64_t(ts.uts.ts64);
9789
} else {
9790
outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9791
<< ts.tsh.count << "\n";
9792
}
9793
} else if (flavor == MachO::x86_FLOAT_STATE) {
9794
outs() << " flavor x86_FLOAT_STATE\n";
9795
if (count == MachO::x86_FLOAT_STATE_COUNT)
9796
outs() << " count x86_FLOAT_STATE_COUNT\n";
9797
else
9798
outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
9799
struct MachO::x86_float_state_t fs;
9800
left = end - begin;
9801
if (left >= sizeof(MachO::x86_float_state_t)) {
9802
memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));
9803
begin += sizeof(MachO::x86_float_state_t);
9804
} else {
9805
memset(&fs, '\0', sizeof(MachO::x86_float_state_t));
9806
memcpy(&fs, begin, left);
9807
begin += left;
9808
}
9809
if (isLittleEndian != sys::IsLittleEndianHost)
9810
swapStruct(fs);
9811
if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
9812
outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
9813
if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
9814
outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
9815
else
9816
outs() << "fsh.count " << fs.fsh.count
9817
<< " (not x86_FLOAT_STATE64_COUNT\n";
9818
Print_x86_float_state_t(fs.ufs.fs64);
9819
} else {
9820
outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
9821
<< fs.fsh.count << "\n";
9822
}
9823
} else if (flavor == MachO::x86_EXCEPTION_STATE) {
9824
outs() << " flavor x86_EXCEPTION_STATE\n";
9825
if (count == MachO::x86_EXCEPTION_STATE_COUNT)
9826
outs() << " count x86_EXCEPTION_STATE_COUNT\n";
9827
else
9828
outs() << " count " << count
9829
<< " (not x86_EXCEPTION_STATE_COUNT)\n";
9830
struct MachO::x86_exception_state_t es;
9831
left = end - begin;
9832
if (left >= sizeof(MachO::x86_exception_state_t)) {
9833
memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));
9834
begin += sizeof(MachO::x86_exception_state_t);
9835
} else {
9836
memset(&es, '\0', sizeof(MachO::x86_exception_state_t));
9837
memcpy(&es, begin, left);
9838
begin += left;
9839
}
9840
if (isLittleEndian != sys::IsLittleEndianHost)
9841
swapStruct(es);
9842
if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
9843
outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
9844
if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
9845
outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
9846
else
9847
outs() << "\t esh.count " << es.esh.count
9848
<< " (not x86_EXCEPTION_STATE64_COUNT\n";
9849
Print_x86_exception_state_t(es.ues.es64);
9850
} else {
9851
outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
9852
<< es.esh.count << "\n";
9853
}
9854
} else if (flavor == MachO::x86_EXCEPTION_STATE64) {
9855
outs() << " flavor x86_EXCEPTION_STATE64\n";
9856
if (count == MachO::x86_EXCEPTION_STATE64_COUNT)
9857
outs() << " count x86_EXCEPTION_STATE64_COUNT\n";
9858
else
9859
outs() << " count " << count
9860
<< " (not x86_EXCEPTION_STATE64_COUNT)\n";
9861
struct MachO::x86_exception_state64_t es64;
9862
left = end - begin;
9863
if (left >= sizeof(MachO::x86_exception_state64_t)) {
9864
memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));
9865
begin += sizeof(MachO::x86_exception_state64_t);
9866
} else {
9867
memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));
9868
memcpy(&es64, begin, left);
9869
begin += left;
9870
}
9871
if (isLittleEndian != sys::IsLittleEndianHost)
9872
swapStruct(es64);
9873
Print_x86_exception_state_t(es64);
9874
} else {
9875
outs() << " flavor " << flavor << " (unknown)\n";
9876
outs() << " count " << count << "\n";
9877
outs() << " state (unknown)\n";
9878
begin += count * sizeof(uint32_t);
9879
}
9880
}
9881
} else if (cputype == MachO::CPU_TYPE_ARM) {
9882
while (begin < end) {
9883
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9884
memcpy((char *)&flavor, begin, sizeof(uint32_t));
9885
begin += sizeof(uint32_t);
9886
} else {
9887
flavor = 0;
9888
begin = end;
9889
}
9890
if (isLittleEndian != sys::IsLittleEndianHost)
9891
sys::swapByteOrder(flavor);
9892
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9893
memcpy((char *)&count, begin, sizeof(uint32_t));
9894
begin += sizeof(uint32_t);
9895
} else {
9896
count = 0;
9897
begin = end;
9898
}
9899
if (isLittleEndian != sys::IsLittleEndianHost)
9900
sys::swapByteOrder(count);
9901
if (flavor == MachO::ARM_THREAD_STATE) {
9902
outs() << " flavor ARM_THREAD_STATE\n";
9903
if (count == MachO::ARM_THREAD_STATE_COUNT)
9904
outs() << " count ARM_THREAD_STATE_COUNT\n";
9905
else
9906
outs() << " count " << count
9907
<< " (not ARM_THREAD_STATE_COUNT)\n";
9908
MachO::arm_thread_state32_t cpu32;
9909
left = end - begin;
9910
if (left >= sizeof(MachO::arm_thread_state32_t)) {
9911
memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));
9912
begin += sizeof(MachO::arm_thread_state32_t);
9913
} else {
9914
memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));
9915
memcpy(&cpu32, begin, left);
9916
begin += left;
9917
}
9918
if (isLittleEndian != sys::IsLittleEndianHost)
9919
swapStruct(cpu32);
9920
Print_arm_thread_state32_t(cpu32);
9921
} else {
9922
outs() << " flavor " << flavor << " (unknown)\n";
9923
outs() << " count " << count << "\n";
9924
outs() << " state (unknown)\n";
9925
begin += count * sizeof(uint32_t);
9926
}
9927
}
9928
} else if (cputype == MachO::CPU_TYPE_ARM64 ||
9929
cputype == MachO::CPU_TYPE_ARM64_32) {
9930
while (begin < end) {
9931
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9932
memcpy((char *)&flavor, begin, sizeof(uint32_t));
9933
begin += sizeof(uint32_t);
9934
} else {
9935
flavor = 0;
9936
begin = end;
9937
}
9938
if (isLittleEndian != sys::IsLittleEndianHost)
9939
sys::swapByteOrder(flavor);
9940
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9941
memcpy((char *)&count, begin, sizeof(uint32_t));
9942
begin += sizeof(uint32_t);
9943
} else {
9944
count = 0;
9945
begin = end;
9946
}
9947
if (isLittleEndian != sys::IsLittleEndianHost)
9948
sys::swapByteOrder(count);
9949
if (flavor == MachO::ARM_THREAD_STATE64) {
9950
outs() << " flavor ARM_THREAD_STATE64\n";
9951
if (count == MachO::ARM_THREAD_STATE64_COUNT)
9952
outs() << " count ARM_THREAD_STATE64_COUNT\n";
9953
else
9954
outs() << " count " << count
9955
<< " (not ARM_THREAD_STATE64_COUNT)\n";
9956
MachO::arm_thread_state64_t cpu64;
9957
left = end - begin;
9958
if (left >= sizeof(MachO::arm_thread_state64_t)) {
9959
memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));
9960
begin += sizeof(MachO::arm_thread_state64_t);
9961
} else {
9962
memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));
9963
memcpy(&cpu64, begin, left);
9964
begin += left;
9965
}
9966
if (isLittleEndian != sys::IsLittleEndianHost)
9967
swapStruct(cpu64);
9968
Print_arm_thread_state64_t(cpu64);
9969
} else {
9970
outs() << " flavor " << flavor << " (unknown)\n";
9971
outs() << " count " << count << "\n";
9972
outs() << " state (unknown)\n";
9973
begin += count * sizeof(uint32_t);
9974
}
9975
}
9976
} else {
9977
while (begin < end) {
9978
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9979
memcpy((char *)&flavor, begin, sizeof(uint32_t));
9980
begin += sizeof(uint32_t);
9981
} else {
9982
flavor = 0;
9983
begin = end;
9984
}
9985
if (isLittleEndian != sys::IsLittleEndianHost)
9986
sys::swapByteOrder(flavor);
9987
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9988
memcpy((char *)&count, begin, sizeof(uint32_t));
9989
begin += sizeof(uint32_t);
9990
} else {
9991
count = 0;
9992
begin = end;
9993
}
9994
if (isLittleEndian != sys::IsLittleEndianHost)
9995
sys::swapByteOrder(count);
9996
outs() << " flavor " << flavor << "\n";
9997
outs() << " count " << count << "\n";
9998
outs() << " state (Unknown cputype/cpusubtype)\n";
9999
begin += count * sizeof(uint32_t);
10000
}
10001
}
10002
}
10003
10004
static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
10005
if (dl.cmd == MachO::LC_ID_DYLIB)
10006
outs() << " cmd LC_ID_DYLIB\n";
10007
else if (dl.cmd == MachO::LC_LOAD_DYLIB)
10008
outs() << " cmd LC_LOAD_DYLIB\n";
10009
else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
10010
outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
10011
else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
10012
outs() << " cmd LC_REEXPORT_DYLIB\n";
10013
else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
10014
outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
10015
else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
10016
outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
10017
else
10018
outs() << " cmd " << dl.cmd << " (unknown)\n";
10019
outs() << " cmdsize " << dl.cmdsize;
10020
if (dl.cmdsize < sizeof(struct MachO::dylib_command))
10021
outs() << " Incorrect size\n";
10022
else
10023
outs() << "\n";
10024
if (dl.dylib.name < dl.cmdsize) {
10025
const char *P = (const char *)(Ptr) + dl.dylib.name;
10026
outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
10027
} else {
10028
outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
10029
}
10030
outs() << " time stamp " << dl.dylib.timestamp << " ";
10031
time_t t = dl.dylib.timestamp;
10032
outs() << ctime(&t);
10033
outs() << " current version ";
10034
if (dl.dylib.current_version == 0xffffffff)
10035
outs() << "n/a\n";
10036
else
10037
outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
10038
<< ((dl.dylib.current_version >> 8) & 0xff) << "."
10039
<< (dl.dylib.current_version & 0xff) << "\n";
10040
outs() << "compatibility version ";
10041
if (dl.dylib.compatibility_version == 0xffffffff)
10042
outs() << "n/a\n";
10043
else
10044
outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
10045
<< ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
10046
<< (dl.dylib.compatibility_version & 0xff) << "\n";
10047
}
10048
10049
static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
10050
uint32_t object_size) {
10051
if (ld.cmd == MachO::LC_CODE_SIGNATURE)
10052
outs() << " cmd LC_CODE_SIGNATURE\n";
10053
else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
10054
outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
10055
else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
10056
outs() << " cmd LC_FUNCTION_STARTS\n";
10057
else if (ld.cmd == MachO::LC_DATA_IN_CODE)
10058
outs() << " cmd LC_DATA_IN_CODE\n";
10059
else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
10060
outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
10061
else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
10062
outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
10063
else if (ld.cmd == MachO::LC_DYLD_EXPORTS_TRIE)
10064
outs() << " cmd LC_DYLD_EXPORTS_TRIE\n";
10065
else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS)
10066
outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n";
10067
else if (ld.cmd == MachO::LC_ATOM_INFO)
10068
outs() << " cmd LC_ATOM_INFO\n";
10069
else
10070
outs() << " cmd " << ld.cmd << " (?)\n";
10071
outs() << " cmdsize " << ld.cmdsize;
10072
if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
10073
outs() << " Incorrect size\n";
10074
else
10075
outs() << "\n";
10076
outs() << " dataoff " << ld.dataoff;
10077
if (ld.dataoff > object_size)
10078
outs() << " (past end of file)\n";
10079
else
10080
outs() << "\n";
10081
outs() << " datasize " << ld.datasize;
10082
uint64_t big_size = ld.dataoff;
10083
big_size += ld.datasize;
10084
if (big_size > object_size)
10085
outs() << " (past end of file)\n";
10086
else
10087
outs() << "\n";
10088
}
10089
10090
static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
10091
uint32_t cputype, bool verbose) {
10092
StringRef Buf = Obj->getData();
10093
unsigned Index = 0;
10094
for (const auto &Command : Obj->load_commands()) {
10095
outs() << "Load command " << Index++ << "\n";
10096
if (Command.C.cmd == MachO::LC_SEGMENT) {
10097
MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
10098
const char *sg_segname = SLC.segname;
10099
PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,
10100
SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,
10101
SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
10102
verbose);
10103
for (unsigned j = 0; j < SLC.nsects; j++) {
10104
MachO::section S = Obj->getSection(Command, j);
10105
PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,
10106
S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,
10107
SLC.cmd, sg_segname, filetype, Buf.size(), verbose);
10108
}
10109
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10110
MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);
10111
const char *sg_segname = SLC_64.segname;
10112
PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,
10113
SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,
10114
SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,
10115
SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);
10116
for (unsigned j = 0; j < SLC_64.nsects; j++) {
10117
MachO::section_64 S_64 = Obj->getSection64(Command, j);
10118
PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,
10119
S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,
10120
S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,
10121
sg_segname, filetype, Buf.size(), verbose);
10122
}
10123
} else if (Command.C.cmd == MachO::LC_SYMTAB) {
10124
MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10125
PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());
10126
} else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
10127
MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
10128
MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
10129
PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),
10130
Obj->is64Bit());
10131
} else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
10132
Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
10133
MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);
10134
PrintDyldInfoLoadCommand(DyldInfo, Buf.size());
10135
} else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
10136
Command.C.cmd == MachO::LC_ID_DYLINKER ||
10137
Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
10138
MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);
10139
PrintDyldLoadCommand(Dyld, Command.Ptr);
10140
} else if (Command.C.cmd == MachO::LC_UUID) {
10141
MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
10142
PrintUuidLoadCommand(Uuid);
10143
} else if (Command.C.cmd == MachO::LC_RPATH) {
10144
MachO::rpath_command Rpath = Obj->getRpathCommand(Command);
10145
PrintRpathLoadCommand(Rpath, Command.Ptr);
10146
} else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
10147
Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||
10148
Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||
10149
Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
10150
MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
10151
PrintVersionMinLoadCommand(Vd);
10152
} else if (Command.C.cmd == MachO::LC_NOTE) {
10153
MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
10154
PrintNoteLoadCommand(Nt);
10155
} else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
10156
MachO::build_version_command Bv =
10157
Obj->getBuildVersionLoadCommand(Command);
10158
PrintBuildVersionLoadCommand(Obj, Bv, verbose);
10159
} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
10160
MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
10161
PrintSourceVersionCommand(Sd);
10162
} else if (Command.C.cmd == MachO::LC_MAIN) {
10163
MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);
10164
PrintEntryPointCommand(Ep);
10165
} else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
10166
MachO::encryption_info_command Ei =
10167
Obj->getEncryptionInfoCommand(Command);
10168
PrintEncryptionInfoCommand(Ei, Buf.size());
10169
} else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
10170
MachO::encryption_info_command_64 Ei =
10171
Obj->getEncryptionInfoCommand64(Command);
10172
PrintEncryptionInfoCommand64(Ei, Buf.size());
10173
} else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
10174
MachO::linker_option_command Lo =
10175
Obj->getLinkerOptionLoadCommand(Command);
10176
PrintLinkerOptionCommand(Lo, Command.Ptr);
10177
} else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
10178
MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);
10179
PrintSubFrameworkCommand(Sf, Command.Ptr);
10180
} else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
10181
MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);
10182
PrintSubUmbrellaCommand(Sf, Command.Ptr);
10183
} else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
10184
MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);
10185
PrintSubLibraryCommand(Sl, Command.Ptr);
10186
} else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
10187
MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);
10188
PrintSubClientCommand(Sc, Command.Ptr);
10189
} else if (Command.C.cmd == MachO::LC_ROUTINES) {
10190
MachO::routines_command Rc = Obj->getRoutinesCommand(Command);
10191
PrintRoutinesCommand(Rc);
10192
} else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
10193
MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);
10194
PrintRoutinesCommand64(Rc);
10195
} else if (Command.C.cmd == MachO::LC_THREAD ||
10196
Command.C.cmd == MachO::LC_UNIXTHREAD) {
10197
MachO::thread_command Tc = Obj->getThreadCommand(Command);
10198
PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);
10199
} else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
10200
Command.C.cmd == MachO::LC_ID_DYLIB ||
10201
Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
10202
Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
10203
Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
10204
Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
10205
MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);
10206
PrintDylibCommand(Dl, Command.Ptr);
10207
} else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
10208
Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
10209
Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
10210
Command.C.cmd == MachO::LC_DATA_IN_CODE ||
10211
Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
10212
Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT ||
10213
Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE ||
10214
Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS ||
10215
Command.C.cmd == MachO::LC_ATOM_INFO) {
10216
MachO::linkedit_data_command Ld =
10217
Obj->getLinkeditDataLoadCommand(Command);
10218
PrintLinkEditDataCommand(Ld, Buf.size());
10219
} else {
10220
outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)
10221
<< ")\n";
10222
outs() << " cmdsize " << Command.C.cmdsize << "\n";
10223
// TODO: get and print the raw bytes of the load command.
10224
}
10225
// TODO: print all the other kinds of load commands.
10226
}
10227
}
10228
10229
static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
10230
if (Obj->is64Bit()) {
10231
MachO::mach_header_64 H_64;
10232
H_64 = Obj->getHeader64();
10233
PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
10234
H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
10235
} else {
10236
MachO::mach_header H;
10237
H = Obj->getHeader();
10238
PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
10239
H.sizeofcmds, H.flags, verbose);
10240
}
10241
}
10242
10243
void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {
10244
const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);
10245
PrintMachHeader(file, Verbose);
10246
}
10247
10248
void MachODumper::printPrivateHeaders() {
10249
printMachOFileHeader(&Obj);
10250
if (!FirstPrivateHeader)
10251
printMachOLoadCommands(&Obj);
10252
}
10253
10254
void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) {
10255
const MachOObjectFile *file = cast<const MachOObjectFile>(Obj);
10256
uint32_t filetype = 0;
10257
uint32_t cputype = 0;
10258
if (file->is64Bit()) {
10259
MachO::mach_header_64 H_64;
10260
H_64 = file->getHeader64();
10261
filetype = H_64.filetype;
10262
cputype = H_64.cputype;
10263
} else {
10264
MachO::mach_header H;
10265
H = file->getHeader();
10266
filetype = H.filetype;
10267
cputype = H.cputype;
10268
}
10269
PrintLoadCommands(file, filetype, cputype, Verbose);
10270
}
10271
10272
//===----------------------------------------------------------------------===//
10273
// export trie dumping
10274
//===----------------------------------------------------------------------===//
10275
10276
static void printMachOExportsTrie(const object::MachOObjectFile *Obj) {
10277
uint64_t BaseSegmentAddress = 0;
10278
for (const auto &Command : Obj->load_commands()) {
10279
if (Command.C.cmd == MachO::LC_SEGMENT) {
10280
MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);
10281
if (Seg.fileoff == 0 && Seg.filesize != 0) {
10282
BaseSegmentAddress = Seg.vmaddr;
10283
break;
10284
}
10285
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10286
MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);
10287
if (Seg.fileoff == 0 && Seg.filesize != 0) {
10288
BaseSegmentAddress = Seg.vmaddr;
10289
break;
10290
}
10291
}
10292
}
10293
Error Err = Error::success();
10294
for (const object::ExportEntry &Entry : Obj->exports(Err)) {
10295
uint64_t Flags = Entry.flags();
10296
bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
10297
bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
10298
bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10299
MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
10300
bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10301
MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
10302
bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
10303
if (ReExport)
10304
outs() << "[re-export] ";
10305
else
10306
outs() << format("0x%08llX ",
10307
Entry.address() + BaseSegmentAddress);
10308
outs() << Entry.name();
10309
if (WeakDef || ThreadLocal || Resolver || Abs) {
10310
ListSeparator LS;
10311
outs() << " [";
10312
if (WeakDef)
10313
outs() << LS << "weak_def";
10314
if (ThreadLocal)
10315
outs() << LS << "per-thread";
10316
if (Abs)
10317
outs() << LS << "absolute";
10318
if (Resolver)
10319
outs() << LS << format("resolver=0x%08llX", Entry.other());
10320
outs() << "]";
10321
}
10322
if (ReExport) {
10323
StringRef DylibName = "unknown";
10324
int Ordinal = Entry.other() - 1;
10325
Obj->getLibraryShortNameByIndex(Ordinal, DylibName);
10326
if (Entry.otherName().empty())
10327
outs() << " (from " << DylibName << ")";
10328
else
10329
outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
10330
}
10331
outs() << "\n";
10332
}
10333
if (Err)
10334
reportError(std::move(Err), Obj->getFileName());
10335
}
10336
10337
//===----------------------------------------------------------------------===//
10338
// rebase table dumping
10339
//===----------------------------------------------------------------------===//
10340
10341
static void printMachORebaseTable(object::MachOObjectFile *Obj) {
10342
outs() << "segment section address type\n";
10343
Error Err = Error::success();
10344
for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
10345
StringRef SegmentName = Entry.segmentName();
10346
StringRef SectionName = Entry.sectionName();
10347
uint64_t Address = Entry.address();
10348
10349
// Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
10350
outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
10351
SegmentName.str().c_str(), SectionName.str().c_str(),
10352
Address, Entry.typeName().str().c_str());
10353
}
10354
if (Err)
10355
reportError(std::move(Err), Obj->getFileName());
10356
}
10357
10358
static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
10359
StringRef DylibName;
10360
switch (Ordinal) {
10361
case MachO::BIND_SPECIAL_DYLIB_SELF:
10362
return "this-image";
10363
case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
10364
return "main-executable";
10365
case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
10366
return "flat-namespace";
10367
case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
10368
return "weak";
10369
default:
10370
if (Ordinal > 0) {
10371
std::error_code EC =
10372
Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);
10373
if (EC)
10374
return "<<bad library ordinal>>";
10375
return DylibName;
10376
}
10377
}
10378
return "<<unknown special ordinal>>";
10379
}
10380
10381
//===----------------------------------------------------------------------===//
10382
// bind table dumping
10383
//===----------------------------------------------------------------------===//
10384
10385
static void printMachOBindTable(object::MachOObjectFile *Obj) {
10386
// Build table of sections so names can used in final output.
10387
outs() << "segment section address type "
10388
"addend dylib symbol\n";
10389
Error Err = Error::success();
10390
for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
10391
StringRef SegmentName = Entry.segmentName();
10392
StringRef SectionName = Entry.sectionName();
10393
uint64_t Address = Entry.address();
10394
10395
// Table lines look like:
10396
// __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
10397
StringRef Attr;
10398
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
10399
Attr = " (weak_import)";
10400
outs() << left_justify(SegmentName, 8) << " "
10401
<< left_justify(SectionName, 18) << " "
10402
<< format_hex(Address, 10, true) << " "
10403
<< left_justify(Entry.typeName(), 8) << " "
10404
<< format_decimal(Entry.addend(), 8) << " "
10405
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
10406
<< Entry.symbolName() << Attr << "\n";
10407
}
10408
if (Err)
10409
reportError(std::move(Err), Obj->getFileName());
10410
}
10411
10412
//===----------------------------------------------------------------------===//
10413
// lazy bind table dumping
10414
//===----------------------------------------------------------------------===//
10415
10416
static void printMachOLazyBindTable(object::MachOObjectFile *Obj) {
10417
outs() << "segment section address "
10418
"dylib symbol\n";
10419
Error Err = Error::success();
10420
for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
10421
StringRef SegmentName = Entry.segmentName();
10422
StringRef SectionName = Entry.sectionName();
10423
uint64_t Address = Entry.address();
10424
10425
// Table lines look like:
10426
// __DATA __got 0x00012010 libSystem ___stack_chk_guard
10427
outs() << left_justify(SegmentName, 8) << " "
10428
<< left_justify(SectionName, 18) << " "
10429
<< format_hex(Address, 10, true) << " "
10430
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
10431
<< Entry.symbolName() << "\n";
10432
}
10433
if (Err)
10434
reportError(std::move(Err), Obj->getFileName());
10435
}
10436
10437
//===----------------------------------------------------------------------===//
10438
// weak bind table dumping
10439
//===----------------------------------------------------------------------===//
10440
10441
static void printMachOWeakBindTable(object::MachOObjectFile *Obj) {
10442
outs() << "segment section address "
10443
"type addend symbol\n";
10444
Error Err = Error::success();
10445
for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
10446
// Strong symbols don't have a location to update.
10447
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
10448
outs() << " strong "
10449
<< Entry.symbolName() << "\n";
10450
continue;
10451
}
10452
StringRef SegmentName = Entry.segmentName();
10453
StringRef SectionName = Entry.sectionName();
10454
uint64_t Address = Entry.address();
10455
10456
// Table lines look like:
10457
// __DATA __data 0x00001000 pointer 0 _foo
10458
outs() << left_justify(SegmentName, 8) << " "
10459
<< left_justify(SectionName, 18) << " "
10460
<< format_hex(Address, 10, true) << " "
10461
<< left_justify(Entry.typeName(), 8) << " "
10462
<< format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
10463
<< "\n";
10464
}
10465
if (Err)
10466
reportError(std::move(Err), Obj->getFileName());
10467
}
10468
10469
// get_dyld_bind_info_symbolname() is used for disassembly and passed an
10470
// address, ReferenceValue, in the Mach-O file and looks in the dyld bind
10471
// information for that address. If the address is found its binding symbol
10472
// name is returned. If not nullptr is returned.
10473
static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
10474
struct DisassembleInfo *info) {
10475
if (info->bindtable == nullptr) {
10476
info->bindtable = std::make_unique<SymbolAddressMap>();
10477
Error Err = Error::success();
10478
for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
10479
uint64_t Address = Entry.address();
10480
StringRef name = Entry.symbolName();
10481
if (!name.empty())
10482
(*info->bindtable)[Address] = name;
10483
}
10484
if (Err)
10485
reportError(std::move(Err), info->O->getFileName());
10486
}
10487
auto name = info->bindtable->lookup(ReferenceValue);
10488
return !name.empty() ? name.data() : nullptr;
10489
}
10490
10491
void objdump::printLazyBindTable(ObjectFile *o) {
10492
outs() << "\nLazy bind table:\n";
10493
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10494
printMachOLazyBindTable(MachO);
10495
else
10496
WithColor::error()
10497
<< "This operation is only currently supported "
10498
"for Mach-O executable files.\n";
10499
}
10500
10501
void objdump::printWeakBindTable(ObjectFile *o) {
10502
outs() << "\nWeak bind table:\n";
10503
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10504
printMachOWeakBindTable(MachO);
10505
else
10506
WithColor::error()
10507
<< "This operation is only currently supported "
10508
"for Mach-O executable files.\n";
10509
}
10510
10511
void objdump::printExportsTrie(const ObjectFile *o) {
10512
outs() << "\nExports trie:\n";
10513
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10514
printMachOExportsTrie(MachO);
10515
else
10516
WithColor::error()
10517
<< "This operation is only currently supported "
10518
"for Mach-O executable files.\n";
10519
}
10520
10521
void objdump::printRebaseTable(ObjectFile *o) {
10522
outs() << "\nRebase table:\n";
10523
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10524
printMachORebaseTable(MachO);
10525
else
10526
WithColor::error()
10527
<< "This operation is only currently supported "
10528
"for Mach-O executable files.\n";
10529
}
10530
10531
void objdump::printBindTable(ObjectFile *o) {
10532
outs() << "\nBind table:\n";
10533
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
10534
printMachOBindTable(MachO);
10535
else
10536
WithColor::error()
10537
<< "This operation is only currently supported "
10538
"for Mach-O executable files.\n";
10539
}
10540
10541