blob: bbee17b9587062cc6b9cce7024c59c7bce79138e [file] [log] [blame]
Benjamin Kramer43a772e2011-09-19 17:56:04 +00001//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Benjamin Kramer43a772e2011-09-19 17:56:04 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the MachO-specific dumper for llvm-objdump.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm-objdump.h"
Kevin Enderby98c9acc2014-09-16 18:00:57 +000014#include "llvm-c/Disassembler.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000015#include "llvm/ADT/STLExtras.h"
Ahmed Bougachaaa790682013-05-24 01:07:04 +000016#include "llvm/ADT/StringExtras.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000017#include "llvm/ADT/Triple.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000018#include "llvm/BinaryFormat/MachO.h"
Kevin Enderby04bf6932014-10-28 23:39:46 +000019#include "llvm/Config/config.h"
Zachary Turner6489d7b2015-04-23 17:37:47 +000020#include "llvm/DebugInfo/DIContext.h"
21#include "llvm/DebugInfo/DWARF/DWARFContext.h"
Rafael Espindolab940b662016-09-06 19:16:48 +000022#include "llvm/Demangle/Demangle.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000023#include "llvm/MC/MCAsmInfo.h"
Lang Hamesa1bc0f52014-04-15 04:40:56 +000024#include "llvm/MC/MCContext.h"
Benjamin Kramerf57c1972016-01-26 16:44:37 +000025#include "llvm/MC/MCDisassembler/MCDisassembler.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000026#include "llvm/MC/MCInst.h"
27#include "llvm/MC/MCInstPrinter.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000028#include "llvm/MC/MCInstrDesc.h"
29#include "llvm/MC/MCInstrInfo.h"
Jim Grosbachfd93a592012-03-05 19:33:20 +000030#include "llvm/MC/MCRegisterInfo.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000031#include "llvm/MC/MCSubtargetInfo.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000032#include "llvm/Object/MachO.h"
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +000033#include "llvm/Object/MachOUniversal.h"
Rafael Espindola9b709252013-04-13 01:45:40 +000034#include "llvm/Support/Casting.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000035#include "llvm/Support/CommandLine.h"
36#include "llvm/Support/Debug.h"
Tim Northover4bd286a2014-08-01 13:07:19 +000037#include "llvm/Support/Endian.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000038#include "llvm/Support/Format.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000039#include "llvm/Support/FormattedStream.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000040#include "llvm/Support/GraphWriter.h"
Kevin Enderby9a509442015-01-27 21:28:24 +000041#include "llvm/Support/LEB128.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000042#include "llvm/Support/MemoryBuffer.h"
43#include "llvm/Support/TargetRegistry.h"
44#include "llvm/Support/TargetSelect.h"
Kevin Enderby9873e2c2016-05-23 21:34:12 +000045#include "llvm/Support/ToolOutputFile.h"
Jonas Devliegheree787efd2018-11-11 22:12:04 +000046#include "llvm/Support/WithColor.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000047#include "llvm/Support/raw_ostream.h"
Benjamin Kramer43a772e2011-09-19 17:56:04 +000048#include <algorithm>
49#include <cstring>
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000050#include <system_error>
Kevin Enderby04bf6932014-10-28 23:39:46 +000051
Kevin Enderby9873e2c2016-05-23 21:34:12 +000052#ifdef HAVE_LIBXAR
53extern "C" {
54#include <xar/xar.h>
55}
56#endif
57
Benjamin Kramer43a772e2011-09-19 17:56:04 +000058using namespace llvm;
59using namespace object;
60
61static cl::opt<bool>
Matthew Voss0f436772019-02-19 19:46:08 +000062 UseDbg("g", cl::Grouping,
Kevin Enderbyb28ed012014-10-29 21:28:24 +000063 cl::desc("Print line information from debug info if available"));
Benjamin Kramer699128e2011-09-21 01:13:19 +000064
Kevin Enderbyb28ed012014-10-29 21:28:24 +000065static cl::opt<std::string> DSYMFile("dsym",
66 cl::desc("Use .dSYM file for debug info"));
Benjamin Kramer699128e2011-09-21 01:13:19 +000067
Kevin Enderbyb28ed012014-10-29 21:28:24 +000068static cl::opt<bool> FullLeadingAddr("full-leading-addr",
69 cl::desc("Print full leading address"));
Kevin Enderbybf246f52014-09-24 23:08:22 +000070
Kevin Enderbyf9d60f02016-11-29 21:43:40 +000071static cl::opt<bool> NoLeadingHeaders("no-leading-headers",
72 cl::desc("Print no leading headers"));
73
Kevin Enderby13023a12015-01-15 23:19:11 +000074cl::opt<bool> llvm::UniversalHeaders("universal-headers",
75 cl::desc("Print Mach-O universal headers "
76 "(requires -macho)"));
77
Kevin Enderby131d1772015-01-09 19:22:37 +000078cl::opt<bool>
Kevin Enderby8972e482015-04-30 20:30:42 +000079 ArchiveMemberOffsets("archive-member-offsets",
80 cl::desc("Print the offset to each archive member for "
81 "Mach-O archives (requires -macho and "
82 "-archive-headers)"));
83
84cl::opt<bool>
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +000085 llvm::IndirectSymbols("indirect-symbols",
86 cl::desc("Print indirect symbol table for Mach-O "
87 "objects (requires -macho)"));
88
Kevin Enderby69fe98d2015-01-23 18:52:17 +000089cl::opt<bool>
90 llvm::DataInCode("data-in-code",
91 cl::desc("Print the data in code table for Mach-O objects "
92 "(requires -macho)"));
93
Kevin Enderby9a509442015-01-27 21:28:24 +000094cl::opt<bool>
95 llvm::LinkOptHints("link-opt-hints",
96 cl::desc("Print the linker optimization hints for "
97 "Mach-O objects (requires -macho)"));
98
Kevin Enderbycd66be52015-03-11 22:06:32 +000099cl::opt<bool>
100 llvm::InfoPlist("info-plist",
101 cl::desc("Print the info plist section as strings for "
102 "Mach-O objects (requires -macho)"));
103
Kevin Enderbyf0640752015-03-13 17:56:32 +0000104cl::opt<bool>
Kevin Enderbybc847fa2015-03-16 20:08:09 +0000105 llvm::DylibsUsed("dylibs-used",
106 cl::desc("Print the shared libraries used for linked "
107 "Mach-O files (requires -macho)"));
108
109cl::opt<bool>
110 llvm::DylibId("dylib-id",
111 cl::desc("Print the shared library's id for the dylib Mach-O "
112 "file (requires -macho)"));
113
114cl::opt<bool>
Kevin Enderbyf0640752015-03-13 17:56:32 +0000115 llvm::NonVerbose("non-verbose",
116 cl::desc("Print the info for Mach-O objects in "
117 "non-verbose or numeric form (requires -macho)"));
118
Kevin Enderby0fc11822015-04-01 20:57:01 +0000119cl::opt<bool>
120 llvm::ObjcMetaData("objc-meta-data",
121 cl::desc("Print the Objective-C runtime meta data for "
122 "Mach-O files (requires -macho)"));
123
Kevin Enderby6a221752015-03-17 17:10:57 +0000124cl::opt<std::string> llvm::DisSymName(
125 "dis-symname",
Saleem Abdulrasoolec6a7742016-09-08 23:17:34 +0000126 cl::desc("disassemble just this symbol's instructions (requires -macho)"));
Kevin Enderby6a221752015-03-17 17:10:57 +0000127
Kevin Enderby8e29ec92015-03-17 22:26:11 +0000128static cl::opt<bool> NoSymbolicOperands(
129 "no-symbolic-operands",
130 cl::desc("do not symbolic operands when disassembling (requires -macho)"));
131
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +0000132static cl::list<std::string>
133 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
134 cl::ZeroOrMore);
Hans Wennborgcc9deb42015-09-29 18:02:48 +0000135
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +0000136bool ArchAll = false;
137
Kevin Enderbyec5ca032014-08-18 20:21:02 +0000138static std::string ThumbTripleName;
139
140static const Target *GetTarget(const MachOObjectFile *MachOObj,
141 const char **McpuDefault,
142 const Target **ThumbTarget) {
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000143 // Figure out the target triple.
Tim Northover9e8eb412016-04-22 23:21:13 +0000144 llvm::Triple TT(TripleName);
Cameron Zwarich88cc16a2012-02-03 06:35:22 +0000145 if (TripleName.empty()) {
Tim Northover9e8eb412016-04-22 23:21:13 +0000146 TT = MachOObj->getArchTriple(McpuDefault);
Cameron Zwarich88cc16a2012-02-03 06:35:22 +0000147 TripleName = TT.str();
Tim Northover9e8eb412016-04-22 23:21:13 +0000148 }
149
150 if (TT.getArch() == Triple::arm) {
151 // We've inferred a 32-bit ARM target from the object file. All MachO CPUs
152 // that support ARM are also capable of Thumb mode.
153 llvm::Triple ThumbTriple = TT;
154 std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();
155 ThumbTriple.setArchName(ThumbName);
Kevin Enderbyec5ca032014-08-18 20:21:02 +0000156 ThumbTripleName = ThumbTriple.str();
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000157 }
158
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000159 // Get the target specific parser.
160 std::string Error;
161 const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
Kevin Enderbyec5ca032014-08-18 20:21:02 +0000162 if (TheTarget && ThumbTripleName.empty())
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000163 return TheTarget;
164
Kevin Enderbyec5ca032014-08-18 20:21:02 +0000165 *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
166 if (*ThumbTarget)
167 return TheTarget;
168
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000169 WithColor::error(errs(), "llvm-objdump") << "unable to get target for '";
Kevin Enderbyec5ca032014-08-18 20:21:02 +0000170 if (!TheTarget)
171 errs() << TripleName;
172 else
173 errs() << ThumbTripleName;
174 errs() << "', see --version and --triple.\n";
Craig Toppere6cb63e2014-04-25 04:24:47 +0000175 return nullptr;
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000176}
177
Owen Andersond9243c42011-10-17 21:37:35 +0000178struct SymbolSorter {
179 bool operator()(const SymbolRef &A, const SymbolRef &B) {
Kevin Enderby7bd8d992016-05-02 20:28:12 +0000180 Expected<SymbolRef::Type> ATypeOrErr = A.getType();
Kevin Enderby844c4ac2016-11-15 23:07:41 +0000181 if (!ATypeOrErr)
Fangrui Songe7834bd2019-04-07 08:19:55 +0000182 report_error(ATypeOrErr.takeError(), A.getObject()->getFileName());
Kevin Enderby5afbc1c2016-03-23 20:27:00 +0000183 SymbolRef::Type AType = *ATypeOrErr;
Kevin Enderby7bd8d992016-05-02 20:28:12 +0000184 Expected<SymbolRef::Type> BTypeOrErr = B.getType();
Kevin Enderby844c4ac2016-11-15 23:07:41 +0000185 if (!BTypeOrErr)
Fangrui Songe7834bd2019-04-07 08:19:55 +0000186 report_error(BTypeOrErr.takeError(), B.getObject()->getFileName());
Kevin Enderby74f58d42016-03-23 21:45:21 +0000187 SymbolRef::Type BType = *BTypeOrErr;
Kevin Enderby5afbc1c2016-03-23 20:27:00 +0000188 uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue();
189 uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue();
Owen Andersond9243c42011-10-17 21:37:35 +0000190 return AAddr < BAddr;
191 }
Benjamin Kramer43a772e2011-09-19 17:56:04 +0000192};
193
Kevin Enderby273ae012013-06-06 17:20:50 +0000194// Types for the storted data in code table that is built before disassembly
195// and the predicate function to sort them.
196typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
197typedef std::vector<DiceTableEntry> DiceTable;
198typedef DiceTable::iterator dice_table_iterator;
199
Francis Ricci195a66f2017-10-06 15:54:20 +0000200#ifdef HAVE_LIBXAR
Francis Ricci6f942972017-10-06 15:33:28 +0000201namespace {
202struct ScopedXarFile {
203 xar_t xar;
Francis Ricci57d84522017-10-09 20:27:14 +0000204 ScopedXarFile(const char *filename, int32_t flags)
205 : xar(xar_open(filename, flags)) {}
Francis Ricci6f942972017-10-06 15:33:28 +0000206 ~ScopedXarFile() {
207 if (xar)
208 xar_close(xar);
209 }
210 ScopedXarFile(const ScopedXarFile &) = delete;
211 ScopedXarFile &operator=(const ScopedXarFile &) = delete;
212 operator xar_t() { return xar; }
213};
214
215struct ScopedXarIter {
216 xar_iter_t iter;
Francis Ricci57d84522017-10-09 20:27:14 +0000217 ScopedXarIter() : iter(xar_iter_new()) {}
Francis Ricci6f942972017-10-06 15:33:28 +0000218 ~ScopedXarIter() {
219 if (iter)
220 xar_iter_free(iter);
221 }
222 ScopedXarIter(const ScopedXarIter &) = delete;
223 ScopedXarIter &operator=(const ScopedXarIter &) = delete;
224 operator xar_iter_t() { return iter; }
225};
226} // namespace
Francis Ricci195a66f2017-10-06 15:54:20 +0000227#endif // defined(HAVE_LIBXAR)
Francis Ricci6f942972017-10-06 15:33:28 +0000228
Kevin Enderby930fdc72014-11-06 19:00:13 +0000229// This is used to search for a data in code table entry for the PC being
230// disassembled. The j parameter has the PC in j.first. A single data in code
231// table entry can cover many bytes for each of its Kind's. So if the offset,
232// aka the i.first value, of the data in code table entry plus its Length
233// covers the PC being searched for this will return true. If not it will
234// return false.
David Majnemerea9b8ee2014-11-04 08:41:48 +0000235static bool compareDiceTableEntries(const DiceTableEntry &i,
236 const DiceTableEntry &j) {
Kevin Enderby930fdc72014-11-06 19:00:13 +0000237 uint16_t Length;
238 i.second.getLength(Length);
239
240 return j.first >= i.first && j.first < i.first + Length;
Kevin Enderby273ae012013-06-06 17:20:50 +0000241}
242
Colin LeMahieufc32b1b2015-03-18 19:27:31 +0000243static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
Kevin Enderby930fdc72014-11-06 19:00:13 +0000244 unsigned short Kind) {
245 uint32_t Value, Size = 1;
Kevin Enderby273ae012013-06-06 17:20:50 +0000246
247 switch (Kind) {
Kevin Enderby930fdc72014-11-06 19:00:13 +0000248 default:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000249 case MachO::DICE_KIND_DATA:
Kevin Enderby930fdc72014-11-06 19:00:13 +0000250 if (Length >= 4) {
251 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000252 dumpBytes(makeArrayRef(bytes, 4), outs());
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000253 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
Kevin Enderby273ae012013-06-06 17:20:50 +0000254 outs() << "\t.long " << Value;
Kevin Enderby930fdc72014-11-06 19:00:13 +0000255 Size = 4;
256 } else if (Length >= 2) {
257 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000258 dumpBytes(makeArrayRef(bytes, 2), outs());
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000259 Value = bytes[1] << 8 | bytes[0];
Kevin Enderby273ae012013-06-06 17:20:50 +0000260 outs() << "\t.short " << Value;
Kevin Enderby930fdc72014-11-06 19:00:13 +0000261 Size = 2;
262 } else {
263 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000264 dumpBytes(makeArrayRef(bytes, 2), outs());
Kevin Enderby273ae012013-06-06 17:20:50 +0000265 Value = bytes[0];
266 outs() << "\t.byte " << Value;
Kevin Enderby930fdc72014-11-06 19:00:13 +0000267 Size = 1;
Kevin Enderby273ae012013-06-06 17:20:50 +0000268 }
Kevin Enderby930fdc72014-11-06 19:00:13 +0000269 if (Kind == MachO::DICE_KIND_DATA)
270 outs() << "\t@ KIND_DATA\n";
271 else
272 outs() << "\t@ data in code kind = " << Kind << "\n";
Kevin Enderby273ae012013-06-06 17:20:50 +0000273 break;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000274 case MachO::DICE_KIND_JUMP_TABLE8:
Kevin Enderby930fdc72014-11-06 19:00:13 +0000275 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000276 dumpBytes(makeArrayRef(bytes, 1), outs());
Kevin Enderby273ae012013-06-06 17:20:50 +0000277 Value = bytes[0];
Kevin Enderby930fdc72014-11-06 19:00:13 +0000278 outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
279 Size = 1;
Kevin Enderby273ae012013-06-06 17:20:50 +0000280 break;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000281 case MachO::DICE_KIND_JUMP_TABLE16:
Kevin Enderby930fdc72014-11-06 19:00:13 +0000282 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000283 dumpBytes(makeArrayRef(bytes, 2), outs());
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000284 Value = bytes[1] << 8 | bytes[0];
Kevin Enderby930fdc72014-11-06 19:00:13 +0000285 outs() << "\t.short " << format("%5u", Value & 0xffff)
286 << "\t@ KIND_JUMP_TABLE16\n";
287 Size = 2;
Kevin Enderby273ae012013-06-06 17:20:50 +0000288 break;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000289 case MachO::DICE_KIND_JUMP_TABLE32:
Kevin Enderby930fdc72014-11-06 19:00:13 +0000290 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
291 if (!NoShowRawInsn)
Craig Topper0013be12015-09-21 05:32:41 +0000292 dumpBytes(makeArrayRef(bytes, 4), outs());
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000293 Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
Kevin Enderby930fdc72014-11-06 19:00:13 +0000294 outs() << "\t.long " << Value;
295 if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
296 outs() << "\t@ KIND_JUMP_TABLE32\n";
297 else
298 outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
299 Size = 4;
Kevin Enderby273ae012013-06-06 17:20:50 +0000300 break;
301 }
Kevin Enderby930fdc72014-11-06 19:00:13 +0000302 return Size;
Kevin Enderby273ae012013-06-06 17:20:50 +0000303}
304
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000305static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
Alexey Samsonov464d2e42014-03-17 07:28:19 +0000306 std::vector<SectionRef> &Sections,
307 std::vector<SymbolRef> &Symbols,
308 SmallVectorImpl<uint64_t> &FoundFns,
309 uint64_t &BaseSegmentAddress) {
Fangrui Songe7834bd2019-04-07 08:19:55 +0000310 const StringRef FileName = MachOObj->getFileName();
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +0000311 for (const SymbolRef &Symbol : MachOObj->symbols()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +0000312 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
313 if (!SymName.startswith("ltmp"))
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +0000314 Symbols.push_back(Symbol);
315 }
Owen Andersond9243c42011-10-17 21:37:35 +0000316
Alexey Samsonov48803e52014-03-13 14:37:36 +0000317 for (const SectionRef &Section : MachOObj->sections()) {
Owen Andersond9243c42011-10-17 21:37:35 +0000318 StringRef SectName;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000319 Section.getName(SectName);
320 Sections.push_back(Section);
Owen Andersond9243c42011-10-17 21:37:35 +0000321 }
322
Kevin Enderby273ae012013-06-06 17:20:50 +0000323 bool BaseSegmentAddressSet = false;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000324 for (const auto &Command : MachOObj->load_commands()) {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000325 if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
Benjamin Kramer699128e2011-09-21 01:13:19 +0000326 // We found a function starts segment, parse the addresses for later
327 // consumption.
Charles Davis8bdfafd2013-09-01 04:28:48 +0000328 MachO::linkedit_data_command LLC =
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000329 MachOObj->getLinkeditDataLoadCommand(Command);
Benjamin Kramer699128e2011-09-21 01:13:19 +0000330
Charles Davis8bdfafd2013-09-01 04:28:48 +0000331 MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000332 } else if (Command.C.cmd == MachO::LC_SEGMENT) {
333 MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
Charles Davis8bdfafd2013-09-01 04:28:48 +0000334 StringRef SegName = SLC.segname;
Kevin Enderbyb28ed012014-10-29 21:28:24 +0000335 if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
Kevin Enderby273ae012013-06-06 17:20:50 +0000336 BaseSegmentAddressSet = true;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000337 BaseSegmentAddress = SLC.vmaddr;
Kevin Enderby273ae012013-06-06 17:20:50 +0000338 }
339 }
Benjamin Kramer8a529dc2011-09-21 22:16:43 +0000340 }
Benjamin Kramer699128e2011-09-21 01:13:19 +0000341}
342
George Rimarc1964882019-01-18 11:33:26 +0000343static void printRelocationTargetName(const MachOObjectFile *O,
344 const MachO::any_relocation_info &RE,
345 raw_string_ostream &Fmt) {
346 // Target of a scattered relocation is an address. In the interest of
347 // generating pretty output, scan through the symbol table looking for a
348 // symbol that aligns with that address. If we find one, print it.
349 // Otherwise, we just print the hex address of the target.
Fangrui Songe7834bd2019-04-07 08:19:55 +0000350 const StringRef FileName = O->getFileName();
George Rimarc1964882019-01-18 11:33:26 +0000351 if (O->isRelocationScattered(RE)) {
352 uint32_t Val = O->getPlainRelocationSymbolNum(RE);
353
354 for (const SymbolRef &Symbol : O->symbols()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +0000355 uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
356 if (Addr != Val)
George Rimarc1964882019-01-18 11:33:26 +0000357 continue;
Fangrui Songe7834bd2019-04-07 08:19:55 +0000358 Fmt << unwrapOrError(Symbol.getName(), FileName);
George Rimarc1964882019-01-18 11:33:26 +0000359 return;
360 }
361
362 // If we couldn't find a symbol that this relocation refers to, try
363 // to find a section beginning instead.
364 for (const SectionRef &Section : ToolSectionFilter(*O)) {
George Rimarc1964882019-01-18 11:33:26 +0000365 StringRef Name;
366 uint64_t Addr = Section.getAddress();
367 if (Addr != Val)
368 continue;
Fangrui Song3f209682019-04-09 05:41:24 +0000369 if (std::error_code EC = Section.getName(Name))
370 report_error(errorCodeToError(EC), O->getFileName());
George Rimarc1964882019-01-18 11:33:26 +0000371 Fmt << Name;
372 return;
373 }
374
375 Fmt << format("0x%x", Val);
376 return;
377 }
378
379 StringRef S;
380 bool isExtern = O->getPlainRelocationExternal(RE);
381 uint64_t Val = O->getPlainRelocationSymbolNum(RE);
382
383 if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
384 Fmt << format("0x%0" PRIx64, Val);
385 return;
386 }
387
388 if (isExtern) {
389 symbol_iterator SI = O->symbol_begin();
390 advance(SI, Val);
Fangrui Songe7834bd2019-04-07 08:19:55 +0000391 S = unwrapOrError(SI->getName(), FileName);
George Rimarc1964882019-01-18 11:33:26 +0000392 } else {
393 section_iterator SI = O->section_begin();
394 // Adjust for the fact that sections are 1-indexed.
395 if (Val == 0) {
396 Fmt << "0 (?,?)";
397 return;
398 }
399 uint32_t I = Val - 1;
400 while (I != 0 && SI != O->section_end()) {
401 --I;
402 advance(SI, 1);
403 }
404 if (SI == O->section_end())
405 Fmt << Val << " (?,?)";
406 else
407 SI->getName(S);
408 }
409
410 Fmt << S;
411}
412
Fangrui Songf67de6c2019-04-08 16:24:08 +0000413Error llvm::getMachORelocationValueString(const MachOObjectFile *Obj,
414 const RelocationRef &RelRef,
415 SmallVectorImpl<char> &Result) {
George Rimarc1964882019-01-18 11:33:26 +0000416 DataRefImpl Rel = RelRef.getRawDataRefImpl();
417 MachO::any_relocation_info RE = Obj->getRelocation(Rel);
418
419 unsigned Arch = Obj->getArch();
420
421 std::string FmtBuf;
422 raw_string_ostream Fmt(FmtBuf);
423 unsigned Type = Obj->getAnyRelocationType(RE);
424 bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
425
426 // Determine any addends that should be displayed with the relocation.
427 // These require decoding the relocation type, which is triple-specific.
428
429 // X86_64 has entirely custom relocation types.
430 if (Arch == Triple::x86_64) {
431 switch (Type) {
432 case MachO::X86_64_RELOC_GOT_LOAD:
433 case MachO::X86_64_RELOC_GOT: {
434 printRelocationTargetName(Obj, RE, Fmt);
435 Fmt << "@GOT";
436 if (IsPCRel)
437 Fmt << "PCREL";
438 break;
439 }
440 case MachO::X86_64_RELOC_SUBTRACTOR: {
441 DataRefImpl RelNext = Rel;
442 Obj->moveRelocationNext(RelNext);
443 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
444
445 // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
446 // X86_64_RELOC_UNSIGNED.
447 // NOTE: Scattered relocations don't exist on x86_64.
448 unsigned RType = Obj->getAnyRelocationType(RENext);
449 if (RType != MachO::X86_64_RELOC_UNSIGNED)
450 report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
451 "X86_64_RELOC_SUBTRACTOR.");
452
453 // The X86_64_RELOC_UNSIGNED contains the minuend symbol;
454 // X86_64_RELOC_SUBTRACTOR contains the subtrahend.
455 printRelocationTargetName(Obj, RENext, Fmt);
456 Fmt << "-";
457 printRelocationTargetName(Obj, RE, Fmt);
458 break;
459 }
460 case MachO::X86_64_RELOC_TLV:
461 printRelocationTargetName(Obj, RE, Fmt);
462 Fmt << "@TLV";
463 if (IsPCRel)
464 Fmt << "P";
465 break;
466 case MachO::X86_64_RELOC_SIGNED_1:
467 printRelocationTargetName(Obj, RE, Fmt);
468 Fmt << "-1";
469 break;
470 case MachO::X86_64_RELOC_SIGNED_2:
471 printRelocationTargetName(Obj, RE, Fmt);
472 Fmt << "-2";
473 break;
474 case MachO::X86_64_RELOC_SIGNED_4:
475 printRelocationTargetName(Obj, RE, Fmt);
476 Fmt << "-4";
477 break;
478 default:
479 printRelocationTargetName(Obj, RE, Fmt);
480 break;
481 }
482 // X86 and ARM share some relocation types in common.
483 } else if (Arch == Triple::x86 || Arch == Triple::arm ||
484 Arch == Triple::ppc) {
485 // Generic relocation types...
486 switch (Type) {
487 case MachO::GENERIC_RELOC_PAIR: // prints no info
Fangrui Songf67de6c2019-04-08 16:24:08 +0000488 return Error::success();
George Rimarc1964882019-01-18 11:33:26 +0000489 case MachO::GENERIC_RELOC_SECTDIFF: {
490 DataRefImpl RelNext = Rel;
491 Obj->moveRelocationNext(RelNext);
492 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
493
494 // X86 sect diff's must be followed by a relocation of type
495 // GENERIC_RELOC_PAIR.
496 unsigned RType = Obj->getAnyRelocationType(RENext);
497
498 if (RType != MachO::GENERIC_RELOC_PAIR)
499 report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
500 "GENERIC_RELOC_SECTDIFF.");
501
502 printRelocationTargetName(Obj, RE, Fmt);
503 Fmt << "-";
504 printRelocationTargetName(Obj, RENext, Fmt);
505 break;
506 }
507 }
508
509 if (Arch == Triple::x86 || Arch == Triple::ppc) {
510 switch (Type) {
511 case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
512 DataRefImpl RelNext = Rel;
513 Obj->moveRelocationNext(RelNext);
514 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
515
516 // X86 sect diff's must be followed by a relocation of type
517 // GENERIC_RELOC_PAIR.
518 unsigned RType = Obj->getAnyRelocationType(RENext);
519 if (RType != MachO::GENERIC_RELOC_PAIR)
520 report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
521 "GENERIC_RELOC_LOCAL_SECTDIFF.");
522
523 printRelocationTargetName(Obj, RE, Fmt);
524 Fmt << "-";
525 printRelocationTargetName(Obj, RENext, Fmt);
526 break;
527 }
528 case MachO::GENERIC_RELOC_TLV: {
529 printRelocationTargetName(Obj, RE, Fmt);
530 Fmt << "@TLV";
531 if (IsPCRel)
532 Fmt << "P";
533 break;
534 }
535 default:
536 printRelocationTargetName(Obj, RE, Fmt);
537 }
538 } else { // ARM-specific relocations
539 switch (Type) {
540 case MachO::ARM_RELOC_HALF:
541 case MachO::ARM_RELOC_HALF_SECTDIFF: {
542 // Half relocations steal a bit from the length field to encode
543 // whether this is an upper16 or a lower16 relocation.
544 bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
545
546 if (isUpper)
547 Fmt << ":upper16:(";
548 else
549 Fmt << ":lower16:(";
550 printRelocationTargetName(Obj, RE, Fmt);
551
552 DataRefImpl RelNext = Rel;
553 Obj->moveRelocationNext(RelNext);
554 MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
555
556 // ARM half relocs must be followed by a relocation of type
557 // ARM_RELOC_PAIR.
558 unsigned RType = Obj->getAnyRelocationType(RENext);
559 if (RType != MachO::ARM_RELOC_PAIR)
560 report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
561 "ARM_RELOC_HALF");
562
563 // NOTE: The half of the target virtual address is stashed in the
564 // address field of the secondary relocation, but we can't reverse
565 // engineer the constant offset from it without decoding the movw/movt
566 // instruction to find the other half in its immediate field.
567
568 // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
569 // symbol/section pointer of the follow-on relocation.
570 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
571 Fmt << "-";
572 printRelocationTargetName(Obj, RENext, Fmt);
573 }
574
575 Fmt << ")";
576 break;
577 }
578 default: {
579 printRelocationTargetName(Obj, RE, Fmt);
580 }
581 }
582 }
583 } else
584 printRelocationTargetName(Obj, RE, Fmt);
585
586 Fmt.flush();
587 Result.append(FmtBuf.begin(), FmtBuf.end());
Fangrui Songf67de6c2019-04-08 16:24:08 +0000588 return Error::success();
George Rimarc1964882019-01-18 11:33:26 +0000589}
590
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +0000591static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
592 uint32_t n, uint32_t count,
593 uint32_t stride, uint64_t addr) {
594 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
595 uint32_t nindirectsyms = Dysymtab.nindirectsyms;
596 if (n > nindirectsyms)
597 outs() << " (entries start past the end of the indirect symbol "
598 "table) (reserved1 field greater than the table size)";
599 else if (n + count > nindirectsyms)
600 outs() << " (entries extends past the end of the indirect symbol "
601 "table)";
602 outs() << "\n";
603 uint32_t cputype = O->getHeader().cputype;
604 if (cputype & MachO::CPU_ARCH_ABI64)
605 outs() << "address index";
606 else
607 outs() << "address index";
608 if (verbose)
609 outs() << " name\n";
610 else
611 outs() << "\n";
612 for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
613 if (cputype & MachO::CPU_ARCH_ABI64)
614 outs() << format("0x%016" PRIx64, addr + j * stride) << " ";
615 else
Tim Northover43978372016-04-26 18:29:16 +0000616 outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " ";
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +0000617 MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
618 uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
619 if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
620 outs() << "LOCAL\n";
621 continue;
622 }
623 if (indirect_symbol ==
624 (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
625 outs() << "LOCAL ABSOLUTE\n";
626 continue;
627 }
628 if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
629 outs() << "ABSOLUTE\n";
630 continue;
631 }
632 outs() << format("%5u ", indirect_symbol);
Kevin Enderbyf0640752015-03-13 17:56:32 +0000633 if (verbose) {
634 MachO::symtab_command Symtab = O->getSymtabLoadCommand();
635 if (indirect_symbol < Symtab.nsyms) {
636 symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
637 SymbolRef Symbol = *Sym;
Fangrui Songe7834bd2019-04-07 08:19:55 +0000638 outs() << unwrapOrError(Symbol.getName(), O->getFileName());
Kevin Enderbyf0640752015-03-13 17:56:32 +0000639 } else {
640 outs() << "?";
641 }
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +0000642 }
643 outs() << "\n";
644 }
645}
646
647static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000648 for (const auto &Load : O->load_commands()) {
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +0000649 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
650 MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
651 for (unsigned J = 0; J < Seg.nsects; ++J) {
652 MachO::section_64 Sec = O->getSection64(Load, J);
653 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
654 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
655 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
656 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
657 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
658 section_type == MachO::S_SYMBOL_STUBS) {
659 uint32_t stride;
660 if (section_type == MachO::S_SYMBOL_STUBS)
661 stride = Sec.reserved2;
662 else
663 stride = 8;
664 if (stride == 0) {
665 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
666 << Sec.sectname << ") "
667 << "(size of stubs in reserved2 field is zero)\n";
668 continue;
669 }
670 uint32_t count = Sec.size / stride;
671 outs() << "Indirect symbols for (" << Sec.segname << ","
672 << Sec.sectname << ") " << count << " entries";
673 uint32_t n = Sec.reserved1;
674 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
675 }
676 }
677 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
678 MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
679 for (unsigned J = 0; J < Seg.nsects; ++J) {
680 MachO::section Sec = O->getSection(Load, J);
681 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
682 if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
683 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
684 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
685 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
686 section_type == MachO::S_SYMBOL_STUBS) {
687 uint32_t stride;
688 if (section_type == MachO::S_SYMBOL_STUBS)
689 stride = Sec.reserved2;
690 else
691 stride = 4;
692 if (stride == 0) {
693 outs() << "Can't print indirect symbols for (" << Sec.segname << ","
694 << Sec.sectname << ") "
695 << "(size of stubs in reserved2 field is zero)\n";
696 continue;
697 }
698 uint32_t count = Sec.size / stride;
699 outs() << "Indirect symbols for (" << Sec.segname << ","
700 << Sec.sectname << ") " << count << " entries";
701 uint32_t n = Sec.reserved1;
702 PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
703 }
704 }
705 }
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +0000706 }
707}
708
Michael Trenta1703b12017-12-15 17:57:40 +0000709static void PrintRType(const uint64_t cputype, const unsigned r_type) {
710 static char const *generic_r_types[] = {
711 "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
712 " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
713 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
714 };
715 static char const *x86_64_r_types[] = {
716 "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
717 "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
718 " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
719 };
720 static char const *arm_r_types[] = {
721 "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
722 "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
723 " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
724 };
725 static char const *arm64_r_types[] = {
726 "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
727 "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
728 "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
729 };
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000730
Michael Trenta1703b12017-12-15 17:57:40 +0000731 if (r_type > 0xf){
732 outs() << format("%-7u", r_type) << " ";
733 return;
734 }
735 switch (cputype) {
736 case MachO::CPU_TYPE_I386:
737 outs() << generic_r_types[r_type];
738 break;
739 case MachO::CPU_TYPE_X86_64:
740 outs() << x86_64_r_types[r_type];
741 break;
742 case MachO::CPU_TYPE_ARM:
743 outs() << arm_r_types[r_type];
744 break;
745 case MachO::CPU_TYPE_ARM64:
746 outs() << arm64_r_types[r_type];
747 break;
748 default:
749 outs() << format("%-7u ", r_type);
750 }
751}
752
753static void PrintRLength(const uint64_t cputype, const unsigned r_type,
754 const unsigned r_length, const bool previous_arm_half){
755 if (cputype == MachO::CPU_TYPE_ARM &&
756 (r_type == llvm::MachO::ARM_RELOC_HALF ||
757 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF ||
758 previous_arm_half == true)) {
759 if ((r_length & 0x1) == 0)
760 outs() << "lo/";
761 else
762 outs() << "hi/";
763 if ((r_length & 0x1) == 0)
764 outs() << "arm ";
765 else
766 outs() << "thm ";
767 } else {
768 switch (r_length) {
769 case 0:
770 outs() << "byte ";
771 break;
772 case 1:
773 outs() << "word ";
774 break;
775 case 2:
776 outs() << "long ";
777 break;
778 case 3:
779 if (cputype == MachO::CPU_TYPE_X86_64)
780 outs() << "quad ";
781 else
782 outs() << format("?(%2d) ", r_length);
783 break;
784 default:
785 outs() << format("?(%2d) ", r_length);
786 }
787 }
788}
789
790static void PrintRelocationEntries(const MachOObjectFile *O,
791 const relocation_iterator Begin,
792 const relocation_iterator End,
793 const uint64_t cputype,
794 const bool verbose) {
795 const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
796 bool previous_arm_half = false;
797 bool previous_sectdiff = false;
798 uint32_t sectdiff_r_type = 0;
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000799
Michael Trenta1703b12017-12-15 17:57:40 +0000800 for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
801 const DataRefImpl Rel = Reloc->getRawDataRefImpl();
802 const MachO::any_relocation_info RE = O->getRelocation(Rel);
803 const unsigned r_type = O->getAnyRelocationType(RE);
804 const bool r_scattered = O->isRelocationScattered(RE);
805 const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
806 const unsigned r_length = O->getAnyRelocationLength(RE);
807 const unsigned r_address = O->getAnyRelocationAddress(RE);
808 const bool r_extern = (r_scattered ? false :
809 O->getPlainRelocationExternal(RE));
810 const uint32_t r_value = (r_scattered ?
811 O->getScatteredRelocationValue(RE) : 0);
812 const unsigned r_symbolnum = (r_scattered ? 0 :
813 O->getPlainRelocationSymbolNum(RE));
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000814
Michael Trenta1703b12017-12-15 17:57:40 +0000815 if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
816 if (verbose) {
817 // scattered: address
818 if ((cputype == MachO::CPU_TYPE_I386 &&
819 r_type == llvm::MachO::GENERIC_RELOC_PAIR) ||
820 (cputype == MachO::CPU_TYPE_ARM &&
821 r_type == llvm::MachO::ARM_RELOC_PAIR))
822 outs() << " ";
823 else
824 outs() << format("%08x ", (unsigned int)r_address);
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000825
Michael Trenta1703b12017-12-15 17:57:40 +0000826 // scattered: pcrel
827 if (r_pcrel)
828 outs() << "True ";
829 else
830 outs() << "False ";
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000831
Michael Trenta1703b12017-12-15 17:57:40 +0000832 // scattered: length
833 PrintRLength(cputype, r_type, r_length, previous_arm_half);
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000834
Michael Trenta1703b12017-12-15 17:57:40 +0000835 // scattered: extern & type
836 outs() << "n/a ";
837 PrintRType(cputype, r_type);
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000838
Michael Trenta1703b12017-12-15 17:57:40 +0000839 // scattered: scattered & value
840 outs() << format("True 0x%08x", (unsigned int)r_value);
841 if (previous_sectdiff == false) {
842 if ((cputype == MachO::CPU_TYPE_ARM &&
843 r_type == llvm::MachO::ARM_RELOC_PAIR))
844 outs() << format(" half = 0x%04x ", (unsigned int)r_address);
845 }
846 else if (cputype == MachO::CPU_TYPE_ARM &&
847 sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)
848 outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
849 if ((cputype == MachO::CPU_TYPE_I386 &&
850 (r_type == llvm::MachO::GENERIC_RELOC_SECTDIFF ||
851 r_type == llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
852 (cputype == MachO::CPU_TYPE_ARM &&
853 (sectdiff_r_type == llvm::MachO::ARM_RELOC_SECTDIFF ||
854 sectdiff_r_type == llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF ||
855 sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))) {
856 previous_sectdiff = true;
857 sectdiff_r_type = r_type;
858 }
859 else {
860 previous_sectdiff = false;
861 sectdiff_r_type = 0;
862 }
863 if (cputype == MachO::CPU_TYPE_ARM &&
864 (r_type == llvm::MachO::ARM_RELOC_HALF ||
865 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
866 previous_arm_half = true;
867 else
868 previous_arm_half = false;
869 outs() << "\n";
870 }
871 else {
872 // scattered: address pcrel length extern type scattered value
873 outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",
874 (unsigned int)r_address, r_pcrel, r_length, r_type,
875 (unsigned int)r_value);
876 }
877 }
878 else {
879 if (verbose) {
880 // plain: address
881 if (cputype == MachO::CPU_TYPE_ARM &&
882 r_type == llvm::MachO::ARM_RELOC_PAIR)
883 outs() << " ";
884 else
885 outs() << format("%08x ", (unsigned int)r_address);
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000886
Michael Trenta1703b12017-12-15 17:57:40 +0000887 // plain: pcrel
888 if (r_pcrel)
889 outs() << "True ";
890 else
891 outs() << "False ";
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000892
Michael Trenta1703b12017-12-15 17:57:40 +0000893 // plain: length
894 PrintRLength(cputype, r_type, r_length, previous_arm_half);
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000895
Michael Trenta1703b12017-12-15 17:57:40 +0000896 if (r_extern) {
897 // plain: extern & type & scattered
898 outs() << "True ";
899 PrintRType(cputype, r_type);
900 outs() << "False ";
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000901
Michael Trenta1703b12017-12-15 17:57:40 +0000902 // plain: symbolnum/value
903 if (r_symbolnum > Symtab.nsyms)
904 outs() << format("?(%d)\n", r_symbolnum);
905 else {
906 SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);
907 Expected<StringRef> SymNameNext = Symbol.getName();
908 const char *name = NULL;
909 if (SymNameNext)
910 name = SymNameNext->data();
911 if (name == NULL)
912 outs() << format("?(%d)\n", r_symbolnum);
913 else
914 outs() << name << "\n";
915 }
916 }
917 else {
918 // plain: extern & type & scattered
919 outs() << "False ";
920 PrintRType(cputype, r_type);
921 outs() << "False ";
Jonas Devliegheree787efd2018-11-11 22:12:04 +0000922
Michael Trenta1703b12017-12-15 17:57:40 +0000923 // plain: symbolnum/value
924 if (cputype == MachO::CPU_TYPE_ARM &&
925 r_type == llvm::MachO::ARM_RELOC_PAIR)
926 outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
927 else if (cputype == MachO::CPU_TYPE_ARM64 &&
928 r_type == llvm::MachO::ARM64_RELOC_ADDEND)
929 outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
930 else {
931 outs() << format("%d ", r_symbolnum);
932 if (r_symbolnum == llvm::MachO::R_ABS)
933 outs() << "R_ABS\n";
934 else {
935 // in this case, r_symbolnum is actually a 1-based section number
936 uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
937 if (r_symbolnum > 0 && r_symbolnum <= nsects) {
938 llvm::object::DataRefImpl DRI;
939 DRI.d.a = r_symbolnum-1;
940 StringRef SegName = O->getSectionFinalSegmentName(DRI);
941 StringRef SectName;
942 if (O->getSectionName(DRI, SectName))
943 outs() << "(?,?)\n";
944 else
945 outs() << "(" << SegName << "," << SectName << ")\n";
946 }
947 else {
948 outs() << "(?,?)\n";
949 }
950 }
951 }
952 }
953 if (cputype == MachO::CPU_TYPE_ARM &&
954 (r_type == llvm::MachO::ARM_RELOC_HALF ||
955 r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
956 previous_arm_half = true;
957 else
958 previous_arm_half = false;
959 }
960 else {
961 // plain: address pcrel length extern type scattered symbolnum/section
962 outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",
963 (unsigned int)r_address, r_pcrel, r_length, r_extern,
964 r_type, r_symbolnum);
965 }
966 }
967 }
968}
969
970static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
971 const uint64_t cputype = O->getHeader().cputype;
972 const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
973 if (Dysymtab.nextrel != 0) {
974 outs() << "External relocation information " << Dysymtab.nextrel
975 << " entries";
976 outs() << "\naddress pcrel length extern type scattered "
977 "symbolnum/value\n";
978 PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,
979 verbose);
980 }
981 if (Dysymtab.nlocrel != 0) {
982 outs() << format("Local relocation information %u entries",
983 Dysymtab.nlocrel);
984 outs() << "\naddress pcrel length extern type scattered "
985 "symbolnum/value\n";
986 PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,
987 verbose);
988 }
989 for (const auto &Load : O->load_commands()) {
990 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
991 const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
992 for (unsigned J = 0; J < Seg.nsects; ++J) {
993 const MachO::section_64 Sec = O->getSection64(Load, J);
994 if (Sec.nreloc != 0) {
995 DataRefImpl DRI;
996 DRI.d.a = J;
997 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
998 StringRef SectName;
999 if (O->getSectionName(DRI, SectName))
1000 outs() << "Relocation information (" << SegName << ",?) "
1001 << format("%u entries", Sec.nreloc);
1002 else
1003 outs() << "Relocation information (" << SegName << ","
1004 << SectName << format(") %u entries", Sec.nreloc);
1005 outs() << "\naddress pcrel length extern type scattered "
1006 "symbolnum/value\n";
1007 PrintRelocationEntries(O, O->section_rel_begin(DRI),
1008 O->section_rel_end(DRI), cputype, verbose);
1009 }
1010 }
1011 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
1012 const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
1013 for (unsigned J = 0; J < Seg.nsects; ++J) {
1014 const MachO::section Sec = O->getSection(Load, J);
1015 if (Sec.nreloc != 0) {
1016 DataRefImpl DRI;
1017 DRI.d.a = J;
1018 const StringRef SegName = O->getSectionFinalSegmentName(DRI);
1019 StringRef SectName;
1020 if (O->getSectionName(DRI, SectName))
1021 outs() << "Relocation information (" << SegName << ",?) "
1022 << format("%u entries", Sec.nreloc);
1023 else
1024 outs() << "Relocation information (" << SegName << ","
1025 << SectName << format(") %u entries", Sec.nreloc);
1026 outs() << "\naddress pcrel length extern type scattered "
1027 "symbolnum/value\n";
1028 PrintRelocationEntries(O, O->section_rel_begin(DRI),
1029 O->section_rel_end(DRI), cputype, verbose);
1030 }
1031 }
1032 }
1033 }
1034}
1035
Kevin Enderby69fe98d2015-01-23 18:52:17 +00001036static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
1037 MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
1038 uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
1039 outs() << "Data in code table (" << nentries << " entries)\n";
1040 outs() << "offset length kind\n";
1041 for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
1042 ++DI) {
1043 uint32_t Offset;
1044 DI->getOffset(Offset);
1045 outs() << format("0x%08" PRIx32, Offset) << " ";
1046 uint16_t Length;
1047 DI->getLength(Length);
1048 outs() << format("%6u", Length) << " ";
1049 uint16_t Kind;
1050 DI->getKind(Kind);
1051 if (verbose) {
1052 switch (Kind) {
1053 case MachO::DICE_KIND_DATA:
1054 outs() << "DATA";
1055 break;
1056 case MachO::DICE_KIND_JUMP_TABLE8:
1057 outs() << "JUMP_TABLE8";
1058 break;
1059 case MachO::DICE_KIND_JUMP_TABLE16:
1060 outs() << "JUMP_TABLE16";
1061 break;
1062 case MachO::DICE_KIND_JUMP_TABLE32:
1063 outs() << "JUMP_TABLE32";
1064 break;
1065 case MachO::DICE_KIND_ABS_JUMP_TABLE32:
1066 outs() << "ABS_JUMP_TABLE32";
1067 break;
1068 default:
1069 outs() << format("0x%04" PRIx32, Kind);
1070 break;
1071 }
1072 } else
1073 outs() << format("0x%04" PRIx32, Kind);
1074 outs() << "\n";
1075 }
1076}
1077
Kevin Enderby9a509442015-01-27 21:28:24 +00001078static void PrintLinkOptHints(MachOObjectFile *O) {
1079 MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
1080 const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
1081 uint32_t nloh = LohLC.datasize;
1082 outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
1083 for (uint32_t i = 0; i < nloh;) {
1084 unsigned n;
1085 uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
1086 i += n;
1087 outs() << " identifier " << identifier << " ";
1088 if (i >= nloh)
1089 return;
1090 switch (identifier) {
1091 case 1:
1092 outs() << "AdrpAdrp\n";
1093 break;
1094 case 2:
1095 outs() << "AdrpLdr\n";
1096 break;
1097 case 3:
1098 outs() << "AdrpAddLdr\n";
1099 break;
1100 case 4:
1101 outs() << "AdrpLdrGotLdr\n";
1102 break;
1103 case 5:
1104 outs() << "AdrpAddStr\n";
1105 break;
1106 case 6:
1107 outs() << "AdrpLdrGotStr\n";
1108 break;
1109 case 7:
1110 outs() << "AdrpAdd\n";
1111 break;
1112 case 8:
1113 outs() << "AdrpLdrGot\n";
1114 break;
1115 default:
1116 outs() << "Unknown identifier value\n";
1117 break;
1118 }
1119 uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
1120 i += n;
1121 outs() << " narguments " << narguments << "\n";
1122 if (i >= nloh)
1123 return;
1124
1125 for (uint32_t j = 0; j < narguments; j++) {
1126 uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
1127 i += n;
1128 outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";
1129 if (i >= nloh)
1130 return;
1131 }
1132 }
1133}
1134
Kevin Enderbybc847fa2015-03-16 20:08:09 +00001135static void PrintDylibs(MachOObjectFile *O, bool JustId) {
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00001136 unsigned Index = 0;
1137 for (const auto &Load : O->load_commands()) {
Kevin Enderbybc847fa2015-03-16 20:08:09 +00001138 if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
1139 (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
1140 Load.C.cmd == MachO::LC_LOAD_DYLIB ||
1141 Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
1142 Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
1143 Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
1144 Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
1145 MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
1146 if (dl.dylib.name < dl.cmdsize) {
1147 const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
1148 if (JustId)
1149 outs() << p << "\n";
1150 else {
1151 outs() << "\t" << p;
1152 outs() << " (compatibility version "
1153 << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
1154 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
1155 << (dl.dylib.compatibility_version & 0xff) << ",";
1156 outs() << " current version "
1157 << ((dl.dylib.current_version >> 16) & 0xffff) << "."
1158 << ((dl.dylib.current_version >> 8) & 0xff) << "."
1159 << (dl.dylib.current_version & 0xff) << ")\n";
1160 }
1161 } else {
1162 outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
1163 if (Load.C.cmd == MachO::LC_ID_DYLIB)
1164 outs() << "LC_ID_DYLIB ";
1165 else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
1166 outs() << "LC_LOAD_DYLIB ";
1167 else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
1168 outs() << "LC_LOAD_WEAK_DYLIB ";
1169 else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
1170 outs() << "LC_LAZY_LOAD_DYLIB ";
1171 else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
1172 outs() << "LC_REEXPORT_DYLIB ";
1173 else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
1174 outs() << "LC_LOAD_UPWARD_DYLIB ";
1175 else
1176 outs() << "LC_??? ";
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00001177 outs() << "command " << Index++ << "\n";
Kevin Enderbybc847fa2015-03-16 20:08:09 +00001178 }
1179 }
Kevin Enderbybc847fa2015-03-16 20:08:09 +00001180 }
1181}
1182
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001183typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
1184
1185static void CreateSymbolAddressMap(MachOObjectFile *O,
1186 SymbolAddressMap *AddrMap) {
1187 // Create a map of symbol addresses to symbol names.
Fangrui Songe7834bd2019-04-07 08:19:55 +00001188 const StringRef FileName = O->getFileName();
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001189 for (const SymbolRef &Symbol : O->symbols()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00001190 SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001191 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
1192 ST == SymbolRef::ST_Other) {
Rafael Espindoladea00162015-07-03 17:44:18 +00001193 uint64_t Address = Symbol.getValue();
Fangrui Songe7834bd2019-04-07 08:19:55 +00001194 StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
Kevin Enderby846c0002015-04-16 17:19:59 +00001195 if (!SymName.startswith(".objc"))
1196 (*AddrMap)[Address] = SymName;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001197 }
1198 }
1199}
1200
1201// GuessSymbolName is passed the address of what might be a symbol and a
1202// pointer to the SymbolAddressMap. It returns the name of a symbol
1203// with that address or nullptr if no symbol is found with that address.
1204static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
1205 const char *SymbolName = nullptr;
1206 // A DenseMap can't lookup up some values.
1207 if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
1208 StringRef name = AddrMap->lookup(value);
1209 if (!name.empty())
1210 SymbolName = name.data();
1211 }
1212 return SymbolName;
1213}
1214
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001215static void DumpCstringChar(const char c) {
1216 char p[2];
1217 p[0] = c;
1218 p[1] = '\0';
1219 outs().write_escaped(p);
1220}
1221
Kevin Enderby10ba0412015-02-04 21:38:42 +00001222static void DumpCstringSection(MachOObjectFile *O, const char *sect,
1223 uint32_t sect_size, uint64_t sect_addr,
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001224 bool print_addresses) {
Kevin Enderby10ba0412015-02-04 21:38:42 +00001225 for (uint32_t i = 0; i < sect_size; i++) {
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001226 if (print_addresses) {
1227 if (O->is64Bit())
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001228 outs() << format("%016" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001229 else
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001230 outs() << format("%08" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001231 }
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001232 for (; i < sect_size && sect[i] != '\0'; i++)
1233 DumpCstringChar(sect[i]);
Kevin Enderby10ba0412015-02-04 21:38:42 +00001234 if (i < sect_size && sect[i] == '\0')
1235 outs() << "\n";
1236 }
1237}
1238
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001239static void DumpLiteral4(uint32_t l, float f) {
1240 outs() << format("0x%08" PRIx32, l);
1241 if ((l & 0x7f800000) != 0x7f800000)
1242 outs() << format(" (%.16e)\n", f);
1243 else {
1244 if (l == 0x7f800000)
1245 outs() << " (+Infinity)\n";
1246 else if (l == 0xff800000)
1247 outs() << " (-Infinity)\n";
1248 else if ((l & 0x00400000) == 0x00400000)
1249 outs() << " (non-signaling Not-a-Number)\n";
1250 else
1251 outs() << " (signaling Not-a-Number)\n";
1252 }
1253}
1254
1255static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
1256 uint32_t sect_size, uint64_t sect_addr,
1257 bool print_addresses) {
1258 for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
1259 if (print_addresses) {
1260 if (O->is64Bit())
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001261 outs() << format("%016" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001262 else
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001263 outs() << format("%08" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001264 }
1265 float f;
1266 memcpy(&f, sect + i, sizeof(float));
1267 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1268 sys::swapByteOrder(f);
1269 uint32_t l;
1270 memcpy(&l, sect + i, sizeof(uint32_t));
1271 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1272 sys::swapByteOrder(l);
1273 DumpLiteral4(l, f);
1274 }
1275}
1276
1277static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
1278 double d) {
1279 outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
1280 uint32_t Hi, Lo;
Davide Italianob627d9f2015-12-12 21:50:11 +00001281 Hi = (O->isLittleEndian()) ? l1 : l0;
1282 Lo = (O->isLittleEndian()) ? l0 : l1;
1283
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001284 // Hi is the high word, so this is equivalent to if(isfinite(d))
1285 if ((Hi & 0x7ff00000) != 0x7ff00000)
1286 outs() << format(" (%.16e)\n", d);
1287 else {
1288 if (Hi == 0x7ff00000 && Lo == 0)
1289 outs() << " (+Infinity)\n";
1290 else if (Hi == 0xfff00000 && Lo == 0)
1291 outs() << " (-Infinity)\n";
1292 else if ((Hi & 0x00080000) == 0x00080000)
1293 outs() << " (non-signaling Not-a-Number)\n";
1294 else
1295 outs() << " (signaling Not-a-Number)\n";
1296 }
1297}
1298
1299static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
1300 uint32_t sect_size, uint64_t sect_addr,
1301 bool print_addresses) {
1302 for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
1303 if (print_addresses) {
1304 if (O->is64Bit())
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001305 outs() << format("%016" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001306 else
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001307 outs() << format("%08" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001308 }
1309 double d;
1310 memcpy(&d, sect + i, sizeof(double));
1311 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1312 sys::swapByteOrder(d);
1313 uint32_t l0, l1;
1314 memcpy(&l0, sect + i, sizeof(uint32_t));
1315 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1316 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1317 sys::swapByteOrder(l0);
1318 sys::swapByteOrder(l1);
1319 }
1320 DumpLiteral8(O, l0, l1, d);
1321 }
1322}
1323
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001324static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
1325 outs() << format("0x%08" PRIx32, l0) << " ";
1326 outs() << format("0x%08" PRIx32, l1) << " ";
1327 outs() << format("0x%08" PRIx32, l2) << " ";
1328 outs() << format("0x%08" PRIx32, l3) << "\n";
1329}
1330
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001331static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
1332 uint32_t sect_size, uint64_t sect_addr,
1333 bool print_addresses) {
1334 for (uint32_t i = 0; i < sect_size; i += 16) {
1335 if (print_addresses) {
1336 if (O->is64Bit())
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001337 outs() << format("%016" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001338 else
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001339 outs() << format("%08" PRIx64, sect_addr + i) << " ";
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001340 }
1341 uint32_t l0, l1, l2, l3;
1342 memcpy(&l0, sect + i, sizeof(uint32_t));
1343 memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
1344 memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
1345 memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
1346 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1347 sys::swapByteOrder(l0);
1348 sys::swapByteOrder(l1);
1349 sys::swapByteOrder(l2);
1350 sys::swapByteOrder(l3);
1351 }
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001352 DumpLiteral16(l0, l1, l2, l3);
1353 }
1354}
1355
1356static void DumpLiteralPointerSection(MachOObjectFile *O,
1357 const SectionRef &Section,
1358 const char *sect, uint32_t sect_size,
1359 uint64_t sect_addr,
1360 bool print_addresses) {
1361 // Collect the literal sections in this Mach-O file.
1362 std::vector<SectionRef> LiteralSections;
1363 for (const SectionRef &Section : O->sections()) {
1364 DataRefImpl Ref = Section.getRawDataRefImpl();
1365 uint32_t section_type;
1366 if (O->is64Bit()) {
1367 const MachO::section_64 Sec = O->getSection64(Ref);
1368 section_type = Sec.flags & MachO::SECTION_TYPE;
1369 } else {
1370 const MachO::section Sec = O->getSection(Ref);
1371 section_type = Sec.flags & MachO::SECTION_TYPE;
1372 }
1373 if (section_type == MachO::S_CSTRING_LITERALS ||
1374 section_type == MachO::S_4BYTE_LITERALS ||
1375 section_type == MachO::S_8BYTE_LITERALS ||
1376 section_type == MachO::S_16BYTE_LITERALS)
1377 LiteralSections.push_back(Section);
1378 }
1379
1380 // Set the size of the literal pointer.
1381 uint32_t lp_size = O->is64Bit() ? 8 : 4;
1382
Eric Christopher572e03a2015-06-19 01:53:21 +00001383 // Collect the external relocation symbols for the literal pointers.
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001384 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1385 for (const RelocationRef &Reloc : Section.relocations()) {
1386 DataRefImpl Rel;
1387 MachO::any_relocation_info RE;
1388 bool isExtern = false;
1389 Rel = Reloc.getRawDataRefImpl();
1390 RE = O->getRelocation(Rel);
1391 isExtern = O->getPlainRelocationExternal(RE);
1392 if (isExtern) {
Rafael Espindola96d071c2015-06-29 23:29:12 +00001393 uint64_t RelocOffset = Reloc.getOffset();
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001394 symbol_iterator RelocSym = Reloc.getSymbol();
1395 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1396 }
1397 }
1398 array_pod_sort(Relocs.begin(), Relocs.end());
1399
1400 // Dump each literal pointer.
1401 for (uint32_t i = 0; i < sect_size; i += lp_size) {
1402 if (print_addresses) {
1403 if (O->is64Bit())
1404 outs() << format("%016" PRIx64, sect_addr + i) << " ";
1405 else
1406 outs() << format("%08" PRIx64, sect_addr + i) << " ";
1407 }
1408 uint64_t lp;
1409 if (O->is64Bit()) {
1410 memcpy(&lp, sect + i, sizeof(uint64_t));
1411 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1412 sys::swapByteOrder(lp);
1413 } else {
1414 uint32_t li;
1415 memcpy(&li, sect + i, sizeof(uint32_t));
1416 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1417 sys::swapByteOrder(li);
1418 lp = li;
1419 }
1420
1421 // First look for an external relocation entry for this literal pointer.
David Majnemer42531262016-08-12 03:55:06 +00001422 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1423 return P.first == i;
1424 });
David Blaikie33dd45d02015-03-23 18:39:02 +00001425 if (Reloc != Relocs.end()) {
1426 symbol_iterator RelocSym = Reloc->second;
Fangrui Songe7834bd2019-04-07 08:19:55 +00001427 StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());
1428 outs() << "external relocation entry for symbol:" << SymName << "\n";
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001429 continue;
David Blaikie33dd45d02015-03-23 18:39:02 +00001430 }
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001431
1432 // For local references see what the section the literal pointer points to.
David Majnemer562e8292016-08-12 00:18:03 +00001433 auto Sect = find_if(LiteralSections, [&](const SectionRef &R) {
1434 return lp >= R.getAddress() && lp < R.getAddress() + R.getSize();
1435 });
David Blaikie33dd45d02015-03-23 18:39:02 +00001436 if (Sect == LiteralSections.end()) {
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001437 outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
David Blaikie33dd45d02015-03-23 18:39:02 +00001438 continue;
1439 }
1440
1441 uint64_t SectAddress = Sect->getAddress();
1442 uint64_t SectSize = Sect->getSize();
1443
1444 StringRef SectName;
1445 Sect->getName(SectName);
1446 DataRefImpl Ref = Sect->getRawDataRefImpl();
1447 StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
1448 outs() << SegmentName << ":" << SectName << ":";
1449
1450 uint32_t section_type;
1451 if (O->is64Bit()) {
1452 const MachO::section_64 Sec = O->getSection64(Ref);
1453 section_type = Sec.flags & MachO::SECTION_TYPE;
1454 } else {
1455 const MachO::section Sec = O->getSection(Ref);
1456 section_type = Sec.flags & MachO::SECTION_TYPE;
1457 }
1458
1459 StringRef BytesStr;
1460 Sect->getContents(BytesStr);
1461 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
1462
1463 switch (section_type) {
1464 case MachO::S_CSTRING_LITERALS:
1465 for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
1466 i++) {
1467 DumpCstringChar(Contents[i]);
1468 }
1469 outs() << "\n";
1470 break;
1471 case MachO::S_4BYTE_LITERALS:
1472 float f;
1473 memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
1474 uint32_t l;
1475 memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
1476 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1477 sys::swapByteOrder(f);
1478 sys::swapByteOrder(l);
1479 }
1480 DumpLiteral4(l, f);
1481 break;
1482 case MachO::S_8BYTE_LITERALS: {
1483 double d;
1484 memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
1485 uint32_t l0, l1;
1486 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1487 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1488 sizeof(uint32_t));
1489 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1490 sys::swapByteOrder(f);
1491 sys::swapByteOrder(l0);
1492 sys::swapByteOrder(l1);
1493 }
1494 DumpLiteral8(O, l0, l1, d);
1495 break;
1496 }
1497 case MachO::S_16BYTE_LITERALS: {
1498 uint32_t l0, l1, l2, l3;
1499 memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
1500 memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
1501 sizeof(uint32_t));
1502 memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
1503 sizeof(uint32_t));
1504 memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
1505 sizeof(uint32_t));
1506 if (O->isLittleEndian() != sys::IsLittleEndianHost) {
1507 sys::swapByteOrder(l0);
1508 sys::swapByteOrder(l1);
1509 sys::swapByteOrder(l2);
1510 sys::swapByteOrder(l3);
1511 }
1512 DumpLiteral16(l0, l1, l2, l3);
1513 break;
1514 }
1515 }
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001516 }
1517}
1518
Kevin Enderby85b7a662018-03-20 20:29:52 +00001519static void DumpInitTermPointerSection(MachOObjectFile *O,
1520 const SectionRef &Section,
1521 const char *sect,
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001522 uint32_t sect_size, uint64_t sect_addr,
1523 SymbolAddressMap *AddrMap,
1524 bool verbose) {
1525 uint32_t stride;
Davide Italiano3eb47e22015-12-15 23:14:21 +00001526 stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
Kevin Enderby85b7a662018-03-20 20:29:52 +00001527
1528 // Collect the external relocation symbols for the pointers.
1529 std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
1530 for (const RelocationRef &Reloc : Section.relocations()) {
1531 DataRefImpl Rel;
1532 MachO::any_relocation_info RE;
1533 bool isExtern = false;
1534 Rel = Reloc.getRawDataRefImpl();
1535 RE = O->getRelocation(Rel);
1536 isExtern = O->getPlainRelocationExternal(RE);
1537 if (isExtern) {
1538 uint64_t RelocOffset = Reloc.getOffset();
1539 symbol_iterator RelocSym = Reloc.getSymbol();
1540 Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
1541 }
1542 }
1543 array_pod_sort(Relocs.begin(), Relocs.end());
1544
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001545 for (uint32_t i = 0; i < sect_size; i += stride) {
1546 const char *SymbolName = nullptr;
Kevin Enderby85b7a662018-03-20 20:29:52 +00001547 uint64_t p;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001548 if (O->is64Bit()) {
1549 outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
1550 uint64_t pointer_value;
1551 memcpy(&pointer_value, sect + i, stride);
1552 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1553 sys::swapByteOrder(pointer_value);
1554 outs() << format("0x%016" PRIx64, pointer_value);
Kevin Enderby85b7a662018-03-20 20:29:52 +00001555 p = pointer_value;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001556 } else {
1557 outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
1558 uint32_t pointer_value;
1559 memcpy(&pointer_value, sect + i, stride);
1560 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1561 sys::swapByteOrder(pointer_value);
1562 outs() << format("0x%08" PRIx32, pointer_value);
Kevin Enderby85b7a662018-03-20 20:29:52 +00001563 p = pointer_value;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001564 }
Kevin Enderby85b7a662018-03-20 20:29:52 +00001565 if (verbose) {
1566 // First look for an external relocation entry for this pointer.
1567 auto Reloc = find_if(Relocs, [&](const std::pair<uint64_t, SymbolRef> &P) {
1568 return P.first == i;
1569 });
1570 if (Reloc != Relocs.end()) {
1571 symbol_iterator RelocSym = Reloc->second;
Fangrui Songe7834bd2019-04-07 08:19:55 +00001572 outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());
Kevin Enderby85b7a662018-03-20 20:29:52 +00001573 } else {
1574 SymbolName = GuessSymbolName(p, AddrMap);
1575 if (SymbolName)
1576 outs() << " " << SymbolName;
1577 }
1578 }
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001579 outs() << "\n";
1580 }
1581}
1582
1583static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
1584 uint32_t size, uint64_t addr) {
1585 uint32_t cputype = O->getHeader().cputype;
1586 if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
1587 uint32_t j;
1588 for (uint32_t i = 0; i < size; i += j, addr += j) {
1589 if (O->is64Bit())
1590 outs() << format("%016" PRIx64, addr) << "\t";
1591 else
Kevin Enderbyf0640752015-03-13 17:56:32 +00001592 outs() << format("%08" PRIx64, addr) << "\t";
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001593 for (j = 0; j < 16 && i + j < size; j++) {
1594 uint8_t byte_word = *(sect + i + j);
1595 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1596 }
1597 outs() << "\n";
1598 }
1599 } else {
1600 uint32_t j;
1601 for (uint32_t i = 0; i < size; i += j, addr += j) {
1602 if (O->is64Bit())
1603 outs() << format("%016" PRIx64, addr) << "\t";
1604 else
Kevin Enderbyc4930852016-04-27 22:36:18 +00001605 outs() << format("%08" PRIx64, addr) << "\t";
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001606 for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
1607 j += sizeof(int32_t)) {
Kevin Enderby8eccdad2016-04-27 23:43:00 +00001608 if (i + j + sizeof(int32_t) <= size) {
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001609 uint32_t long_word;
1610 memcpy(&long_word, sect + i + j, sizeof(int32_t));
1611 if (O->isLittleEndian() != sys::IsLittleEndianHost)
1612 sys::swapByteOrder(long_word);
1613 outs() << format("%08" PRIx32, long_word) << " ";
1614 } else {
1615 for (uint32_t k = 0; i + j + k < size; k++) {
Kevin Enderby8eccdad2016-04-27 23:43:00 +00001616 uint8_t byte_word = *(sect + i + j + k);
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001617 outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
1618 }
1619 }
1620 }
1621 outs() << "\n";
1622 }
1623 }
1624}
1625
Kevin Enderby95df54c2015-02-04 01:01:38 +00001626static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
1627 StringRef DisSegName, StringRef DisSectName);
Kevin Enderby4ad9bde2015-04-16 22:33:20 +00001628static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
1629 uint32_t size, uint32_t addr);
Kevin Enderby9873e2c2016-05-23 21:34:12 +00001630#ifdef HAVE_LIBXAR
1631static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
1632 uint32_t size, bool verbose,
1633 bool PrintXarHeader, bool PrintXarFileHeaders,
1634 std::string XarMemberName);
1635#endif // defined(HAVE_LIBXAR)
Kevin Enderby95df54c2015-02-04 01:01:38 +00001636
1637static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
1638 bool verbose) {
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001639 SymbolAddressMap AddrMap;
1640 if (verbose)
1641 CreateSymbolAddressMap(O, &AddrMap);
1642
Colin LeMahieufcc32762015-07-29 19:08:10 +00001643 for (unsigned i = 0; i < FilterSections.size(); ++i) {
1644 StringRef DumpSection = FilterSections[i];
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001645 std::pair<StringRef, StringRef> DumpSegSectName;
1646 DumpSegSectName = DumpSection.split(',');
1647 StringRef DumpSegName, DumpSectName;
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00001648 if (!DumpSegSectName.second.empty()) {
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001649 DumpSegName = DumpSegSectName.first;
1650 DumpSectName = DumpSegSectName.second;
1651 } else {
1652 DumpSegName = "";
1653 DumpSectName = DumpSegSectName.first;
1654 }
1655 for (const SectionRef &Section : O->sections()) {
1656 StringRef SectName;
1657 Section.getName(SectName);
1658 DataRefImpl Ref = Section.getRawDataRefImpl();
1659 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1660 if ((DumpSegName.empty() || SegName == DumpSegName) &&
1661 (SectName == DumpSectName)) {
Adrian Prantlc2401dd2015-03-27 17:31:15 +00001662
Kevin Enderby95df54c2015-02-04 01:01:38 +00001663 uint32_t section_flags;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001664 if (O->is64Bit()) {
1665 const MachO::section_64 Sec = O->getSection64(Ref);
Kevin Enderby95df54c2015-02-04 01:01:38 +00001666 section_flags = Sec.flags;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001667
1668 } else {
1669 const MachO::section Sec = O->getSection(Ref);
Kevin Enderby95df54c2015-02-04 01:01:38 +00001670 section_flags = Sec.flags;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001671 }
Kevin Enderby95df54c2015-02-04 01:01:38 +00001672 uint32_t section_type = section_flags & MachO::SECTION_TYPE;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001673
1674 StringRef BytesStr;
1675 Section.getContents(BytesStr);
1676 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
1677 uint32_t sect_size = BytesStr.size();
1678 uint64_t sect_addr = Section.getAddress();
1679
Adrian Prantlc2401dd2015-03-27 17:31:15 +00001680 outs() << "Contents of (" << SegName << "," << SectName
1681 << ") section\n";
1682
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001683 if (verbose) {
Kevin Enderby95df54c2015-02-04 01:01:38 +00001684 if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
1685 (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
1686 DisassembleMachO(Filename, O, SegName, SectName);
1687 continue;
1688 }
Kevin Enderbycd66be52015-03-11 22:06:32 +00001689 if (SegName == "__TEXT" && SectName == "__info_plist") {
1690 outs() << sect;
1691 continue;
1692 }
Kevin Enderby4ad9bde2015-04-16 22:33:20 +00001693 if (SegName == "__OBJC" && SectName == "__protocol") {
1694 DumpProtocolSection(O, sect, sect_size, sect_addr);
1695 continue;
1696 }
Kevin Enderby9873e2c2016-05-23 21:34:12 +00001697#ifdef HAVE_LIBXAR
1698 if (SegName == "__LLVM" && SectName == "__bundle") {
1699 DumpBitcodeSection(O, sect, sect_size, verbose, !NoSymbolicOperands,
1700 ArchiveHeaders, "");
1701 continue;
1702 }
1703#endif // defined(HAVE_LIBXAR)
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001704 switch (section_type) {
1705 case MachO::S_REGULAR:
1706 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1707 break;
1708 case MachO::S_ZEROFILL:
1709 outs() << "zerofill section and has no contents in the file\n";
1710 break;
Kevin Enderby10ba0412015-02-04 21:38:42 +00001711 case MachO::S_CSTRING_LITERALS:
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00001712 DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr);
Kevin Enderby10ba0412015-02-04 21:38:42 +00001713 break;
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001714 case MachO::S_4BYTE_LITERALS:
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00001715 DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001716 break;
1717 case MachO::S_8BYTE_LITERALS:
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00001718 DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
Kevin Enderby74b43cb2015-02-06 23:25:38 +00001719 break;
1720 case MachO::S_16BYTE_LITERALS:
Kevin Enderby0fc11822015-04-01 20:57:01 +00001721 DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
1722 break;
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001723 case MachO::S_LITERAL_POINTERS:
1724 DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00001725 !NoLeadingAddr);
Kevin Enderby578fe5a2015-02-17 21:35:48 +00001726 break;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001727 case MachO::S_MOD_INIT_FUNC_POINTERS:
1728 case MachO::S_MOD_TERM_FUNC_POINTERS:
Kevin Enderby85b7a662018-03-20 20:29:52 +00001729 DumpInitTermPointerSection(O, Section, sect, sect_size, sect_addr,
1730 &AddrMap, verbose);
Kevin Enderbyf6d25852015-01-31 00:37:11 +00001731 break;
1732 default:
1733 outs() << "Unknown section type ("
1734 << format("0x%08" PRIx32, section_type) << ")\n";
1735 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1736 break;
1737 }
1738 } else {
1739 if (section_type == MachO::S_ZEROFILL)
1740 outs() << "zerofill section and has no contents in the file\n";
1741 else
1742 DumpRawSectionContents(O, sect, sect_size, sect_addr);
1743 }
1744 }
1745 }
1746 }
1747}
1748
Kevin Enderbycd66be52015-03-11 22:06:32 +00001749static void DumpInfoPlistSectionContents(StringRef Filename,
1750 MachOObjectFile *O) {
1751 for (const SectionRef &Section : O->sections()) {
1752 StringRef SectName;
1753 Section.getName(SectName);
1754 DataRefImpl Ref = Section.getRawDataRefImpl();
1755 StringRef SegName = O->getSectionFinalSegmentName(Ref);
1756 if (SegName == "__TEXT" && SectName == "__info_plist") {
Kevin Enderby30cf2e82017-06-20 21:00:25 +00001757 if (!NoLeadingHeaders)
1758 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
Kevin Enderbycd66be52015-03-11 22:06:32 +00001759 StringRef BytesStr;
1760 Section.getContents(BytesStr);
1761 const char *sect = reinterpret_cast<const char *>(BytesStr.data());
Kevin Enderby418659f2017-02-06 21:01:08 +00001762 outs() << format("%.*s", BytesStr.size(), sect) << "\n";
Kevin Enderbycd66be52015-03-11 22:06:32 +00001763 return;
1764 }
1765 }
1766}
1767
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00001768// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
1769// and if it is and there is a list of architecture flags is specified then
1770// check to make sure this Mach-O file is one of those architectures or all
1771// architectures were specified. If not then an error is generated and this
1772// routine returns false. Else it returns true.
1773static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
David Majnemer91160d82016-10-31 17:11:31 +00001774 auto *MachO = dyn_cast<MachOObjectFile>(O);
1775
1776 if (!MachO || ArchAll || ArchFlags.empty())
1777 return true;
1778
1779 MachO::mach_header H;
1780 MachO::mach_header_64 H_64;
1781 Triple T;
Kevin Enderby59343a92016-12-16 22:54:02 +00001782 const char *McpuDefault, *ArchFlag;
David Majnemer91160d82016-10-31 17:11:31 +00001783 if (MachO->is64Bit()) {
1784 H_64 = MachO->MachOObjectFile::getHeader64();
Kevin Enderby59343a92016-12-16 22:54:02 +00001785 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
1786 &McpuDefault, &ArchFlag);
David Majnemer91160d82016-10-31 17:11:31 +00001787 } else {
1788 H = MachO->MachOObjectFile::getHeader();
Kevin Enderby59343a92016-12-16 22:54:02 +00001789 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
1790 &McpuDefault, &ArchFlag);
David Majnemer91160d82016-10-31 17:11:31 +00001791 }
Kevin Enderby59343a92016-12-16 22:54:02 +00001792 const std::string ArchFlagName(ArchFlag);
David Majnemer91160d82016-10-31 17:11:31 +00001793 if (none_of(ArchFlags, [&](const std::string &Name) {
Kevin Enderby59343a92016-12-16 22:54:02 +00001794 return Name == ArchFlagName;
David Majnemer91160d82016-10-31 17:11:31 +00001795 })) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00001796 WithColor::error(errs(), "llvm-objdump")
1797 << Filename << ": no architecture specified.\n";
David Majnemer91160d82016-10-31 17:11:31 +00001798 return false;
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00001799 }
1800 return true;
1801}
1802
Kevin Enderby0fc11822015-04-01 20:57:01 +00001803static void printObjcMetaData(MachOObjectFile *O, bool verbose);
1804
Kevin Enderbye2297dd2015-01-07 21:02:18 +00001805// ProcessMachO() is passed a single opened Mach-O file, which may be an
1806// archive member and or in a slice of a universal file. It prints the
1807// the file name and header info and then processes it according to the
1808// command line options.
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001809static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
Kevin Enderbye2297dd2015-01-07 21:02:18 +00001810 StringRef ArchiveMemberName = StringRef(),
1811 StringRef ArchitectureName = StringRef()) {
Kevin Enderby131d1772015-01-09 19:22:37 +00001812 // If we are doing some processing here on the Mach-O file print the header
1813 // info. And don't print it otherwise like in the case of printing the
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +00001814 // UniversalHeaders or ArchiveHeaders.
Michael Trenta1703b12017-12-15 17:57:40 +00001815 if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
1816 Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
1817 DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData ||
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00001818 (!FilterSections.empty())) {
Kevin Enderbyf9d60f02016-11-29 21:43:40 +00001819 if (!NoLeadingHeaders) {
1820 outs() << Name;
1821 if (!ArchiveMemberName.empty())
1822 outs() << '(' << ArchiveMemberName << ')';
1823 if (!ArchitectureName.empty())
1824 outs() << " (architecture " << ArchitectureName << ")";
1825 outs() << ":\n";
1826 }
Kevin Enderby131d1772015-01-09 19:22:37 +00001827 }
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001828 // To use the report_error() form with an ArchiveName and FileName set
1829 // these up based on what is passed for Name and ArchiveMemberName.
1830 StringRef ArchiveName;
1831 StringRef FileName;
1832 if (!ArchiveMemberName.empty()) {
1833 ArchiveName = Name;
1834 FileName = ArchiveMemberName;
1835 } else {
1836 ArchiveName = StringRef();
1837 FileName = Name;
1838 }
1839
1840 // If we need the symbol table to do the operation then check it here to
1841 // produce a good error message as to where the Mach-O file comes from in
1842 // the error message.
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00001843 if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001844 if (Error Err = MachOOF->checkSymbolTable())
Fangrui Songe7834bd2019-04-07 08:19:55 +00001845 report_error(std::move(Err), ArchiveName, FileName, ArchitectureName);
1846
Michael Trent7e660212019-01-15 20:41:30 +00001847 if (DisassembleAll) {
1848 for (const SectionRef &Section : MachOOF->sections()) {
1849 StringRef SectName;
1850 Section.getName(SectName);
1851 if (SectName.equals("__text")) {
1852 DataRefImpl Ref = Section.getRawDataRefImpl();
1853 StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref);
1854 DisassembleMachO(FileName, MachOOF, SegName, SectName);
1855 }
1856 }
1857 }
1858 else if (Disassemble) {
Kevin Enderbyaf2999a2017-06-22 19:50:56 +00001859 if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00001860 MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
Kevin Enderbyaf2999a2017-06-22 19:50:56 +00001861 DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
1862 else
1863 DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
1864 }
Kevin Enderbya7bdc7e2015-01-22 18:55:27 +00001865 if (IndirectSymbols)
Kevin Enderbyf0640752015-03-13 17:56:32 +00001866 PrintIndirectSymbols(MachOOF, !NonVerbose);
Kevin Enderby69fe98d2015-01-23 18:52:17 +00001867 if (DataInCode)
Kevin Enderbyf0640752015-03-13 17:56:32 +00001868 PrintDataInCodeTable(MachOOF, !NonVerbose);
Kevin Enderby9a509442015-01-27 21:28:24 +00001869 if (LinkOptHints)
1870 PrintLinkOptHints(MachOOF);
Kevin Enderby98da6132015-01-20 21:47:46 +00001871 if (Relocations)
Michael Trenta1703b12017-12-15 17:57:40 +00001872 PrintRelocations(MachOOF, !NonVerbose);
Kevin Enderby98da6132015-01-20 21:47:46 +00001873 if (SectionHeaders)
George Rimar73a27232019-01-15 09:19:18 +00001874 printSectionHeaders(MachOOF);
Kevin Enderby98da6132015-01-20 21:47:46 +00001875 if (SectionContents)
George Rimar73a27232019-01-15 09:19:18 +00001876 printSectionContents(MachOOF);
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00001877 if (!FilterSections.empty())
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001878 DumpSectionContents(FileName, MachOOF, !NonVerbose);
Kevin Enderbycd66be52015-03-11 22:06:32 +00001879 if (InfoPlist)
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001880 DumpInfoPlistSectionContents(FileName, MachOOF);
Kevin Enderbybc847fa2015-03-16 20:08:09 +00001881 if (DylibsUsed)
1882 PrintDylibs(MachOOF, false);
1883 if (DylibId)
1884 PrintDylibs(MachOOF, true);
Kevin Enderby844c4ac2016-11-15 23:07:41 +00001885 if (SymbolTable)
George Rimar73a27232019-01-15 09:19:18 +00001886 printSymbolTable(MachOOF, ArchiveName, ArchitectureName);
Kevin Enderby98da6132015-01-20 21:47:46 +00001887 if (UnwindInfo)
1888 printMachOUnwindInfo(MachOOF);
Kevin Enderby0ae163f2016-01-13 00:25:36 +00001889 if (PrivateHeaders) {
1890 printMachOFileHeader(MachOOF);
1891 printMachOLoadCommands(MachOOF);
1892 }
1893 if (FirstPrivateHeader)
Kevin Enderbye2297dd2015-01-07 21:02:18 +00001894 printMachOFileHeader(MachOOF);
Kevin Enderby0fc11822015-04-01 20:57:01 +00001895 if (ObjcMetaData)
1896 printObjcMetaData(MachOOF, !NonVerbose);
Kevin Enderbye2297dd2015-01-07 21:02:18 +00001897 if (ExportsTrie)
1898 printExportsTrie(MachOOF);
1899 if (Rebase)
1900 printRebaseTable(MachOOF);
1901 if (Bind)
1902 printBindTable(MachOOF);
1903 if (LazyBind)
1904 printLazyBindTable(MachOOF);
1905 if (WeakBind)
1906 printWeakBindTable(MachOOF);
Igor Laevsky03a670c2016-01-26 15:09:42 +00001907
1908 if (DwarfDumpType != DIDT_Null) {
Rafael Espindolac398e672017-07-19 22:27:28 +00001909 std::unique_ptr<DIContext> DICtx = DWARFContext::create(*MachOOF);
Igor Laevsky03a670c2016-01-26 15:09:42 +00001910 // Dump the complete DWARF structure.
Adrian Prantlf4bc1f72017-06-01 18:18:23 +00001911 DIDumpOptions DumpOpts;
1912 DumpOpts.DumpType = DwarfDumpType;
Adrian Prantlf4bc1f72017-06-01 18:18:23 +00001913 DICtx->dump(outs(), DumpOpts);
Igor Laevsky03a670c2016-01-26 15:09:42 +00001914 }
Kevin Enderbye2297dd2015-01-07 21:02:18 +00001915}
1916
Kevin Enderby131d1772015-01-09 19:22:37 +00001917// printUnknownCPUType() helps print_fat_headers for unknown CPU's.
1918static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) {
1919 outs() << " cputype (" << cputype << ")\n";
1920 outs() << " cpusubtype (" << cpusubtype << ")\n";
1921}
1922
1923// printCPUType() helps print_fat_headers by printing the cputype and
1924// pusubtype (symbolically for the one's it knows about).
1925static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
1926 switch (cputype) {
1927 case MachO::CPU_TYPE_I386:
1928 switch (cpusubtype) {
1929 case MachO::CPU_SUBTYPE_I386_ALL:
1930 outs() << " cputype CPU_TYPE_I386\n";
1931 outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n";
1932 break;
1933 default:
1934 printUnknownCPUType(cputype, cpusubtype);
1935 break;
1936 }
1937 break;
1938 case MachO::CPU_TYPE_X86_64:
1939 switch (cpusubtype) {
1940 case MachO::CPU_SUBTYPE_X86_64_ALL:
1941 outs() << " cputype CPU_TYPE_X86_64\n";
1942 outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n";
1943 break;
1944 case MachO::CPU_SUBTYPE_X86_64_H:
1945 outs() << " cputype CPU_TYPE_X86_64\n";
1946 outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n";
1947 break;
1948 default:
1949 printUnknownCPUType(cputype, cpusubtype);
1950 break;
1951 }
1952 break;
1953 case MachO::CPU_TYPE_ARM:
1954 switch (cpusubtype) {
1955 case MachO::CPU_SUBTYPE_ARM_ALL:
1956 outs() << " cputype CPU_TYPE_ARM\n";
1957 outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n";
1958 break;
1959 case MachO::CPU_SUBTYPE_ARM_V4T:
1960 outs() << " cputype CPU_TYPE_ARM\n";
1961 outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n";
1962 break;
1963 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
1964 outs() << " cputype CPU_TYPE_ARM\n";
1965 outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n";
1966 break;
1967 case MachO::CPU_SUBTYPE_ARM_XSCALE:
1968 outs() << " cputype CPU_TYPE_ARM\n";
1969 outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n";
1970 break;
1971 case MachO::CPU_SUBTYPE_ARM_V6:
1972 outs() << " cputype CPU_TYPE_ARM\n";
1973 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n";
1974 break;
1975 case MachO::CPU_SUBTYPE_ARM_V6M:
1976 outs() << " cputype CPU_TYPE_ARM\n";
1977 outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n";
1978 break;
1979 case MachO::CPU_SUBTYPE_ARM_V7:
1980 outs() << " cputype CPU_TYPE_ARM\n";
1981 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n";
1982 break;
1983 case MachO::CPU_SUBTYPE_ARM_V7EM:
1984 outs() << " cputype CPU_TYPE_ARM\n";
1985 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n";
1986 break;
1987 case MachO::CPU_SUBTYPE_ARM_V7K:
1988 outs() << " cputype CPU_TYPE_ARM\n";
1989 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n";
1990 break;
1991 case MachO::CPU_SUBTYPE_ARM_V7M:
1992 outs() << " cputype CPU_TYPE_ARM\n";
1993 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n";
1994 break;
1995 case MachO::CPU_SUBTYPE_ARM_V7S:
1996 outs() << " cputype CPU_TYPE_ARM\n";
1997 outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n";
1998 break;
1999 default:
2000 printUnknownCPUType(cputype, cpusubtype);
2001 break;
2002 }
2003 break;
2004 case MachO::CPU_TYPE_ARM64:
2005 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
2006 case MachO::CPU_SUBTYPE_ARM64_ALL:
2007 outs() << " cputype CPU_TYPE_ARM64\n";
2008 outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
2009 break;
Shoaib Meenai867131a2019-04-08 21:37:08 +00002010 case MachO::CPU_SUBTYPE_ARM64E:
2011 outs() << " cputype CPU_TYPE_ARM64\n";
2012 outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";
2013 break;
Kevin Enderby131d1772015-01-09 19:22:37 +00002014 default:
2015 printUnknownCPUType(cputype, cpusubtype);
2016 break;
2017 }
2018 break;
2019 default:
2020 printUnknownCPUType(cputype, cpusubtype);
2021 break;
2022 }
2023}
2024
2025static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
2026 bool verbose) {
2027 outs() << "Fat headers\n";
Kevin Enderby606a3382016-06-21 21:55:01 +00002028 if (verbose) {
2029 if (UB->getMagic() == MachO::FAT_MAGIC)
2030 outs() << "fat_magic FAT_MAGIC\n";
2031 else // UB->getMagic() == MachO::FAT_MAGIC_64
2032 outs() << "fat_magic FAT_MAGIC_64\n";
2033 } else
Kevin Enderby131d1772015-01-09 19:22:37 +00002034 outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n";
2035
2036 uint32_t nfat_arch = UB->getNumberOfObjects();
2037 StringRef Buf = UB->getData();
2038 uint64_t size = Buf.size();
2039 uint64_t big_size = sizeof(struct MachO::fat_header) +
2040 nfat_arch * sizeof(struct MachO::fat_arch);
2041 outs() << "nfat_arch " << UB->getNumberOfObjects();
2042 if (nfat_arch == 0)
2043 outs() << " (malformed, contains zero architecture types)\n";
2044 else if (big_size > size)
2045 outs() << " (malformed, architectures past end of file)\n";
2046 else
2047 outs() << "\n";
2048
2049 for (uint32_t i = 0; i < nfat_arch; ++i) {
2050 MachOUniversalBinary::ObjectForArch OFA(UB, i);
2051 uint32_t cputype = OFA.getCPUType();
2052 uint32_t cpusubtype = OFA.getCPUSubType();
2053 outs() << "architecture ";
2054 for (uint32_t j = 0; i != 0 && j <= i - 1; j++) {
2055 MachOUniversalBinary::ObjectForArch other_OFA(UB, j);
2056 uint32_t other_cputype = other_OFA.getCPUType();
2057 uint32_t other_cpusubtype = other_OFA.getCPUSubType();
Kevin Enderby0512bd72015-01-09 21:55:03 +00002058 if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype &&
Kevin Enderby131d1772015-01-09 19:22:37 +00002059 (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) ==
Kevin Enderby0512bd72015-01-09 21:55:03 +00002060 (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) {
Kevin Enderby131d1772015-01-09 19:22:37 +00002061 outs() << "(illegal duplicate architecture) ";
2062 break;
Kevin Enderby0512bd72015-01-09 21:55:03 +00002063 }
Kevin Enderby131d1772015-01-09 19:22:37 +00002064 }
2065 if (verbose) {
Kevin Enderby59343a92016-12-16 22:54:02 +00002066 outs() << OFA.getArchFlagName() << "\n";
Kevin Enderby131d1772015-01-09 19:22:37 +00002067 printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
2068 } else {
2069 outs() << i << "\n";
2070 outs() << " cputype " << cputype << "\n";
2071 outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
2072 << "\n";
2073 }
2074 if (verbose &&
2075 (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
2076 outs() << " capabilities CPU_SUBTYPE_LIB64\n";
2077 else
2078 outs() << " capabilities "
2079 << format("0x%" PRIx32,
2080 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n";
2081 outs() << " offset " << OFA.getOffset();
2082 if (OFA.getOffset() > size)
2083 outs() << " (past end of file)";
2084 if (OFA.getOffset() % (1 << OFA.getAlign()) != 0)
2085 outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";
2086 outs() << "\n";
2087 outs() << " size " << OFA.getSize();
2088 big_size = OFA.getOffset() + OFA.getSize();
2089 if (big_size > size)
2090 outs() << " (past end of file)";
2091 outs() << "\n";
2092 outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign())
2093 << ")\n";
2094 }
2095}
2096
Kevin Enderby6524bd82016-07-19 20:47:07 +00002097static void printArchiveChild(StringRef Filename, const Archive::Child &C,
2098 bool verbose, bool print_offset,
2099 StringRef ArchitectureName = StringRef()) {
Kevin Enderby13023a12015-01-15 23:19:11 +00002100 if (print_offset)
2101 outs() << C.getChildOffset() << "\t";
Fangrui Songe7834bd2019-04-07 08:19:55 +00002102 sys::fs::perms Mode =
2103 unwrapOrError(C.getAccessMode(), Filename, C, ArchitectureName);
Kevin Enderby13023a12015-01-15 23:19:11 +00002104 if (verbose) {
2105 // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
2106 // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
2107 outs() << "-";
Davide Italianobb9a6cc2015-09-07 20:47:03 +00002108 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
2109 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
2110 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
2111 outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
2112 outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
2113 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
2114 outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
2115 outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
2116 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
Kevin Enderby13023a12015-01-15 23:19:11 +00002117 } else {
2118 outs() << format("0%o ", Mode);
2119 }
2120
Fangrui Songe7834bd2019-04-07 08:19:55 +00002121 outs() << format(
2122 "%3d/%-3d %5" PRId64 " ",
2123 unwrapOrError(C.getUID(), Filename, C, ArchitectureName),
2124 unwrapOrError(C.getGID(), Filename, C, ArchitectureName),
2125 unwrapOrError(C.getRawSize(), Filename, C, ArchitectureName));
Kevin Enderby13023a12015-01-15 23:19:11 +00002126
2127 StringRef RawLastModified = C.getRawLastModified();
2128 if (verbose) {
2129 unsigned Seconds;
2130 if (RawLastModified.getAsInteger(10, Seconds))
Vedant Kumar4031d9f2016-08-03 19:02:50 +00002131 outs() << "(date: \"" << RawLastModified
2132 << "\" contains non-decimal chars) ";
Kevin Enderby13023a12015-01-15 23:19:11 +00002133 else {
2134 // Since cime(3) returns a 26 character string of the form:
2135 // "Sun Sep 16 01:03:52 1973\n\0"
2136 // just print 24 characters.
2137 time_t t = Seconds;
2138 outs() << format("%.24s ", ctime(&t));
2139 }
2140 } else {
2141 outs() << RawLastModified << " ";
2142 }
2143
2144 if (verbose) {
Kevin Enderbyf4586032016-07-29 17:44:13 +00002145 Expected<StringRef> NameOrErr = C.getName();
2146 if (!NameOrErr) {
2147 consumeError(NameOrErr.takeError());
Fangrui Songe7834bd2019-04-07 08:19:55 +00002148 outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName)
2149 << "\n";
Kevin Enderby13023a12015-01-15 23:19:11 +00002150 } else {
2151 StringRef Name = NameOrErr.get();
2152 outs() << Name << "\n";
2153 }
2154 } else {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002155 outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName)
2156 << "\n";
Kevin Enderby13023a12015-01-15 23:19:11 +00002157 }
2158}
2159
Kevin Enderby6524bd82016-07-19 20:47:07 +00002160static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
2161 bool print_offset,
2162 StringRef ArchitectureName = StringRef()) {
Mehdi Amini41af4302016-11-11 04:28:40 +00002163 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +00002164 for (const auto &C : A->children(Err, false))
Kevin Enderby6524bd82016-07-19 20:47:07 +00002165 printArchiveChild(Filename, C, verbose, print_offset, ArchitectureName);
2166
Lang Hamesfc209622016-07-14 02:24:01 +00002167 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +00002168 report_error(std::move(Err), StringRef(), Filename, ArchitectureName);
Kevin Enderby13023a12015-01-15 23:19:11 +00002169}
2170
Dave Lee3fb120f2018-08-03 00:06:38 +00002171static bool ValidateArchFlags() {
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002172 // Check for -arch all and verifiy the -arch flags are valid.
2173 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2174 if (ArchFlags[i] == "all") {
2175 ArchAll = true;
2176 } else {
2177 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00002178 WithColor::error(errs(), "llvm-objdump")
2179 << "unknown architecture named '" + ArchFlags[i] +
2180 "'for the -arch option\n";
Dave Lee3fb120f2018-08-03 00:06:38 +00002181 return false;
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002182 }
2183 }
2184 }
Dave Lee3fb120f2018-08-03 00:06:38 +00002185 return true;
2186}
2187
2188// ParseInputMachO() parses the named Mach-O file in Filename and handles the
2189// -arch flags selecting just those slices as specified by them and also parses
2190// archive files. Then for each individual Mach-O file ProcessMachO() is
2191// called to process the file based on the command line options.
George Rimar73a27232019-01-15 09:19:18 +00002192void llvm::parseInputMachO(StringRef Filename) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002193 if (!ValidateArchFlags())
2194 return;
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002195
2196 // Attempt to open the binary.
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +00002197 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
Kevin Enderby98898f22017-01-30 20:53:17 +00002198 if (!BinaryOrErr) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002199 if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
2200 report_error(std::move(E), Filename);
Kevin Enderby98898f22017-01-30 20:53:17 +00002201 else
2202 outs() << Filename << ": is not an object file\n";
2203 return;
2204 }
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002205 Binary &Bin = *BinaryOrErr.get().getBinary();
Kevin Enderby3f0ffab2014-12-03 22:29:40 +00002206
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002207 if (Archive *A = dyn_cast<Archive>(&Bin)) {
2208 outs() << "Archive : " << Filename << "\n";
Kevin Enderby13023a12015-01-15 23:19:11 +00002209 if (ArchiveHeaders)
Kevin Enderby6524bd82016-07-19 20:47:07 +00002210 printArchiveHeaders(Filename, A, !NonVerbose, ArchiveMemberOffsets);
2211
Mehdi Amini41af4302016-11-11 04:28:40 +00002212 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +00002213 for (auto &C : A->children(Err)) {
Kevin Enderbyac9e1552016-05-17 17:10:12 +00002214 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2215 if (!ChildOrErr) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002216 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2217 report_error(std::move(E), Filename, C);
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002218 continue;
Kevin Enderbyac9e1552016-05-17 17:10:12 +00002219 }
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002220 if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2221 if (!checkMachOAndArchFlags(O, Filename))
2222 return;
Kevin Enderbye2297dd2015-01-07 21:02:18 +00002223 ProcessMachO(Filename, O, O->getFileName());
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002224 }
2225 }
Lang Hamesfc209622016-07-14 02:24:01 +00002226 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +00002227 report_error(std::move(Err), Filename);
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002228 return;
2229 }
2230 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
George Rimar73a27232019-01-15 09:19:18 +00002231 parseInputMachO(UB);
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00002232 return;
2233 }
2234 if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
2235 if (!checkMachOAndArchFlags(O, Filename))
2236 return;
Dave Lee3fb120f2018-08-03 00:06:38 +00002237 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*O))
Kevin Enderbye2297dd2015-01-07 21:02:18 +00002238 ProcessMachO(Filename, MachOOF);
Dave Lee3fb120f2018-08-03 00:06:38 +00002239 else
Jonas Devliegheree787efd2018-11-11 22:12:04 +00002240 WithColor::error(errs(), "llvm-objdump")
2241 << Filename << "': "
2242 << "object is not a Mach-O file type.\n";
Davide Italiano25d84582016-01-13 04:11:36 +00002243 return;
2244 }
2245 llvm_unreachable("Input object can't be invalid at this point");
Rafael Espindola9b709252013-04-13 01:45:40 +00002246}
2247
George Rimar73a27232019-01-15 09:19:18 +00002248void llvm::parseInputMachO(MachOUniversalBinary *UB) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002249 if (!ValidateArchFlags())
2250 return;
2251
2252 auto Filename = UB->getFileName();
2253
2254 if (UniversalHeaders)
2255 printMachOUniversalHeaders(UB, !NonVerbose);
2256
2257 // If we have a list of architecture flags specified dump only those.
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00002258 if (!ArchAll && !ArchFlags.empty()) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002259 // Look for a slice in the universal binary that matches each ArchFlag.
2260 bool ArchFound;
2261 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2262 ArchFound = false;
2263 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2264 E = UB->end_objects();
2265 I != E; ++I) {
2266 if (ArchFlags[i] == I->getArchFlagName()) {
2267 ArchFound = true;
2268 Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
2269 I->getAsObjectFile();
2270 std::string ArchitectureName = "";
2271 if (ArchFlags.size() > 1)
2272 ArchitectureName = I->getArchFlagName();
2273 if (ObjOrErr) {
2274 ObjectFile &O = *ObjOrErr.get();
2275 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2276 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
Fangrui Songe7834bd2019-04-07 08:19:55 +00002277 } else if (Error E = isNotObjectErrorInvalidFileType(
2278 ObjOrErr.takeError())) {
2279 report_error(std::move(E), Filename, StringRef(), ArchitectureName);
Dave Lee3fb120f2018-08-03 00:06:38 +00002280 continue;
2281 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Fangrui Songe7834bd2019-04-07 08:19:55 +00002282 I->getAsArchive()) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002283 std::unique_ptr<Archive> &A = *AOrErr;
2284 outs() << "Archive : " << Filename;
2285 if (!ArchitectureName.empty())
2286 outs() << " (architecture " << ArchitectureName << ")";
2287 outs() << "\n";
2288 if (ArchiveHeaders)
2289 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2290 ArchiveMemberOffsets, ArchitectureName);
2291 Error Err = Error::success();
2292 for (auto &C : A->children(Err)) {
2293 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2294 if (!ChildOrErr) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002295 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2296 report_error(std::move(E), Filename, C, ArchitectureName);
Dave Lee3fb120f2018-08-03 00:06:38 +00002297 continue;
2298 }
2299 if (MachOObjectFile *O =
2300 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2301 ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
2302 }
2303 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +00002304 report_error(std::move(Err), Filename);
Dave Lee3fb120f2018-08-03 00:06:38 +00002305 } else {
2306 consumeError(AOrErr.takeError());
2307 error("Mach-O universal file: " + Filename + " for " +
2308 "architecture " + StringRef(I->getArchFlagName()) +
2309 " is not a Mach-O file or an archive file");
2310 }
2311 }
2312 }
2313 if (!ArchFound) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00002314 WithColor::error(errs(), "llvm-objdump")
2315 << "file: " + Filename + " does not contain "
2316 << "architecture: " + ArchFlags[i] + "\n";
Dave Lee3fb120f2018-08-03 00:06:38 +00002317 return;
2318 }
2319 }
2320 return;
2321 }
2322 // No architecture flags were specified so if this contains a slice that
2323 // matches the host architecture dump only that.
2324 if (!ArchAll) {
2325 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2326 E = UB->end_objects();
2327 I != E; ++I) {
2328 if (MachOObjectFile::getHostArch().getArchName() ==
2329 I->getArchFlagName()) {
2330 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2331 std::string ArchiveName;
2332 ArchiveName.clear();
2333 if (ObjOrErr) {
2334 ObjectFile &O = *ObjOrErr.get();
2335 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
2336 ProcessMachO(Filename, MachOOF);
Fangrui Songe7834bd2019-04-07 08:19:55 +00002337 } else if (Error E =
2338 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2339 report_error(std::move(E), Filename);
Dave Lee3fb120f2018-08-03 00:06:38 +00002340 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Fangrui Songe7834bd2019-04-07 08:19:55 +00002341 I->getAsArchive()) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002342 std::unique_ptr<Archive> &A = *AOrErr;
2343 outs() << "Archive : " << Filename << "\n";
2344 if (ArchiveHeaders)
2345 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2346 ArchiveMemberOffsets);
2347 Error Err = Error::success();
2348 for (auto &C : A->children(Err)) {
2349 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2350 if (!ChildOrErr) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002351 if (Error E =
2352 isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2353 report_error(std::move(E), Filename, C);
Dave Lee3fb120f2018-08-03 00:06:38 +00002354 continue;
2355 }
2356 if (MachOObjectFile *O =
2357 dyn_cast<MachOObjectFile>(&*ChildOrErr.get()))
2358 ProcessMachO(Filename, O, O->getFileName());
2359 }
2360 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +00002361 report_error(std::move(Err), Filename);
Dave Lee3fb120f2018-08-03 00:06:38 +00002362 } else {
2363 consumeError(AOrErr.takeError());
2364 error("Mach-O universal file: " + Filename + " for architecture " +
2365 StringRef(I->getArchFlagName()) +
2366 " is not a Mach-O file or an archive file");
2367 }
2368 return;
2369 }
2370 }
2371 }
2372 // Either all architectures have been specified or none have been specified
2373 // and this does not contain the host architecture so dump all the slices.
2374 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
2375 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
2376 E = UB->end_objects();
2377 I != E; ++I) {
2378 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
2379 std::string ArchitectureName = "";
2380 if (moreThanOneArch)
2381 ArchitectureName = I->getArchFlagName();
2382 if (ObjOrErr) {
2383 ObjectFile &Obj = *ObjOrErr.get();
2384 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
2385 ProcessMachO(Filename, MachOOF, "", ArchitectureName);
Fangrui Songe7834bd2019-04-07 08:19:55 +00002386 } else if (Error E =
2387 isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
2388 report_error(std::move(E), StringRef(), Filename, ArchitectureName);
2389 } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
Dave Lee3fb120f2018-08-03 00:06:38 +00002390 std::unique_ptr<Archive> &A = *AOrErr;
2391 outs() << "Archive : " << Filename;
2392 if (!ArchitectureName.empty())
2393 outs() << " (architecture " << ArchitectureName << ")";
2394 outs() << "\n";
2395 if (ArchiveHeaders)
2396 printArchiveHeaders(Filename, A.get(), !NonVerbose,
2397 ArchiveMemberOffsets, ArchitectureName);
2398 Error Err = Error::success();
2399 for (auto &C : A->children(Err)) {
2400 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
2401 if (!ChildOrErr) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002402 if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
2403 report_error(std::move(E), Filename, C, ArchitectureName);
Dave Lee3fb120f2018-08-03 00:06:38 +00002404 continue;
2405 }
2406 if (MachOObjectFile *O =
2407 dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
2408 if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
2409 ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
2410 ArchitectureName);
2411 }
2412 }
2413 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +00002414 report_error(std::move(Err), Filename);
Dave Lee3fb120f2018-08-03 00:06:38 +00002415 } else {
2416 consumeError(AOrErr.takeError());
2417 error("Mach-O universal file: " + Filename + " for architecture " +
2418 StringRef(I->getArchFlagName()) +
2419 " is not a Mach-O file or an archive file");
2420 }
2421 }
2422}
2423
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002424// The block of info used by the Symbolizer call backs.
2425struct DisassembleInfo {
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00002426 DisassembleInfo(MachOObjectFile *O, SymbolAddressMap *AddrMap,
2427 std::vector<SectionRef> *Sections, bool verbose)
2428 : verbose(verbose), O(O), AddrMap(AddrMap), Sections(Sections) {}
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002429 bool verbose;
2430 MachOObjectFile *O;
2431 SectionRef S;
Kevin Enderbybf246f52014-09-24 23:08:22 +00002432 SymbolAddressMap *AddrMap;
Kevin Enderby6f326ce2014-10-23 19:37:31 +00002433 std::vector<SectionRef> *Sections;
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00002434 const char *class_name = nullptr;
2435 const char *selector_name = nullptr;
David Blaikie0e550682018-02-20 18:48:51 +00002436 std::unique_ptr<char[]> method = nullptr;
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00002437 char *demangled_name = nullptr;
2438 uint64_t adrp_addr = 0;
2439 uint32_t adrp_inst = 0;
Saleem Abdulrasool1d84d9a2017-01-08 19:14:15 +00002440 std::unique_ptr<SymbolAddressMap> bindtable;
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00002441 uint32_t depth = 0;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002442};
2443
2444// SymbolizerGetOpInfo() is the operand information call back function.
2445// This is called to get the symbolic information for operand(s) of an
2446// instruction when it is being done. This routine does this from
2447// the relocation information, symbol table, etc. That block of information
2448// is a pointer to the struct DisassembleInfo that was passed when the
2449// disassembler context was created and passed to back to here when
2450// called back by the disassembler for instruction operands that could have
2451// relocation information. The address of the instruction containing operand is
2452// at the Pc parameter. The immediate value the operand has is passed in
2453// op_info->Value and is at Offset past the start of the instruction and has a
2454// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
2455// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
2456// names and addends of the symbolic expression to add for the operand. The
2457// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
2458// information is returned then this function returns 1 else it returns 0.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00002459static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
2460 uint64_t Size, int TagType, void *TagBuf) {
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002461 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
2462 struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002463 uint64_t value = op_info->Value;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002464
2465 // Make sure all fields returned are zero if we don't set them.
2466 memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
2467 op_info->Value = value;
2468
2469 // If the TagType is not the value 1 which it code knows about or if no
2470 // verbose symbolic information is wanted then just return 0, indicating no
2471 // information is being returned.
David Blaikie33dd45d02015-03-23 18:39:02 +00002472 if (TagType != 1 || !info->verbose)
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002473 return 0;
2474
2475 unsigned int Arch = info->O->getArch();
2476 if (Arch == Triple::x86) {
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002477 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2478 return 0;
Kevin Enderbyd90a4172015-10-10 00:05:01 +00002479 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2480 // TODO:
2481 // Search the external relocation entries of a fully linked image
2482 // (if any) for an entry that matches this segment offset.
2483 // uint32_t seg_offset = (Pc + Offset);
2484 return 0;
2485 }
2486 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2487 // for an entry for this section offset.
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002488 uint32_t sect_addr = info->S.getAddress();
2489 uint32_t sect_offset = (Pc + Offset) - sect_addr;
2490 bool reloc_found = false;
2491 DataRefImpl Rel;
2492 MachO::any_relocation_info RE;
2493 bool isExtern = false;
2494 SymbolRef Symbol;
2495 bool r_scattered = false;
2496 uint32_t r_value, pair_r_value, r_type;
2497 for (const RelocationRef &Reloc : info->S.relocations()) {
Rafael Espindola96d071c2015-06-29 23:29:12 +00002498 uint64_t RelocOffset = Reloc.getOffset();
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002499 if (RelocOffset == sect_offset) {
2500 Rel = Reloc.getRawDataRefImpl();
2501 RE = info->O->getRelocation(Rel);
Kevin Enderby3eb73e12014-11-11 19:16:45 +00002502 r_type = info->O->getAnyRelocationType(RE);
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002503 r_scattered = info->O->isRelocationScattered(RE);
2504 if (r_scattered) {
2505 r_value = info->O->getScatteredRelocationValue(RE);
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002506 if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2507 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
2508 DataRefImpl RelNext = Rel;
2509 info->O->moveRelocationNext(RelNext);
2510 MachO::any_relocation_info RENext;
2511 RENext = info->O->getRelocation(RelNext);
2512 if (info->O->isRelocationScattered(RENext))
Kevin Enderby930fdc72014-11-06 19:00:13 +00002513 pair_r_value = info->O->getScatteredRelocationValue(RENext);
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002514 else
2515 return 0;
2516 }
2517 } else {
2518 isExtern = info->O->getPlainRelocationExternal(RE);
2519 if (isExtern) {
2520 symbol_iterator RelocSym = Reloc.getSymbol();
2521 Symbol = *RelocSym;
2522 }
2523 }
2524 reloc_found = true;
2525 break;
2526 }
2527 }
2528 if (reloc_found && isExtern) {
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002529 op_info->AddSymbol.Present = 1;
Fangrui Songe7834bd2019-04-07 08:19:55 +00002530 op_info->AddSymbol.Name =
2531 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002532 // For i386 extern relocation entries the value in the instruction is
2533 // the offset from the symbol, and value is already set in op_info->Value.
2534 return 1;
2535 }
2536 if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
2537 r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
Kevin Enderbyf6d25852015-01-31 00:37:11 +00002538 const char *add = GuessSymbolName(r_value, info->AddrMap);
2539 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
Kevin Enderby9907d0a2014-11-04 00:43:16 +00002540 uint32_t offset = value - (r_value - pair_r_value);
2541 op_info->AddSymbol.Present = 1;
2542 if (add != nullptr)
2543 op_info->AddSymbol.Name = add;
2544 else
2545 op_info->AddSymbol.Value = r_value;
2546 op_info->SubtractSymbol.Present = 1;
2547 if (sub != nullptr)
2548 op_info->SubtractSymbol.Name = sub;
2549 else
2550 op_info->SubtractSymbol.Value = pair_r_value;
2551 op_info->Value = offset;
2552 return 1;
2553 }
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002554 return 0;
David Blaikie33dd45d02015-03-23 18:39:02 +00002555 }
2556 if (Arch == Triple::x86_64) {
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002557 if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
2558 return 0;
Kevin Enderbyabf10f22017-06-22 17:41:22 +00002559 // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
2560 // relocation entries of a linked image (if any) for an entry that matches
2561 // this segment offset.
Kevin Enderbyd90a4172015-10-10 00:05:01 +00002562 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
Kevin Enderbyabf10f22017-06-22 17:41:22 +00002563 uint64_t seg_offset = Pc + Offset;
2564 bool reloc_found = false;
2565 DataRefImpl Rel;
2566 MachO::any_relocation_info RE;
2567 bool isExtern = false;
2568 SymbolRef Symbol;
2569 for (const RelocationRef &Reloc : info->O->external_relocations()) {
2570 uint64_t RelocOffset = Reloc.getOffset();
2571 if (RelocOffset == seg_offset) {
2572 Rel = Reloc.getRawDataRefImpl();
2573 RE = info->O->getRelocation(Rel);
2574 // external relocation entries should always be external.
2575 isExtern = info->O->getPlainRelocationExternal(RE);
2576 if (isExtern) {
2577 symbol_iterator RelocSym = Reloc.getSymbol();
2578 Symbol = *RelocSym;
2579 }
2580 reloc_found = true;
2581 break;
2582 }
2583 }
2584 if (reloc_found && isExtern) {
2585 // The Value passed in will be adjusted by the Pc if the instruction
2586 // adds the Pc. But for x86_64 external relocation entries the Value
2587 // is the offset from the external symbol.
2588 if (info->O->getAnyRelocationPCRel(RE))
2589 op_info->Value -= Pc + Offset + Size;
Fangrui Songe7834bd2019-04-07 08:19:55 +00002590 const char *name =
2591 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
Kevin Enderbyabf10f22017-06-22 17:41:22 +00002592 op_info->AddSymbol.Present = 1;
2593 op_info->AddSymbol.Name = name;
2594 return 1;
2595 }
Kevin Enderbyd90a4172015-10-10 00:05:01 +00002596 return 0;
2597 }
2598 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2599 // for an entry for this section offset.
Rafael Espindola80291272014-10-08 15:28:58 +00002600 uint64_t sect_addr = info->S.getAddress();
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002601 uint64_t sect_offset = (Pc + Offset) - sect_addr;
2602 bool reloc_found = false;
2603 DataRefImpl Rel;
2604 MachO::any_relocation_info RE;
2605 bool isExtern = false;
2606 SymbolRef Symbol;
2607 for (const RelocationRef &Reloc : info->S.relocations()) {
Rafael Espindola96d071c2015-06-29 23:29:12 +00002608 uint64_t RelocOffset = Reloc.getOffset();
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002609 if (RelocOffset == sect_offset) {
2610 Rel = Reloc.getRawDataRefImpl();
2611 RE = info->O->getRelocation(Rel);
2612 // NOTE: Scattered relocations don't exist on x86_64.
2613 isExtern = info->O->getPlainRelocationExternal(RE);
2614 if (isExtern) {
2615 symbol_iterator RelocSym = Reloc.getSymbol();
2616 Symbol = *RelocSym;
2617 }
2618 reloc_found = true;
2619 break;
2620 }
2621 }
2622 if (reloc_found && isExtern) {
2623 // The Value passed in will be adjusted by the Pc if the instruction
2624 // adds the Pc. But for x86_64 external relocation entries the Value
2625 // is the offset from the external symbol.
2626 if (info->O->getAnyRelocationPCRel(RE))
2627 op_info->Value -= Pc + Offset + Size;
Fangrui Songe7834bd2019-04-07 08:19:55 +00002628 const char *name =
2629 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002630 unsigned Type = info->O->getAnyRelocationType(RE);
2631 if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
2632 DataRefImpl RelNext = Rel;
2633 info->O->moveRelocationNext(RelNext);
2634 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2635 unsigned TypeNext = info->O->getAnyRelocationType(RENext);
2636 bool isExternNext = info->O->getPlainRelocationExternal(RENext);
2637 unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
2638 if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
2639 op_info->SubtractSymbol.Present = 1;
2640 op_info->SubtractSymbol.Name = name;
2641 symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
2642 Symbol = *RelocSymNext;
Fangrui Songe7834bd2019-04-07 08:19:55 +00002643 name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002644 }
2645 }
2646 // TODO: add the VariantKinds to op_info->VariantKind for relocation types
2647 // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
2648 op_info->AddSymbol.Present = 1;
2649 op_info->AddSymbol.Name = name;
2650 return 1;
2651 }
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002652 return 0;
David Blaikie33dd45d02015-03-23 18:39:02 +00002653 }
2654 if (Arch == Triple::arm) {
Kevin Enderby930fdc72014-11-06 19:00:13 +00002655 if (Offset != 0 || (Size != 4 && Size != 2))
2656 return 0;
Kevin Enderbyd90a4172015-10-10 00:05:01 +00002657 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2658 // TODO:
2659 // Search the external relocation entries of a fully linked image
2660 // (if any) for an entry that matches this segment offset.
2661 // uint32_t seg_offset = (Pc + Offset);
2662 return 0;
2663 }
2664 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2665 // for an entry for this section offset.
Kevin Enderby930fdc72014-11-06 19:00:13 +00002666 uint32_t sect_addr = info->S.getAddress();
2667 uint32_t sect_offset = (Pc + Offset) - sect_addr;
Kevin Enderby930fdc72014-11-06 19:00:13 +00002668 DataRefImpl Rel;
2669 MachO::any_relocation_info RE;
2670 bool isExtern = false;
2671 SymbolRef Symbol;
2672 bool r_scattered = false;
2673 uint32_t r_value, pair_r_value, r_type, r_length, other_half;
David Blaikie33dd45d02015-03-23 18:39:02 +00002674 auto Reloc =
David Majnemer562e8292016-08-12 00:18:03 +00002675 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2676 uint64_t RelocOffset = Reloc.getOffset();
2677 return RelocOffset == sect_offset;
2678 });
David Blaikie33dd45d02015-03-23 18:39:02 +00002679
2680 if (Reloc == info->S.relocations().end())
2681 return 0;
2682
2683 Rel = Reloc->getRawDataRefImpl();
2684 RE = info->O->getRelocation(Rel);
2685 r_length = info->O->getAnyRelocationLength(RE);
2686 r_scattered = info->O->isRelocationScattered(RE);
2687 if (r_scattered) {
2688 r_value = info->O->getScatteredRelocationValue(RE);
2689 r_type = info->O->getScatteredRelocationType(RE);
2690 } else {
2691 r_type = info->O->getAnyRelocationType(RE);
2692 isExtern = info->O->getPlainRelocationExternal(RE);
2693 if (isExtern) {
2694 symbol_iterator RelocSym = Reloc->getSymbol();
2695 Symbol = *RelocSym;
Kevin Enderby930fdc72014-11-06 19:00:13 +00002696 }
2697 }
David Blaikie33dd45d02015-03-23 18:39:02 +00002698 if (r_type == MachO::ARM_RELOC_HALF ||
2699 r_type == MachO::ARM_RELOC_SECTDIFF ||
2700 r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
2701 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2702 DataRefImpl RelNext = Rel;
2703 info->O->moveRelocationNext(RelNext);
2704 MachO::any_relocation_info RENext;
2705 RENext = info->O->getRelocation(RelNext);
2706 other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
2707 if (info->O->isRelocationScattered(RENext))
2708 pair_r_value = info->O->getScatteredRelocationValue(RENext);
2709 }
2710
2711 if (isExtern) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00002712 const char *name =
2713 unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
Kevin Enderby930fdc72014-11-06 19:00:13 +00002714 op_info->AddSymbol.Present = 1;
2715 op_info->AddSymbol.Name = name;
Sylvestre Ledru648cced2015-02-05 17:00:23 +00002716 switch (r_type) {
2717 case MachO::ARM_RELOC_HALF:
2718 if ((r_length & 0x1) == 1) {
2719 op_info->Value = value << 16 | other_half;
2720 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
2721 } else {
2722 op_info->Value = other_half << 16 | value;
2723 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
Sylvestre Ledrufe0c7ad2015-02-05 16:35:44 +00002724 }
Sylvestre Ledru648cced2015-02-05 17:00:23 +00002725 break;
2726 default:
2727 break;
Kevin Enderby930fdc72014-11-06 19:00:13 +00002728 }
2729 return 1;
2730 }
2731 // If we have a branch that is not an external relocation entry then
2732 // return 0 so the code in tryAddingSymbolicOperand() can use the
2733 // SymbolLookUp call back with the branch target address to look up the
Simon Pilgrimdae11f72016-11-20 13:31:13 +00002734 // symbol and possibility add an annotation for a symbol stub.
David Blaikie33dd45d02015-03-23 18:39:02 +00002735 if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
2736 r_type == MachO::ARM_THUMB_RELOC_BR22))
Kevin Enderby930fdc72014-11-06 19:00:13 +00002737 return 0;
2738
2739 uint32_t offset = 0;
David Blaikie33dd45d02015-03-23 18:39:02 +00002740 if (r_type == MachO::ARM_RELOC_HALF ||
2741 r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
2742 if ((r_length & 0x1) == 1)
2743 value = value << 16 | other_half;
2744 else
2745 value = other_half << 16 | value;
2746 }
2747 if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
2748 r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
2749 offset = value - r_value;
2750 value = r_value;
Kevin Enderby930fdc72014-11-06 19:00:13 +00002751 }
2752
David Blaikie33dd45d02015-03-23 18:39:02 +00002753 if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
Kevin Enderby930fdc72014-11-06 19:00:13 +00002754 if ((r_length & 0x1) == 1)
2755 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
2756 else
2757 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
Kevin Enderbyf6d25852015-01-31 00:37:11 +00002758 const char *add = GuessSymbolName(r_value, info->AddrMap);
2759 const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
Kevin Enderby930fdc72014-11-06 19:00:13 +00002760 int32_t offset = value - (r_value - pair_r_value);
2761 op_info->AddSymbol.Present = 1;
2762 if (add != nullptr)
2763 op_info->AddSymbol.Name = add;
2764 else
2765 op_info->AddSymbol.Value = r_value;
2766 op_info->SubtractSymbol.Present = 1;
2767 if (sub != nullptr)
2768 op_info->SubtractSymbol.Name = sub;
2769 else
2770 op_info->SubtractSymbol.Value = pair_r_value;
2771 op_info->Value = offset;
2772 return 1;
2773 }
2774
Kevin Enderby930fdc72014-11-06 19:00:13 +00002775 op_info->AddSymbol.Present = 1;
2776 op_info->Value = offset;
David Blaikie33dd45d02015-03-23 18:39:02 +00002777 if (r_type == MachO::ARM_RELOC_HALF) {
2778 if ((r_length & 0x1) == 1)
2779 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
2780 else
2781 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
Kevin Enderby930fdc72014-11-06 19:00:13 +00002782 }
Kevin Enderbyf6d25852015-01-31 00:37:11 +00002783 const char *add = GuessSymbolName(value, info->AddrMap);
Kevin Enderby930fdc72014-11-06 19:00:13 +00002784 if (add != nullptr) {
2785 op_info->AddSymbol.Name = add;
2786 return 1;
2787 }
2788 op_info->AddSymbol.Value = value;
2789 return 1;
David Blaikie33dd45d02015-03-23 18:39:02 +00002790 }
2791 if (Arch == Triple::aarch64) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002792 if (Offset != 0 || Size != 4)
2793 return 0;
Kevin Enderbyd90a4172015-10-10 00:05:01 +00002794 if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
2795 // TODO:
2796 // Search the external relocation entries of a fully linked image
2797 // (if any) for an entry that matches this segment offset.
2798 // uint64_t seg_offset = (Pc + Offset);
2799 return 0;
2800 }
2801 // In MH_OBJECT filetypes search the section's relocation entries (if any)
2802 // for an entry for this section offset.
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002803 uint64_t sect_addr = info->S.getAddress();
2804 uint64_t sect_offset = (Pc + Offset) - sect_addr;
David Blaikie33dd45d02015-03-23 18:39:02 +00002805 auto Reloc =
David Majnemer562e8292016-08-12 00:18:03 +00002806 find_if(info->S.relocations(), [&](const RelocationRef &Reloc) {
2807 uint64_t RelocOffset = Reloc.getOffset();
2808 return RelocOffset == sect_offset;
2809 });
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002810
David Blaikie33dd45d02015-03-23 18:39:02 +00002811 if (Reloc == info->S.relocations().end())
2812 return 0;
2813
2814 DataRefImpl Rel = Reloc->getRawDataRefImpl();
2815 MachO::any_relocation_info RE = info->O->getRelocation(Rel);
2816 uint32_t r_type = info->O->getAnyRelocationType(RE);
2817 if (r_type == MachO::ARM64_RELOC_ADDEND) {
2818 DataRefImpl RelNext = Rel;
2819 info->O->moveRelocationNext(RelNext);
2820 MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
2821 if (value == 0) {
2822 value = info->O->getPlainRelocationSymbolNum(RENext);
2823 op_info->Value = value;
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002824 }
Kevin Enderbyae3c1262014-11-14 21:52:18 +00002825 }
David Blaikie33dd45d02015-03-23 18:39:02 +00002826 // NOTE: Scattered relocations don't exist on arm64.
2827 if (!info->O->getPlainRelocationExternal(RE))
2828 return 0;
Fangrui Songe7834bd2019-04-07 08:19:55 +00002829 const char *name =
2830 unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())
2831 .data();
David Blaikie33dd45d02015-03-23 18:39:02 +00002832 op_info->AddSymbol.Present = 1;
2833 op_info->AddSymbol.Name = name;
2834
2835 switch (r_type) {
2836 case MachO::ARM64_RELOC_PAGE21:
2837 /* @page */
2838 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
2839 break;
2840 case MachO::ARM64_RELOC_PAGEOFF12:
2841 /* @pageoff */
2842 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
2843 break;
2844 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
2845 /* @gotpage */
2846 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
2847 break;
2848 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
2849 /* @gotpageoff */
2850 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
2851 break;
2852 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
2853 /* @tvlppage is not implemented in llvm-mc */
2854 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
2855 break;
2856 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
2857 /* @tvlppageoff is not implemented in llvm-mc */
2858 op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
2859 break;
2860 default:
2861 case MachO::ARM64_RELOC_BRANCH26:
2862 op_info->VariantKind = LLVMDisassembler_VariantKind_None;
2863 break;
2864 }
2865 return 1;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002866 }
David Blaikie33dd45d02015-03-23 18:39:02 +00002867 return 0;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00002868}
2869
Kevin Enderbybf246f52014-09-24 23:08:22 +00002870// GuessCstringPointer is passed the address of what might be a pointer to a
2871// literal string in a cstring section. If that address is in a cstring section
2872// it returns a pointer to that string. Else it returns nullptr.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00002873static const char *GuessCstringPointer(uint64_t ReferenceValue,
2874 struct DisassembleInfo *info) {
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00002875 for (const auto &Load : info->O->load_commands()) {
Kevin Enderbybf246f52014-09-24 23:08:22 +00002876 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2877 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2878 for (unsigned J = 0; J < Seg.nsects; ++J) {
2879 MachO::section_64 Sec = info->O->getSection64(Load, J);
2880 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2881 if (section_type == MachO::S_CSTRING_LITERALS &&
2882 ReferenceValue >= Sec.addr &&
2883 ReferenceValue < Sec.addr + Sec.size) {
2884 uint64_t sect_offset = ReferenceValue - Sec.addr;
2885 uint64_t object_offset = Sec.offset + sect_offset;
2886 StringRef MachOContents = info->O->getData();
2887 uint64_t object_size = MachOContents.size();
2888 const char *object_addr = (const char *)MachOContents.data();
2889 if (object_offset < object_size) {
2890 const char *name = object_addr + object_offset;
2891 return name;
2892 } else {
2893 return nullptr;
2894 }
2895 }
2896 }
2897 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2898 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2899 for (unsigned J = 0; J < Seg.nsects; ++J) {
2900 MachO::section Sec = info->O->getSection(Load, J);
2901 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2902 if (section_type == MachO::S_CSTRING_LITERALS &&
2903 ReferenceValue >= Sec.addr &&
2904 ReferenceValue < Sec.addr + Sec.size) {
2905 uint64_t sect_offset = ReferenceValue - Sec.addr;
2906 uint64_t object_offset = Sec.offset + sect_offset;
2907 StringRef MachOContents = info->O->getData();
2908 uint64_t object_size = MachOContents.size();
2909 const char *object_addr = (const char *)MachOContents.data();
2910 if (object_offset < object_size) {
2911 const char *name = object_addr + object_offset;
2912 return name;
2913 } else {
2914 return nullptr;
2915 }
2916 }
2917 }
2918 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00002919 }
2920 return nullptr;
2921}
2922
Kevin Enderby85974882014-09-26 22:20:44 +00002923// GuessIndirectSymbol returns the name of the indirect symbol for the
2924// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
2925// an address of a symbol stub or a lazy or non-lazy pointer to associate the
2926// symbol name being referenced by the stub or pointer.
2927static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
2928 struct DisassembleInfo *info) {
Kevin Enderby85974882014-09-26 22:20:44 +00002929 MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
2930 MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00002931 for (const auto &Load : info->O->load_commands()) {
Kevin Enderby85974882014-09-26 22:20:44 +00002932 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
2933 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
2934 for (unsigned J = 0; J < Seg.nsects; ++J) {
2935 MachO::section_64 Sec = info->O->getSection64(Load, J);
2936 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2937 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2938 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2939 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2940 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2941 section_type == MachO::S_SYMBOL_STUBS) &&
2942 ReferenceValue >= Sec.addr &&
2943 ReferenceValue < Sec.addr + Sec.size) {
2944 uint32_t stride;
2945 if (section_type == MachO::S_SYMBOL_STUBS)
2946 stride = Sec.reserved2;
2947 else
2948 stride = 8;
2949 if (stride == 0)
2950 return nullptr;
2951 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2952 if (index < Dysymtab.nindirectsyms) {
2953 uint32_t indirect_symbol =
Kevin Enderby6f326ce2014-10-23 19:37:31 +00002954 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
Kevin Enderby85974882014-09-26 22:20:44 +00002955 if (indirect_symbol < Symtab.nsyms) {
2956 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
Fangrui Songe7834bd2019-04-07 08:19:55 +00002957 return unwrapOrError(Sym->getName(), info->O->getFileName())
2958 .data();
Kevin Enderby85974882014-09-26 22:20:44 +00002959 }
2960 }
2961 }
2962 }
2963 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
2964 MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
2965 for (unsigned J = 0; J < Seg.nsects; ++J) {
2966 MachO::section Sec = info->O->getSection(Load, J);
2967 uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
2968 if ((section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
2969 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
2970 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
2971 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
2972 section_type == MachO::S_SYMBOL_STUBS) &&
2973 ReferenceValue >= Sec.addr &&
2974 ReferenceValue < Sec.addr + Sec.size) {
2975 uint32_t stride;
2976 if (section_type == MachO::S_SYMBOL_STUBS)
2977 stride = Sec.reserved2;
2978 else
2979 stride = 4;
2980 if (stride == 0)
2981 return nullptr;
2982 uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
2983 if (index < Dysymtab.nindirectsyms) {
2984 uint32_t indirect_symbol =
Kevin Enderby6f326ce2014-10-23 19:37:31 +00002985 info->O->getIndirectSymbolTableEntry(Dysymtab, index);
Kevin Enderby85974882014-09-26 22:20:44 +00002986 if (indirect_symbol < Symtab.nsyms) {
2987 symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
Fangrui Songe7834bd2019-04-07 08:19:55 +00002988 return unwrapOrError(Sym->getName(), info->O->getFileName())
2989 .data();
Kevin Enderby85974882014-09-26 22:20:44 +00002990 }
2991 }
2992 }
2993 }
2994 }
Kevin Enderby85974882014-09-26 22:20:44 +00002995 }
2996 return nullptr;
2997}
2998
Kevin Enderby6f326ce2014-10-23 19:37:31 +00002999// method_reference() is called passing it the ReferenceName that might be
3000// a reference it to an Objective-C method call. If so then it allocates and
3001// assembles a method call string with the values last seen and saved in
3002// the DisassembleInfo's class_name and selector_name fields. This is saved
3003// into the method field of the info and any previous string is free'ed.
3004// Then the class_name field in the info is set to nullptr. The method call
3005// string is set into ReferenceName and ReferenceType is set to
3006// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
3007// then both ReferenceType and ReferenceName are left unchanged.
3008static void method_reference(struct DisassembleInfo *info,
3009 uint64_t *ReferenceType,
3010 const char **ReferenceName) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003011 unsigned int Arch = info->O->getArch();
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003012 if (*ReferenceName != nullptr) {
3013 if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003014 if (info->selector_name != nullptr) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003015 if (info->class_name != nullptr) {
David Blaikie0e550682018-02-20 18:48:51 +00003016 info->method = llvm::make_unique<char[]>(
3017 5 + strlen(info->class_name) + strlen(info->selector_name));
3018 char *method = info->method.get();
3019 if (method != nullptr) {
3020 strcpy(method, "+[");
3021 strcat(method, info->class_name);
3022 strcat(method, " ");
3023 strcat(method, info->selector_name);
3024 strcat(method, "]");
3025 *ReferenceName = method;
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003026 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3027 }
3028 } else {
David Blaikie0e550682018-02-20 18:48:51 +00003029 info->method =
3030 llvm::make_unique<char[]>(9 + strlen(info->selector_name));
3031 char *method = info->method.get();
3032 if (method != nullptr) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003033 if (Arch == Triple::x86_64)
David Blaikie0e550682018-02-20 18:48:51 +00003034 strcpy(method, "-[%rdi ");
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003035 else if (Arch == Triple::aarch64)
David Blaikie0e550682018-02-20 18:48:51 +00003036 strcpy(method, "-[x0 ");
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003037 else
David Blaikie0e550682018-02-20 18:48:51 +00003038 strcpy(method, "-[r? ");
3039 strcat(method, info->selector_name);
3040 strcat(method, "]");
3041 *ReferenceName = method;
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003042 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3043 }
3044 }
3045 info->class_name = nullptr;
3046 }
3047 } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003048 if (info->selector_name != nullptr) {
David Blaikie0e550682018-02-20 18:48:51 +00003049 info->method =
3050 llvm::make_unique<char[]>(17 + strlen(info->selector_name));
3051 char *method = info->method.get();
3052 if (method != nullptr) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003053 if (Arch == Triple::x86_64)
David Blaikie0e550682018-02-20 18:48:51 +00003054 strcpy(method, "-[[%rdi super] ");
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003055 else if (Arch == Triple::aarch64)
David Blaikie0e550682018-02-20 18:48:51 +00003056 strcpy(method, "-[[x0 super] ");
Kevin Enderbyae3c1262014-11-14 21:52:18 +00003057 else
David Blaikie0e550682018-02-20 18:48:51 +00003058 strcpy(method, "-[[r? super] ");
3059 strcat(method, info->selector_name);
3060 strcat(method, "]");
3061 *ReferenceName = method;
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003062 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
3063 }
3064 info->class_name = nullptr;
3065 }
3066 }
3067 }
3068}
3069
3070// GuessPointerPointer() is passed the address of what might be a pointer to
3071// a reference to an Objective-C class, selector, message ref or cfstring.
3072// If so the value of the pointer is returned and one of the booleans are set
3073// to true. If not zero is returned and all the booleans are set to false.
3074static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
3075 struct DisassembleInfo *info,
3076 bool &classref, bool &selref, bool &msgref,
3077 bool &cfstring) {
3078 classref = false;
3079 selref = false;
3080 msgref = false;
3081 cfstring = false;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00003082 for (const auto &Load : info->O->load_commands()) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003083 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
3084 MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
3085 for (unsigned J = 0; J < Seg.nsects; ++J) {
3086 MachO::section_64 Sec = info->O->getSection64(Load, J);
3087 if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
3088 strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3089 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
3090 strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
3091 strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
3092 ReferenceValue >= Sec.addr &&
3093 ReferenceValue < Sec.addr + Sec.size) {
3094 uint64_t sect_offset = ReferenceValue - Sec.addr;
3095 uint64_t object_offset = Sec.offset + sect_offset;
3096 StringRef MachOContents = info->O->getData();
3097 uint64_t object_size = MachOContents.size();
3098 const char *object_addr = (const char *)MachOContents.data();
3099 if (object_offset < object_size) {
3100 uint64_t pointer_value;
3101 memcpy(&pointer_value, object_addr + object_offset,
3102 sizeof(uint64_t));
3103 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3104 sys::swapByteOrder(pointer_value);
3105 if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
3106 selref = true;
3107 else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
3108 strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
3109 classref = true;
3110 else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
3111 ReferenceValue + 8 < Sec.addr + Sec.size) {
3112 msgref = true;
3113 memcpy(&pointer_value, object_addr + object_offset + 8,
3114 sizeof(uint64_t));
3115 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3116 sys::swapByteOrder(pointer_value);
3117 } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
3118 cfstring = true;
3119 return pointer_value;
3120 } else {
3121 return 0;
3122 }
3123 }
3124 }
3125 }
3126 // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003127 }
3128 return 0;
3129}
3130
3131// get_pointer_64 returns a pointer to the bytes in the object file at the
3132// Address from a section in the Mach-O file. And indirectly returns the
3133// offset into the section, number of bytes left in the section past the offset
3134// and which section is was being referenced. If the Address is not in a
3135// section nullptr is returned.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00003136static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
3137 uint32_t &left, SectionRef &S,
Kevin Enderby846c0002015-04-16 17:19:59 +00003138 DisassembleInfo *info,
3139 bool objc_only = false) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003140 offset = 0;
3141 left = 0;
3142 S = SectionRef();
3143 for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
3144 uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
3145 uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
Kevin Enderby46e642f2015-10-08 22:50:55 +00003146 if (SectSize == 0)
3147 continue;
Kevin Enderby846c0002015-04-16 17:19:59 +00003148 if (objc_only) {
3149 StringRef SectName;
3150 ((*(info->Sections))[SectIdx]).getName(SectName);
3151 DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
3152 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
3153 if (SegName != "__OBJC" && SectName != "__cstring")
3154 continue;
3155 }
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003156 if (Address >= SectAddress && Address < SectAddress + SectSize) {
3157 S = (*(info->Sections))[SectIdx];
3158 offset = Address - SectAddress;
3159 left = SectSize - offset;
3160 StringRef SectContents;
3161 ((*(info->Sections))[SectIdx]).getContents(SectContents);
3162 return SectContents.data() + offset;
3163 }
3164 }
3165 return nullptr;
3166}
3167
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003168static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
3169 uint32_t &left, SectionRef &S,
Kevin Enderby846c0002015-04-16 17:19:59 +00003170 DisassembleInfo *info,
3171 bool objc_only = false) {
3172 return get_pointer_64(Address, offset, left, S, info, objc_only);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003173}
3174
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003175// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
3176// the symbol indirectly through n_value. Based on the relocation information
3177// for the specified section offset in the specified section reference.
Kevin Enderby0fc11822015-04-01 20:57:01 +00003178// If no relocation information is found and a non-zero ReferenceValue for the
3179// symbol is passed, look up that address in the info's AddrMap.
Rafael Espindolad7a32ea2015-06-24 10:20:30 +00003180static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
3181 DisassembleInfo *info, uint64_t &n_value,
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +00003182 uint64_t ReferenceValue = 0) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003183 n_value = 0;
David Blaikie33dd45d02015-03-23 18:39:02 +00003184 if (!info->verbose)
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003185 return nullptr;
3186
3187 // See if there is an external relocation entry at the sect_offset.
3188 bool reloc_found = false;
3189 DataRefImpl Rel;
3190 MachO::any_relocation_info RE;
3191 bool isExtern = false;
3192 SymbolRef Symbol;
3193 for (const RelocationRef &Reloc : S.relocations()) {
Rafael Espindola96d071c2015-06-29 23:29:12 +00003194 uint64_t RelocOffset = Reloc.getOffset();
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003195 if (RelocOffset == sect_offset) {
3196 Rel = Reloc.getRawDataRefImpl();
3197 RE = info->O->getRelocation(Rel);
3198 if (info->O->isRelocationScattered(RE))
3199 continue;
3200 isExtern = info->O->getPlainRelocationExternal(RE);
3201 if (isExtern) {
3202 symbol_iterator RelocSym = Reloc.getSymbol();
3203 Symbol = *RelocSym;
3204 }
3205 reloc_found = true;
3206 break;
3207 }
3208 }
3209 // If there is an external relocation entry for a symbol in this section
3210 // at this section_offset then use that symbol's value for the n_value
3211 // and return its name.
3212 const char *SymbolName = nullptr;
3213 if (reloc_found && isExtern) {
Rafael Espindoladea00162015-07-03 17:44:18 +00003214 n_value = Symbol.getValue();
Fangrui Songe7834bd2019-04-07 08:19:55 +00003215 StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());
Rafael Espindola5d0c2ff2015-07-02 20:55:21 +00003216 if (!Name.empty()) {
3217 SymbolName = Name.data();
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003218 return SymbolName;
3219 }
3220 }
3221
3222 // TODO: For fully linked images, look through the external relocation
3223 // entries off the dynamic symtab command. For these the r_offset is from the
3224 // start of the first writeable segment in the Mach-O file. So the offset
3225 // to this section from that segment is passed to this routine by the caller,
3226 // as the database_offset. Which is the difference of the section's starting
3227 // address and the first writable segment.
3228 //
3229 // NOTE: need add passing the database_offset to this routine.
3230
Kevin Enderby0fc11822015-04-01 20:57:01 +00003231 // We did not find an external relocation entry so look up the ReferenceValue
3232 // as an address of a symbol and if found return that symbol's name.
Rafael Espindolabe8b0ea2015-07-07 17:12:59 +00003233 SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003234
3235 return SymbolName;
3236}
3237
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003238static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
3239 DisassembleInfo *info,
3240 uint32_t ReferenceValue) {
3241 uint64_t n_value64;
3242 return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
3243}
3244
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003245// These are structs in the Objective-C meta data and read to produce the
3246// comments for disassembly. While these are part of the ABI they are no
Zachary Turner264b5d92017-06-07 03:48:56 +00003247// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
3248// .
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003249
3250// The cfstring object in a 64-bit Mach-O file.
3251struct cfstring64_t {
3252 uint64_t isa; // class64_t * (64-bit pointer)
3253 uint64_t flags; // flag bits
3254 uint64_t characters; // char * (64-bit pointer)
3255 uint64_t length; // number of non-NULL characters in above
3256};
3257
3258// The class object in a 64-bit Mach-O file.
3259struct class64_t {
3260 uint64_t isa; // class64_t * (64-bit pointer)
3261 uint64_t superclass; // class64_t * (64-bit pointer)
3262 uint64_t cache; // Cache (64-bit pointer)
3263 uint64_t vtable; // IMP * (64-bit pointer)
3264 uint64_t data; // class_ro64_t * (64-bit pointer)
3265};
3266
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003267struct class32_t {
3268 uint32_t isa; /* class32_t * (32-bit pointer) */
3269 uint32_t superclass; /* class32_t * (32-bit pointer) */
3270 uint32_t cache; /* Cache (32-bit pointer) */
3271 uint32_t vtable; /* IMP * (32-bit pointer) */
3272 uint32_t data; /* class_ro32_t * (32-bit pointer) */
3273};
3274
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003275struct class_ro64_t {
3276 uint32_t flags;
3277 uint32_t instanceStart;
3278 uint32_t instanceSize;
3279 uint32_t reserved;
3280 uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
3281 uint64_t name; // const char * (64-bit pointer)
3282 uint64_t baseMethods; // const method_list_t * (64-bit pointer)
3283 uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
3284 uint64_t ivars; // const ivar_list_t * (64-bit pointer)
3285 uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
3286 uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
3287};
3288
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003289struct class_ro32_t {
3290 uint32_t flags;
3291 uint32_t instanceStart;
3292 uint32_t instanceSize;
3293 uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
3294 uint32_t name; /* const char * (32-bit pointer) */
3295 uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
3296 uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
3297 uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
3298 uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
3299 uint32_t baseProperties; /* const struct objc_property_list *
3300 (32-bit pointer) */
3301};
3302
3303/* Values for class_ro{64,32}_t->flags */
Kevin Enderby0fc11822015-04-01 20:57:01 +00003304#define RO_META (1 << 0)
3305#define RO_ROOT (1 << 1)
3306#define RO_HAS_CXX_STRUCTORS (1 << 2)
3307
3308struct method_list64_t {
3309 uint32_t entsize;
3310 uint32_t count;
3311 /* struct method64_t first; These structures follow inline */
3312};
3313
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003314struct method_list32_t {
3315 uint32_t entsize;
3316 uint32_t count;
3317 /* struct method32_t first; These structures follow inline */
3318};
3319
Kevin Enderby0fc11822015-04-01 20:57:01 +00003320struct method64_t {
3321 uint64_t name; /* SEL (64-bit pointer) */
3322 uint64_t types; /* const char * (64-bit pointer) */
3323 uint64_t imp; /* IMP (64-bit pointer) */
3324};
3325
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003326struct method32_t {
3327 uint32_t name; /* SEL (32-bit pointer) */
3328 uint32_t types; /* const char * (32-bit pointer) */
3329 uint32_t imp; /* IMP (32-bit pointer) */
3330};
3331
Kevin Enderby0fc11822015-04-01 20:57:01 +00003332struct protocol_list64_t {
3333 uint64_t count; /* uintptr_t (a 64-bit value) */
3334 /* struct protocol64_t * list[0]; These pointers follow inline */
3335};
3336
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003337struct protocol_list32_t {
3338 uint32_t count; /* uintptr_t (a 32-bit value) */
3339 /* struct protocol32_t * list[0]; These pointers follow inline */
3340};
3341
Kevin Enderby0fc11822015-04-01 20:57:01 +00003342struct protocol64_t {
3343 uint64_t isa; /* id * (64-bit pointer) */
3344 uint64_t name; /* const char * (64-bit pointer) */
3345 uint64_t protocols; /* struct protocol_list64_t *
3346 (64-bit pointer) */
3347 uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
3348 uint64_t classMethods; /* method_list_t * (64-bit pointer) */
3349 uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
3350 uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
3351 uint64_t instanceProperties; /* struct objc_property_list *
3352 (64-bit pointer) */
3353};
3354
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003355struct protocol32_t {
3356 uint32_t isa; /* id * (32-bit pointer) */
3357 uint32_t name; /* const char * (32-bit pointer) */
3358 uint32_t protocols; /* struct protocol_list_t *
3359 (32-bit pointer) */
3360 uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
3361 uint32_t classMethods; /* method_list_t * (32-bit pointer) */
3362 uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
3363 uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
3364 uint32_t instanceProperties; /* struct objc_property_list *
3365 (32-bit pointer) */
3366};
3367
Kevin Enderby0fc11822015-04-01 20:57:01 +00003368struct ivar_list64_t {
3369 uint32_t entsize;
3370 uint32_t count;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003371 /* struct ivar64_t first; These structures follow inline */
3372};
3373
3374struct ivar_list32_t {
3375 uint32_t entsize;
3376 uint32_t count;
3377 /* struct ivar32_t first; These structures follow inline */
Kevin Enderby0fc11822015-04-01 20:57:01 +00003378};
3379
3380struct ivar64_t {
3381 uint64_t offset; /* uintptr_t * (64-bit pointer) */
3382 uint64_t name; /* const char * (64-bit pointer) */
3383 uint64_t type; /* const char * (64-bit pointer) */
3384 uint32_t alignment;
3385 uint32_t size;
3386};
3387
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003388struct ivar32_t {
3389 uint32_t offset; /* uintptr_t * (32-bit pointer) */
3390 uint32_t name; /* const char * (32-bit pointer) */
3391 uint32_t type; /* const char * (32-bit pointer) */
3392 uint32_t alignment;
3393 uint32_t size;
3394};
3395
Kevin Enderby0fc11822015-04-01 20:57:01 +00003396struct objc_property_list64 {
3397 uint32_t entsize;
3398 uint32_t count;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003399 /* struct objc_property64 first; These structures follow inline */
3400};
3401
3402struct objc_property_list32 {
3403 uint32_t entsize;
3404 uint32_t count;
3405 /* struct objc_property32 first; These structures follow inline */
Kevin Enderby0fc11822015-04-01 20:57:01 +00003406};
3407
3408struct objc_property64 {
3409 uint64_t name; /* const char * (64-bit pointer) */
3410 uint64_t attributes; /* const char * (64-bit pointer) */
3411};
3412
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003413struct objc_property32 {
3414 uint32_t name; /* const char * (32-bit pointer) */
3415 uint32_t attributes; /* const char * (32-bit pointer) */
3416};
3417
Kevin Enderby0fc11822015-04-01 20:57:01 +00003418struct category64_t {
3419 uint64_t name; /* const char * (64-bit pointer) */
3420 uint64_t cls; /* struct class_t * (64-bit pointer) */
3421 uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
3422 uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
3423 uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
3424 uint64_t instanceProperties; /* struct objc_property_list *
3425 (64-bit pointer) */
3426};
3427
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003428struct category32_t {
3429 uint32_t name; /* const char * (32-bit pointer) */
3430 uint32_t cls; /* struct class_t * (32-bit pointer) */
3431 uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
3432 uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
3433 uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
3434 uint32_t instanceProperties; /* struct objc_property_list *
3435 (32-bit pointer) */
3436};
3437
Kevin Enderby0fc11822015-04-01 20:57:01 +00003438struct objc_image_info64 {
3439 uint32_t version;
3440 uint32_t flags;
3441};
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003442struct objc_image_info32 {
3443 uint32_t version;
3444 uint32_t flags;
3445};
Kevin Enderby846c0002015-04-16 17:19:59 +00003446struct imageInfo_t {
3447 uint32_t version;
3448 uint32_t flags;
3449};
Kevin Enderby0fc11822015-04-01 20:57:01 +00003450/* masks for objc_image_info.flags */
3451#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
3452#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
Dave Lee390abe42018-07-06 05:11:35 +00003453#define OBJC_IMAGE_IS_SIMULATED (1 << 5)
3454#define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES (1 << 6)
Kevin Enderby0fc11822015-04-01 20:57:01 +00003455
3456struct message_ref64 {
3457 uint64_t imp; /* IMP (64-bit pointer) */
3458 uint64_t sel; /* SEL (64-bit pointer) */
3459};
3460
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003461struct message_ref32 {
3462 uint32_t imp; /* IMP (32-bit pointer) */
3463 uint32_t sel; /* SEL (32-bit pointer) */
3464};
3465
Kevin Enderby846c0002015-04-16 17:19:59 +00003466// Objective-C 1 (32-bit only) meta data structs.
3467
3468struct objc_module_t {
3469 uint32_t version;
3470 uint32_t size;
3471 uint32_t name; /* char * (32-bit pointer) */
3472 uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
3473};
3474
3475struct objc_symtab_t {
3476 uint32_t sel_ref_cnt;
3477 uint32_t refs; /* SEL * (32-bit pointer) */
3478 uint16_t cls_def_cnt;
3479 uint16_t cat_def_cnt;
3480 // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
3481};
3482
3483struct objc_class_t {
3484 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3485 uint32_t super_class; /* struct objc_class * (32-bit pointer) */
3486 uint32_t name; /* const char * (32-bit pointer) */
3487 int32_t version;
3488 int32_t info;
3489 int32_t instance_size;
3490 uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
3491 uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
3492 uint32_t cache; /* struct objc_cache * (32-bit pointer) */
3493 uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
3494};
3495
3496#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
3497// class is not a metaclass
3498#define CLS_CLASS 0x1
3499// class is a metaclass
3500#define CLS_META 0x2
3501
3502struct objc_category_t {
3503 uint32_t category_name; /* char * (32-bit pointer) */
3504 uint32_t class_name; /* char * (32-bit pointer) */
3505 uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
3506 uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
3507 uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
3508};
3509
3510struct objc_ivar_t {
3511 uint32_t ivar_name; /* char * (32-bit pointer) */
3512 uint32_t ivar_type; /* char * (32-bit pointer) */
3513 int32_t ivar_offset;
3514};
3515
3516struct objc_ivar_list_t {
3517 int32_t ivar_count;
3518 // struct objc_ivar_t ivar_list[1]; /* variable length structure */
3519};
3520
3521struct objc_method_list_t {
3522 uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
3523 int32_t method_count;
3524 // struct objc_method_t method_list[1]; /* variable length structure */
3525};
3526
3527struct objc_method_t {
3528 uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3529 uint32_t method_types; /* char * (32-bit pointer) */
3530 uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
3531 (32-bit pointer) */
3532};
3533
3534struct objc_protocol_list_t {
3535 uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
3536 int32_t count;
3537 // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
3538 // (32-bit pointer) */
3539};
3540
3541struct objc_protocol_t {
3542 uint32_t isa; /* struct objc_class * (32-bit pointer) */
3543 uint32_t protocol_name; /* char * (32-bit pointer) */
3544 uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
3545 uint32_t instance_methods; /* struct objc_method_description_list *
3546 (32-bit pointer) */
3547 uint32_t class_methods; /* struct objc_method_description_list *
3548 (32-bit pointer) */
3549};
3550
3551struct objc_method_description_list_t {
3552 int32_t count;
3553 // struct objc_method_description_t list[1];
3554};
3555
3556struct objc_method_description_t {
3557 uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
3558 uint32_t types; /* char * (32-bit pointer) */
3559};
3560
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003561inline void swapStruct(struct cfstring64_t &cfs) {
3562 sys::swapByteOrder(cfs.isa);
3563 sys::swapByteOrder(cfs.flags);
3564 sys::swapByteOrder(cfs.characters);
3565 sys::swapByteOrder(cfs.length);
3566}
3567
3568inline void swapStruct(struct class64_t &c) {
3569 sys::swapByteOrder(c.isa);
3570 sys::swapByteOrder(c.superclass);
3571 sys::swapByteOrder(c.cache);
3572 sys::swapByteOrder(c.vtable);
3573 sys::swapByteOrder(c.data);
3574}
3575
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003576inline void swapStruct(struct class32_t &c) {
3577 sys::swapByteOrder(c.isa);
3578 sys::swapByteOrder(c.superclass);
3579 sys::swapByteOrder(c.cache);
3580 sys::swapByteOrder(c.vtable);
3581 sys::swapByteOrder(c.data);
3582}
3583
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003584inline void swapStruct(struct class_ro64_t &cro) {
3585 sys::swapByteOrder(cro.flags);
3586 sys::swapByteOrder(cro.instanceStart);
3587 sys::swapByteOrder(cro.instanceSize);
3588 sys::swapByteOrder(cro.reserved);
3589 sys::swapByteOrder(cro.ivarLayout);
3590 sys::swapByteOrder(cro.name);
3591 sys::swapByteOrder(cro.baseMethods);
3592 sys::swapByteOrder(cro.baseProtocols);
3593 sys::swapByteOrder(cro.ivars);
3594 sys::swapByteOrder(cro.weakIvarLayout);
3595 sys::swapByteOrder(cro.baseProperties);
3596}
3597
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003598inline void swapStruct(struct class_ro32_t &cro) {
3599 sys::swapByteOrder(cro.flags);
3600 sys::swapByteOrder(cro.instanceStart);
3601 sys::swapByteOrder(cro.instanceSize);
3602 sys::swapByteOrder(cro.ivarLayout);
3603 sys::swapByteOrder(cro.name);
3604 sys::swapByteOrder(cro.baseMethods);
3605 sys::swapByteOrder(cro.baseProtocols);
3606 sys::swapByteOrder(cro.ivars);
3607 sys::swapByteOrder(cro.weakIvarLayout);
3608 sys::swapByteOrder(cro.baseProperties);
3609}
3610
Kevin Enderby0fc11822015-04-01 20:57:01 +00003611inline void swapStruct(struct method_list64_t &ml) {
3612 sys::swapByteOrder(ml.entsize);
3613 sys::swapByteOrder(ml.count);
3614}
3615
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003616inline void swapStruct(struct method_list32_t &ml) {
3617 sys::swapByteOrder(ml.entsize);
3618 sys::swapByteOrder(ml.count);
3619}
3620
Kevin Enderby0fc11822015-04-01 20:57:01 +00003621inline void swapStruct(struct method64_t &m) {
3622 sys::swapByteOrder(m.name);
3623 sys::swapByteOrder(m.types);
3624 sys::swapByteOrder(m.imp);
3625}
3626
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003627inline void swapStruct(struct method32_t &m) {
3628 sys::swapByteOrder(m.name);
3629 sys::swapByteOrder(m.types);
3630 sys::swapByteOrder(m.imp);
3631}
3632
Kevin Enderby0fc11822015-04-01 20:57:01 +00003633inline void swapStruct(struct protocol_list64_t &pl) {
3634 sys::swapByteOrder(pl.count);
3635}
3636
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003637inline void swapStruct(struct protocol_list32_t &pl) {
3638 sys::swapByteOrder(pl.count);
3639}
3640
Kevin Enderby0fc11822015-04-01 20:57:01 +00003641inline void swapStruct(struct protocol64_t &p) {
3642 sys::swapByteOrder(p.isa);
3643 sys::swapByteOrder(p.name);
3644 sys::swapByteOrder(p.protocols);
3645 sys::swapByteOrder(p.instanceMethods);
3646 sys::swapByteOrder(p.classMethods);
3647 sys::swapByteOrder(p.optionalInstanceMethods);
3648 sys::swapByteOrder(p.optionalClassMethods);
3649 sys::swapByteOrder(p.instanceProperties);
3650}
3651
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003652inline void swapStruct(struct protocol32_t &p) {
3653 sys::swapByteOrder(p.isa);
3654 sys::swapByteOrder(p.name);
3655 sys::swapByteOrder(p.protocols);
3656 sys::swapByteOrder(p.instanceMethods);
3657 sys::swapByteOrder(p.classMethods);
3658 sys::swapByteOrder(p.optionalInstanceMethods);
3659 sys::swapByteOrder(p.optionalClassMethods);
3660 sys::swapByteOrder(p.instanceProperties);
3661}
3662
Kevin Enderby0fc11822015-04-01 20:57:01 +00003663inline void swapStruct(struct ivar_list64_t &il) {
3664 sys::swapByteOrder(il.entsize);
3665 sys::swapByteOrder(il.count);
3666}
3667
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003668inline void swapStruct(struct ivar_list32_t &il) {
3669 sys::swapByteOrder(il.entsize);
3670 sys::swapByteOrder(il.count);
3671}
3672
Kevin Enderby0fc11822015-04-01 20:57:01 +00003673inline void swapStruct(struct ivar64_t &i) {
3674 sys::swapByteOrder(i.offset);
3675 sys::swapByteOrder(i.name);
3676 sys::swapByteOrder(i.type);
3677 sys::swapByteOrder(i.alignment);
3678 sys::swapByteOrder(i.size);
3679}
3680
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003681inline void swapStruct(struct ivar32_t &i) {
3682 sys::swapByteOrder(i.offset);
3683 sys::swapByteOrder(i.name);
3684 sys::swapByteOrder(i.type);
3685 sys::swapByteOrder(i.alignment);
3686 sys::swapByteOrder(i.size);
3687}
3688
Kevin Enderby0fc11822015-04-01 20:57:01 +00003689inline void swapStruct(struct objc_property_list64 &pl) {
3690 sys::swapByteOrder(pl.entsize);
3691 sys::swapByteOrder(pl.count);
3692}
3693
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003694inline void swapStruct(struct objc_property_list32 &pl) {
3695 sys::swapByteOrder(pl.entsize);
3696 sys::swapByteOrder(pl.count);
3697}
3698
Kevin Enderby0fc11822015-04-01 20:57:01 +00003699inline void swapStruct(struct objc_property64 &op) {
3700 sys::swapByteOrder(op.name);
3701 sys::swapByteOrder(op.attributes);
3702}
3703
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003704inline void swapStruct(struct objc_property32 &op) {
3705 sys::swapByteOrder(op.name);
3706 sys::swapByteOrder(op.attributes);
3707}
3708
Kevin Enderby0fc11822015-04-01 20:57:01 +00003709inline void swapStruct(struct category64_t &c) {
3710 sys::swapByteOrder(c.name);
3711 sys::swapByteOrder(c.cls);
3712 sys::swapByteOrder(c.instanceMethods);
3713 sys::swapByteOrder(c.classMethods);
3714 sys::swapByteOrder(c.protocols);
3715 sys::swapByteOrder(c.instanceProperties);
3716}
3717
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003718inline void swapStruct(struct category32_t &c) {
3719 sys::swapByteOrder(c.name);
3720 sys::swapByteOrder(c.cls);
3721 sys::swapByteOrder(c.instanceMethods);
3722 sys::swapByteOrder(c.classMethods);
3723 sys::swapByteOrder(c.protocols);
3724 sys::swapByteOrder(c.instanceProperties);
3725}
3726
Kevin Enderby0fc11822015-04-01 20:57:01 +00003727inline void swapStruct(struct objc_image_info64 &o) {
3728 sys::swapByteOrder(o.version);
3729 sys::swapByteOrder(o.flags);
3730}
3731
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003732inline void swapStruct(struct objc_image_info32 &o) {
3733 sys::swapByteOrder(o.version);
3734 sys::swapByteOrder(o.flags);
3735}
3736
Kevin Enderby846c0002015-04-16 17:19:59 +00003737inline void swapStruct(struct imageInfo_t &o) {
3738 sys::swapByteOrder(o.version);
3739 sys::swapByteOrder(o.flags);
3740}
3741
Kevin Enderby0fc11822015-04-01 20:57:01 +00003742inline void swapStruct(struct message_ref64 &mr) {
3743 sys::swapByteOrder(mr.imp);
3744 sys::swapByteOrder(mr.sel);
3745}
3746
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00003747inline void swapStruct(struct message_ref32 &mr) {
3748 sys::swapByteOrder(mr.imp);
3749 sys::swapByteOrder(mr.sel);
3750}
3751
Kevin Enderby846c0002015-04-16 17:19:59 +00003752inline void swapStruct(struct objc_module_t &module) {
3753 sys::swapByteOrder(module.version);
3754 sys::swapByteOrder(module.size);
3755 sys::swapByteOrder(module.name);
3756 sys::swapByteOrder(module.symtab);
Jingyue Wufedecc42015-04-16 18:43:44 +00003757}
Kevin Enderby846c0002015-04-16 17:19:59 +00003758
3759inline void swapStruct(struct objc_symtab_t &symtab) {
3760 sys::swapByteOrder(symtab.sel_ref_cnt);
3761 sys::swapByteOrder(symtab.refs);
3762 sys::swapByteOrder(symtab.cls_def_cnt);
3763 sys::swapByteOrder(symtab.cat_def_cnt);
Jingyue Wufedecc42015-04-16 18:43:44 +00003764}
Kevin Enderby846c0002015-04-16 17:19:59 +00003765
3766inline void swapStruct(struct objc_class_t &objc_class) {
3767 sys::swapByteOrder(objc_class.isa);
3768 sys::swapByteOrder(objc_class.super_class);
3769 sys::swapByteOrder(objc_class.name);
3770 sys::swapByteOrder(objc_class.version);
3771 sys::swapByteOrder(objc_class.info);
3772 sys::swapByteOrder(objc_class.instance_size);
3773 sys::swapByteOrder(objc_class.ivars);
3774 sys::swapByteOrder(objc_class.methodLists);
3775 sys::swapByteOrder(objc_class.cache);
3776 sys::swapByteOrder(objc_class.protocols);
Jingyue Wufedecc42015-04-16 18:43:44 +00003777}
Kevin Enderby846c0002015-04-16 17:19:59 +00003778
3779inline void swapStruct(struct objc_category_t &objc_category) {
3780 sys::swapByteOrder(objc_category.category_name);
3781 sys::swapByteOrder(objc_category.class_name);
3782 sys::swapByteOrder(objc_category.instance_methods);
3783 sys::swapByteOrder(objc_category.class_methods);
3784 sys::swapByteOrder(objc_category.protocols);
3785}
3786
3787inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
3788 sys::swapByteOrder(objc_ivar_list.ivar_count);
3789}
3790
3791inline void swapStruct(struct objc_ivar_t &objc_ivar) {
3792 sys::swapByteOrder(objc_ivar.ivar_name);
3793 sys::swapByteOrder(objc_ivar.ivar_type);
3794 sys::swapByteOrder(objc_ivar.ivar_offset);
Jingyue Wufedecc42015-04-16 18:43:44 +00003795}
Kevin Enderby846c0002015-04-16 17:19:59 +00003796
3797inline void swapStruct(struct objc_method_list_t &method_list) {
3798 sys::swapByteOrder(method_list.obsolete);
3799 sys::swapByteOrder(method_list.method_count);
3800}
3801
3802inline void swapStruct(struct objc_method_t &method) {
3803 sys::swapByteOrder(method.method_name);
3804 sys::swapByteOrder(method.method_types);
3805 sys::swapByteOrder(method.method_imp);
3806}
3807
3808inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
3809 sys::swapByteOrder(protocol_list.next);
3810 sys::swapByteOrder(protocol_list.count);
3811}
3812
3813inline void swapStruct(struct objc_protocol_t &protocol) {
3814 sys::swapByteOrder(protocol.isa);
3815 sys::swapByteOrder(protocol.protocol_name);
3816 sys::swapByteOrder(protocol.protocol_list);
3817 sys::swapByteOrder(protocol.instance_methods);
3818 sys::swapByteOrder(protocol.class_methods);
3819}
3820
3821inline void swapStruct(struct objc_method_description_list_t &mdl) {
3822 sys::swapByteOrder(mdl.count);
3823}
3824
3825inline void swapStruct(struct objc_method_description_t &md) {
3826 sys::swapByteOrder(md.name);
3827 sys::swapByteOrder(md.types);
3828}
3829
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003830static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
3831 struct DisassembleInfo *info);
3832
3833// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
3834// to an Objective-C class and returns the class name. It is also passed the
3835// address of the pointer, so when the pointer is zero as it can be in an .o
3836// file, that is used to look for an external relocation entry with a symbol
3837// name.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00003838static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
3839 uint64_t ReferenceValue,
3840 struct DisassembleInfo *info) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003841 const char *r;
3842 uint32_t offset, left;
3843 SectionRef S;
3844
3845 // The pointer_value can be 0 in an object file and have a relocation
3846 // entry for the class symbol at the ReferenceValue (the address of the
3847 // pointer).
3848 if (pointer_value == 0) {
3849 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3850 if (r == nullptr || left < sizeof(uint64_t))
3851 return nullptr;
3852 uint64_t n_value;
3853 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3854 if (symbol_name == nullptr)
3855 return nullptr;
Hans Wennborgdb53e302014-10-23 21:59:17 +00003856 const char *class_name = strrchr(symbol_name, '$');
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003857 if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
3858 return class_name + 2;
3859 else
3860 return nullptr;
3861 }
3862
3863 // The case were the pointer_value is non-zero and points to a class defined
3864 // in this Mach-O file.
3865 r = get_pointer_64(pointer_value, offset, left, S, info);
3866 if (r == nullptr || left < sizeof(struct class64_t))
3867 return nullptr;
3868 struct class64_t c;
3869 memcpy(&c, r, sizeof(struct class64_t));
3870 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3871 swapStruct(c);
3872 if (c.data == 0)
3873 return nullptr;
3874 r = get_pointer_64(c.data, offset, left, S, info);
3875 if (r == nullptr || left < sizeof(struct class_ro64_t))
3876 return nullptr;
3877 struct class_ro64_t cro;
3878 memcpy(&cro, r, sizeof(struct class_ro64_t));
3879 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3880 swapStruct(cro);
3881 if (cro.name == 0)
3882 return nullptr;
3883 const char *name = get_pointer_64(cro.name, offset, left, S, info);
3884 return name;
3885}
3886
3887// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
3888// pointer to a cfstring and returns its name or nullptr.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00003889static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
3890 struct DisassembleInfo *info) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003891 const char *r, *name;
3892 uint32_t offset, left;
3893 SectionRef S;
3894 struct cfstring64_t cfs;
3895 uint64_t cfs_characters;
3896
3897 r = get_pointer_64(ReferenceValue, offset, left, S, info);
3898 if (r == nullptr || left < sizeof(struct cfstring64_t))
3899 return nullptr;
3900 memcpy(&cfs, r, sizeof(struct cfstring64_t));
3901 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
3902 swapStruct(cfs);
3903 if (cfs.characters == 0) {
3904 uint64_t n_value;
3905 const char *symbol_name = get_symbol_64(
3906 offset + offsetof(struct cfstring64_t, characters), S, info, n_value);
3907 if (symbol_name == nullptr)
3908 return nullptr;
3909 cfs_characters = n_value;
3910 } else
3911 cfs_characters = cfs.characters;
3912 name = get_pointer_64(cfs_characters, offset, left, S, info);
3913
3914 return name;
3915}
3916
3917// get_objc2_64bit_selref() is used for disassembly and is passed a the address
3918// of a pointer to an Objective-C selector reference when the pointer value is
3919// zero as in a .o file and is likely to have a external relocation entry with
3920// who's symbol's n_value is the real pointer to the selector name. If that is
3921// the case the real pointer to the selector name is returned else 0 is
3922// returned
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00003923static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
3924 struct DisassembleInfo *info) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00003925 uint32_t offset, left;
3926 SectionRef S;
3927
3928 const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
3929 if (r == nullptr || left < sizeof(uint64_t))
3930 return 0;
3931 uint64_t n_value;
3932 const char *symbol_name = get_symbol_64(offset, S, info, n_value);
3933 if (symbol_name == nullptr)
3934 return 0;
3935 return n_value;
3936}
3937
Kevin Enderby0fc11822015-04-01 20:57:01 +00003938static const SectionRef get_section(MachOObjectFile *O, const char *segname,
3939 const char *sectname) {
3940 for (const SectionRef &Section : O->sections()) {
3941 StringRef SectName;
3942 Section.getName(SectName);
3943 DataRefImpl Ref = Section.getRawDataRefImpl();
3944 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3945 if (SegName == segname && SectName == sectname)
3946 return Section;
3947 }
3948 return SectionRef();
3949}
3950
3951static void
3952walk_pointer_list_64(const char *listname, const SectionRef S,
3953 MachOObjectFile *O, struct DisassembleInfo *info,
3954 void (*func)(uint64_t, struct DisassembleInfo *info)) {
3955 if (S == SectionRef())
3956 return;
3957
3958 StringRef SectName;
3959 S.getName(SectName);
3960 DataRefImpl Ref = S.getRawDataRefImpl();
3961 StringRef SegName = O->getSectionFinalSegmentName(Ref);
3962 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
3963
3964 StringRef BytesStr;
3965 S.getContents(BytesStr);
3966 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
3967
3968 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
3969 uint32_t left = S.getSize() - i;
3970 uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
3971 uint64_t p = 0;
3972 memcpy(&p, Contents + i, size);
3973 if (i + sizeof(uint64_t) > S.getSize())
3974 outs() << listname << " list pointer extends past end of (" << SegName
3975 << "," << SectName << ") section\n";
3976 outs() << format("%016" PRIx64, S.getAddress() + i) << " ";
3977
3978 if (O->isLittleEndian() != sys::IsLittleEndianHost)
3979 sys::swapByteOrder(p);
3980
3981 uint64_t n_value = 0;
3982 const char *name = get_symbol_64(i, S, info, n_value, p);
3983 if (name == nullptr)
3984 name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
3985
3986 if (n_value != 0) {
3987 outs() << format("0x%" PRIx64, n_value);
3988 if (p != 0)
3989 outs() << " + " << format("0x%" PRIx64, p);
3990 } else
3991 outs() << format("0x%" PRIx64, p);
3992 if (name != nullptr)
3993 outs() << " " << name;
3994 outs() << "\n";
3995
3996 p += n_value;
3997 if (func)
3998 func(p, info);
3999 }
4000}
4001
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004002static void
4003walk_pointer_list_32(const char *listname, const SectionRef S,
4004 MachOObjectFile *O, struct DisassembleInfo *info,
4005 void (*func)(uint32_t, struct DisassembleInfo *info)) {
4006 if (S == SectionRef())
4007 return;
4008
4009 StringRef SectName;
4010 S.getName(SectName);
4011 DataRefImpl Ref = S.getRawDataRefImpl();
4012 StringRef SegName = O->getSectionFinalSegmentName(Ref);
4013 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
4014
4015 StringRef BytesStr;
4016 S.getContents(BytesStr);
4017 const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
4018
4019 for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
4020 uint32_t left = S.getSize() - i;
4021 uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
4022 uint32_t p = 0;
4023 memcpy(&p, Contents + i, size);
4024 if (i + sizeof(uint32_t) > S.getSize())
4025 outs() << listname << " list pointer extends past end of (" << SegName
4026 << "," << SectName << ") section\n";
Kevin Enderbycf261312015-04-06 22:33:43 +00004027 uint32_t Address = S.getAddress() + i;
4028 outs() << format("%08" PRIx32, Address) << " ";
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004029
4030 if (O->isLittleEndian() != sys::IsLittleEndianHost)
4031 sys::swapByteOrder(p);
4032 outs() << format("0x%" PRIx32, p);
4033
4034 const char *name = get_symbol_32(i, S, info, p);
4035 if (name != nullptr)
4036 outs() << " " << name;
4037 outs() << "\n";
4038
4039 if (func)
4040 func(p, info);
4041 }
4042}
4043
4044static void print_layout_map(const char *layout_map, uint32_t left) {
Kevin Enderbya59824a2015-10-06 22:27:08 +00004045 if (layout_map == nullptr)
4046 return;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004047 outs() << " layout map: ";
4048 do {
4049 outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";
4050 left--;
4051 layout_map++;
4052 } while (*layout_map != '\0' && left != 0);
4053 outs() << "\n";
4054}
4055
Kevin Enderby0fc11822015-04-01 20:57:01 +00004056static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
4057 uint32_t offset, left;
4058 SectionRef S;
4059 const char *layout_map;
4060
4061 if (p == 0)
4062 return;
4063 layout_map = get_pointer_64(p, offset, left, S, info);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004064 print_layout_map(layout_map, left);
4065}
4066
4067static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
4068 uint32_t offset, left;
4069 SectionRef S;
4070 const char *layout_map;
4071
4072 if (p == 0)
4073 return;
4074 layout_map = get_pointer_32(p, offset, left, S, info);
4075 print_layout_map(layout_map, left);
Kevin Enderby0fc11822015-04-01 20:57:01 +00004076}
4077
4078static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
4079 const char *indent) {
4080 struct method_list64_t ml;
4081 struct method64_t m;
4082 const char *r;
4083 uint32_t offset, xoffset, left, i;
4084 SectionRef S, xS;
4085 const char *name, *sym_name;
4086 uint64_t n_value;
4087
4088 r = get_pointer_64(p, offset, left, S, info);
4089 if (r == nullptr)
4090 return;
4091 memset(&ml, '\0', sizeof(struct method_list64_t));
4092 if (left < sizeof(struct method_list64_t)) {
4093 memcpy(&ml, r, left);
4094 outs() << " (method_list_t entends past the end of the section)\n";
4095 } else
4096 memcpy(&ml, r, sizeof(struct method_list64_t));
4097 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4098 swapStruct(ml);
4099 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4100 outs() << indent << "\t\t count " << ml.count << "\n";
4101
4102 p += sizeof(struct method_list64_t);
4103 offset += sizeof(struct method_list64_t);
4104 for (i = 0; i < ml.count; i++) {
4105 r = get_pointer_64(p, offset, left, S, info);
4106 if (r == nullptr)
4107 return;
4108 memset(&m, '\0', sizeof(struct method64_t));
4109 if (left < sizeof(struct method64_t)) {
Kevin Enderbya59824a2015-10-06 22:27:08 +00004110 memcpy(&m, r, left);
4111 outs() << indent << " (method_t extends past the end of the section)\n";
Kevin Enderby0fc11822015-04-01 20:57:01 +00004112 } else
4113 memcpy(&m, r, sizeof(struct method64_t));
4114 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4115 swapStruct(m);
4116
4117 outs() << indent << "\t\t name ";
4118 sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,
4119 info, n_value, m.name);
4120 if (n_value != 0) {
4121 if (info->verbose && sym_name != nullptr)
4122 outs() << sym_name;
4123 else
4124 outs() << format("0x%" PRIx64, n_value);
4125 if (m.name != 0)
4126 outs() << " + " << format("0x%" PRIx64, m.name);
4127 } else
4128 outs() << format("0x%" PRIx64, m.name);
4129 name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
4130 if (name != nullptr)
4131 outs() << format(" %.*s", left, name);
4132 outs() << "\n";
4133
4134 outs() << indent << "\t\t types ";
4135 sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,
4136 info, n_value, m.types);
4137 if (n_value != 0) {
4138 if (info->verbose && sym_name != nullptr)
4139 outs() << sym_name;
4140 else
4141 outs() << format("0x%" PRIx64, n_value);
4142 if (m.types != 0)
4143 outs() << " + " << format("0x%" PRIx64, m.types);
4144 } else
4145 outs() << format("0x%" PRIx64, m.types);
4146 name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
4147 if (name != nullptr)
4148 outs() << format(" %.*s", left, name);
4149 outs() << "\n";
4150
4151 outs() << indent << "\t\t imp ";
4152 name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,
4153 n_value, m.imp);
4154 if (info->verbose && name == nullptr) {
4155 if (n_value != 0) {
4156 outs() << format("0x%" PRIx64, n_value) << " ";
4157 if (m.imp != 0)
4158 outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";
4159 } else
4160 outs() << format("0x%" PRIx64, m.imp) << " ";
4161 }
4162 if (name != nullptr)
4163 outs() << name;
4164 outs() << "\n";
4165
4166 p += sizeof(struct method64_t);
4167 offset += sizeof(struct method64_t);
4168 }
4169}
4170
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004171static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
4172 const char *indent) {
4173 struct method_list32_t ml;
4174 struct method32_t m;
Kevin Enderby846c0002015-04-16 17:19:59 +00004175 const char *r, *name;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004176 uint32_t offset, xoffset, left, i;
4177 SectionRef S, xS;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004178
4179 r = get_pointer_32(p, offset, left, S, info);
4180 if (r == nullptr)
4181 return;
4182 memset(&ml, '\0', sizeof(struct method_list32_t));
4183 if (left < sizeof(struct method_list32_t)) {
4184 memcpy(&ml, r, left);
4185 outs() << " (method_list_t entends past the end of the section)\n";
4186 } else
4187 memcpy(&ml, r, sizeof(struct method_list32_t));
4188 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4189 swapStruct(ml);
4190 outs() << indent << "\t\t entsize " << ml.entsize << "\n";
4191 outs() << indent << "\t\t count " << ml.count << "\n";
4192
4193 p += sizeof(struct method_list32_t);
4194 offset += sizeof(struct method_list32_t);
4195 for (i = 0; i < ml.count; i++) {
4196 r = get_pointer_32(p, offset, left, S, info);
4197 if (r == nullptr)
4198 return;
4199 memset(&m, '\0', sizeof(struct method32_t));
4200 if (left < sizeof(struct method32_t)) {
4201 memcpy(&ml, r, left);
4202 outs() << indent << " (method_t entends past the end of the section)\n";
4203 } else
4204 memcpy(&m, r, sizeof(struct method32_t));
4205 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4206 swapStruct(m);
4207
4208 outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4209 name = get_pointer_32(m.name, xoffset, left, xS, info);
4210 if (name != nullptr)
4211 outs() << format(" %.*s", left, name);
4212 outs() << "\n";
4213
4214 outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4215 name = get_pointer_32(m.types, xoffset, left, xS, info);
4216 if (name != nullptr)
4217 outs() << format(" %.*s", left, name);
4218 outs() << "\n";
4219
4220 outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4221 name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,
4222 m.imp);
4223 if (name != nullptr)
4224 outs() << " " << name;
4225 outs() << "\n";
4226
4227 p += sizeof(struct method32_t);
4228 offset += sizeof(struct method32_t);
4229 }
4230}
4231
Kevin Enderby846c0002015-04-16 17:19:59 +00004232static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
4233 uint32_t offset, left, xleft;
4234 SectionRef S;
4235 struct objc_method_list_t method_list;
4236 struct objc_method_t method;
4237 const char *r, *methods, *name, *SymbolName;
4238 int32_t i;
4239
4240 r = get_pointer_32(p, offset, left, S, info, true);
4241 if (r == nullptr)
4242 return true;
4243
4244 outs() << "\n";
4245 if (left > sizeof(struct objc_method_list_t)) {
4246 memcpy(&method_list, r, sizeof(struct objc_method_list_t));
4247 } else {
4248 outs() << "\t\t objc_method_list extends past end of the section\n";
4249 memset(&method_list, '\0', sizeof(struct objc_method_list_t));
4250 memcpy(&method_list, r, left);
4251 }
4252 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4253 swapStruct(method_list);
4254
4255 outs() << "\t\t obsolete "
4256 << format("0x%08" PRIx32, method_list.obsolete) << "\n";
4257 outs() << "\t\t method_count " << method_list.method_count << "\n";
4258
4259 methods = r + sizeof(struct objc_method_list_t);
4260 for (i = 0; i < method_list.method_count; i++) {
4261 if ((i + 1) * sizeof(struct objc_method_t) > left) {
4262 outs() << "\t\t remaining method's extend past the of the section\n";
4263 break;
4264 }
4265 memcpy(&method, methods + i * sizeof(struct objc_method_t),
4266 sizeof(struct objc_method_t));
4267 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4268 swapStruct(method);
4269
4270 outs() << "\t\t method_name "
4271 << format("0x%08" PRIx32, method.method_name);
4272 if (info->verbose) {
4273 name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
4274 if (name != nullptr)
4275 outs() << format(" %.*s", xleft, name);
4276 else
4277 outs() << " (not in an __OBJC section)";
4278 }
4279 outs() << "\n";
4280
4281 outs() << "\t\t method_types "
4282 << format("0x%08" PRIx32, method.method_types);
4283 if (info->verbose) {
4284 name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
4285 if (name != nullptr)
4286 outs() << format(" %.*s", xleft, name);
4287 else
4288 outs() << " (not in an __OBJC section)";
4289 }
4290 outs() << "\n";
4291
4292 outs() << "\t\t method_imp "
4293 << format("0x%08" PRIx32, method.method_imp) << " ";
4294 if (info->verbose) {
4295 SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
4296 if (SymbolName != nullptr)
4297 outs() << SymbolName;
4298 }
4299 outs() << "\n";
4300 }
4301 return false;
4302}
4303
Kevin Enderby0fc11822015-04-01 20:57:01 +00004304static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
4305 struct protocol_list64_t pl;
4306 uint64_t q, n_value;
4307 struct protocol64_t pc;
4308 const char *r;
4309 uint32_t offset, xoffset, left, i;
4310 SectionRef S, xS;
4311 const char *name, *sym_name;
4312
4313 r = get_pointer_64(p, offset, left, S, info);
4314 if (r == nullptr)
4315 return;
4316 memset(&pl, '\0', sizeof(struct protocol_list64_t));
4317 if (left < sizeof(struct protocol_list64_t)) {
4318 memcpy(&pl, r, left);
4319 outs() << " (protocol_list_t entends past the end of the section)\n";
4320 } else
4321 memcpy(&pl, r, sizeof(struct protocol_list64_t));
4322 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4323 swapStruct(pl);
4324 outs() << " count " << pl.count << "\n";
4325
4326 p += sizeof(struct protocol_list64_t);
4327 offset += sizeof(struct protocol_list64_t);
4328 for (i = 0; i < pl.count; i++) {
4329 r = get_pointer_64(p, offset, left, S, info);
4330 if (r == nullptr)
4331 return;
4332 q = 0;
4333 if (left < sizeof(uint64_t)) {
4334 memcpy(&q, r, left);
4335 outs() << " (protocol_t * entends past the end of the section)\n";
4336 } else
4337 memcpy(&q, r, sizeof(uint64_t));
4338 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4339 sys::swapByteOrder(q);
4340
4341 outs() << "\t\t list[" << i << "] ";
4342 sym_name = get_symbol_64(offset, S, info, n_value, q);
4343 if (n_value != 0) {
4344 if (info->verbose && sym_name != nullptr)
4345 outs() << sym_name;
4346 else
4347 outs() << format("0x%" PRIx64, n_value);
4348 if (q != 0)
4349 outs() << " + " << format("0x%" PRIx64, q);
4350 } else
4351 outs() << format("0x%" PRIx64, q);
4352 outs() << " (struct protocol_t *)\n";
4353
4354 r = get_pointer_64(q + n_value, offset, left, S, info);
4355 if (r == nullptr)
4356 return;
4357 memset(&pc, '\0', sizeof(struct protocol64_t));
4358 if (left < sizeof(struct protocol64_t)) {
4359 memcpy(&pc, r, left);
4360 outs() << " (protocol_t entends past the end of the section)\n";
4361 } else
4362 memcpy(&pc, r, sizeof(struct protocol64_t));
4363 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4364 swapStruct(pc);
4365
4366 outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";
4367
4368 outs() << "\t\t\t name ";
4369 sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,
4370 info, n_value, pc.name);
4371 if (n_value != 0) {
4372 if (info->verbose && sym_name != nullptr)
4373 outs() << sym_name;
4374 else
4375 outs() << format("0x%" PRIx64, n_value);
4376 if (pc.name != 0)
4377 outs() << " + " << format("0x%" PRIx64, pc.name);
4378 } else
4379 outs() << format("0x%" PRIx64, pc.name);
4380 name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
4381 if (name != nullptr)
4382 outs() << format(" %.*s", left, name);
4383 outs() << "\n";
4384
4385 outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";
4386
4387 outs() << "\t\t instanceMethods ";
4388 sym_name =
4389 get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),
4390 S, info, n_value, pc.instanceMethods);
4391 if (n_value != 0) {
4392 if (info->verbose && sym_name != nullptr)
4393 outs() << sym_name;
4394 else
4395 outs() << format("0x%" PRIx64, n_value);
4396 if (pc.instanceMethods != 0)
4397 outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);
4398 } else
4399 outs() << format("0x%" PRIx64, pc.instanceMethods);
4400 outs() << " (struct method_list_t *)\n";
4401 if (pc.instanceMethods + n_value != 0)
4402 print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
4403
4404 outs() << "\t\t classMethods ";
4405 sym_name =
4406 get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,
4407 info, n_value, pc.classMethods);
4408 if (n_value != 0) {
4409 if (info->verbose && sym_name != nullptr)
4410 outs() << sym_name;
4411 else
4412 outs() << format("0x%" PRIx64, n_value);
4413 if (pc.classMethods != 0)
4414 outs() << " + " << format("0x%" PRIx64, pc.classMethods);
4415 } else
4416 outs() << format("0x%" PRIx64, pc.classMethods);
4417 outs() << " (struct method_list_t *)\n";
4418 if (pc.classMethods + n_value != 0)
4419 print_method_list64_t(pc.classMethods + n_value, info, "\t");
4420
4421 outs() << "\t optionalInstanceMethods "
4422 << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";
4423 outs() << "\t optionalClassMethods "
4424 << format("0x%" PRIx64, pc.optionalClassMethods) << "\n";
4425 outs() << "\t instanceProperties "
4426 << format("0x%" PRIx64, pc.instanceProperties) << "\n";
4427
4428 p += sizeof(uint64_t);
4429 offset += sizeof(uint64_t);
4430 }
4431}
4432
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004433static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
4434 struct protocol_list32_t pl;
4435 uint32_t q;
4436 struct protocol32_t pc;
4437 const char *r;
4438 uint32_t offset, xoffset, left, i;
4439 SectionRef S, xS;
4440 const char *name;
4441
4442 r = get_pointer_32(p, offset, left, S, info);
4443 if (r == nullptr)
4444 return;
4445 memset(&pl, '\0', sizeof(struct protocol_list32_t));
4446 if (left < sizeof(struct protocol_list32_t)) {
4447 memcpy(&pl, r, left);
4448 outs() << " (protocol_list_t entends past the end of the section)\n";
4449 } else
4450 memcpy(&pl, r, sizeof(struct protocol_list32_t));
4451 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4452 swapStruct(pl);
4453 outs() << " count " << pl.count << "\n";
4454
4455 p += sizeof(struct protocol_list32_t);
4456 offset += sizeof(struct protocol_list32_t);
4457 for (i = 0; i < pl.count; i++) {
4458 r = get_pointer_32(p, offset, left, S, info);
4459 if (r == nullptr)
4460 return;
4461 q = 0;
4462 if (left < sizeof(uint32_t)) {
4463 memcpy(&q, r, left);
4464 outs() << " (protocol_t * entends past the end of the section)\n";
4465 } else
4466 memcpy(&q, r, sizeof(uint32_t));
4467 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4468 sys::swapByteOrder(q);
4469 outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)
4470 << " (struct protocol_t *)\n";
4471 r = get_pointer_32(q, offset, left, S, info);
4472 if (r == nullptr)
4473 return;
4474 memset(&pc, '\0', sizeof(struct protocol32_t));
4475 if (left < sizeof(struct protocol32_t)) {
4476 memcpy(&pc, r, left);
4477 outs() << " (protocol_t entends past the end of the section)\n";
4478 } else
4479 memcpy(&pc, r, sizeof(struct protocol32_t));
4480 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4481 swapStruct(pc);
4482 outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";
4483 outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);
4484 name = get_pointer_32(pc.name, xoffset, left, xS, info);
4485 if (name != nullptr)
4486 outs() << format(" %.*s", left, name);
4487 outs() << "\n";
4488 outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";
4489 outs() << "\t\t instanceMethods "
4490 << format("0x%" PRIx32, pc.instanceMethods)
4491 << " (struct method_list_t *)\n";
4492 if (pc.instanceMethods != 0)
4493 print_method_list32_t(pc.instanceMethods, info, "\t");
4494 outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)
4495 << " (struct method_list_t *)\n";
4496 if (pc.classMethods != 0)
4497 print_method_list32_t(pc.classMethods, info, "\t");
4498 outs() << "\t optionalInstanceMethods "
4499 << format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";
4500 outs() << "\t optionalClassMethods "
4501 << format("0x%" PRIx32, pc.optionalClassMethods) << "\n";
4502 outs() << "\t instanceProperties "
4503 << format("0x%" PRIx32, pc.instanceProperties) << "\n";
4504 p += sizeof(uint32_t);
4505 offset += sizeof(uint32_t);
4506 }
4507}
4508
Kevin Enderby846c0002015-04-16 17:19:59 +00004509static void print_indent(uint32_t indent) {
4510 for (uint32_t i = 0; i < indent;) {
4511 if (indent - i >= 8) {
4512 outs() << "\t";
4513 i += 8;
4514 } else {
4515 for (uint32_t j = i; j < indent; j++)
4516 outs() << " ";
4517 return;
4518 }
4519 }
4520}
4521
4522static bool print_method_description_list(uint32_t p, uint32_t indent,
4523 struct DisassembleInfo *info) {
4524 uint32_t offset, left, xleft;
4525 SectionRef S;
4526 struct objc_method_description_list_t mdl;
4527 struct objc_method_description_t md;
4528 const char *r, *list, *name;
4529 int32_t i;
4530
4531 r = get_pointer_32(p, offset, left, S, info, true);
4532 if (r == nullptr)
4533 return true;
4534
4535 outs() << "\n";
4536 if (left > sizeof(struct objc_method_description_list_t)) {
4537 memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
4538 } else {
4539 print_indent(indent);
4540 outs() << " objc_method_description_list extends past end of the section\n";
4541 memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
4542 memcpy(&mdl, r, left);
4543 }
4544 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4545 swapStruct(mdl);
4546
4547 print_indent(indent);
4548 outs() << " count " << mdl.count << "\n";
4549
4550 list = r + sizeof(struct objc_method_description_list_t);
4551 for (i = 0; i < mdl.count; i++) {
4552 if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
4553 print_indent(indent);
4554 outs() << " remaining list entries extend past the of the section\n";
4555 break;
4556 }
4557 print_indent(indent);
4558 outs() << " list[" << i << "]\n";
4559 memcpy(&md, list + i * sizeof(struct objc_method_description_t),
4560 sizeof(struct objc_method_description_t));
4561 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4562 swapStruct(md);
4563
4564 print_indent(indent);
4565 outs() << " name " << format("0x%08" PRIx32, md.name);
4566 if (info->verbose) {
4567 name = get_pointer_32(md.name, offset, xleft, S, info, true);
4568 if (name != nullptr)
4569 outs() << format(" %.*s", xleft, name);
4570 else
4571 outs() << " (not in an __OBJC section)";
4572 }
4573 outs() << "\n";
4574
4575 print_indent(indent);
4576 outs() << " types " << format("0x%08" PRIx32, md.types);
4577 if (info->verbose) {
4578 name = get_pointer_32(md.types, offset, xleft, S, info, true);
4579 if (name != nullptr)
4580 outs() << format(" %.*s", xleft, name);
4581 else
4582 outs() << " (not in an __OBJC section)";
4583 }
4584 outs() << "\n";
4585 }
4586 return false;
4587}
4588
4589static bool print_protocol_list(uint32_t p, uint32_t indent,
4590 struct DisassembleInfo *info);
4591
4592static bool print_protocol(uint32_t p, uint32_t indent,
4593 struct DisassembleInfo *info) {
4594 uint32_t offset, left;
4595 SectionRef S;
4596 struct objc_protocol_t protocol;
4597 const char *r, *name;
4598
4599 r = get_pointer_32(p, offset, left, S, info, true);
4600 if (r == nullptr)
4601 return true;
4602
4603 outs() << "\n";
4604 if (left >= sizeof(struct objc_protocol_t)) {
4605 memcpy(&protocol, r, sizeof(struct objc_protocol_t));
4606 } else {
4607 print_indent(indent);
4608 outs() << " Protocol extends past end of the section\n";
4609 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
4610 memcpy(&protocol, r, left);
4611 }
4612 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4613 swapStruct(protocol);
4614
4615 print_indent(indent);
4616 outs() << " isa " << format("0x%08" PRIx32, protocol.isa)
4617 << "\n";
4618
4619 print_indent(indent);
4620 outs() << " protocol_name "
4621 << format("0x%08" PRIx32, protocol.protocol_name);
4622 if (info->verbose) {
4623 name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
4624 if (name != nullptr)
4625 outs() << format(" %.*s", left, name);
4626 else
4627 outs() << " (not in an __OBJC section)";
4628 }
4629 outs() << "\n";
4630
4631 print_indent(indent);
4632 outs() << " protocol_list "
4633 << format("0x%08" PRIx32, protocol.protocol_list);
4634 if (print_protocol_list(protocol.protocol_list, indent + 4, info))
4635 outs() << " (not in an __OBJC section)\n";
4636
4637 print_indent(indent);
4638 outs() << " instance_methods "
4639 << format("0x%08" PRIx32, protocol.instance_methods);
4640 if (print_method_description_list(protocol.instance_methods, indent, info))
4641 outs() << " (not in an __OBJC section)\n";
4642
4643 print_indent(indent);
4644 outs() << " class_methods "
4645 << format("0x%08" PRIx32, protocol.class_methods);
4646 if (print_method_description_list(protocol.class_methods, indent, info))
4647 outs() << " (not in an __OBJC section)\n";
4648
4649 return false;
4650}
4651
4652static bool print_protocol_list(uint32_t p, uint32_t indent,
4653 struct DisassembleInfo *info) {
4654 uint32_t offset, left, l;
4655 SectionRef S;
4656 struct objc_protocol_list_t protocol_list;
4657 const char *r, *list;
4658 int32_t i;
4659
4660 r = get_pointer_32(p, offset, left, S, info, true);
4661 if (r == nullptr)
4662 return true;
4663
4664 outs() << "\n";
4665 if (left > sizeof(struct objc_protocol_list_t)) {
4666 memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
4667 } else {
4668 outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
4669 memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
4670 memcpy(&protocol_list, r, left);
4671 }
4672 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4673 swapStruct(protocol_list);
4674
4675 print_indent(indent);
4676 outs() << " next " << format("0x%08" PRIx32, protocol_list.next)
4677 << "\n";
4678 print_indent(indent);
4679 outs() << " count " << protocol_list.count << "\n";
4680
4681 list = r + sizeof(struct objc_protocol_list_t);
4682 for (i = 0; i < protocol_list.count; i++) {
4683 if ((i + 1) * sizeof(uint32_t) > left) {
4684 outs() << "\t\t remaining list entries extend past the of the section\n";
4685 break;
4686 }
4687 memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
4688 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4689 sys::swapByteOrder(l);
4690
4691 print_indent(indent);
4692 outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);
4693 if (print_protocol(l, indent, info))
4694 outs() << "(not in an __OBJC section)\n";
4695 }
4696 return false;
4697}
4698
Kevin Enderby0fc11822015-04-01 20:57:01 +00004699static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
4700 struct ivar_list64_t il;
4701 struct ivar64_t i;
4702 const char *r;
4703 uint32_t offset, xoffset, left, j;
4704 SectionRef S, xS;
4705 const char *name, *sym_name, *ivar_offset_p;
4706 uint64_t ivar_offset, n_value;
4707
4708 r = get_pointer_64(p, offset, left, S, info);
4709 if (r == nullptr)
4710 return;
4711 memset(&il, '\0', sizeof(struct ivar_list64_t));
4712 if (left < sizeof(struct ivar_list64_t)) {
4713 memcpy(&il, r, left);
4714 outs() << " (ivar_list_t entends past the end of the section)\n";
4715 } else
4716 memcpy(&il, r, sizeof(struct ivar_list64_t));
4717 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4718 swapStruct(il);
4719 outs() << " entsize " << il.entsize << "\n";
4720 outs() << " count " << il.count << "\n";
4721
4722 p += sizeof(struct ivar_list64_t);
4723 offset += sizeof(struct ivar_list64_t);
4724 for (j = 0; j < il.count; j++) {
4725 r = get_pointer_64(p, offset, left, S, info);
4726 if (r == nullptr)
4727 return;
4728 memset(&i, '\0', sizeof(struct ivar64_t));
4729 if (left < sizeof(struct ivar64_t)) {
4730 memcpy(&i, r, left);
4731 outs() << " (ivar_t entends past the end of the section)\n";
4732 } else
4733 memcpy(&i, r, sizeof(struct ivar64_t));
4734 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4735 swapStruct(i);
4736
4737 outs() << "\t\t\t offset ";
4738 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,
4739 info, n_value, i.offset);
4740 if (n_value != 0) {
4741 if (info->verbose && sym_name != nullptr)
4742 outs() << sym_name;
4743 else
4744 outs() << format("0x%" PRIx64, n_value);
4745 if (i.offset != 0)
4746 outs() << " + " << format("0x%" PRIx64, i.offset);
4747 } else
4748 outs() << format("0x%" PRIx64, i.offset);
4749 ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
4750 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4751 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4752 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4753 sys::swapByteOrder(ivar_offset);
4754 outs() << " " << ivar_offset << "\n";
4755 } else
4756 outs() << "\n";
4757
4758 outs() << "\t\t\t name ";
4759 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,
4760 n_value, i.name);
4761 if (n_value != 0) {
4762 if (info->verbose && sym_name != nullptr)
4763 outs() << sym_name;
4764 else
4765 outs() << format("0x%" PRIx64, n_value);
4766 if (i.name != 0)
4767 outs() << " + " << format("0x%" PRIx64, i.name);
4768 } else
4769 outs() << format("0x%" PRIx64, i.name);
4770 name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
4771 if (name != nullptr)
4772 outs() << format(" %.*s", left, name);
4773 outs() << "\n";
4774
4775 outs() << "\t\t\t type ";
4776 sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,
4777 n_value, i.name);
4778 name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
4779 if (n_value != 0) {
4780 if (info->verbose && sym_name != nullptr)
4781 outs() << sym_name;
4782 else
4783 outs() << format("0x%" PRIx64, n_value);
4784 if (i.type != 0)
4785 outs() << " + " << format("0x%" PRIx64, i.type);
4786 } else
4787 outs() << format("0x%" PRIx64, i.type);
4788 if (name != nullptr)
4789 outs() << format(" %.*s", left, name);
4790 outs() << "\n";
4791
4792 outs() << "\t\t\talignment " << i.alignment << "\n";
4793 outs() << "\t\t\t size " << i.size << "\n";
4794
4795 p += sizeof(struct ivar64_t);
4796 offset += sizeof(struct ivar64_t);
4797 }
4798}
4799
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004800static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
4801 struct ivar_list32_t il;
4802 struct ivar32_t i;
4803 const char *r;
4804 uint32_t offset, xoffset, left, j;
4805 SectionRef S, xS;
4806 const char *name, *ivar_offset_p;
4807 uint32_t ivar_offset;
4808
4809 r = get_pointer_32(p, offset, left, S, info);
4810 if (r == nullptr)
4811 return;
4812 memset(&il, '\0', sizeof(struct ivar_list32_t));
4813 if (left < sizeof(struct ivar_list32_t)) {
4814 memcpy(&il, r, left);
4815 outs() << " (ivar_list_t entends past the end of the section)\n";
4816 } else
4817 memcpy(&il, r, sizeof(struct ivar_list32_t));
4818 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4819 swapStruct(il);
4820 outs() << " entsize " << il.entsize << "\n";
4821 outs() << " count " << il.count << "\n";
4822
4823 p += sizeof(struct ivar_list32_t);
4824 offset += sizeof(struct ivar_list32_t);
4825 for (j = 0; j < il.count; j++) {
4826 r = get_pointer_32(p, offset, left, S, info);
4827 if (r == nullptr)
4828 return;
4829 memset(&i, '\0', sizeof(struct ivar32_t));
4830 if (left < sizeof(struct ivar32_t)) {
4831 memcpy(&i, r, left);
4832 outs() << " (ivar_t entends past the end of the section)\n";
4833 } else
4834 memcpy(&i, r, sizeof(struct ivar32_t));
4835 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4836 swapStruct(i);
4837
4838 outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);
4839 ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
4840 if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
4841 memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
4842 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4843 sys::swapByteOrder(ivar_offset);
4844 outs() << " " << ivar_offset << "\n";
4845 } else
4846 outs() << "\n";
4847
4848 outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);
4849 name = get_pointer_32(i.name, xoffset, left, xS, info);
4850 if (name != nullptr)
4851 outs() << format(" %.*s", left, name);
4852 outs() << "\n";
4853
4854 outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);
4855 name = get_pointer_32(i.type, xoffset, left, xS, info);
4856 if (name != nullptr)
4857 outs() << format(" %.*s", left, name);
4858 outs() << "\n";
4859
4860 outs() << "\t\t\talignment " << i.alignment << "\n";
4861 outs() << "\t\t\t size " << i.size << "\n";
4862
4863 p += sizeof(struct ivar32_t);
4864 offset += sizeof(struct ivar32_t);
4865 }
4866}
4867
Kevin Enderby0fc11822015-04-01 20:57:01 +00004868static void print_objc_property_list64(uint64_t p,
4869 struct DisassembleInfo *info) {
4870 struct objc_property_list64 opl;
4871 struct objc_property64 op;
4872 const char *r;
4873 uint32_t offset, xoffset, left, j;
4874 SectionRef S, xS;
4875 const char *name, *sym_name;
4876 uint64_t n_value;
4877
4878 r = get_pointer_64(p, offset, left, S, info);
4879 if (r == nullptr)
4880 return;
4881 memset(&opl, '\0', sizeof(struct objc_property_list64));
4882 if (left < sizeof(struct objc_property_list64)) {
4883 memcpy(&opl, r, left);
4884 outs() << " (objc_property_list entends past the end of the section)\n";
4885 } else
4886 memcpy(&opl, r, sizeof(struct objc_property_list64));
4887 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4888 swapStruct(opl);
4889 outs() << " entsize " << opl.entsize << "\n";
4890 outs() << " count " << opl.count << "\n";
4891
4892 p += sizeof(struct objc_property_list64);
4893 offset += sizeof(struct objc_property_list64);
4894 for (j = 0; j < opl.count; j++) {
4895 r = get_pointer_64(p, offset, left, S, info);
4896 if (r == nullptr)
4897 return;
4898 memset(&op, '\0', sizeof(struct objc_property64));
4899 if (left < sizeof(struct objc_property64)) {
4900 memcpy(&op, r, left);
4901 outs() << " (objc_property entends past the end of the section)\n";
4902 } else
4903 memcpy(&op, r, sizeof(struct objc_property64));
4904 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4905 swapStruct(op);
4906
4907 outs() << "\t\t\t name ";
4908 sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,
4909 info, n_value, op.name);
4910 if (n_value != 0) {
4911 if (info->verbose && sym_name != nullptr)
4912 outs() << sym_name;
4913 else
4914 outs() << format("0x%" PRIx64, n_value);
4915 if (op.name != 0)
4916 outs() << " + " << format("0x%" PRIx64, op.name);
4917 } else
4918 outs() << format("0x%" PRIx64, op.name);
4919 name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
4920 if (name != nullptr)
4921 outs() << format(" %.*s", left, name);
4922 outs() << "\n";
4923
4924 outs() << "\t\t\tattributes ";
4925 sym_name =
4926 get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,
4927 info, n_value, op.attributes);
4928 if (n_value != 0) {
4929 if (info->verbose && sym_name != nullptr)
4930 outs() << sym_name;
4931 else
4932 outs() << format("0x%" PRIx64, n_value);
4933 if (op.attributes != 0)
4934 outs() << " + " << format("0x%" PRIx64, op.attributes);
4935 } else
4936 outs() << format("0x%" PRIx64, op.attributes);
4937 name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
4938 if (name != nullptr)
4939 outs() << format(" %.*s", left, name);
4940 outs() << "\n";
4941
4942 p += sizeof(struct objc_property64);
4943 offset += sizeof(struct objc_property64);
4944 }
4945}
4946
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00004947static void print_objc_property_list32(uint32_t p,
4948 struct DisassembleInfo *info) {
4949 struct objc_property_list32 opl;
4950 struct objc_property32 op;
4951 const char *r;
4952 uint32_t offset, xoffset, left, j;
4953 SectionRef S, xS;
4954 const char *name;
4955
4956 r = get_pointer_32(p, offset, left, S, info);
4957 if (r == nullptr)
4958 return;
4959 memset(&opl, '\0', sizeof(struct objc_property_list32));
4960 if (left < sizeof(struct objc_property_list32)) {
4961 memcpy(&opl, r, left);
4962 outs() << " (objc_property_list entends past the end of the section)\n";
4963 } else
4964 memcpy(&opl, r, sizeof(struct objc_property_list32));
4965 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4966 swapStruct(opl);
4967 outs() << " entsize " << opl.entsize << "\n";
4968 outs() << " count " << opl.count << "\n";
4969
4970 p += sizeof(struct objc_property_list32);
4971 offset += sizeof(struct objc_property_list32);
4972 for (j = 0; j < opl.count; j++) {
4973 r = get_pointer_32(p, offset, left, S, info);
4974 if (r == nullptr)
4975 return;
4976 memset(&op, '\0', sizeof(struct objc_property32));
4977 if (left < sizeof(struct objc_property32)) {
4978 memcpy(&op, r, left);
4979 outs() << " (objc_property entends past the end of the section)\n";
4980 } else
4981 memcpy(&op, r, sizeof(struct objc_property32));
4982 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4983 swapStruct(op);
4984
4985 outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);
4986 name = get_pointer_32(op.name, xoffset, left, xS, info);
4987 if (name != nullptr)
4988 outs() << format(" %.*s", left, name);
4989 outs() << "\n";
4990
4991 outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);
4992 name = get_pointer_32(op.attributes, xoffset, left, xS, info);
4993 if (name != nullptr)
4994 outs() << format(" %.*s", left, name);
4995 outs() << "\n";
4996
4997 p += sizeof(struct objc_property32);
4998 offset += sizeof(struct objc_property32);
4999 }
5000}
5001
Richard Smith81ff44d2015-10-09 22:09:56 +00005002static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
Kevin Enderby0fc11822015-04-01 20:57:01 +00005003 bool &is_meta_class) {
5004 struct class_ro64_t cro;
5005 const char *r;
5006 uint32_t offset, xoffset, left;
5007 SectionRef S, xS;
5008 const char *name, *sym_name;
5009 uint64_t n_value;
5010
5011 r = get_pointer_64(p, offset, left, S, info);
5012 if (r == nullptr || left < sizeof(struct class_ro64_t))
Richard Smith81ff44d2015-10-09 22:09:56 +00005013 return false;
Chandler Carruth33e58902016-11-04 07:10:24 +00005014 memcpy(&cro, r, sizeof(struct class_ro64_t));
Kevin Enderby0fc11822015-04-01 20:57:01 +00005015 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5016 swapStruct(cro);
5017 outs() << " flags " << format("0x%" PRIx32, cro.flags);
5018 if (cro.flags & RO_META)
5019 outs() << " RO_META";
5020 if (cro.flags & RO_ROOT)
5021 outs() << " RO_ROOT";
5022 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5023 outs() << " RO_HAS_CXX_STRUCTORS";
5024 outs() << "\n";
5025 outs() << " instanceStart " << cro.instanceStart << "\n";
5026 outs() << " instanceSize " << cro.instanceSize << "\n";
5027 outs() << " reserved " << format("0x%" PRIx32, cro.reserved)
5028 << "\n";
5029 outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)
5030 << "\n";
5031 print_layout_map64(cro.ivarLayout, info);
5032
5033 outs() << " name ";
5034 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,
5035 info, n_value, cro.name);
5036 if (n_value != 0) {
5037 if (info->verbose && sym_name != nullptr)
5038 outs() << sym_name;
5039 else
5040 outs() << format("0x%" PRIx64, n_value);
5041 if (cro.name != 0)
5042 outs() << " + " << format("0x%" PRIx64, cro.name);
5043 } else
5044 outs() << format("0x%" PRIx64, cro.name);
5045 name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
5046 if (name != nullptr)
5047 outs() << format(" %.*s", left, name);
5048 outs() << "\n";
5049
5050 outs() << " baseMethods ";
5051 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),
5052 S, info, n_value, cro.baseMethods);
5053 if (n_value != 0) {
5054 if (info->verbose && sym_name != nullptr)
5055 outs() << sym_name;
5056 else
5057 outs() << format("0x%" PRIx64, n_value);
5058 if (cro.baseMethods != 0)
5059 outs() << " + " << format("0x%" PRIx64, cro.baseMethods);
5060 } else
5061 outs() << format("0x%" PRIx64, cro.baseMethods);
5062 outs() << " (struct method_list_t *)\n";
5063 if (cro.baseMethods + n_value != 0)
5064 print_method_list64_t(cro.baseMethods + n_value, info, "");
5065
5066 outs() << " baseProtocols ";
5067 sym_name =
5068 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,
5069 info, n_value, cro.baseProtocols);
5070 if (n_value != 0) {
5071 if (info->verbose && sym_name != nullptr)
5072 outs() << sym_name;
5073 else
5074 outs() << format("0x%" PRIx64, n_value);
5075 if (cro.baseProtocols != 0)
5076 outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);
5077 } else
5078 outs() << format("0x%" PRIx64, cro.baseProtocols);
5079 outs() << "\n";
5080 if (cro.baseProtocols + n_value != 0)
5081 print_protocol_list64_t(cro.baseProtocols + n_value, info);
5082
5083 outs() << " ivars ";
5084 sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005085 info, n_value, cro.ivars);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005086 if (n_value != 0) {
5087 if (info->verbose && sym_name != nullptr)
5088 outs() << sym_name;
5089 else
5090 outs() << format("0x%" PRIx64, n_value);
5091 if (cro.ivars != 0)
5092 outs() << " + " << format("0x%" PRIx64, cro.ivars);
5093 } else
5094 outs() << format("0x%" PRIx64, cro.ivars);
5095 outs() << "\n";
5096 if (cro.ivars + n_value != 0)
5097 print_ivar_list64_t(cro.ivars + n_value, info);
5098
5099 outs() << " weakIvarLayout ";
5100 sym_name =
5101 get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,
5102 info, n_value, cro.weakIvarLayout);
5103 if (n_value != 0) {
5104 if (info->verbose && sym_name != nullptr)
5105 outs() << sym_name;
5106 else
5107 outs() << format("0x%" PRIx64, n_value);
5108 if (cro.weakIvarLayout != 0)
5109 outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);
5110 } else
5111 outs() << format("0x%" PRIx64, cro.weakIvarLayout);
5112 outs() << "\n";
5113 print_layout_map64(cro.weakIvarLayout + n_value, info);
5114
5115 outs() << " baseProperties ";
5116 sym_name =
5117 get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,
5118 info, n_value, cro.baseProperties);
5119 if (n_value != 0) {
5120 if (info->verbose && sym_name != nullptr)
5121 outs() << sym_name;
5122 else
5123 outs() << format("0x%" PRIx64, n_value);
5124 if (cro.baseProperties != 0)
5125 outs() << " + " << format("0x%" PRIx64, cro.baseProperties);
5126 } else
5127 outs() << format("0x%" PRIx64, cro.baseProperties);
5128 outs() << "\n";
5129 if (cro.baseProperties + n_value != 0)
5130 print_objc_property_list64(cro.baseProperties + n_value, info);
5131
Rafael Espindolab9091322015-10-24 23:19:10 +00005132 is_meta_class = (cro.flags & RO_META) != 0;
Richard Smith81ff44d2015-10-09 22:09:56 +00005133 return true;
Kevin Enderby0fc11822015-04-01 20:57:01 +00005134}
5135
Richard Smith81ff44d2015-10-09 22:09:56 +00005136static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005137 bool &is_meta_class) {
5138 struct class_ro32_t cro;
5139 const char *r;
5140 uint32_t offset, xoffset, left;
5141 SectionRef S, xS;
5142 const char *name;
5143
5144 r = get_pointer_32(p, offset, left, S, info);
5145 if (r == nullptr)
Richard Smith81ff44d2015-10-09 22:09:56 +00005146 return false;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005147 memset(&cro, '\0', sizeof(struct class_ro32_t));
5148 if (left < sizeof(struct class_ro32_t)) {
5149 memcpy(&cro, r, left);
5150 outs() << " (class_ro_t entends past the end of the section)\n";
5151 } else
5152 memcpy(&cro, r, sizeof(struct class_ro32_t));
5153 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5154 swapStruct(cro);
5155 outs() << " flags " << format("0x%" PRIx32, cro.flags);
5156 if (cro.flags & RO_META)
5157 outs() << " RO_META";
5158 if (cro.flags & RO_ROOT)
5159 outs() << " RO_ROOT";
5160 if (cro.flags & RO_HAS_CXX_STRUCTORS)
5161 outs() << " RO_HAS_CXX_STRUCTORS";
5162 outs() << "\n";
5163 outs() << " instanceStart " << cro.instanceStart << "\n";
5164 outs() << " instanceSize " << cro.instanceSize << "\n";
5165 outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)
5166 << "\n";
5167 print_layout_map32(cro.ivarLayout, info);
5168
5169 outs() << " name " << format("0x%" PRIx32, cro.name);
5170 name = get_pointer_32(cro.name, xoffset, left, xS, info);
5171 if (name != nullptr)
5172 outs() << format(" %.*s", left, name);
5173 outs() << "\n";
5174
5175 outs() << " baseMethods "
5176 << format("0x%" PRIx32, cro.baseMethods)
5177 << " (struct method_list_t *)\n";
5178 if (cro.baseMethods != 0)
5179 print_method_list32_t(cro.baseMethods, info, "");
5180
5181 outs() << " baseProtocols "
5182 << format("0x%" PRIx32, cro.baseProtocols) << "\n";
5183 if (cro.baseProtocols != 0)
5184 print_protocol_list32_t(cro.baseProtocols, info);
5185 outs() << " ivars " << format("0x%" PRIx32, cro.ivars)
5186 << "\n";
5187 if (cro.ivars != 0)
5188 print_ivar_list32_t(cro.ivars, info);
5189 outs() << " weakIvarLayout "
5190 << format("0x%" PRIx32, cro.weakIvarLayout) << "\n";
5191 print_layout_map32(cro.weakIvarLayout, info);
5192 outs() << " baseProperties "
5193 << format("0x%" PRIx32, cro.baseProperties) << "\n";
5194 if (cro.baseProperties != 0)
5195 print_objc_property_list32(cro.baseProperties, info);
Rafael Espindolab9091322015-10-24 23:19:10 +00005196 is_meta_class = (cro.flags & RO_META) != 0;
Richard Smith81ff44d2015-10-09 22:09:56 +00005197 return true;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005198}
5199
Kevin Enderby0fc11822015-04-01 20:57:01 +00005200static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
5201 struct class64_t c;
5202 const char *r;
5203 uint32_t offset, left;
5204 SectionRef S;
5205 const char *name;
5206 uint64_t isa_n_value, n_value;
5207
5208 r = get_pointer_64(p, offset, left, S, info);
5209 if (r == nullptr || left < sizeof(struct class64_t))
5210 return;
Chandler Carruth33e58902016-11-04 07:10:24 +00005211 memcpy(&c, r, sizeof(struct class64_t));
Kevin Enderby0fc11822015-04-01 20:57:01 +00005212 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5213 swapStruct(c);
5214
5215 outs() << " isa " << format("0x%" PRIx64, c.isa);
5216 name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,
5217 isa_n_value, c.isa);
5218 if (name != nullptr)
5219 outs() << " " << name;
5220 outs() << "\n";
5221
5222 outs() << " superclass " << format("0x%" PRIx64, c.superclass);
5223 name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,
5224 n_value, c.superclass);
5225 if (name != nullptr)
5226 outs() << " " << name;
Kevin Enderby1ce38582017-06-20 22:55:11 +00005227 else {
5228 name = get_dyld_bind_info_symbolname(S.getAddress() +
5229 offset + offsetof(struct class64_t, superclass), info);
5230 if (name != nullptr)
5231 outs() << " " << name;
5232 }
Kevin Enderby0fc11822015-04-01 20:57:01 +00005233 outs() << "\n";
5234
5235 outs() << " cache " << format("0x%" PRIx64, c.cache);
5236 name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,
5237 n_value, c.cache);
5238 if (name != nullptr)
5239 outs() << " " << name;
5240 outs() << "\n";
5241
5242 outs() << " vtable " << format("0x%" PRIx64, c.vtable);
5243 name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,
5244 n_value, c.vtable);
5245 if (name != nullptr)
5246 outs() << " " << name;
5247 outs() << "\n";
5248
5249 name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,
5250 n_value, c.data);
5251 outs() << " data ";
5252 if (n_value != 0) {
5253 if (info->verbose && name != nullptr)
5254 outs() << name;
5255 else
5256 outs() << format("0x%" PRIx64, n_value);
5257 if (c.data != 0)
5258 outs() << " + " << format("0x%" PRIx64, c.data);
5259 } else
5260 outs() << format("0x%" PRIx64, c.data);
5261 outs() << " (struct class_ro_t *)";
5262
5263 // This is a Swift class if some of the low bits of the pointer are set.
5264 if ((c.data + n_value) & 0x7)
5265 outs() << " Swift class";
5266 outs() << "\n";
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005267 bool is_meta_class;
Richard Smith81ff44d2015-10-09 22:09:56 +00005268 if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class))
5269 return;
Kevin Enderby0fc11822015-04-01 20:57:01 +00005270
Kevin Enderbyaac75382015-10-08 16:56:35 +00005271 if (!is_meta_class &&
5272 c.isa + isa_n_value != p &&
5273 c.isa + isa_n_value != 0 &&
5274 info->depth < 100) {
5275 info->depth++;
5276 outs() << "Meta Class\n";
5277 print_class64_t(c.isa + isa_n_value, info);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005278 }
5279}
5280
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005281static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
5282 struct class32_t c;
5283 const char *r;
5284 uint32_t offset, left;
5285 SectionRef S;
5286 const char *name;
5287
5288 r = get_pointer_32(p, offset, left, S, info);
5289 if (r == nullptr)
5290 return;
5291 memset(&c, '\0', sizeof(struct class32_t));
5292 if (left < sizeof(struct class32_t)) {
5293 memcpy(&c, r, left);
5294 outs() << " (class_t entends past the end of the section)\n";
5295 } else
5296 memcpy(&c, r, sizeof(struct class32_t));
5297 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5298 swapStruct(c);
5299
5300 outs() << " isa " << format("0x%" PRIx32, c.isa);
5301 name =
5302 get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);
5303 if (name != nullptr)
5304 outs() << " " << name;
5305 outs() << "\n";
5306
5307 outs() << " superclass " << format("0x%" PRIx32, c.superclass);
5308 name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,
5309 c.superclass);
5310 if (name != nullptr)
5311 outs() << " " << name;
5312 outs() << "\n";
5313
5314 outs() << " cache " << format("0x%" PRIx32, c.cache);
5315 name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,
5316 c.cache);
5317 if (name != nullptr)
5318 outs() << " " << name;
5319 outs() << "\n";
5320
5321 outs() << " vtable " << format("0x%" PRIx32, c.vtable);
5322 name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,
5323 c.vtable);
5324 if (name != nullptr)
5325 outs() << " " << name;
5326 outs() << "\n";
5327
5328 name =
5329 get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);
5330 outs() << " data " << format("0x%" PRIx32, c.data)
5331 << " (struct class_ro_t *)";
5332
5333 // This is a Swift class if some of the low bits of the pointer are set.
5334 if (c.data & 0x3)
5335 outs() << " Swift class";
5336 outs() << "\n";
5337 bool is_meta_class;
Richard Smith81ff44d2015-10-09 22:09:56 +00005338 if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class))
5339 return;
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005340
Hans Wennborgcc9deb42015-09-29 18:02:48 +00005341 if (!is_meta_class) {
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005342 outs() << "Meta Class\n";
5343 print_class32_t(c.isa, info);
5344 }
5345}
5346
Kevin Enderby846c0002015-04-16 17:19:59 +00005347static void print_objc_class_t(struct objc_class_t *objc_class,
5348 struct DisassembleInfo *info) {
5349 uint32_t offset, left, xleft;
5350 const char *name, *p, *ivar_list;
5351 SectionRef S;
5352 int32_t i;
5353 struct objc_ivar_list_t objc_ivar_list;
5354 struct objc_ivar_t ivar;
5355
5356 outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);
5357 if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {
5358 name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
5359 if (name != nullptr)
5360 outs() << format(" %.*s", left, name);
5361 else
5362 outs() << " (not in an __OBJC section)";
5363 }
5364 outs() << "\n";
5365
5366 outs() << "\t super_class "
5367 << format("0x%08" PRIx32, objc_class->super_class);
5368 if (info->verbose) {
5369 name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
5370 if (name != nullptr)
5371 outs() << format(" %.*s", left, name);
5372 else
5373 outs() << " (not in an __OBJC section)";
5374 }
5375 outs() << "\n";
5376
5377 outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);
5378 if (info->verbose) {
5379 name = get_pointer_32(objc_class->name, offset, left, S, info, true);
5380 if (name != nullptr)
5381 outs() << format(" %.*s", left, name);
5382 else
5383 outs() << " (not in an __OBJC section)";
5384 }
5385 outs() << "\n";
5386
5387 outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)
5388 << "\n";
5389
5390 outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);
5391 if (info->verbose) {
5392 if (CLS_GETINFO(objc_class, CLS_CLASS))
5393 outs() << " CLS_CLASS";
5394 else if (CLS_GETINFO(objc_class, CLS_META))
5395 outs() << " CLS_META";
5396 }
5397 outs() << "\n";
5398
5399 outs() << "\t instance_size "
5400 << format("0x%08" PRIx32, objc_class->instance_size) << "\n";
5401
5402 p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
5403 outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);
5404 if (p != nullptr) {
5405 if (left > sizeof(struct objc_ivar_list_t)) {
5406 outs() << "\n";
5407 memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
5408 } else {
5409 outs() << " (entends past the end of the section)\n";
5410 memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
5411 memcpy(&objc_ivar_list, p, left);
5412 }
5413 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5414 swapStruct(objc_ivar_list);
5415 outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
5416 ivar_list = p + sizeof(struct objc_ivar_list_t);
5417 for (i = 0; i < objc_ivar_list.ivar_count; i++) {
5418 if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
5419 outs() << "\t\t remaining ivar's extend past the of the section\n";
5420 break;
5421 }
5422 memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
5423 sizeof(struct objc_ivar_t));
5424 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5425 swapStruct(ivar);
5426
5427 outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);
5428 if (info->verbose) {
5429 name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
5430 if (name != nullptr)
5431 outs() << format(" %.*s", xleft, name);
5432 else
5433 outs() << " (not in an __OBJC section)";
5434 }
5435 outs() << "\n";
5436
5437 outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);
5438 if (info->verbose) {
5439 name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
5440 if (name != nullptr)
5441 outs() << format(" %.*s", xleft, name);
5442 else
5443 outs() << " (not in an __OBJC section)";
5444 }
5445 outs() << "\n";
5446
5447 outs() << "\t\t ivar_offset "
5448 << format("0x%08" PRIx32, ivar.ivar_offset) << "\n";
5449 }
5450 } else {
5451 outs() << " (not in an __OBJC section)\n";
5452 }
5453
5454 outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);
5455 if (print_method_list(objc_class->methodLists, info))
5456 outs() << " (not in an __OBJC section)\n";
5457
5458 outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)
5459 << "\n";
5460
5461 outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);
5462 if (print_protocol_list(objc_class->protocols, 16, info))
5463 outs() << " (not in an __OBJC section)\n";
5464}
5465
5466static void print_objc_objc_category_t(struct objc_category_t *objc_category,
5467 struct DisassembleInfo *info) {
5468 uint32_t offset, left;
5469 const char *name;
5470 SectionRef S;
5471
5472 outs() << "\t category name "
5473 << format("0x%08" PRIx32, objc_category->category_name);
5474 if (info->verbose) {
5475 name = get_pointer_32(objc_category->category_name, offset, left, S, info,
5476 true);
5477 if (name != nullptr)
5478 outs() << format(" %.*s", left, name);
5479 else
5480 outs() << " (not in an __OBJC section)";
5481 }
5482 outs() << "\n";
5483
5484 outs() << "\t\t class name "
5485 << format("0x%08" PRIx32, objc_category->class_name);
5486 if (info->verbose) {
5487 name =
5488 get_pointer_32(objc_category->class_name, offset, left, S, info, true);
5489 if (name != nullptr)
5490 outs() << format(" %.*s", left, name);
5491 else
5492 outs() << " (not in an __OBJC section)";
5493 }
5494 outs() << "\n";
5495
5496 outs() << "\t instance methods "
5497 << format("0x%08" PRIx32, objc_category->instance_methods);
5498 if (print_method_list(objc_category->instance_methods, info))
5499 outs() << " (not in an __OBJC section)\n";
5500
5501 outs() << "\t class methods "
5502 << format("0x%08" PRIx32, objc_category->class_methods);
5503 if (print_method_list(objc_category->class_methods, info))
5504 outs() << " (not in an __OBJC section)\n";
5505}
5506
Kevin Enderby0fc11822015-04-01 20:57:01 +00005507static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
5508 struct category64_t c;
5509 const char *r;
5510 uint32_t offset, xoffset, left;
5511 SectionRef S, xS;
5512 const char *name, *sym_name;
5513 uint64_t n_value;
5514
5515 r = get_pointer_64(p, offset, left, S, info);
5516 if (r == nullptr)
5517 return;
5518 memset(&c, '\0', sizeof(struct category64_t));
5519 if (left < sizeof(struct category64_t)) {
5520 memcpy(&c, r, left);
5521 outs() << " (category_t entends past the end of the section)\n";
5522 } else
5523 memcpy(&c, r, sizeof(struct category64_t));
5524 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5525 swapStruct(c);
5526
5527 outs() << " name ";
5528 sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,
5529 info, n_value, c.name);
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 (c.name != 0)
5536 outs() << " + " << format("0x%" PRIx64, c.name);
5537 } else
5538 outs() << format("0x%" PRIx64, c.name);
5539 name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
5540 if (name != nullptr)
5541 outs() << format(" %.*s", left, name);
5542 outs() << "\n";
5543
5544 outs() << " cls ";
5545 sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,
5546 n_value, c.cls);
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 (c.cls != 0)
5553 outs() << " + " << format("0x%" PRIx64, c.cls);
5554 } else
5555 outs() << format("0x%" PRIx64, c.cls);
5556 outs() << "\n";
5557 if (c.cls + n_value != 0)
5558 print_class64_t(c.cls + n_value, info);
5559
5560 outs() << " instanceMethods ";
5561 sym_name =
5562 get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,
5563 info, n_value, c.instanceMethods);
5564 if (n_value != 0) {
5565 if (info->verbose && sym_name != nullptr)
5566 outs() << sym_name;
5567 else
5568 outs() << format("0x%" PRIx64, n_value);
5569 if (c.instanceMethods != 0)
5570 outs() << " + " << format("0x%" PRIx64, c.instanceMethods);
5571 } else
5572 outs() << format("0x%" PRIx64, c.instanceMethods);
5573 outs() << "\n";
5574 if (c.instanceMethods + n_value != 0)
5575 print_method_list64_t(c.instanceMethods + n_value, info, "");
5576
5577 outs() << " classMethods ";
5578 sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),
5579 S, info, n_value, c.classMethods);
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 (c.classMethods != 0)
5586 outs() << " + " << format("0x%" PRIx64, c.classMethods);
5587 } else
5588 outs() << format("0x%" PRIx64, c.classMethods);
5589 outs() << "\n";
5590 if (c.classMethods + n_value != 0)
5591 print_method_list64_t(c.classMethods + n_value, info, "");
5592
5593 outs() << " protocols ";
5594 sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,
5595 info, n_value, c.protocols);
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 (c.protocols != 0)
5602 outs() << " + " << format("0x%" PRIx64, c.protocols);
5603 } else
5604 outs() << format("0x%" PRIx64, c.protocols);
5605 outs() << "\n";
5606 if (c.protocols + n_value != 0)
5607 print_protocol_list64_t(c.protocols + n_value, info);
5608
5609 outs() << "instanceProperties ";
5610 sym_name =
5611 get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),
5612 S, info, n_value, c.instanceProperties);
5613 if (n_value != 0) {
5614 if (info->verbose && sym_name != nullptr)
5615 outs() << sym_name;
5616 else
5617 outs() << format("0x%" PRIx64, n_value);
5618 if (c.instanceProperties != 0)
5619 outs() << " + " << format("0x%" PRIx64, c.instanceProperties);
5620 } else
5621 outs() << format("0x%" PRIx64, c.instanceProperties);
5622 outs() << "\n";
5623 if (c.instanceProperties + n_value != 0)
5624 print_objc_property_list64(c.instanceProperties + n_value, info);
5625}
5626
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005627static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
5628 struct category32_t c;
5629 const char *r;
5630 uint32_t offset, left;
5631 SectionRef S, xS;
5632 const char *name;
5633
5634 r = get_pointer_32(p, offset, left, S, info);
5635 if (r == nullptr)
5636 return;
5637 memset(&c, '\0', sizeof(struct category32_t));
5638 if (left < sizeof(struct category32_t)) {
5639 memcpy(&c, r, left);
5640 outs() << " (category_t entends past the end of the section)\n";
5641 } else
5642 memcpy(&c, r, sizeof(struct category32_t));
5643 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5644 swapStruct(c);
5645
5646 outs() << " name " << format("0x%" PRIx32, c.name);
5647 name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,
5648 c.name);
Hans Wennborgcc9deb42015-09-29 18:02:48 +00005649 if (name)
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005650 outs() << " " << name;
5651 outs() << "\n";
5652
5653 outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";
5654 if (c.cls != 0)
5655 print_class32_t(c.cls, info);
5656 outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)
5657 << "\n";
5658 if (c.instanceMethods != 0)
5659 print_method_list32_t(c.instanceMethods, info, "");
5660 outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)
5661 << "\n";
5662 if (c.classMethods != 0)
5663 print_method_list32_t(c.classMethods, info, "");
5664 outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";
5665 if (c.protocols != 0)
5666 print_protocol_list32_t(c.protocols, info);
5667 outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)
5668 << "\n";
5669 if (c.instanceProperties != 0)
5670 print_objc_property_list32(c.instanceProperties, info);
5671}
5672
Kevin Enderby0fc11822015-04-01 20:57:01 +00005673static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
5674 uint32_t i, left, offset, xoffset;
5675 uint64_t p, n_value;
5676 struct message_ref64 mr;
5677 const char *name, *sym_name;
5678 const char *r;
5679 SectionRef xS;
5680
5681 if (S == SectionRef())
5682 return;
5683
5684 StringRef SectName;
5685 S.getName(SectName);
5686 DataRefImpl Ref = S.getRawDataRefImpl();
5687 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5688 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5689 offset = 0;
5690 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5691 p = S.getAddress() + i;
5692 r = get_pointer_64(p, offset, left, S, info);
5693 if (r == nullptr)
5694 return;
5695 memset(&mr, '\0', sizeof(struct message_ref64));
5696 if (left < sizeof(struct message_ref64)) {
5697 memcpy(&mr, r, left);
5698 outs() << " (message_ref entends past the end of the section)\n";
5699 } else
5700 memcpy(&mr, r, sizeof(struct message_ref64));
5701 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5702 swapStruct(mr);
5703
5704 outs() << " imp ";
5705 name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,
5706 n_value, mr.imp);
5707 if (n_value != 0) {
5708 outs() << format("0x%" PRIx64, n_value) << " ";
5709 if (mr.imp != 0)
5710 outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";
5711 } else
5712 outs() << format("0x%" PRIx64, mr.imp) << " ";
5713 if (name != nullptr)
5714 outs() << " " << name;
5715 outs() << "\n";
5716
5717 outs() << " sel ";
5718 sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,
5719 info, n_value, mr.sel);
5720 if (n_value != 0) {
5721 if (info->verbose && sym_name != nullptr)
5722 outs() << sym_name;
5723 else
5724 outs() << format("0x%" PRIx64, n_value);
5725 if (mr.sel != 0)
5726 outs() << " + " << format("0x%" PRIx64, mr.sel);
5727 } else
5728 outs() << format("0x%" PRIx64, mr.sel);
5729 name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
5730 if (name != nullptr)
5731 outs() << format(" %.*s", left, name);
5732 outs() << "\n";
5733
5734 offset += sizeof(struct message_ref64);
5735 }
5736}
5737
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005738static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
5739 uint32_t i, left, offset, xoffset, p;
5740 struct message_ref32 mr;
5741 const char *name, *r;
5742 SectionRef xS;
5743
5744 if (S == SectionRef())
5745 return;
5746
5747 StringRef SectName;
5748 S.getName(SectName);
5749 DataRefImpl Ref = S.getRawDataRefImpl();
5750 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5751 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5752 offset = 0;
5753 for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
5754 p = S.getAddress() + i;
5755 r = get_pointer_32(p, offset, left, S, info);
5756 if (r == nullptr)
5757 return;
5758 memset(&mr, '\0', sizeof(struct message_ref32));
5759 if (left < sizeof(struct message_ref32)) {
5760 memcpy(&mr, r, left);
5761 outs() << " (message_ref entends past the end of the section)\n";
5762 } else
5763 memcpy(&mr, r, sizeof(struct message_ref32));
5764 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5765 swapStruct(mr);
5766
5767 outs() << " imp " << format("0x%" PRIx32, mr.imp);
5768 name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,
5769 mr.imp);
5770 if (name != nullptr)
5771 outs() << " " << name;
5772 outs() << "\n";
5773
5774 outs() << " sel " << format("0x%" PRIx32, mr.sel);
5775 name = get_pointer_32(mr.sel, xoffset, left, xS, info);
5776 if (name != nullptr)
5777 outs() << " " << name;
5778 outs() << "\n";
5779
5780 offset += sizeof(struct message_ref32);
5781 }
5782}
5783
Kevin Enderby0fc11822015-04-01 20:57:01 +00005784static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
5785 uint32_t left, offset, swift_version;
5786 uint64_t p;
5787 struct objc_image_info64 o;
5788 const char *r;
5789
Kevin Enderbyaf7c9d02015-10-09 16:48:44 +00005790 if (S == SectionRef())
5791 return;
5792
Kevin Enderby0fc11822015-04-01 20:57:01 +00005793 StringRef SectName;
5794 S.getName(SectName);
5795 DataRefImpl Ref = S.getRawDataRefImpl();
5796 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5797 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5798 p = S.getAddress();
5799 r = get_pointer_64(p, offset, left, S, info);
5800 if (r == nullptr)
5801 return;
5802 memset(&o, '\0', sizeof(struct objc_image_info64));
5803 if (left < sizeof(struct objc_image_info64)) {
5804 memcpy(&o, r, left);
5805 outs() << " (objc_image_info entends past the end of the section)\n";
5806 } else
5807 memcpy(&o, r, sizeof(struct objc_image_info64));
5808 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5809 swapStruct(o);
5810 outs() << " version " << o.version << "\n";
5811 outs() << " flags " << format("0x%" PRIx32, o.flags);
5812 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
5813 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5814 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
5815 outs() << " OBJC_IMAGE_SUPPORTS_GC";
Dave Lee390abe42018-07-06 05:11:35 +00005816 if (o.flags & OBJC_IMAGE_IS_SIMULATED)
5817 outs() << " OBJC_IMAGE_IS_SIMULATED";
5818 if (o.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES)
5819 outs() << " OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES";
Kevin Enderby0fc11822015-04-01 20:57:01 +00005820 swift_version = (o.flags >> 8) & 0xff;
5821 if (swift_version != 0) {
5822 if (swift_version == 1)
5823 outs() << " Swift 1.0";
5824 else if (swift_version == 2)
5825 outs() << " Swift 1.1";
Kevin Enderbycda2ced2018-02-09 19:31:27 +00005826 else if(swift_version == 3)
5827 outs() << " Swift 2.0";
5828 else if(swift_version == 4)
5829 outs() << " Swift 3.0";
5830 else if(swift_version == 5)
5831 outs() << " Swift 4.0";
5832 else if(swift_version == 6)
Michael Trentf7254a62018-12-07 19:55:03 +00005833 outs() << " Swift 4.1/Swift 4.2";
5834 else if(swift_version == 7)
5835 outs() << " Swift 5 or later";
Kevin Enderby0fc11822015-04-01 20:57:01 +00005836 else
5837 outs() << " unknown future Swift version (" << swift_version << ")";
5838 }
5839 outs() << "\n";
5840}
5841
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005842static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
5843 uint32_t left, offset, swift_version, p;
5844 struct objc_image_info32 o;
5845 const char *r;
5846
Kevin Enderby19be2512016-04-21 19:49:29 +00005847 if (S == SectionRef())
5848 return;
5849
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005850 StringRef SectName;
5851 S.getName(SectName);
5852 DataRefImpl Ref = S.getRawDataRefImpl();
5853 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5854 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5855 p = S.getAddress();
5856 r = get_pointer_32(p, offset, left, S, info);
5857 if (r == nullptr)
5858 return;
5859 memset(&o, '\0', sizeof(struct objc_image_info32));
5860 if (left < sizeof(struct objc_image_info32)) {
5861 memcpy(&o, r, left);
5862 outs() << " (objc_image_info entends past the end of the section)\n";
5863 } else
5864 memcpy(&o, r, sizeof(struct objc_image_info32));
5865 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5866 swapStruct(o);
5867 outs() << " version " << o.version << "\n";
5868 outs() << " flags " << format("0x%" PRIx32, o.flags);
5869 if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
5870 outs() << " OBJC_IMAGE_IS_REPLACEMENT";
5871 if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
5872 outs() << " OBJC_IMAGE_SUPPORTS_GC";
5873 swift_version = (o.flags >> 8) & 0xff;
5874 if (swift_version != 0) {
5875 if (swift_version == 1)
5876 outs() << " Swift 1.0";
5877 else if (swift_version == 2)
5878 outs() << " Swift 1.1";
Kevin Enderbycda2ced2018-02-09 19:31:27 +00005879 else if(swift_version == 3)
5880 outs() << " Swift 2.0";
5881 else if(swift_version == 4)
5882 outs() << " Swift 3.0";
5883 else if(swift_version == 5)
5884 outs() << " Swift 4.0";
5885 else if(swift_version == 6)
Michael Trentf7254a62018-12-07 19:55:03 +00005886 outs() << " Swift 4.1/Swift 4.2";
5887 else if(swift_version == 7)
5888 outs() << " Swift 5 or later";
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00005889 else
5890 outs() << " unknown future Swift version (" << swift_version << ")";
5891 }
5892 outs() << "\n";
5893}
5894
Kevin Enderby846c0002015-04-16 17:19:59 +00005895static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
5896 uint32_t left, offset, p;
5897 struct imageInfo_t o;
5898 const char *r;
5899
5900 StringRef SectName;
5901 S.getName(SectName);
5902 DataRefImpl Ref = S.getRawDataRefImpl();
5903 StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
5904 outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
5905 p = S.getAddress();
5906 r = get_pointer_32(p, offset, left, S, info);
5907 if (r == nullptr)
5908 return;
5909 memset(&o, '\0', sizeof(struct imageInfo_t));
5910 if (left < sizeof(struct imageInfo_t)) {
5911 memcpy(&o, r, left);
5912 outs() << " (imageInfo entends past the end of the section)\n";
5913 } else
5914 memcpy(&o, r, sizeof(struct imageInfo_t));
5915 if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
5916 swapStruct(o);
5917 outs() << " version " << o.version << "\n";
5918 outs() << " flags " << format("0x%" PRIx32, o.flags);
5919 if (o.flags & 0x1)
5920 outs() << " F&C";
5921 if (o.flags & 0x2)
5922 outs() << " GC";
5923 if (o.flags & 0x4)
5924 outs() << " GC-only";
5925 else
5926 outs() << " RR";
5927 outs() << "\n";
5928}
5929
Kevin Enderby0fc11822015-04-01 20:57:01 +00005930static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
5931 SymbolAddressMap AddrMap;
5932 if (verbose)
5933 CreateSymbolAddressMap(O, &AddrMap);
5934
5935 std::vector<SectionRef> Sections;
5936 for (const SectionRef &Section : O->sections()) {
5937 StringRef SectName;
5938 Section.getName(SectName);
5939 Sections.push_back(Section);
5940 }
5941
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00005942 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005943
Davide Italiano62507042015-12-11 22:27:59 +00005944 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
5945 if (CL == SectionRef())
5946 CL = get_section(O, "__DATA", "__objc_classlist");
Kevin Enderby5879a482017-02-09 17:56:26 +00005947 if (CL == SectionRef())
5948 CL = get_section(O, "__DATA_CONST", "__objc_classlist");
5949 if (CL == SectionRef())
5950 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
Davide Italiano62507042015-12-11 22:27:59 +00005951 info.S = CL;
5952 walk_pointer_list_64("class", CL, O, &info, print_class64_t);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005953
Davide Italiano62507042015-12-11 22:27:59 +00005954 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
5955 if (CR == SectionRef())
5956 CR = get_section(O, "__DATA", "__objc_classrefs");
Kevin Enderby5879a482017-02-09 17:56:26 +00005957 if (CR == SectionRef())
5958 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
5959 if (CR == SectionRef())
5960 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
Davide Italiano62507042015-12-11 22:27:59 +00005961 info.S = CR;
5962 walk_pointer_list_64("class refs", CR, O, &info, nullptr);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005963
Davide Italiano62507042015-12-11 22:27:59 +00005964 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
5965 if (SR == SectionRef())
5966 SR = get_section(O, "__DATA", "__objc_superrefs");
Kevin Enderby5879a482017-02-09 17:56:26 +00005967 if (SR == SectionRef())
5968 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
5969 if (SR == SectionRef())
5970 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
Davide Italiano62507042015-12-11 22:27:59 +00005971 info.S = SR;
5972 walk_pointer_list_64("super refs", SR, O, &info, nullptr);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005973
Davide Italiano62507042015-12-11 22:27:59 +00005974 SectionRef CA = get_section(O, "__OBJC2", "__category_list");
5975 if (CA == SectionRef())
5976 CA = get_section(O, "__DATA", "__objc_catlist");
Kevin Enderby5879a482017-02-09 17:56:26 +00005977 if (CA == SectionRef())
5978 CA = get_section(O, "__DATA_CONST", "__objc_catlist");
5979 if (CA == SectionRef())
5980 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
Davide Italiano62507042015-12-11 22:27:59 +00005981 info.S = CA;
5982 walk_pointer_list_64("category", CA, O, &info, print_category64_t);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005983
Davide Italiano62507042015-12-11 22:27:59 +00005984 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
5985 if (PL == SectionRef())
5986 PL = get_section(O, "__DATA", "__objc_protolist");
Kevin Enderby5879a482017-02-09 17:56:26 +00005987 if (PL == SectionRef())
5988 PL = get_section(O, "__DATA_CONST", "__objc_protolist");
5989 if (PL == SectionRef())
5990 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
Davide Italiano62507042015-12-11 22:27:59 +00005991 info.S = PL;
5992 walk_pointer_list_64("protocol", PL, O, &info, nullptr);
Kevin Enderby0fc11822015-04-01 20:57:01 +00005993
Davide Italiano62507042015-12-11 22:27:59 +00005994 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
5995 if (MR == SectionRef())
5996 MR = get_section(O, "__DATA", "__objc_msgrefs");
Kevin Enderby5879a482017-02-09 17:56:26 +00005997 if (MR == SectionRef())
5998 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
5999 if (MR == SectionRef())
6000 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
Davide Italiano62507042015-12-11 22:27:59 +00006001 info.S = MR;
6002 print_message_refs64(MR, &info);
Kevin Enderby0fc11822015-04-01 20:57:01 +00006003
Davide Italiano62507042015-12-11 22:27:59 +00006004 SectionRef II = get_section(O, "__OBJC2", "__image_info");
6005 if (II == SectionRef())
6006 II = get_section(O, "__DATA", "__objc_imageinfo");
Kevin Enderby5879a482017-02-09 17:56:26 +00006007 if (II == SectionRef())
6008 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6009 if (II == SectionRef())
6010 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
Davide Italiano62507042015-12-11 22:27:59 +00006011 info.S = II;
6012 print_image_info64(II, &info);
Kevin Enderby0fc11822015-04-01 20:57:01 +00006013}
6014
6015static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006016 SymbolAddressMap AddrMap;
6017 if (verbose)
6018 CreateSymbolAddressMap(O, &AddrMap);
6019
6020 std::vector<SectionRef> Sections;
6021 for (const SectionRef &Section : O->sections()) {
6022 StringRef SectName;
6023 Section.getName(SectName);
6024 Sections.push_back(Section);
6025 }
6026
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00006027 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006028
Kevin Enderby5879a482017-02-09 17:56:26 +00006029 SectionRef CL = get_section(O, "__OBJC2", "__class_list");
6030 if (CL == SectionRef())
6031 CL = get_section(O, "__DATA", "__objc_classlist");
6032 if (CL == SectionRef())
6033 CL = get_section(O, "__DATA_CONST", "__objc_classlist");
6034 if (CL == SectionRef())
6035 CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
6036 info.S = CL;
6037 walk_pointer_list_32("class", CL, O, &info, print_class32_t);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006038
Kevin Enderby5879a482017-02-09 17:56:26 +00006039 SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
6040 if (CR == SectionRef())
6041 CR = get_section(O, "__DATA", "__objc_classrefs");
6042 if (CR == SectionRef())
6043 CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
6044 if (CR == SectionRef())
6045 CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
6046 info.S = CR;
6047 walk_pointer_list_32("class refs", CR, O, &info, nullptr);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006048
Kevin Enderby5879a482017-02-09 17:56:26 +00006049 SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
6050 if (SR == SectionRef())
6051 SR = get_section(O, "__DATA", "__objc_superrefs");
6052 if (SR == SectionRef())
6053 SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
6054 if (SR == SectionRef())
6055 SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
6056 info.S = SR;
6057 walk_pointer_list_32("super refs", SR, O, &info, nullptr);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006058
Kevin Enderby5879a482017-02-09 17:56:26 +00006059 SectionRef CA = get_section(O, "__OBJC2", "__category_list");
6060 if (CA == SectionRef())
6061 CA = get_section(O, "__DATA", "__objc_catlist");
6062 if (CA == SectionRef())
6063 CA = get_section(O, "__DATA_CONST", "__objc_catlist");
6064 if (CA == SectionRef())
6065 CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
6066 info.S = CA;
6067 walk_pointer_list_32("category", CA, O, &info, print_category32_t);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006068
Kevin Enderby5879a482017-02-09 17:56:26 +00006069 SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
6070 if (PL == SectionRef())
6071 PL = get_section(O, "__DATA", "__objc_protolist");
6072 if (PL == SectionRef())
6073 PL = get_section(O, "__DATA_CONST", "__objc_protolist");
6074 if (PL == SectionRef())
6075 PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
6076 info.S = PL;
6077 walk_pointer_list_32("protocol", PL, O, &info, nullptr);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006078
Kevin Enderby5879a482017-02-09 17:56:26 +00006079 SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
6080 if (MR == SectionRef())
6081 MR = get_section(O, "__DATA", "__objc_msgrefs");
6082 if (MR == SectionRef())
6083 MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
6084 if (MR == SectionRef())
6085 MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
6086 info.S = MR;
6087 print_message_refs32(MR, &info);
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006088
Kevin Enderby5879a482017-02-09 17:56:26 +00006089 SectionRef II = get_section(O, "__OBJC2", "__image_info");
6090 if (II == SectionRef())
6091 II = get_section(O, "__DATA", "__objc_imageinfo");
6092 if (II == SectionRef())
6093 II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
6094 if (II == SectionRef())
6095 II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
6096 info.S = II;
6097 print_image_info32(II, &info);
Kevin Enderby0fc11822015-04-01 20:57:01 +00006098}
6099
6100static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
Kevin Enderby846c0002015-04-16 17:19:59 +00006101 uint32_t i, j, p, offset, xoffset, left, defs_left, def;
6102 const char *r, *name, *defs;
6103 struct objc_module_t module;
6104 SectionRef S, xS;
6105 struct objc_symtab_t symtab;
6106 struct objc_class_t objc_class;
6107 struct objc_category_t objc_category;
6108
Kevin Enderby28c1c1b2015-04-06 17:47:03 +00006109 outs() << "Objective-C segment\n";
Kevin Enderby846c0002015-04-16 17:19:59 +00006110 S = get_section(O, "__OBJC", "__module_info");
6111 if (S == SectionRef())
6112 return false;
6113
6114 SymbolAddressMap AddrMap;
6115 if (verbose)
6116 CreateSymbolAddressMap(O, &AddrMap);
6117
6118 std::vector<SectionRef> Sections;
6119 for (const SectionRef &Section : O->sections()) {
6120 StringRef SectName;
6121 Section.getName(SectName);
6122 Sections.push_back(Section);
Kevin Enderby0fc11822015-04-01 20:57:01 +00006123 }
Kevin Enderby846c0002015-04-16 17:19:59 +00006124
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00006125 struct DisassembleInfo info(O, &AddrMap, &Sections, verbose);
Kevin Enderby846c0002015-04-16 17:19:59 +00006126
6127 for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
6128 p = S.getAddress() + i;
6129 r = get_pointer_32(p, offset, left, S, &info, true);
6130 if (r == nullptr)
6131 return true;
6132 memset(&module, '\0', sizeof(struct objc_module_t));
6133 if (left < sizeof(struct objc_module_t)) {
6134 memcpy(&module, r, left);
6135 outs() << " (module extends past end of __module_info section)\n";
6136 } else
6137 memcpy(&module, r, sizeof(struct objc_module_t));
6138 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6139 swapStruct(module);
6140
6141 outs() << "Module " << format("0x%" PRIx32, p) << "\n";
6142 outs() << " version " << module.version << "\n";
6143 outs() << " size " << module.size << "\n";
6144 outs() << " name ";
6145 name = get_pointer_32(module.name, xoffset, left, xS, &info, true);
6146 if (name != nullptr)
6147 outs() << format("%.*s", left, name);
6148 else
6149 outs() << format("0x%08" PRIx32, module.name)
6150 << "(not in an __OBJC section)";
6151 outs() << "\n";
6152
6153 r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);
6154 if (module.symtab == 0 || r == nullptr) {
6155 outs() << " symtab " << format("0x%08" PRIx32, module.symtab)
6156 << " (not in an __OBJC section)\n";
6157 continue;
6158 }
6159 outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";
6160 memset(&symtab, '\0', sizeof(struct objc_symtab_t));
6161 defs_left = 0;
6162 defs = nullptr;
6163 if (left < sizeof(struct objc_symtab_t)) {
6164 memcpy(&symtab, r, left);
6165 outs() << "\tsymtab extends past end of an __OBJC section)\n";
6166 } else {
6167 memcpy(&symtab, r, sizeof(struct objc_symtab_t));
6168 if (left > sizeof(struct objc_symtab_t)) {
6169 defs_left = left - sizeof(struct objc_symtab_t);
6170 defs = r + sizeof(struct objc_symtab_t);
6171 }
6172 }
6173 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6174 swapStruct(symtab);
6175
6176 outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
6177 r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);
6178 outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);
6179 if (r == nullptr)
6180 outs() << " (not in an __OBJC section)";
6181 outs() << "\n";
6182 outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
6183 outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
6184 if (symtab.cls_def_cnt > 0)
6185 outs() << "\tClass Definitions\n";
6186 for (j = 0; j < symtab.cls_def_cnt; j++) {
6187 if ((j + 1) * sizeof(uint32_t) > defs_left) {
6188 outs() << "\t(remaining class defs entries entends past the end of the "
6189 << "section)\n";
6190 break;
6191 }
6192 memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));
6193 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6194 sys::swapByteOrder(def);
6195
6196 r = get_pointer_32(def, xoffset, left, xS, &info, true);
6197 outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);
6198 if (r != nullptr) {
6199 if (left > sizeof(struct objc_class_t)) {
6200 outs() << "\n";
6201 memcpy(&objc_class, r, sizeof(struct objc_class_t));
6202 } else {
6203 outs() << " (entends past the end of the section)\n";
6204 memset(&objc_class, '\0', sizeof(struct objc_class_t));
6205 memcpy(&objc_class, r, left);
6206 }
6207 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6208 swapStruct(objc_class);
6209 print_objc_class_t(&objc_class, &info);
6210 } else {
6211 outs() << "(not in an __OBJC section)\n";
6212 }
6213
6214 if (CLS_GETINFO(&objc_class, CLS_CLASS)) {
6215 outs() << "\tMeta Class";
6216 r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);
6217 if (r != nullptr) {
6218 if (left > sizeof(struct objc_class_t)) {
6219 outs() << "\n";
6220 memcpy(&objc_class, r, sizeof(struct objc_class_t));
6221 } else {
6222 outs() << " (entends past the end of the section)\n";
6223 memset(&objc_class, '\0', sizeof(struct objc_class_t));
6224 memcpy(&objc_class, r, left);
6225 }
6226 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6227 swapStruct(objc_class);
6228 print_objc_class_t(&objc_class, &info);
6229 } else {
6230 outs() << "(not in an __OBJC section)\n";
6231 }
6232 }
6233 }
6234 if (symtab.cat_def_cnt > 0)
6235 outs() << "\tCategory Definitions\n";
6236 for (j = 0; j < symtab.cat_def_cnt; j++) {
6237 if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
6238 outs() << "\t(remaining category defs entries entends past the end of "
6239 << "the section)\n";
6240 break;
6241 }
6242 memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
6243 sizeof(uint32_t));
6244 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6245 sys::swapByteOrder(def);
6246
6247 r = get_pointer_32(def, xoffset, left, xS, &info, true);
6248 outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
6249 << format("0x%08" PRIx32, def);
6250 if (r != nullptr) {
6251 if (left > sizeof(struct objc_category_t)) {
6252 outs() << "\n";
6253 memcpy(&objc_category, r, sizeof(struct objc_category_t));
6254 } else {
6255 outs() << " (entends past the end of the section)\n";
6256 memset(&objc_category, '\0', sizeof(struct objc_category_t));
6257 memcpy(&objc_category, r, left);
6258 }
6259 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6260 swapStruct(objc_category);
6261 print_objc_objc_category_t(&objc_category, &info);
6262 } else {
6263 outs() << "(not in an __OBJC section)\n";
6264 }
6265 }
6266 }
6267 const SectionRef II = get_section(O, "__OBJC", "__image_info");
6268 if (II != SectionRef())
6269 print_image_info(II, &info);
6270
6271 return true;
Kevin Enderby0fc11822015-04-01 20:57:01 +00006272}
6273
Kevin Enderby4ad9bde2015-04-16 22:33:20 +00006274static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
6275 uint32_t size, uint32_t addr) {
6276 SymbolAddressMap AddrMap;
6277 CreateSymbolAddressMap(O, &AddrMap);
6278
6279 std::vector<SectionRef> Sections;
6280 for (const SectionRef &Section : O->sections()) {
6281 StringRef SectName;
6282 Section.getName(SectName);
6283 Sections.push_back(Section);
6284 }
6285
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00006286 struct DisassembleInfo info(O, &AddrMap, &Sections, true);
Kevin Enderby4ad9bde2015-04-16 22:33:20 +00006287
6288 const char *p;
6289 struct objc_protocol_t protocol;
6290 uint32_t left, paddr;
6291 for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
6292 memset(&protocol, '\0', sizeof(struct objc_protocol_t));
6293 left = size - (p - sect);
6294 if (left < sizeof(struct objc_protocol_t)) {
6295 outs() << "Protocol extends past end of __protocol section\n";
6296 memcpy(&protocol, p, left);
6297 } else
6298 memcpy(&protocol, p, sizeof(struct objc_protocol_t));
6299 if (O->isLittleEndian() != sys::IsLittleEndianHost)
6300 swapStruct(protocol);
6301 paddr = addr + (p - sect);
6302 outs() << "Protocol " << format("0x%" PRIx32, paddr);
6303 if (print_protocol(paddr, 0, &info))
6304 outs() << "(not in an __OBJC section)\n";
6305 }
6306}
6307
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006308#ifdef HAVE_LIBXAR
6309inline void swapStruct(struct xar_header &xar) {
6310 sys::swapByteOrder(xar.magic);
6311 sys::swapByteOrder(xar.size);
6312 sys::swapByteOrder(xar.version);
6313 sys::swapByteOrder(xar.toc_length_compressed);
6314 sys::swapByteOrder(xar.toc_length_uncompressed);
6315 sys::swapByteOrder(xar.cksum_alg);
6316}
6317
6318static void PrintModeVerbose(uint32_t mode) {
6319 switch(mode & S_IFMT){
6320 case S_IFDIR:
6321 outs() << "d";
6322 break;
6323 case S_IFCHR:
6324 outs() << "c";
6325 break;
6326 case S_IFBLK:
6327 outs() << "b";
6328 break;
6329 case S_IFREG:
6330 outs() << "-";
6331 break;
6332 case S_IFLNK:
6333 outs() << "l";
6334 break;
6335 case S_IFSOCK:
6336 outs() << "s";
6337 break;
6338 default:
6339 outs() << "?";
6340 break;
6341 }
6342
6343 /* owner permissions */
6344 if(mode & S_IREAD)
6345 outs() << "r";
6346 else
6347 outs() << "-";
6348 if(mode & S_IWRITE)
6349 outs() << "w";
6350 else
6351 outs() << "-";
6352 if(mode & S_ISUID)
6353 outs() << "s";
6354 else if(mode & S_IEXEC)
6355 outs() << "x";
6356 else
6357 outs() << "-";
6358
6359 /* group permissions */
6360 if(mode & (S_IREAD >> 3))
6361 outs() << "r";
6362 else
6363 outs() << "-";
6364 if(mode & (S_IWRITE >> 3))
6365 outs() << "w";
6366 else
6367 outs() << "-";
6368 if(mode & S_ISGID)
6369 outs() << "s";
6370 else if(mode & (S_IEXEC >> 3))
6371 outs() << "x";
6372 else
6373 outs() << "-";
6374
6375 /* other permissions */
6376 if(mode & (S_IREAD >> 6))
6377 outs() << "r";
6378 else
6379 outs() << "-";
6380 if(mode & (S_IWRITE >> 6))
6381 outs() << "w";
6382 else
6383 outs() << "-";
6384 if(mode & S_ISVTX)
6385 outs() << "t";
6386 else if(mode & (S_IEXEC >> 6))
6387 outs() << "x";
6388 else
6389 outs() << "-";
6390}
6391
6392static void PrintXarFilesSummary(const char *XarFilename, xar_t xar) {
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006393 xar_file_t xf;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006394 const char *key, *type, *mode, *user, *group, *size, *mtime, *name, *m;
6395 char *endp;
6396 uint32_t mode_value;
6397
Francis Ricci6f942972017-10-06 15:33:28 +00006398 ScopedXarIter xi;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006399 if (!xi) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006400 WithColor::error(errs(), "llvm-objdump")
6401 << "can't obtain an xar iterator for xar archive " << XarFilename
6402 << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006403 return;
6404 }
6405
6406 // Go through the xar's files.
6407 for (xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)) {
Francis Ricci6f942972017-10-06 15:33:28 +00006408 ScopedXarIter xp;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006409 if(!xp){
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006410 WithColor::error(errs(), "llvm-objdump")
6411 << "can't obtain an xar iterator for xar archive " << XarFilename
6412 << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006413 return;
6414 }
6415 type = nullptr;
6416 mode = nullptr;
6417 user = nullptr;
6418 group = nullptr;
6419 size = nullptr;
6420 mtime = nullptr;
6421 name = nullptr;
6422 for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
Jonas Devliegherec0a758d2017-09-18 14:15:57 +00006423 const char *val = nullptr;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006424 xar_prop_get(xf, key, &val);
6425#if 0 // Useful for debugging.
6426 outs() << "key: " << key << " value: " << val << "\n";
6427#endif
6428 if(strcmp(key, "type") == 0)
6429 type = val;
6430 if(strcmp(key, "mode") == 0)
6431 mode = val;
6432 if(strcmp(key, "user") == 0)
6433 user = val;
6434 if(strcmp(key, "group") == 0)
6435 group = val;
6436 if(strcmp(key, "data/size") == 0)
6437 size = val;
6438 if(strcmp(key, "mtime") == 0)
6439 mtime = val;
6440 if(strcmp(key, "name") == 0)
6441 name = val;
6442 }
6443 if(mode != nullptr){
6444 mode_value = strtoul(mode, &endp, 8);
6445 if(*endp != '\0')
6446 outs() << "(mode: \"" << mode << "\" contains non-octal chars) ";
6447 if(strcmp(type, "file") == 0)
6448 mode_value |= S_IFREG;
6449 PrintModeVerbose(mode_value);
6450 outs() << " ";
6451 }
6452 if(user != nullptr)
6453 outs() << format("%10s/", user);
6454 if(group != nullptr)
6455 outs() << format("%-10s ", group);
6456 if(size != nullptr)
6457 outs() << format("%7s ", size);
6458 if(mtime != nullptr){
6459 for(m = mtime; *m != 'T' && *m != '\0'; m++)
6460 outs() << *m;
6461 if(*m == 'T')
6462 m++;
6463 outs() << " ";
6464 for( ; *m != 'Z' && *m != '\0'; m++)
6465 outs() << *m;
6466 outs() << " ";
6467 }
6468 if(name != nullptr)
6469 outs() << name;
6470 outs() << "\n";
6471 }
6472}
6473
6474static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
6475 uint32_t size, bool verbose,
6476 bool PrintXarHeader, bool PrintXarFileHeaders,
6477 std::string XarMemberName) {
6478 if(size < sizeof(struct xar_header)) {
6479 outs() << "size of (__LLVM,__bundle) section too small (smaller than size "
6480 "of struct xar_header)\n";
6481 return;
6482 }
6483 struct xar_header XarHeader;
6484 memcpy(&XarHeader, sect, sizeof(struct xar_header));
6485 if (sys::IsLittleEndianHost)
6486 swapStruct(XarHeader);
6487 if (PrintXarHeader) {
6488 if (!XarMemberName.empty())
6489 outs() << "In xar member " << XarMemberName << ": ";
6490 else
6491 outs() << "For (__LLVM,__bundle) section: ";
6492 outs() << "xar header\n";
6493 if (XarHeader.magic == XAR_HEADER_MAGIC)
6494 outs() << " magic XAR_HEADER_MAGIC\n";
6495 else
6496 outs() << " magic "
6497 << format_hex(XarHeader.magic, 10, true)
6498 << " (not XAR_HEADER_MAGIC)\n";
6499 outs() << " size " << XarHeader.size << "\n";
6500 outs() << " version " << XarHeader.version << "\n";
6501 outs() << " toc_length_compressed " << XarHeader.toc_length_compressed
6502 << "\n";
6503 outs() << "toc_length_uncompressed " << XarHeader.toc_length_uncompressed
6504 << "\n";
6505 outs() << " cksum_alg ";
6506 switch (XarHeader.cksum_alg) {
6507 case XAR_CKSUM_NONE:
6508 outs() << "XAR_CKSUM_NONE\n";
6509 break;
6510 case XAR_CKSUM_SHA1:
6511 outs() << "XAR_CKSUM_SHA1\n";
6512 break;
6513 case XAR_CKSUM_MD5:
6514 outs() << "XAR_CKSUM_MD5\n";
6515 break;
Kevin Enderby42882282016-05-23 22:18:59 +00006516#ifdef XAR_CKSUM_SHA256
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006517 case XAR_CKSUM_SHA256:
6518 outs() << "XAR_CKSUM_SHA256\n";
6519 break;
Kevin Enderby42882282016-05-23 22:18:59 +00006520#endif
6521#ifdef XAR_CKSUM_SHA512
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006522 case XAR_CKSUM_SHA512:
6523 outs() << "XAR_CKSUM_SHA512\n";
6524 break;
Kevin Enderby42882282016-05-23 22:18:59 +00006525#endif
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006526 default:
6527 outs() << XarHeader.cksum_alg << "\n";
6528 }
6529 }
6530
6531 SmallString<128> XarFilename;
6532 int FD;
6533 std::error_code XarEC =
6534 sys::fs::createTemporaryFile("llvm-objdump", "xar", FD, XarFilename);
6535 if (XarEC) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006536 WithColor::error(errs(), "llvm-objdump") << XarEC.message() << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006537 return;
6538 }
Reid Kleckner3fc649c2017-09-23 01:03:17 +00006539 ToolOutputFile XarFile(XarFilename, FD);
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006540 raw_fd_ostream &XarOut = XarFile.os();
6541 StringRef XarContents(sect, size);
6542 XarOut << XarContents;
6543 XarOut.close();
6544 if (XarOut.has_error())
6545 return;
6546
Francis Ricci6f942972017-10-06 15:33:28 +00006547 ScopedXarFile xar(XarFilename.c_str(), READ);
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006548 if (!xar) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006549 WithColor::error(errs(), "llvm-objdump")
6550 << "can't create temporary xar archive " << XarFilename << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006551 return;
6552 }
6553
6554 SmallString<128> TocFilename;
6555 std::error_code TocEC =
6556 sys::fs::createTemporaryFile("llvm-objdump", "toc", TocFilename);
6557 if (TocEC) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006558 WithColor::error(errs(), "llvm-objdump") << TocEC.message() << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006559 return;
6560 }
6561 xar_serialize(xar, TocFilename.c_str());
6562
6563 if (PrintXarFileHeaders) {
6564 if (!XarMemberName.empty())
6565 outs() << "In xar member " << XarMemberName << ": ";
6566 else
6567 outs() << "For (__LLVM,__bundle) section: ";
6568 outs() << "xar archive files:\n";
6569 PrintXarFilesSummary(XarFilename.c_str(), xar);
6570 }
6571
6572 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
6573 MemoryBuffer::getFileOrSTDIN(TocFilename.c_str());
6574 if (std::error_code EC = FileOrErr.getError()) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006575 WithColor::error(errs(), "llvm-objdump") << EC.message() << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006576 return;
6577 }
6578 std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
6579
6580 if (!XarMemberName.empty())
6581 outs() << "In xar member " << XarMemberName << ": ";
6582 else
6583 outs() << "For (__LLVM,__bundle) section: ";
6584 outs() << "xar table of contents:\n";
6585 outs() << Buffer->getBuffer() << "\n";
6586
6587 // TODO: Go through the xar's files.
Francis Ricci6f942972017-10-06 15:33:28 +00006588 ScopedXarIter xi;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006589 if(!xi){
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006590 WithColor::error(errs(), "llvm-objdump")
6591 << "can't obtain an xar iterator for xar archive "
6592 << XarFilename.c_str() << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006593 return;
6594 }
6595 for(xar_file_t xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)){
6596 const char *key;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006597 const char *member_name, *member_type, *member_size_string;
6598 size_t member_size;
6599
Francis Ricci6f942972017-10-06 15:33:28 +00006600 ScopedXarIter xp;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006601 if(!xp){
Jonas Devliegheree787efd2018-11-11 22:12:04 +00006602 WithColor::error(errs(), "llvm-objdump")
6603 << "can't obtain an xar iterator for xar archive "
6604 << XarFilename.c_str() << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006605 return;
6606 }
6607 member_name = NULL;
6608 member_type = NULL;
6609 member_size_string = NULL;
6610 for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
Jonas Devliegherec0a758d2017-09-18 14:15:57 +00006611 const char *val = nullptr;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006612 xar_prop_get(xf, key, &val);
6613#if 0 // Useful for debugging.
6614 outs() << "key: " << key << " value: " << val << "\n";
6615#endif
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006616 if (strcmp(key, "name") == 0)
6617 member_name = val;
6618 if (strcmp(key, "type") == 0)
6619 member_type = val;
6620 if (strcmp(key, "data/size") == 0)
6621 member_size_string = val;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006622 }
6623 /*
6624 * If we find a file with a name, date/size and type properties
6625 * and with the type being "file" see if that is a xar file.
6626 */
6627 if (member_name != NULL && member_type != NULL &&
6628 strcmp(member_type, "file") == 0 &&
6629 member_size_string != NULL){
6630 // Extract the file into a buffer.
6631 char *endptr;
6632 member_size = strtoul(member_size_string, &endptr, 10);
6633 if (*endptr == '\0' && member_size != 0) {
Francis Ricci1bae0ac2017-09-13 13:57:45 +00006634 char *buffer;
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006635 if (xar_extract_tobuffersz(xar, xf, &buffer, &member_size) == 0) {
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006636#if 0 // Useful for debugging.
NAKAMURA Takumi6f43bd42017-10-18 13:31:28 +00006637 outs() << "xar member: " << member_name << " extracted\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006638#endif
6639 // Set the XarMemberName we want to see printed in the header.
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006640 std::string OldXarMemberName;
6641 // If XarMemberName is already set this is nested. So
6642 // save the old name and create the nested name.
6643 if (!XarMemberName.empty()) {
6644 OldXarMemberName = XarMemberName;
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006645 XarMemberName =
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006646 (Twine("[") + XarMemberName + "]" + member_name).str();
6647 } else {
6648 OldXarMemberName = "";
6649 XarMemberName = member_name;
6650 }
6651 // See if this is could be a xar file (nested).
6652 if (member_size >= sizeof(struct xar_header)) {
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006653#if 0 // Useful for debugging.
NAKAMURA Takumi6f43bd42017-10-18 13:31:28 +00006654 outs() << "could be a xar file: " << member_name << "\n";
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006655#endif
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006656 memcpy((char *)&XarHeader, buffer, sizeof(struct xar_header));
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006657 if (sys::IsLittleEndianHost)
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006658 swapStruct(XarHeader);
6659 if (XarHeader.magic == XAR_HEADER_MAGIC)
6660 DumpBitcodeSection(O, buffer, member_size, verbose,
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006661 PrintXarHeader, PrintXarFileHeaders,
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006662 XarMemberName);
6663 }
6664 XarMemberName = OldXarMemberName;
Francis Ricci1bae0ac2017-09-13 13:57:45 +00006665 delete buffer;
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00006666 }
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006667 }
6668 }
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006669 }
Kevin Enderby9873e2c2016-05-23 21:34:12 +00006670}
6671#endif // defined(HAVE_LIBXAR)
6672
Kevin Enderby0fc11822015-04-01 20:57:01 +00006673static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
6674 if (O->is64Bit())
6675 printObjc2_64bit_MetaData(O, verbose);
6676 else {
6677 MachO::mach_header H;
6678 H = O->getHeader();
6679 if (H.cputype == MachO::CPU_TYPE_ARM)
6680 printObjc2_32bit_MetaData(O, verbose);
6681 else {
6682 // This is the 32-bit non-arm cputype case. Which is normally
6683 // the first Objective-C ABI. But it may be the case of a
6684 // binary for the iOS simulator which is the second Objective-C
6685 // ABI. In that case printObjc1_32bit_MetaData() will determine that
6686 // and return false.
Hans Wennborgcc9deb42015-09-29 18:02:48 +00006687 if (!printObjc1_32bit_MetaData(O, verbose))
Kevin Enderby0fc11822015-04-01 20:57:01 +00006688 printObjc2_32bit_MetaData(O, verbose);
6689 }
6690 }
6691}
6692
Kevin Enderbybf246f52014-09-24 23:08:22 +00006693// GuessLiteralPointer returns a string which for the item in the Mach-O file
6694// for the address passed in as ReferenceValue for printing as a comment with
6695// the instruction and also returns the corresponding type of that item
6696// indirectly through ReferenceType.
6697//
6698// If ReferenceValue is an address of literal cstring then a pointer to the
6699// cstring is returned and ReferenceType is set to
6700// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
6701//
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006702// If ReferenceValue is an address of an Objective-C CFString, Selector ref or
6703// Class ref that name is returned and the ReferenceType is set accordingly.
6704//
6705// Lastly, literals which are Symbol address in a literal pool are looked for
6706// and if found the symbol name is returned and ReferenceType is set to
6707// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
6708//
6709// If there is no item in the Mach-O file for the address passed in as
6710// ReferenceValue nullptr is returned and ReferenceType is unchanged.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00006711static const char *GuessLiteralPointer(uint64_t ReferenceValue,
6712 uint64_t ReferencePC,
6713 uint64_t *ReferenceType,
6714 struct DisassembleInfo *info) {
Kevin Enderbybf246f52014-09-24 23:08:22 +00006715 // First see if there is an external relocation entry at the ReferencePC.
Kevin Enderbyd90a4172015-10-10 00:05:01 +00006716 if (info->O->getHeader().filetype == MachO::MH_OBJECT) {
6717 uint64_t sect_addr = info->S.getAddress();
6718 uint64_t sect_offset = ReferencePC - sect_addr;
6719 bool reloc_found = false;
6720 DataRefImpl Rel;
6721 MachO::any_relocation_info RE;
6722 bool isExtern = false;
6723 SymbolRef Symbol;
6724 for (const RelocationRef &Reloc : info->S.relocations()) {
6725 uint64_t RelocOffset = Reloc.getOffset();
6726 if (RelocOffset == sect_offset) {
6727 Rel = Reloc.getRawDataRefImpl();
6728 RE = info->O->getRelocation(Rel);
6729 if (info->O->isRelocationScattered(RE))
6730 continue;
6731 isExtern = info->O->getPlainRelocationExternal(RE);
6732 if (isExtern) {
6733 symbol_iterator RelocSym = Reloc.getSymbol();
6734 Symbol = *RelocSym;
6735 }
6736 reloc_found = true;
6737 break;
Kevin Enderbybf246f52014-09-24 23:08:22 +00006738 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00006739 }
Kevin Enderbyd90a4172015-10-10 00:05:01 +00006740 // If there is an external relocation entry for a symbol in a section
6741 // then used that symbol's value for the value of the reference.
6742 if (reloc_found && isExtern) {
6743 if (info->O->getAnyRelocationPCRel(RE)) {
6744 unsigned Type = info->O->getAnyRelocationType(RE);
6745 if (Type == MachO::X86_64_RELOC_SIGNED) {
6746 ReferenceValue = Symbol.getValue();
6747 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00006748 }
6749 }
6750 }
6751
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006752 // Look for literals such as Objective-C CFStrings refs, Selector refs,
6753 // Message refs and Class refs.
6754 bool classref, selref, msgref, cfstring;
6755 uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
6756 selref, msgref, cfstring);
David Blaikie33dd45d02015-03-23 18:39:02 +00006757 if (classref && pointer_value == 0) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006758 // Note the ReferenceValue is a pointer into the __objc_classrefs section.
6759 // And the pointer_value in that section is typically zero as it will be
6760 // set by dyld as part of the "bind information".
6761 const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
6762 if (name != nullptr) {
6763 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
Hans Wennborgdb53e302014-10-23 21:59:17 +00006764 const char *class_name = strrchr(name, '$');
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006765 if (class_name != nullptr && class_name[1] == '_' &&
6766 class_name[2] != '\0') {
6767 info->class_name = class_name + 2;
6768 return name;
6769 }
6770 }
6771 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00006772
David Blaikie33dd45d02015-03-23 18:39:02 +00006773 if (classref) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006774 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
6775 const char *name =
6776 get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
6777 if (name != nullptr)
6778 info->class_name = name;
6779 else
6780 name = "bad class ref";
Kevin Enderbybf246f52014-09-24 23:08:22 +00006781 return name;
6782 }
6783
David Blaikie33dd45d02015-03-23 18:39:02 +00006784 if (cfstring) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006785 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
6786 const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
6787 return name;
6788 }
6789
David Blaikie33dd45d02015-03-23 18:39:02 +00006790 if (selref && pointer_value == 0)
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006791 pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
6792
6793 if (pointer_value != 0)
6794 ReferenceValue = pointer_value;
6795
6796 const char *name = GuessCstringPointer(ReferenceValue, info);
6797 if (name) {
David Blaikie33dd45d02015-03-23 18:39:02 +00006798 if (pointer_value != 0 && selref) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006799 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
6800 info->selector_name = name;
David Blaikie33dd45d02015-03-23 18:39:02 +00006801 } else if (pointer_value != 0 && msgref) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006802 info->class_name = nullptr;
6803 *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
6804 info->selector_name = name;
6805 } else
6806 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;
6807 return name;
6808 }
6809
6810 // Lastly look for an indirect symbol with this ReferenceValue which is in
6811 // a literal pool. If found return that symbol name.
6812 name = GuessIndirectSymbol(ReferenceValue, info);
6813 if (name) {
6814 *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
6815 return name;
6816 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00006817
6818 return nullptr;
6819}
6820
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006821// SymbolizerSymbolLookUp is the symbol lookup function passed when creating
Kevin Enderbybf246f52014-09-24 23:08:22 +00006822// the Symbolizer. It looks up the ReferenceValue using the info passed via the
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006823// pointer to the struct DisassembleInfo that was passed when MCSymbolizer
6824// is created and returns the symbol name that matches the ReferenceValue or
6825// nullptr if none. The ReferenceType is passed in for the IN type of
6826// reference the instruction is making from the values in defined in the header
6827// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
6828// Out type and the ReferenceName will also be set which is added as a comment
6829// to the disassembled instruction.
6830//
Kevin Enderby04bf6932014-10-28 23:39:46 +00006831// If the symbol name is a C++ mangled name then the demangled name is
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006832// returned through ReferenceName and ReferenceType is set to
6833// LLVMDisassembler_ReferenceType_DeMangled_Name .
6834//
6835// When this is called to get a symbol name for a branch target then the
6836// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
6837// SymbolValue will be looked for in the indirect symbol table to determine if
6838// it is an address for a symbol stub. If so then the symbol name for that
6839// stub is returned indirectly through ReferenceName and then ReferenceType is
6840// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
6841//
Kevin Enderbybf246f52014-09-24 23:08:22 +00006842// When this is called with an value loaded via a PC relative load then
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006843// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
6844// SymbolValue is checked to be an address of literal pointer, symbol pointer,
6845// or an Objective-C meta data reference. If so the output ReferenceType is
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006846// set to correspond to that as well as setting the ReferenceName.
Benjamin Kramerf044d3f2015-03-09 16:23:46 +00006847static const char *SymbolizerSymbolLookUp(void *DisInfo,
6848 uint64_t ReferenceValue,
6849 uint64_t *ReferenceType,
6850 uint64_t ReferencePC,
6851 const char **ReferenceName) {
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006852 struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
Kevin Enderbybf246f52014-09-24 23:08:22 +00006853 // If no verbose symbolic information is wanted then just return nullptr.
David Blaikie33dd45d02015-03-23 18:39:02 +00006854 if (!info->verbose) {
Kevin Enderbybf246f52014-09-24 23:08:22 +00006855 *ReferenceName = nullptr;
6856 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00006857 return nullptr;
6858 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00006859
Kevin Enderbyf6d25852015-01-31 00:37:11 +00006860 const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
Kevin Enderbybf246f52014-09-24 23:08:22 +00006861
Kevin Enderby85974882014-09-26 22:20:44 +00006862 if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
6863 *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
Kevin Enderby04bf6932014-10-28 23:39:46 +00006864 if (*ReferenceName != nullptr) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006865 method_reference(info, ReferenceType, ReferenceName);
6866 if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
6867 *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
Rafael Espindolab940b662016-09-06 19:16:48 +00006868 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
Kevin Enderby04bf6932014-10-28 23:39:46 +00006869 if (info->demangled_name != nullptr)
6870 free(info->demangled_name);
6871 int status;
Kevin Enderbyb28ed012014-10-29 21:28:24 +00006872 info->demangled_name =
Rafael Espindolab940b662016-09-06 19:16:48 +00006873 itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status);
Kevin Enderby04bf6932014-10-28 23:39:46 +00006874 if (info->demangled_name != nullptr) {
6875 *ReferenceName = info->demangled_name;
6876 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
6877 } else
6878 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6879 } else
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006880 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6881 } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
6882 *ReferenceName =
6883 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
Kevin Enderby85974882014-09-26 22:20:44 +00006884 if (*ReferenceName)
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006885 method_reference(info, ReferenceType, ReferenceName);
Kevin Enderby85974882014-09-26 22:20:44 +00006886 else
6887 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
Kevin Enderbyae3c1262014-11-14 21:52:18 +00006888 // If this is arm64 and the reference is an adrp instruction save the
6889 // instruction, passed in ReferenceValue and the address of the instruction
6890 // for use later if we see and add immediate instruction.
6891 } else if (info->O->getArch() == Triple::aarch64 &&
6892 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
6893 info->adrp_inst = ReferenceValue;
6894 info->adrp_addr = ReferencePC;
6895 SymbolName = nullptr;
6896 *ReferenceName = nullptr;
6897 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6898 // If this is arm64 and reference is an add immediate instruction and we
6899 // have
6900 // seen an adrp instruction just before it and the adrp's Xd register
6901 // matches
6902 // this add's Xn register reconstruct the value being referenced and look to
6903 // see if it is a literal pointer. Note the add immediate instruction is
6904 // passed in ReferenceValue.
6905 } else if (info->O->getArch() == Triple::aarch64 &&
6906 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
6907 ReferencePC - 4 == info->adrp_addr &&
6908 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
6909 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
6910 uint32_t addxri_inst;
6911 uint64_t adrp_imm, addxri_imm;
6912
6913 adrp_imm =
6914 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
6915 if (info->adrp_inst & 0x0200000)
6916 adrp_imm |= 0xfffffffffc000000LL;
6917
6918 addxri_inst = ReferenceValue;
6919 addxri_imm = (addxri_inst >> 10) & 0xfff;
6920 if (((addxri_inst >> 22) & 0x3) == 1)
6921 addxri_imm <<= 12;
6922
6923 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
6924 (adrp_imm << 12) + addxri_imm;
6925
6926 *ReferenceName =
6927 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
6928 if (*ReferenceName == nullptr)
6929 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6930 // If this is arm64 and the reference is a load register instruction and we
6931 // have seen an adrp instruction just before it and the adrp's Xd register
6932 // matches this add's Xn register reconstruct the value being referenced and
6933 // look to see if it is a literal pointer. Note the load register
6934 // instruction is passed in ReferenceValue.
6935 } else if (info->O->getArch() == Triple::aarch64 &&
6936 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&
6937 ReferencePC - 4 == info->adrp_addr &&
6938 (info->adrp_inst & 0x9f000000) == 0x90000000 &&
6939 (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
6940 uint32_t ldrxui_inst;
6941 uint64_t adrp_imm, ldrxui_imm;
6942
6943 adrp_imm =
6944 ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
6945 if (info->adrp_inst & 0x0200000)
6946 adrp_imm |= 0xfffffffffc000000LL;
6947
6948 ldrxui_inst = ReferenceValue;
6949 ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
6950
6951 ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
6952 (adrp_imm << 12) + (ldrxui_imm << 3);
6953
6954 *ReferenceName =
6955 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
6956 if (*ReferenceName == nullptr)
6957 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6958 }
6959 // If this arm64 and is an load register (PC-relative) instruction the
6960 // ReferenceValue is the PC plus the immediate value.
6961 else if (info->O->getArch() == Triple::aarch64 &&
6962 (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||
6963 *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {
6964 *ReferenceName =
6965 GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
6966 if (*ReferenceName == nullptr)
6967 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
Rafael Espindolab940b662016-09-06 19:16:48 +00006968 } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
Kevin Enderby04bf6932014-10-28 23:39:46 +00006969 if (info->demangled_name != nullptr)
6970 free(info->demangled_name);
6971 int status;
Kevin Enderbyb28ed012014-10-29 21:28:24 +00006972 info->demangled_name =
Rafael Espindolab940b662016-09-06 19:16:48 +00006973 itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status);
Kevin Enderby04bf6932014-10-28 23:39:46 +00006974 if (info->demangled_name != nullptr) {
6975 *ReferenceName = info->demangled_name;
6976 *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
6977 }
6978 }
Kevin Enderby6f326ce2014-10-23 19:37:31 +00006979 else {
Kevin Enderbybf246f52014-09-24 23:08:22 +00006980 *ReferenceName = nullptr;
6981 *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
6982 }
6983
6984 return SymbolName;
6985}
6986
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00006987/// Emits the comments that are stored in the CommentStream.
Kevin Enderbybf246f52014-09-24 23:08:22 +00006988/// Each comment in the CommentStream must end with a newline.
6989static void emitComments(raw_svector_ostream &CommentStream,
6990 SmallString<128> &CommentsToEmit,
6991 formatted_raw_ostream &FormattedOS,
6992 const MCAsmInfo &MAI) {
6993 // Flush the stream before taking its content.
Kevin Enderbybf246f52014-09-24 23:08:22 +00006994 StringRef Comments = CommentsToEmit.str();
6995 // Get the default information for printing a comment.
Mehdi Amini36d33fc2016-10-01 06:46:33 +00006996 StringRef CommentBegin = MAI.getCommentString();
Kevin Enderbybf246f52014-09-24 23:08:22 +00006997 unsigned CommentColumn = MAI.getCommentColumn();
6998 bool IsFirst = true;
6999 while (!Comments.empty()) {
7000 if (!IsFirst)
7001 FormattedOS << '\n';
7002 // Emit a line of comments.
7003 FormattedOS.PadToColumn(CommentColumn);
7004 size_t Position = Comments.find('\n');
7005 FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
7006 // Move after the newline character.
7007 Comments = Comments.substr(Position + 1);
7008 IsFirst = false;
7009 }
7010 FormattedOS.flush();
7011
7012 // Tell the comment stream that the vector changed underneath it.
7013 CommentsToEmit.clear();
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007014}
7015
Kevin Enderby95df54c2015-02-04 01:01:38 +00007016static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
7017 StringRef DisSegName, StringRef DisSectName) {
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007018 const char *McpuDefault = nullptr;
7019 const Target *ThumbTarget = nullptr;
7020 const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007021 if (!TheTarget) {
7022 // GetTarget prints out stuff.
7023 return;
7024 }
Kevin Enderbyf310e622017-09-21 21:45:02 +00007025 std::string MachOMCPU;
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007026 if (MCPU.empty() && McpuDefault)
Kevin Enderbyf310e622017-09-21 21:45:02 +00007027 MachOMCPU = McpuDefault;
7028 else
7029 MachOMCPU = MCPU;
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007030
Ahmed Charles56440fd2014-03-06 05:51:42 +00007031 std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007032 std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
Kevin Enderbyae3c1262014-11-14 21:52:18 +00007033 if (ThumbTarget)
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007034 ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007035
Kevin Enderbyc9595622014-08-06 23:24:41 +00007036 // Package up features to be passed to target/subtarget
7037 std::string FeaturesStr;
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00007038 if (!MAttrs.empty()) {
Kevin Enderbyc9595622014-08-06 23:24:41 +00007039 SubtargetFeatures Features;
7040 for (unsigned i = 0; i != MAttrs.size(); ++i)
7041 Features.AddFeature(MAttrs[i]);
7042 FeaturesStr = Features.getString();
7043 }
7044
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007045 // Set up disassembler.
Ahmed Charles56440fd2014-03-06 05:51:42 +00007046 std::unique_ptr<const MCRegisterInfo> MRI(
7047 TheTarget->createMCRegInfo(TripleName));
7048 std::unique_ptr<const MCAsmInfo> AsmInfo(
Rafael Espindola227144c2013-05-13 01:16:13 +00007049 TheTarget->createMCAsmInfo(*MRI, TripleName));
Ahmed Charles56440fd2014-03-06 05:51:42 +00007050 std::unique_ptr<const MCSubtargetInfo> STI(
Kevin Enderbyf310e622017-09-21 21:45:02 +00007051 TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr));
Craig Toppere6cb63e2014-04-25 04:24:47 +00007052 MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr);
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007053 std::unique_ptr<MCDisassembler> DisAsm(
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007054 TheTarget->createMCDisassembler(*STI, Ctx));
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007055 std::unique_ptr<MCSymbolizer> Symbolizer;
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00007056 struct DisassembleInfo SymbolizerInfo(nullptr, nullptr, nullptr, false);
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007057 std::unique_ptr<MCRelocationInfo> RelInfo(
7058 TheTarget->createMCRelocationInfo(TripleName, Ctx));
7059 if (RelInfo) {
7060 Symbolizer.reset(TheTarget->createMCSymbolizer(
7061 TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
David Blaikie186db432015-01-18 20:45:48 +00007062 &SymbolizerInfo, &Ctx, std::move(RelInfo)));
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007063 DisAsm->setSymbolizer(std::move(Symbolizer));
7064 }
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007065 int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
Ahmed Charles56440fd2014-03-06 05:51:42 +00007066 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
Daniel Sanders50f17232015-09-15 16:17:27 +00007067 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));
Kevin Enderbybf246f52014-09-24 23:08:22 +00007068 // Set the display preference for hex vs. decimal immediates.
7069 IP->setPrintImmHex(PrintImmHex);
7070 // Comment stream and backing vector.
7071 SmallString<128> CommentsToEmit;
7072 raw_svector_ostream CommentStream(CommentsToEmit);
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00007073 // FIXME: Setting the CommentStream in the InstPrinter is problematic in that
7074 // if it is done then arm64 comments for string literals don't get printed
7075 // and some constant get printed instead and not setting it causes intel
7076 // (32-bit and 64-bit) comments printed with different spacing before the
7077 // comment causing different diffs with the 'C' disassembler library API.
7078 // IP->setCommentStream(CommentStream);
Benjamin Kramer2ad2eb52011-09-20 17:53:01 +00007079
Kevin Enderbyae3c1262014-11-14 21:52:18 +00007080 if (!AsmInfo || !STI || !DisAsm || !IP) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00007081 WithColor::error(errs(), "llvm-objdump")
7082 << "couldn't initialize disassembler for target " << TripleName << '\n';
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007083 return;
7084 }
7085
Tim Northover09ca33e2016-04-22 23:23:31 +00007086 // Set up separate thumb disassembler if needed.
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007087 std::unique_ptr<const MCRegisterInfo> ThumbMRI;
7088 std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
7089 std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
Kevin Enderby930fdc72014-11-06 19:00:13 +00007090 std::unique_ptr<MCDisassembler> ThumbDisAsm;
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007091 std::unique_ptr<MCInstPrinter> ThumbIP;
7092 std::unique_ptr<MCContext> ThumbCtx;
Kevin Enderby930fdc72014-11-06 19:00:13 +00007093 std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
Serge Pavlove4e9a1f2018-02-14 03:26:27 +00007094 struct DisassembleInfo ThumbSymbolizerInfo(nullptr, nullptr, nullptr, false);
Kevin Enderby930fdc72014-11-06 19:00:13 +00007095 std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007096 if (ThumbTarget) {
7097 ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
7098 ThumbAsmInfo.reset(
7099 ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName));
7100 ThumbSTI.reset(
Kevin Enderbyf310e622017-09-21 21:45:02 +00007101 ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU,
7102 FeaturesStr));
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007103 ThumbCtx.reset(new MCContext(ThumbAsmInfo.get(), ThumbMRI.get(), nullptr));
7104 ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
Kevin Enderby930fdc72014-11-06 19:00:13 +00007105 MCContext *PtrThumbCtx = ThumbCtx.get();
7106 ThumbRelInfo.reset(
7107 ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));
7108 if (ThumbRelInfo) {
7109 ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
7110 ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
David Blaikie186db432015-01-18 20:45:48 +00007111 &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
Kevin Enderby930fdc72014-11-06 19:00:13 +00007112 ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
7113 }
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007114 int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
7115 ThumbIP.reset(ThumbTarget->createMCInstPrinter(
Daniel Sanders50f17232015-09-15 16:17:27 +00007116 Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,
7117 *ThumbInstrInfo, *ThumbMRI));
Kevin Enderbybf246f52014-09-24 23:08:22 +00007118 // Set the display preference for hex vs. decimal immediates.
7119 ThumbIP->setPrintImmHex(PrintImmHex);
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007120 }
7121
Kevin Enderbyae3c1262014-11-14 21:52:18 +00007122 if (ThumbTarget && (!ThumbAsmInfo || !ThumbSTI || !ThumbDisAsm || !ThumbIP)) {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00007123 WithColor::error(errs(), "llvm-objdump")
7124 << "couldn't initialize disassembler for target " << ThumbTripleName
7125 << '\n';
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007126 return;
7127 }
7128
Charles Davis8bdfafd2013-09-01 04:28:48 +00007129 MachO::mach_header Header = MachOOF->getHeader();
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007130
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007131 // FIXME: Using the -cfg command line option, this code used to be able to
7132 // annotate relocations with the referenced symbol's name, and if this was
7133 // inside a __[cf]string section, the data it points to. This is now replaced
7134 // by the upcoming MCSymbolizer, which needs the appropriate setup done above.
Owen Andersond9243c42011-10-17 21:37:35 +00007135 std::vector<SectionRef> Sections;
7136 std::vector<SymbolRef> Symbols;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007137 SmallVector<uint64_t, 8> FoundFns;
Kevin Enderby273ae012013-06-06 17:20:50 +00007138 uint64_t BaseSegmentAddress;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007139
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00007140 getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,
Kevin Enderby273ae012013-06-06 17:20:50 +00007141 BaseSegmentAddress);
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007142
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007143 // Sort the symbols by address, just in case they didn't come in that way.
Fangrui Song0cac7262018-09-27 02:13:45 +00007144 llvm::sort(Symbols, SymbolSorter());
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007145
Kevin Enderby273ae012013-06-06 17:20:50 +00007146 // Build a data in code table that is sorted on by the address of each entry.
7147 uint64_t BaseAddress = 0;
Charles Davis8bdfafd2013-09-01 04:28:48 +00007148 if (Header.filetype == MachO::MH_OBJECT)
Rafael Espindola80291272014-10-08 15:28:58 +00007149 BaseAddress = Sections[0].getAddress();
Kevin Enderby273ae012013-06-06 17:20:50 +00007150 else
7151 BaseAddress = BaseSegmentAddress;
7152 DiceTable Dices;
Kevin Enderby273ae012013-06-06 17:20:50 +00007153 for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
Rafael Espindola5e812af2014-01-30 02:49:50 +00007154 DI != DE; ++DI) {
Kevin Enderby273ae012013-06-06 17:20:50 +00007155 uint32_t Offset;
7156 DI->getOffset(Offset);
7157 Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
7158 }
7159 array_pod_sort(Dices.begin(), Dices.end());
7160
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007161#ifndef NDEBUG
7162 raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
7163#else
7164 raw_ostream &DebugOut = nulls();
7165#endif
7166
Ahmed Charles56440fd2014-03-06 05:51:42 +00007167 std::unique_ptr<DIContext> diContext;
Rafael Espindola9b709252013-04-13 01:45:40 +00007168 ObjectFile *DbgObj = MachOOF;
Francis Visoiu Mistrih8e864be2018-08-31 13:10:54 +00007169 std::unique_ptr<MemoryBuffer> DSYMBuf;
Benjamin Kramer699128e2011-09-21 01:13:19 +00007170 // Try to find debug info and set up the DIContext for it.
7171 if (UseDbg) {
Benjamin Kramer699128e2011-09-21 01:13:19 +00007172 // A separate DSym file path was specified, parse it as a macho file,
7173 // get the sections and supply it to the section name parsing machinery.
7174 if (!DSYMFile.empty()) {
Rafael Espindola48af1c22014-08-19 18:44:46 +00007175 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
Rafael Espindolaadf21f22014-07-06 17:43:13 +00007176 MemoryBuffer::getFileOrSTDIN(DSYMFile);
Rafael Espindola48af1c22014-08-19 18:44:46 +00007177 if (std::error_code EC = BufOrErr.getError()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00007178 report_error(errorCodeToError(EC), DSYMFile);
Benjamin Kramer699128e2011-09-21 01:13:19 +00007179 return;
7180 }
Francis Visoiu Mistrihb8819dc2019-01-10 17:36:54 +00007181
Fangrui Songe7834bd2019-04-07 08:19:55 +00007182 std::unique_ptr<MachOObjectFile> DbgObjCheck = unwrapOrError(
7183 ObjectFile::createMachOObjectFile(BufOrErr.get()->getMemBufferRef()),
7184 DSYMFile.getValue());
7185 DbgObj = DbgObjCheck.release();
Francis Visoiu Mistrih8e864be2018-08-31 13:10:54 +00007186 // We need to keep the file alive, because we're replacing DbgObj with it.
7187 DSYMBuf = std::move(BufOrErr.get());
Benjamin Kramer699128e2011-09-21 01:13:19 +00007188 }
7189
Eric Christopher7370b552012-11-12 21:40:38 +00007190 // Setup the DIContext
Rafael Espindolac398e672017-07-19 22:27:28 +00007191 diContext = DWARFContext::create(*DbgObj);
Benjamin Kramer699128e2011-09-21 01:13:19 +00007192 }
7193
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00007194 if (FilterSections.empty())
Kevin Enderby95df54c2015-02-04 01:01:38 +00007195 outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00007196
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007197 for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
Owen Andersond9243c42011-10-17 21:37:35 +00007198 StringRef SectName;
Kevin Enderby95df54c2015-02-04 01:01:38 +00007199 if (Sections[SectIdx].getName(SectName) || SectName != DisSectName)
7200 continue;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007201
Rafael Espindolaa9f810b2012-12-21 03:47:03 +00007202 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007203
Rafael Espindolab0f76a42013-04-05 15:15:22 +00007204 StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
Kevin Enderby95df54c2015-02-04 01:01:38 +00007205 if (SegmentName != DisSegName)
Rafael Espindolaa9f810b2012-12-21 03:47:03 +00007206 continue;
7207
Rafael Espindola7fc5b872014-11-12 02:04:27 +00007208 StringRef BytesStr;
7209 Sections[SectIdx].getContents(BytesStr);
Fangrui Song6a0746a2019-04-07 03:58:42 +00007210 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);
Rafael Espindola80291272014-10-08 15:28:58 +00007211 uint64_t SectAddress = Sections[SectIdx].getAddress();
Rafael Espindolabd604f22014-11-07 00:52:15 +00007212
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007213 bool symbolTableWorked = false;
7214
Kevin Enderbybf246f52014-09-24 23:08:22 +00007215 // Create a map of symbol addresses to symbol names for use by
7216 // the SymbolizerSymbolLookUp() routine.
7217 SymbolAddressMap AddrMap;
Kevin Enderby6a221752015-03-17 17:10:57 +00007218 bool DisSymNameFound = false;
Kevin Enderbybf246f52014-09-24 23:08:22 +00007219 for (const SymbolRef &Symbol : MachOOF->symbols()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00007220 SymbolRef::Type ST =
7221 unwrapOrError(Symbol.getType(), MachOOF->getFileName());
Kevin Enderbybf246f52014-09-24 23:08:22 +00007222 if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
7223 ST == SymbolRef::ST_Other) {
Rafael Espindoladea00162015-07-03 17:44:18 +00007224 uint64_t Address = Symbol.getValue();
Fangrui Songe7834bd2019-04-07 08:19:55 +00007225 StringRef SymName =
7226 unwrapOrError(Symbol.getName(), MachOOF->getFileName());
Kevin Enderbybf246f52014-09-24 23:08:22 +00007227 AddrMap[Address] = SymName;
Kevin Enderby6a221752015-03-17 17:10:57 +00007228 if (!DisSymName.empty() && DisSymName == SymName)
7229 DisSymNameFound = true;
Kevin Enderbybf246f52014-09-24 23:08:22 +00007230 }
7231 }
David Blaikie33dd45d02015-03-23 18:39:02 +00007232 if (!DisSymName.empty() && !DisSymNameFound) {
Kevin Enderby6a221752015-03-17 17:10:57 +00007233 outs() << "Can't find -dis-symname: " << DisSymName << "\n";
7234 return;
7235 }
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007236 // Set up the block of info used by the Symbolizer call backs.
Kevin Enderby8e29ec92015-03-17 22:26:11 +00007237 SymbolizerInfo.verbose = !NoSymbolicOperands;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007238 SymbolizerInfo.O = MachOOF;
7239 SymbolizerInfo.S = Sections[SectIdx];
Kevin Enderbybf246f52014-09-24 23:08:22 +00007240 SymbolizerInfo.AddrMap = &AddrMap;
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007241 SymbolizerInfo.Sections = &Sections;
Kevin Enderby930fdc72014-11-06 19:00:13 +00007242 // Same for the ThumbSymbolizer
Kevin Enderby8e29ec92015-03-17 22:26:11 +00007243 ThumbSymbolizerInfo.verbose = !NoSymbolicOperands;
Kevin Enderby930fdc72014-11-06 19:00:13 +00007244 ThumbSymbolizerInfo.O = MachOOF;
7245 ThumbSymbolizerInfo.S = Sections[SectIdx];
7246 ThumbSymbolizerInfo.AddrMap = &AddrMap;
7247 ThumbSymbolizerInfo.Sections = &Sections;
Kevin Enderby98c9acc2014-09-16 18:00:57 +00007248
Kevin Enderby4b627be2016-04-28 20:14:13 +00007249 unsigned int Arch = MachOOF->getArch();
7250
Tim Northoverf203ab52016-07-14 22:13:32 +00007251 // Skip all symbols if this is a stubs file.
Jordan Rupprecht16a0de22018-12-20 00:57:06 +00007252 if (Bytes.empty())
Tim Northoverf203ab52016-07-14 22:13:32 +00007253 return;
7254
Kevin Enderbyc138da32017-02-06 18:43:18 +00007255 // If the section has symbols but no symbol at the start of the section
7256 // these are used to make sure the bytes before the first symbol are
7257 // disassembled.
7258 bool FirstSymbol = true;
7259 bool FirstSymbolAtSectionStart = true;
7260
Benjamin Kramer2ad2eb52011-09-20 17:53:01 +00007261 // Disassemble symbol by symbol.
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007262 for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00007263 StringRef SymName =
7264 unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());
7265 SymbolRef::Type ST =
7266 unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());
Kuba Breckade833222015-11-12 09:40:29 +00007267 if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
Owen Andersond9243c42011-10-17 21:37:35 +00007268 continue;
7269
Benjamin Kramer2ad2eb52011-09-20 17:53:01 +00007270 // Make sure the symbol is defined in this section.
Rafael Espindola80291272014-10-08 15:28:58 +00007271 bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);
Kevin Enderbyd8a6e832016-06-15 21:14:01 +00007272 if (!containsSym) {
7273 if (!DisSymName.empty() && DisSymName == SymName) {
7274 outs() << "-dis-symname: " << DisSymName << " not in the section\n";
7275 return;
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +00007276 }
Kevin Enderbyd8a6e832016-06-15 21:14:01 +00007277 continue;
7278 }
7279 // The __mh_execute_header is special and we need to deal with that fact
7280 // this symbol is before the start of the (__TEXT,__text) section and at the
7281 // address of the start of the __TEXT segment. This is because this symbol
7282 // is an N_SECT symbol in the (__TEXT,__text) but its address is before the
7283 // start of the section in a standard MH_EXECUTE filetype.
7284 if (!DisSymName.empty() && DisSymName == "__mh_execute_header") {
7285 outs() << "-dis-symname: __mh_execute_header not in any section\n";
7286 return;
7287 }
Tim Northoverfbefee32016-07-14 23:13:03 +00007288 // When this code is trying to disassemble a symbol at a time and in the
7289 // case there is only the __mh_execute_header symbol left as in a stripped
7290 // executable, we need to deal with this by ignoring this symbol so the
7291 // whole section is disassembled and this symbol is then not displayed.
7292 if (SymName == "__mh_execute_header" || SymName == "__mh_dylib_header" ||
7293 SymName == "__mh_bundle_header" || SymName == "__mh_object_header" ||
7294 SymName == "__mh_preload_header" || SymName == "__mh_dylinker_header")
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007295 continue;
7296
Kevin Enderby6a221752015-03-17 17:10:57 +00007297 // If we are only disassembling one symbol see if this is that symbol.
7298 if (!DisSymName.empty() && DisSymName != SymName)
7299 continue;
7300
Benjamin Kramer2ad2eb52011-09-20 17:53:01 +00007301 // Start at the address of the symbol relative to the section's address.
Tim Northoverf203ab52016-07-14 22:13:32 +00007302 uint64_t SectSize = Sections[SectIdx].getSize();
Rafael Espindoladea00162015-07-03 17:44:18 +00007303 uint64_t Start = Symbols[SymIdx].getValue();
Rafael Espindola80291272014-10-08 15:28:58 +00007304 uint64_t SectionAddress = Sections[SectIdx].getAddress();
Cameron Zwarich54478a52012-02-03 05:42:17 +00007305 Start -= SectionAddress;
Owen Andersond9243c42011-10-17 21:37:35 +00007306
Tim Northoverf203ab52016-07-14 22:13:32 +00007307 if (Start > SectSize) {
7308 outs() << "section data ends, " << SymName
7309 << " lies outside valid range\n";
7310 return;
7311 }
7312
Benjamin Kramer2ad2eb52011-09-20 17:53:01 +00007313 // Stop disassembling either at the beginning of the next symbol or at
7314 // the end of the section.
Kevin Enderbyedd58722012-05-15 18:57:14 +00007315 bool containsNextSym = false;
Owen Andersond9243c42011-10-17 21:37:35 +00007316 uint64_t NextSym = 0;
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007317 uint64_t NextSymIdx = SymIdx + 1;
Owen Andersond9243c42011-10-17 21:37:35 +00007318 while (Symbols.size() > NextSymIdx) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00007319 SymbolRef::Type NextSymType = unwrapOrError(
7320 Symbols[NextSymIdx].getType(), MachOOF->getFileName());
Owen Andersond9243c42011-10-17 21:37:35 +00007321 if (NextSymType == SymbolRef::ST_Function) {
Rafael Espindola80291272014-10-08 15:28:58 +00007322 containsNextSym =
7323 Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
Rafael Espindoladea00162015-07-03 17:44:18 +00007324 NextSym = Symbols[NextSymIdx].getValue();
Cameron Zwarich54478a52012-02-03 05:42:17 +00007325 NextSym -= SectionAddress;
Owen Andersond9243c42011-10-17 21:37:35 +00007326 break;
7327 }
7328 ++NextSymIdx;
7329 }
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007330
Tim Northoverf203ab52016-07-14 22:13:32 +00007331 uint64_t End = containsNextSym ? std::min(NextSym, SectSize) : SectSize;
Owen Andersond9243c42011-10-17 21:37:35 +00007332 uint64_t Size;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007333
7334 symbolTableWorked = true;
Rafael Espindolabd604f22014-11-07 00:52:15 +00007335
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007336 DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
Tim Northover09ca33e2016-04-22 23:23:31 +00007337 bool IsThumb = MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb;
7338
7339 // We only need the dedicated Thumb target if there's a real choice
7340 // (i.e. we're not targeting M-class) and the function is Thumb.
7341 bool UseThumbTarget = IsThumb && ThumbTarget;
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007342
Kevin Enderbyc138da32017-02-06 18:43:18 +00007343 // If we are not specifying a symbol to start disassembly with and this
7344 // is the first symbol in the section but not at the start of the section
7345 // then move the disassembly index to the start of the section and
7346 // don't print the symbol name just yet. This is so the bytes before the
7347 // first symbol are disassembled.
7348 uint64_t SymbolStart = Start;
7349 if (DisSymName.empty() && FirstSymbol && Start != 0) {
7350 FirstSymbolAtSectionStart = false;
7351 Start = 0;
7352 }
7353 else
7354 outs() << SymName << ":\n";
7355
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007356 DILineInfo lastLine;
7357 for (uint64_t Index = Start; Index < End; Index += Size) {
7358 MCInst Inst;
Owen Andersond9243c42011-10-17 21:37:35 +00007359
Kevin Enderbyc138da32017-02-06 18:43:18 +00007360 // If this is the first symbol in the section and it was not at the
7361 // start of the section, see if we are at its Index now and if so print
7362 // the symbol name.
7363 if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
7364 outs() << SymName << ":\n";
7365
Kevin Enderbybf246f52014-09-24 23:08:22 +00007366 uint64_t PC = SectAddress + Index;
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00007367 if (!NoLeadingAddr) {
7368 if (FullLeadingAddr) {
7369 if (MachOOF->is64Bit())
7370 outs() << format("%016" PRIx64, PC);
7371 else
7372 outs() << format("%08" PRIx64, PC);
7373 } else {
7374 outs() << format("%8" PRIx64 ":", PC);
7375 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00007376 }
Kevin Enderby4b627be2016-04-28 20:14:13 +00007377 if (!NoShowRawInsn || Arch == Triple::arm)
Kevin Enderbybf246f52014-09-24 23:08:22 +00007378 outs() << "\t";
Kevin Enderby273ae012013-06-06 17:20:50 +00007379
7380 // Check the data in code table here to see if this is data not an
7381 // instruction to be disassembled.
7382 DiceTable Dice;
Kevin Enderbybf246f52014-09-24 23:08:22 +00007383 Dice.push_back(std::make_pair(PC, DiceRef()));
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007384 dice_table_iterator DTI =
7385 std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),
7386 compareDiceTableEntries);
7387 if (DTI != Dices.end()) {
Kevin Enderby273ae012013-06-06 17:20:50 +00007388 uint16_t Length;
7389 DTI->second.getLength(Length);
Kevin Enderby273ae012013-06-06 17:20:50 +00007390 uint16_t Kind;
7391 DTI->second.getKind(Kind);
Colin LeMahieufc32b1b2015-03-18 19:27:31 +00007392 Size = DumpDataInCode(Bytes.data() + Index, Length, Kind);
Kevin Enderby930fdc72014-11-06 19:00:13 +00007393 if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
7394 (PC == (DTI->first + Length - 1)) && (Length & 1))
7395 Size++;
Kevin Enderby273ae012013-06-06 17:20:50 +00007396 continue;
7397 }
7398
Kevin Enderbybf246f52014-09-24 23:08:22 +00007399 SmallVector<char, 64> AnnotationsBytes;
7400 raw_svector_ostream Annotations(AnnotationsBytes);
7401
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007402 bool gotInst;
Tim Northover09ca33e2016-04-22 23:23:31 +00007403 if (UseThumbTarget)
Rafael Espindola7fc5b872014-11-12 02:04:27 +00007404 gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007405 PC, DebugOut, Annotations);
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007406 else
Rafael Espindola7fc5b872014-11-12 02:04:27 +00007407 gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,
Kevin Enderbybf246f52014-09-24 23:08:22 +00007408 DebugOut, Annotations);
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007409 if (gotInst) {
Kevin Enderby4b627be2016-04-28 20:14:13 +00007410 if (!NoShowRawInsn || Arch == Triple::arm) {
Craig Topper0013be12015-09-21 05:32:41 +00007411 dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs());
Kevin Enderbybf246f52014-09-24 23:08:22 +00007412 }
7413 formatted_raw_ostream FormattedOS(outs());
Kevin Enderbybf246f52014-09-24 23:08:22 +00007414 StringRef AnnotationsStr = Annotations.str();
Tim Northover09ca33e2016-04-22 23:23:31 +00007415 if (UseThumbTarget)
Akira Hatanakab46d0232015-03-27 20:36:02 +00007416 ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI);
Kevin Enderbyec5ca032014-08-18 20:21:02 +00007417 else
Akira Hatanaka1d079942015-03-28 20:44:05 +00007418 IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI);
Kevin Enderbybf246f52014-09-24 23:08:22 +00007419 emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
Owen Andersond9243c42011-10-17 21:37:35 +00007420
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007421 // Print debug info.
7422 if (diContext) {
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00007423 DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007424 // Print valid line info if it changed.
Alexey Samsonovd0109992014-04-18 21:36:39 +00007425 if (dli != lastLine && dli.Line != 0)
7426 outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
7427 << dli.Column;
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007428 lastLine = dli;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007429 }
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007430 outs() << "\n";
7431 } else {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007432 unsigned int Arch = MachOOF->getArch();
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007433 if (Arch == Triple::x86_64 || Arch == Triple::x86) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007434 outs() << format("\t.byte 0x%02x #bad opcode\n",
7435 *(Bytes.data() + Index) & 0xff);
7436 Size = 1; // skip exactly one illegible byte and move on.
Tim Northover09ca33e2016-04-22 23:23:31 +00007437 } else if (Arch == Triple::aarch64 ||
7438 (Arch == Triple::arm && !IsThumb)) {
Kevin Enderbyae3c1262014-11-14 21:52:18 +00007439 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7440 (*(Bytes.data() + Index + 1) & 0xff) << 8 |
7441 (*(Bytes.data() + Index + 2) & 0xff) << 16 |
7442 (*(Bytes.data() + Index + 3) & 0xff) << 24;
7443 outs() << format("\t.long\t0x%08x\n", opcode);
7444 Size = 4;
Tim Northover09ca33e2016-04-22 23:23:31 +00007445 } else if (Arch == Triple::arm) {
7446 assert(IsThumb && "ARM mode should have been dealt with above");
7447 uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
7448 (*(Bytes.data() + Index + 1) & 0xff) << 8;
7449 outs() << format("\t.short\t0x%04x\n", opcode);
7450 Size = 2;
7451 } else{
Jonas Devliegheree787efd2018-11-11 22:12:04 +00007452 WithColor::warning(errs(), "llvm-objdump")
7453 << "invalid instruction encoding\n";
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007454 if (Size == 0)
7455 Size = 1; // skip illegible bytes
7456 }
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007457 }
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007458 }
Kevin Enderbyc138da32017-02-06 18:43:18 +00007459 // Now that we are done disassembled the first symbol set the bool that
7460 // were doing this to false.
7461 FirstSymbol = false;
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007462 }
Ahmed Bougachaaa790682013-05-24 01:07:04 +00007463 if (!symbolTableWorked) {
Rafael Espindola80291272014-10-08 15:28:58 +00007464 // Reading the symbol table didn't work, disassemble the whole section.
7465 uint64_t SectAddress = Sections[SectIdx].getAddress();
7466 uint64_t SectSize = Sections[SectIdx].getSize();
Kevin Enderbybadd1002012-05-18 00:13:56 +00007467 uint64_t InstSize;
7468 for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
Bill Wendling4e68e062012-07-19 00:17:40 +00007469 MCInst Inst;
Kevin Enderbybadd1002012-05-18 00:13:56 +00007470
Kevin Enderbybf246f52014-09-24 23:08:22 +00007471 uint64_t PC = SectAddress + Index;
Kevin Enderby02d3a372017-01-31 18:09:10 +00007472 SmallVector<char, 64> AnnotationsBytes;
7473 raw_svector_ostream Annotations(AnnotationsBytes);
Rafael Espindola7fc5b872014-11-12 02:04:27 +00007474 if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
Kevin Enderby02d3a372017-01-31 18:09:10 +00007475 DebugOut, Annotations)) {
Kevin Enderbyab5e6c92015-03-17 21:07:39 +00007476 if (!NoLeadingAddr) {
7477 if (FullLeadingAddr) {
7478 if (MachOOF->is64Bit())
7479 outs() << format("%016" PRIx64, PC);
7480 else
7481 outs() << format("%08" PRIx64, PC);
7482 } else {
7483 outs() << format("%8" PRIx64 ":", PC);
7484 }
Kevin Enderbybf246f52014-09-24 23:08:22 +00007485 }
Kevin Enderby4b627be2016-04-28 20:14:13 +00007486 if (!NoShowRawInsn || Arch == Triple::arm) {
Kevin Enderbybf246f52014-09-24 23:08:22 +00007487 outs() << "\t";
Craig Topper0013be12015-09-21 05:32:41 +00007488 dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
Kevin Enderbybf246f52014-09-24 23:08:22 +00007489 }
Kevin Enderby02d3a372017-01-31 18:09:10 +00007490 StringRef AnnotationsStr = Annotations.str();
7491 IP->printInst(&Inst, outs(), AnnotationsStr, *STI);
Bill Wendling4e68e062012-07-19 00:17:40 +00007492 outs() << "\n";
7493 } else {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007494 unsigned int Arch = MachOOF->getArch();
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007495 if (Arch == Triple::x86_64 || Arch == Triple::x86) {
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007496 outs() << format("\t.byte 0x%02x #bad opcode\n",
7497 *(Bytes.data() + Index) & 0xff);
7498 InstSize = 1; // skip exactly one illegible byte and move on.
7499 } else {
Jonas Devliegheree787efd2018-11-11 22:12:04 +00007500 WithColor::warning(errs(), "llvm-objdump")
7501 << "invalid instruction encoding\n";
Kevin Enderby6f326ce2014-10-23 19:37:31 +00007502 if (InstSize == 0)
7503 InstSize = 1; // skip illegible bytes
7504 }
Bill Wendling4e68e062012-07-19 00:17:40 +00007505 }
Kevin Enderbybadd1002012-05-18 00:13:56 +00007506 }
7507 }
Kevin Enderbyef3ad2f2014-12-04 23:56:27 +00007508 // The TripleName's need to be reset if we are called again for a different
7509 // archtecture.
7510 TripleName = "";
7511 ThumbTripleName = "";
7512
Kevin Enderby04bf6932014-10-28 23:39:46 +00007513 if (SymbolizerInfo.demangled_name != nullptr)
7514 free(SymbolizerInfo.demangled_name);
Kevin Enderby930fdc72014-11-06 19:00:13 +00007515 if (ThumbSymbolizerInfo.demangled_name != nullptr)
7516 free(ThumbSymbolizerInfo.demangled_name);
Benjamin Kramer43a772e2011-09-19 17:56:04 +00007517 }
7518}
Tim Northover4bd286a2014-08-01 13:07:19 +00007519
Tim Northover39c70bb2014-08-12 11:52:59 +00007520//===----------------------------------------------------------------------===//
7521// __compact_unwind section dumping
7522//===----------------------------------------------------------------------===//
7523
Tim Northover4bd286a2014-08-01 13:07:19 +00007524namespace {
Tim Northover39c70bb2014-08-12 11:52:59 +00007525
Tim Northover3a4e1c72018-01-23 13:51:57 +00007526template <typename T>
7527static uint64_t read(StringRef Contents, ptrdiff_t Offset) {
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007528 using llvm::support::little;
7529 using llvm::support::unaligned;
Tim Northover39c70bb2014-08-12 11:52:59 +00007530
Tim Northover3a4e1c72018-01-23 13:51:57 +00007531 if (Offset + sizeof(T) > Contents.size()) {
7532 outs() << "warning: attempt to read past end of buffer\n";
7533 return T();
7534 }
7535
7536 uint64_t Val =
7537 support::endian::read<T, little, unaligned>(Contents.data() + Offset);
7538 return Val;
7539}
7540
7541template <typename T>
7542static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) {
7543 T Val = read<T>(Contents, Offset);
7544 Offset += sizeof(T);
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007545 return Val;
7546}
Tim Northover39c70bb2014-08-12 11:52:59 +00007547
Tim Northover4bd286a2014-08-01 13:07:19 +00007548struct CompactUnwindEntry {
7549 uint32_t OffsetInSection;
7550
7551 uint64_t FunctionAddr;
7552 uint32_t Length;
7553 uint32_t CompactEncoding;
7554 uint64_t PersonalityAddr;
7555 uint64_t LSDAAddr;
7556
7557 RelocationRef FunctionReloc;
7558 RelocationRef PersonalityReloc;
7559 RelocationRef LSDAReloc;
7560
7561 CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007562 : OffsetInSection(Offset) {
Tim Northover4bd286a2014-08-01 13:07:19 +00007563 if (Is64)
Tim Northover3a4e1c72018-01-23 13:51:57 +00007564 read<uint64_t>(Contents, Offset);
Tim Northover4bd286a2014-08-01 13:07:19 +00007565 else
Tim Northover3a4e1c72018-01-23 13:51:57 +00007566 read<uint32_t>(Contents, Offset);
Tim Northover4bd286a2014-08-01 13:07:19 +00007567 }
7568
7569private:
Tim Northover3a4e1c72018-01-23 13:51:57 +00007570 template <typename UIntPtr> void read(StringRef Contents, ptrdiff_t Offset) {
7571 FunctionAddr = readNext<UIntPtr>(Contents, Offset);
7572 Length = readNext<uint32_t>(Contents, Offset);
7573 CompactEncoding = readNext<uint32_t>(Contents, Offset);
7574 PersonalityAddr = readNext<UIntPtr>(Contents, Offset);
7575 LSDAAddr = readNext<UIntPtr>(Contents, Offset);
Tim Northover4bd286a2014-08-01 13:07:19 +00007576 }
7577};
7578}
7579
7580/// Given a relocation from __compact_unwind, consisting of the RelocationRef
7581/// and data being relocated, determine the best base Name and Addend to use for
7582/// display purposes.
7583///
7584/// 1. An Extern relocation will directly reference a symbol (and the data is
7585/// then already an addend), so use that.
7586/// 2. Otherwise the data is an offset in the object file's layout; try to find
7587// a symbol before it in the same section, and use the offset from there.
7588/// 3. Finally, if all that fails, fall back to an offset from the start of the
7589/// referenced section.
7590static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
7591 std::map<uint64_t, SymbolRef> &Symbols,
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007592 const RelocationRef &Reloc, uint64_t Addr,
Tim Northover4bd286a2014-08-01 13:07:19 +00007593 StringRef &Name, uint64_t &Addend) {
7594 if (Reloc.getSymbol() != Obj->symbol_end()) {
Fangrui Songe7834bd2019-04-07 08:19:55 +00007595 Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());
Tim Northover4bd286a2014-08-01 13:07:19 +00007596 Addend = Addr;
7597 return;
7598 }
7599
7600 auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
Keno Fischerc780e8e2015-05-21 21:24:32 +00007601 SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
Tim Northover4bd286a2014-08-01 13:07:19 +00007602
Rafael Espindola80291272014-10-08 15:28:58 +00007603 uint64_t SectionAddr = RelocSection.getAddress();
Tim Northover4bd286a2014-08-01 13:07:19 +00007604
7605 auto Sym = Symbols.upper_bound(Addr);
7606 if (Sym == Symbols.begin()) {
7607 // The first symbol in the object is after this reference, the best we can
7608 // do is section-relative notation.
7609 RelocSection.getName(Name);
7610 Addend = Addr - SectionAddr;
7611 return;
7612 }
7613
7614 // Go back one so that SymbolAddress <= Addr.
7615 --Sym;
7616
Fangrui Songe7834bd2019-04-07 08:19:55 +00007617 section_iterator SymSection =
7618 unwrapOrError(Sym->second.getSection(), Obj->getFileName());
Tim Northover4bd286a2014-08-01 13:07:19 +00007619 if (RelocSection == *SymSection) {
7620 // There's a valid symbol in the same section before this reference.
Fangrui Songe7834bd2019-04-07 08:19:55 +00007621 Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());
Tim Northover4bd286a2014-08-01 13:07:19 +00007622 Addend = Addr - Sym->first;
7623 return;
7624 }
7625
7626 // There is a symbol before this reference, but it's in a different
7627 // section. Probably not helpful to mention it, so use the section name.
7628 RelocSection.getName(Name);
7629 Addend = Addr - SectionAddr;
7630}
7631
7632static void printUnwindRelocDest(const MachOObjectFile *Obj,
7633 std::map<uint64_t, SymbolRef> &Symbols,
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007634 const RelocationRef &Reloc, uint64_t Addr) {
Tim Northover4bd286a2014-08-01 13:07:19 +00007635 StringRef Name;
7636 uint64_t Addend;
7637
Rafael Espindola854038e2015-06-26 14:51:16 +00007638 if (!Reloc.getObject())
Tim Northover0b0add52014-09-09 10:45:06 +00007639 return;
7640
Tim Northover4bd286a2014-08-01 13:07:19 +00007641 findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
7642
7643 outs() << Name;
7644 if (Addend)
Tim Northover63a25622014-08-11 09:14:06 +00007645 outs() << " + " << format("0x%" PRIx64, Addend);
Tim Northover4bd286a2014-08-01 13:07:19 +00007646}
7647
7648static void
7649printMachOCompactUnwindSection(const MachOObjectFile *Obj,
7650 std::map<uint64_t, SymbolRef> &Symbols,
7651 const SectionRef &CompactUnwind) {
7652
Tim Northoverbf55f7e2016-11-15 20:26:01 +00007653 if (!Obj->isLittleEndian()) {
7654 outs() << "Skipping big-endian __compact_unwind section\n";
7655 return;
7656 }
Tim Northover4bd286a2014-08-01 13:07:19 +00007657
7658 bool Is64 = Obj->is64Bit();
7659 uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
7660 uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
7661
7662 StringRef Contents;
7663 CompactUnwind.getContents(Contents);
7664
7665 SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
7666
7667 // First populate the initial raw offsets, encodings and so on from the entry.
7668 for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007669 CompactUnwindEntry Entry(Contents, Offset, Is64);
Tim Northover4bd286a2014-08-01 13:07:19 +00007670 CompactUnwinds.push_back(Entry);
7671 }
7672
7673 // Next we need to look at the relocations to find out what objects are
7674 // actually being referred to.
7675 for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
Rafael Espindola96d071c2015-06-29 23:29:12 +00007676 uint64_t RelocAddress = Reloc.getOffset();
Tim Northover4bd286a2014-08-01 13:07:19 +00007677
7678 uint32_t EntryIdx = RelocAddress / EntrySize;
7679 uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
7680 CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
7681
7682 if (OffsetInEntry == 0)
7683 Entry.FunctionReloc = Reloc;
7684 else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
7685 Entry.PersonalityReloc = Reloc;
7686 else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
7687 Entry.LSDAReloc = Reloc;
Tim Northoverbf55f7e2016-11-15 20:26:01 +00007688 else {
7689 outs() << "Invalid relocation in __compact_unwind section\n";
7690 return;
7691 }
Tim Northover4bd286a2014-08-01 13:07:19 +00007692 }
7693
7694 // Finally, we're ready to print the data we've gathered.
7695 outs() << "Contents of __compact_unwind section:\n";
7696 for (auto &Entry : CompactUnwinds) {
Tim Northover06af2602014-08-08 12:08:51 +00007697 outs() << " Entry at offset "
7698 << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";
Tim Northover4bd286a2014-08-01 13:07:19 +00007699
7700 // 1. Start of the region this entry applies to.
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007701 outs() << " start: " << format("0x%" PRIx64,
7702 Entry.FunctionAddr) << ' ';
7703 printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);
Tim Northover4bd286a2014-08-01 13:07:19 +00007704 outs() << '\n';
7705
7706 // 2. Length of the region this entry applies to.
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007707 outs() << " length: " << format("0x%" PRIx32, Entry.Length)
7708 << '\n';
Tim Northover4bd286a2014-08-01 13:07:19 +00007709 // 3. The 32-bit compact encoding.
7710 outs() << " compact encoding: "
Tim Northoverb911bf82014-08-08 12:00:09 +00007711 << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';
Tim Northover4bd286a2014-08-01 13:07:19 +00007712
7713 // 4. The personality function, if present.
Rafael Espindola854038e2015-06-26 14:51:16 +00007714 if (Entry.PersonalityReloc.getObject()) {
Tim Northover4bd286a2014-08-01 13:07:19 +00007715 outs() << " personality function: "
Tim Northoverb911bf82014-08-08 12:00:09 +00007716 << format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';
Tim Northover4bd286a2014-08-01 13:07:19 +00007717 printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
7718 Entry.PersonalityAddr);
7719 outs() << '\n';
7720 }
7721
7722 // 5. This entry's language-specific data area.
Rafael Espindola854038e2015-06-26 14:51:16 +00007723 if (Entry.LSDAReloc.getObject()) {
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007724 outs() << " LSDA: " << format("0x%" PRIx64,
7725 Entry.LSDAAddr) << ' ';
Tim Northover4bd286a2014-08-01 13:07:19 +00007726 printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
7727 outs() << '\n';
7728 }
7729 }
7730}
7731
Tim Northover39c70bb2014-08-12 11:52:59 +00007732//===----------------------------------------------------------------------===//
7733// __unwind_info section dumping
7734//===----------------------------------------------------------------------===//
7735
Tim Northover3a4e1c72018-01-23 13:51:57 +00007736static void printRegularSecondLevelUnwindPage(StringRef PageData) {
7737 ptrdiff_t Pos = 0;
7738 uint32_t Kind = readNext<uint32_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007739 (void)Kind;
7740 assert(Kind == 2 && "kind for a regular 2nd level index should be 2");
7741
Tim Northover3a4e1c72018-01-23 13:51:57 +00007742 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7743 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007744
Tim Northover3a4e1c72018-01-23 13:51:57 +00007745 Pos = EntriesStart;
Tim Northover39c70bb2014-08-12 11:52:59 +00007746 for (unsigned i = 0; i < NumEntries; ++i) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007747 uint32_t FunctionOffset = readNext<uint32_t>(PageData, Pos);
7748 uint32_t Encoding = readNext<uint32_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007749
7750 outs() << " [" << i << "]: "
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007751 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
7752 << ", "
7753 << "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';
Tim Northover39c70bb2014-08-12 11:52:59 +00007754 }
7755}
7756
7757static void printCompressedSecondLevelUnwindPage(
Tim Northover3a4e1c72018-01-23 13:51:57 +00007758 StringRef PageData, uint32_t FunctionBase,
Tim Northover39c70bb2014-08-12 11:52:59 +00007759 const SmallVectorImpl<uint32_t> &CommonEncodings) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007760 ptrdiff_t Pos = 0;
7761 uint32_t Kind = readNext<uint32_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007762 (void)Kind;
7763 assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");
7764
Tim Northover3a4e1c72018-01-23 13:51:57 +00007765 uint16_t EntriesStart = readNext<uint16_t>(PageData, Pos);
7766 uint16_t NumEntries = readNext<uint16_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007767
Tim Northover3a4e1c72018-01-23 13:51:57 +00007768 uint16_t EncodingsStart = readNext<uint16_t>(PageData, Pos);
7769 readNext<uint16_t>(PageData, Pos);
7770 StringRef PageEncodings = PageData.substr(EncodingsStart, StringRef::npos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007771
Tim Northover3a4e1c72018-01-23 13:51:57 +00007772 Pos = EntriesStart;
Tim Northover39c70bb2014-08-12 11:52:59 +00007773 for (unsigned i = 0; i < NumEntries; ++i) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007774 uint32_t Entry = readNext<uint32_t>(PageData, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007775 uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
7776 uint32_t EncodingIdx = Entry >> 24;
7777
7778 uint32_t Encoding;
7779 if (EncodingIdx < CommonEncodings.size())
7780 Encoding = CommonEncodings[EncodingIdx];
7781 else
Tim Northover3a4e1c72018-01-23 13:51:57 +00007782 Encoding = read<uint32_t>(PageEncodings,
7783 sizeof(uint32_t) *
7784 (EncodingIdx - CommonEncodings.size()));
Tim Northover39c70bb2014-08-12 11:52:59 +00007785
7786 outs() << " [" << i << "]: "
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007787 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
7788 << ", "
7789 << "encoding[" << EncodingIdx
7790 << "]=" << format("0x%08" PRIx32, Encoding) << '\n';
Tim Northover39c70bb2014-08-12 11:52:59 +00007791 }
7792}
7793
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007794static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
7795 std::map<uint64_t, SymbolRef> &Symbols,
7796 const SectionRef &UnwindInfo) {
Tim Northover39c70bb2014-08-12 11:52:59 +00007797
Tim Northoverbf55f7e2016-11-15 20:26:01 +00007798 if (!Obj->isLittleEndian()) {
7799 outs() << "Skipping big-endian __unwind_info section\n";
7800 return;
7801 }
Tim Northover39c70bb2014-08-12 11:52:59 +00007802
7803 outs() << "Contents of __unwind_info section:\n";
7804
7805 StringRef Contents;
7806 UnwindInfo.getContents(Contents);
Tim Northover3a4e1c72018-01-23 13:51:57 +00007807 ptrdiff_t Pos = 0;
Tim Northover39c70bb2014-08-12 11:52:59 +00007808
7809 //===----------------------------------
7810 // Section header
7811 //===----------------------------------
7812
Tim Northover3a4e1c72018-01-23 13:51:57 +00007813 uint32_t Version = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007814 outs() << " Version: "
7815 << format("0x%" PRIx32, Version) << '\n';
Tim Northoverbf55f7e2016-11-15 20:26:01 +00007816 if (Version != 1) {
7817 outs() << " Skipping section with unknown version\n";
7818 return;
7819 }
Tim Northover39c70bb2014-08-12 11:52:59 +00007820
Tim Northover3a4e1c72018-01-23 13:51:57 +00007821 uint32_t CommonEncodingsStart = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007822 outs() << " Common encodings array section offset: "
7823 << format("0x%" PRIx32, CommonEncodingsStart) << '\n';
Tim Northover3a4e1c72018-01-23 13:51:57 +00007824 uint32_t NumCommonEncodings = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007825 outs() << " Number of common encodings in array: "
7826 << format("0x%" PRIx32, NumCommonEncodings) << '\n';
7827
Tim Northover3a4e1c72018-01-23 13:51:57 +00007828 uint32_t PersonalitiesStart = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007829 outs() << " Personality function array section offset: "
7830 << format("0x%" PRIx32, PersonalitiesStart) << '\n';
Tim Northover3a4e1c72018-01-23 13:51:57 +00007831 uint32_t NumPersonalities = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007832 outs() << " Number of personality functions in array: "
7833 << format("0x%" PRIx32, NumPersonalities) << '\n';
7834
Tim Northover3a4e1c72018-01-23 13:51:57 +00007835 uint32_t IndicesStart = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007836 outs() << " Index array section offset: "
7837 << format("0x%" PRIx32, IndicesStart) << '\n';
Tim Northover3a4e1c72018-01-23 13:51:57 +00007838 uint32_t NumIndices = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007839 outs() << " Number of indices in array: "
7840 << format("0x%" PRIx32, NumIndices) << '\n';
7841
7842 //===----------------------------------
7843 // A shared list of common encodings
7844 //===----------------------------------
7845
7846 // These occupy indices in the range [0, N] whenever an encoding is referenced
7847 // from a compressed 2nd level index table. In practice the linker only
7848 // creates ~128 of these, so that indices are available to embed encodings in
7849 // the 2nd level index.
7850
7851 SmallVector<uint32_t, 64> CommonEncodings;
7852 outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
Tim Northover3a4e1c72018-01-23 13:51:57 +00007853 Pos = CommonEncodingsStart;
Tim Northover39c70bb2014-08-12 11:52:59 +00007854 for (unsigned i = 0; i < NumCommonEncodings; ++i) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007855 uint32_t Encoding = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007856 CommonEncodings.push_back(Encoding);
7857
7858 outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)
7859 << '\n';
7860 }
7861
Tim Northover39c70bb2014-08-12 11:52:59 +00007862 //===----------------------------------
7863 // Personality functions used in this executable
7864 //===----------------------------------
7865
7866 // There should be only a handful of these (one per source language,
7867 // roughly). Particularly since they only get 2 bits in the compact encoding.
7868
7869 outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
Tim Northover3a4e1c72018-01-23 13:51:57 +00007870 Pos = PersonalitiesStart;
Tim Northover39c70bb2014-08-12 11:52:59 +00007871 for (unsigned i = 0; i < NumPersonalities; ++i) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007872 uint32_t PersonalityFn = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007873 outs() << " personality[" << i + 1
7874 << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';
7875 }
7876
7877 //===----------------------------------
7878 // The level 1 index entries
7879 //===----------------------------------
7880
7881 // These specify an approximate place to start searching for the more detailed
7882 // information, sorted by PC.
7883
7884 struct IndexEntry {
7885 uint32_t FunctionOffset;
7886 uint32_t SecondLevelPageStart;
7887 uint32_t LSDAStart;
7888 };
7889
7890 SmallVector<IndexEntry, 4> IndexEntries;
7891
7892 outs() << " Top level indices: (count = " << NumIndices << ")\n";
Tim Northover3a4e1c72018-01-23 13:51:57 +00007893 Pos = IndicesStart;
Tim Northover39c70bb2014-08-12 11:52:59 +00007894 for (unsigned i = 0; i < NumIndices; ++i) {
7895 IndexEntry Entry;
7896
Tim Northover3a4e1c72018-01-23 13:51:57 +00007897 Entry.FunctionOffset = readNext<uint32_t>(Contents, Pos);
7898 Entry.SecondLevelPageStart = readNext<uint32_t>(Contents, Pos);
7899 Entry.LSDAStart = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007900 IndexEntries.push_back(Entry);
7901
7902 outs() << " [" << i << "]: "
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007903 << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)
7904 << ", "
Tim Northover39c70bb2014-08-12 11:52:59 +00007905 << "2nd level page offset="
7906 << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007907 << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';
Tim Northover39c70bb2014-08-12 11:52:59 +00007908 }
7909
Tim Northover39c70bb2014-08-12 11:52:59 +00007910 //===----------------------------------
7911 // Next come the LSDA tables
7912 //===----------------------------------
7913
7914 // The LSDA layout is rather implicit: it's a contiguous array of entries from
7915 // the first top-level index's LSDAOffset to the last (sentinel).
7916
7917 outs() << " LSDA descriptors:\n";
Tim Northover3a4e1c72018-01-23 13:51:57 +00007918 Pos = IndexEntries[0].LSDAStart;
7919 const uint32_t LSDASize = 2 * sizeof(uint32_t);
7920 int NumLSDAs =
7921 (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize;
7922
Tim Northover39c70bb2014-08-12 11:52:59 +00007923 for (int i = 0; i < NumLSDAs; ++i) {
Tim Northover3a4e1c72018-01-23 13:51:57 +00007924 uint32_t FunctionOffset = readNext<uint32_t>(Contents, Pos);
7925 uint32_t LSDAOffset = readNext<uint32_t>(Contents, Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007926 outs() << " [" << i << "]: "
Kevin Enderbyb28ed012014-10-29 21:28:24 +00007927 << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
7928 << ", "
7929 << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';
Tim Northover39c70bb2014-08-12 11:52:59 +00007930 }
7931
7932 //===----------------------------------
7933 // Finally, the 2nd level indices
7934 //===----------------------------------
7935
7936 // Generally these are 4K in size, and have 2 possible forms:
7937 // + Regular stores up to 511 entries with disparate encodings
7938 // + Compressed stores up to 1021 entries if few enough compact encoding
7939 // values are used.
7940 outs() << " Second level indices:\n";
7941 for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
7942 // The final sentinel top-level index has no associated 2nd level page
7943 if (IndexEntries[i].SecondLevelPageStart == 0)
7944 break;
7945
7946 outs() << " Second level index[" << i << "]: "
7947 << "offset in section="
7948 << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)
7949 << ", "
7950 << "base function offset="
7951 << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';
7952
Tim Northover3a4e1c72018-01-23 13:51:57 +00007953 Pos = IndexEntries[i].SecondLevelPageStart;
7954 if (Pos + sizeof(uint32_t) > Contents.size()) {
7955 outs() << "warning: invalid offset for second level page: " << Pos << '\n';
7956 continue;
7957 }
7958
7959 uint32_t Kind =
7960 *reinterpret_cast<const support::ulittle32_t *>(Contents.data() + Pos);
Tim Northover39c70bb2014-08-12 11:52:59 +00007961 if (Kind == 2)
Tim Northover3a4e1c72018-01-23 13:51:57 +00007962 printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096));
Tim Northover39c70bb2014-08-12 11:52:59 +00007963 else if (Kind == 3)
Tim Northover3a4e1c72018-01-23 13:51:57 +00007964 printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096),
7965 IndexEntries[i].FunctionOffset,
Tim Northover39c70bb2014-08-12 11:52:59 +00007966 CommonEncodings);
7967 else
Tim Northoverbf55f7e2016-11-15 20:26:01 +00007968 outs() << " Skipping 2nd level page with unknown kind " << Kind
7969 << '\n';
Tim Northover39c70bb2014-08-12 11:52:59 +00007970 }
7971}
7972
Tim Northover4bd286a2014-08-01 13:07:19 +00007973void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
7974 std::map<uint64_t, SymbolRef> Symbols;
7975 for (const SymbolRef &SymRef : Obj->symbols()) {
7976 // Discard any undefined or absolute symbols. They're not going to take part
7977 // in the convenience lookup for unwind info and just take up resources.
Kevin Enderby7bd8d992016-05-02 20:28:12 +00007978 auto SectOrErr = SymRef.getSection();
7979 if (!SectOrErr) {
7980 // TODO: Actually report errors helpfully.
7981 consumeError(SectOrErr.takeError());
7982 continue;
7983 }
7984 section_iterator Section = *SectOrErr;
Tim Northover4bd286a2014-08-01 13:07:19 +00007985 if (Section == Obj->section_end())
7986 continue;
7987
Rafael Espindoladea00162015-07-03 17:44:18 +00007988 uint64_t Addr = SymRef.getValue();
Tim Northover4bd286a2014-08-01 13:07:19 +00007989 Symbols.insert(std::make_pair(Addr, SymRef));
7990 }
7991
7992 for (const SectionRef &Section : Obj->sections()) {
7993 StringRef SectName;
7994 Section.getName(SectName);
7995 if (SectName == "__compact_unwind")
7996 printMachOCompactUnwindSection(Obj, Symbols, Section);
7997 else if (SectName == "__unwind_info")
Tim Northover39c70bb2014-08-12 11:52:59 +00007998 printMachOUnwindInfoSection(Obj, Symbols, Section);
Tim Northover4bd286a2014-08-01 13:07:19 +00007999 }
8000}
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008001
8002static void PrintMachHeader(uint32_t magic, uint32_t cputype,
8003 uint32_t cpusubtype, uint32_t filetype,
8004 uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
8005 bool verbose) {
8006 outs() << "Mach header\n";
8007 outs() << " magic cputype cpusubtype caps filetype ncmds "
8008 "sizeofcmds flags\n";
8009 if (verbose) {
8010 if (magic == MachO::MH_MAGIC)
8011 outs() << " MH_MAGIC";
8012 else if (magic == MachO::MH_MAGIC_64)
8013 outs() << "MH_MAGIC_64";
8014 else
8015 outs() << format(" 0x%08" PRIx32, magic);
8016 switch (cputype) {
8017 case MachO::CPU_TYPE_I386:
8018 outs() << " I386";
8019 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8020 case MachO::CPU_SUBTYPE_I386_ALL:
8021 outs() << " ALL";
8022 break;
8023 default:
8024 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8025 break;
8026 }
8027 break;
8028 case MachO::CPU_TYPE_X86_64:
8029 outs() << " X86_64";
Kevin Enderby131d1772015-01-09 19:22:37 +00008030 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8031 case MachO::CPU_SUBTYPE_X86_64_ALL:
8032 outs() << " ALL";
8033 break;
8034 case MachO::CPU_SUBTYPE_X86_64_H:
8035 outs() << " Haswell";
8036 break;
8037 default:
8038 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8039 break;
8040 }
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008041 break;
8042 case MachO::CPU_TYPE_ARM:
8043 outs() << " ARM";
8044 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8045 case MachO::CPU_SUBTYPE_ARM_ALL:
8046 outs() << " ALL";
8047 break;
8048 case MachO::CPU_SUBTYPE_ARM_V4T:
8049 outs() << " V4T";
8050 break;
8051 case MachO::CPU_SUBTYPE_ARM_V5TEJ:
8052 outs() << " V5TEJ";
8053 break;
8054 case MachO::CPU_SUBTYPE_ARM_XSCALE:
8055 outs() << " XSCALE";
8056 break;
8057 case MachO::CPU_SUBTYPE_ARM_V6:
8058 outs() << " V6";
8059 break;
8060 case MachO::CPU_SUBTYPE_ARM_V6M:
8061 outs() << " V6M";
8062 break;
8063 case MachO::CPU_SUBTYPE_ARM_V7:
8064 outs() << " V7";
8065 break;
8066 case MachO::CPU_SUBTYPE_ARM_V7EM:
8067 outs() << " V7EM";
8068 break;
8069 case MachO::CPU_SUBTYPE_ARM_V7K:
8070 outs() << " V7K";
8071 break;
8072 case MachO::CPU_SUBTYPE_ARM_V7M:
8073 outs() << " V7M";
8074 break;
8075 case MachO::CPU_SUBTYPE_ARM_V7S:
8076 outs() << " V7S";
8077 break;
8078 default:
8079 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8080 break;
8081 }
8082 break;
8083 case MachO::CPU_TYPE_ARM64:
8084 outs() << " ARM64";
8085 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8086 case MachO::CPU_SUBTYPE_ARM64_ALL:
8087 outs() << " ALL";
8088 break;
Shoaib Meenai867131a2019-04-08 21:37:08 +00008089 case MachO::CPU_SUBTYPE_ARM64E:
8090 outs() << " E";
8091 break;
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008092 default:
8093 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8094 break;
8095 }
8096 break;
8097 case MachO::CPU_TYPE_POWERPC:
8098 outs() << " PPC";
8099 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8100 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8101 outs() << " ALL";
8102 break;
8103 default:
8104 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8105 break;
8106 }
8107 break;
8108 case MachO::CPU_TYPE_POWERPC64:
8109 outs() << " PPC64";
8110 switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
8111 case MachO::CPU_SUBTYPE_POWERPC_ALL:
8112 outs() << " ALL";
8113 break;
8114 default:
8115 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8116 break;
8117 }
8118 break;
Kevin Enderby40fdbf82016-01-26 18:20:49 +00008119 default:
8120 outs() << format(" %7d", cputype);
8121 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8122 break;
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008123 }
8124 if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008125 outs() << " LIB64";
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008126 } else {
8127 outs() << format(" 0x%02" PRIx32,
8128 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8129 }
8130 switch (filetype) {
8131 case MachO::MH_OBJECT:
8132 outs() << " OBJECT";
8133 break;
8134 case MachO::MH_EXECUTE:
8135 outs() << " EXECUTE";
8136 break;
8137 case MachO::MH_FVMLIB:
8138 outs() << " FVMLIB";
8139 break;
8140 case MachO::MH_CORE:
8141 outs() << " CORE";
8142 break;
8143 case MachO::MH_PRELOAD:
8144 outs() << " PRELOAD";
8145 break;
8146 case MachO::MH_DYLIB:
8147 outs() << " DYLIB";
8148 break;
8149 case MachO::MH_DYLIB_STUB:
8150 outs() << " DYLIB_STUB";
8151 break;
8152 case MachO::MH_DYLINKER:
8153 outs() << " DYLINKER";
8154 break;
8155 case MachO::MH_BUNDLE:
8156 outs() << " BUNDLE";
8157 break;
8158 case MachO::MH_DSYM:
8159 outs() << " DSYM";
8160 break;
8161 case MachO::MH_KEXT_BUNDLE:
8162 outs() << " KEXTBUNDLE";
8163 break;
8164 default:
8165 outs() << format(" %10u", filetype);
8166 break;
8167 }
8168 outs() << format(" %5u", ncmds);
8169 outs() << format(" %10u", sizeofcmds);
8170 uint32_t f = flags;
8171 if (f & MachO::MH_NOUNDEFS) {
8172 outs() << " NOUNDEFS";
8173 f &= ~MachO::MH_NOUNDEFS;
8174 }
8175 if (f & MachO::MH_INCRLINK) {
8176 outs() << " INCRLINK";
8177 f &= ~MachO::MH_INCRLINK;
8178 }
8179 if (f & MachO::MH_DYLDLINK) {
8180 outs() << " DYLDLINK";
8181 f &= ~MachO::MH_DYLDLINK;
8182 }
8183 if (f & MachO::MH_BINDATLOAD) {
8184 outs() << " BINDATLOAD";
8185 f &= ~MachO::MH_BINDATLOAD;
8186 }
8187 if (f & MachO::MH_PREBOUND) {
8188 outs() << " PREBOUND";
8189 f &= ~MachO::MH_PREBOUND;
8190 }
8191 if (f & MachO::MH_SPLIT_SEGS) {
8192 outs() << " SPLIT_SEGS";
8193 f &= ~MachO::MH_SPLIT_SEGS;
8194 }
8195 if (f & MachO::MH_LAZY_INIT) {
8196 outs() << " LAZY_INIT";
8197 f &= ~MachO::MH_LAZY_INIT;
8198 }
8199 if (f & MachO::MH_TWOLEVEL) {
8200 outs() << " TWOLEVEL";
8201 f &= ~MachO::MH_TWOLEVEL;
8202 }
8203 if (f & MachO::MH_FORCE_FLAT) {
8204 outs() << " FORCE_FLAT";
8205 f &= ~MachO::MH_FORCE_FLAT;
8206 }
8207 if (f & MachO::MH_NOMULTIDEFS) {
8208 outs() << " NOMULTIDEFS";
8209 f &= ~MachO::MH_NOMULTIDEFS;
8210 }
8211 if (f & MachO::MH_NOFIXPREBINDING) {
8212 outs() << " NOFIXPREBINDING";
8213 f &= ~MachO::MH_NOFIXPREBINDING;
8214 }
8215 if (f & MachO::MH_PREBINDABLE) {
8216 outs() << " PREBINDABLE";
8217 f &= ~MachO::MH_PREBINDABLE;
8218 }
8219 if (f & MachO::MH_ALLMODSBOUND) {
8220 outs() << " ALLMODSBOUND";
8221 f &= ~MachO::MH_ALLMODSBOUND;
8222 }
8223 if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
8224 outs() << " SUBSECTIONS_VIA_SYMBOLS";
8225 f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
8226 }
8227 if (f & MachO::MH_CANONICAL) {
8228 outs() << " CANONICAL";
8229 f &= ~MachO::MH_CANONICAL;
8230 }
8231 if (f & MachO::MH_WEAK_DEFINES) {
8232 outs() << " WEAK_DEFINES";
8233 f &= ~MachO::MH_WEAK_DEFINES;
8234 }
8235 if (f & MachO::MH_BINDS_TO_WEAK) {
8236 outs() << " BINDS_TO_WEAK";
8237 f &= ~MachO::MH_BINDS_TO_WEAK;
8238 }
8239 if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
8240 outs() << " ALLOW_STACK_EXECUTION";
8241 f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
8242 }
8243 if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
8244 outs() << " DEAD_STRIPPABLE_DYLIB";
8245 f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
8246 }
8247 if (f & MachO::MH_PIE) {
8248 outs() << " PIE";
8249 f &= ~MachO::MH_PIE;
8250 }
8251 if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
8252 outs() << " NO_REEXPORTED_DYLIBS";
8253 f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
8254 }
8255 if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
8256 outs() << " MH_HAS_TLV_DESCRIPTORS";
8257 f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
8258 }
8259 if (f & MachO::MH_NO_HEAP_EXECUTION) {
8260 outs() << " MH_NO_HEAP_EXECUTION";
8261 f &= ~MachO::MH_NO_HEAP_EXECUTION;
8262 }
8263 if (f & MachO::MH_APP_EXTENSION_SAFE) {
8264 outs() << " APP_EXTENSION_SAFE";
8265 f &= ~MachO::MH_APP_EXTENSION_SAFE;
8266 }
Kevin Enderbydf0d6da2017-06-19 19:38:22 +00008267 if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
8268 outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
8269 f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
8270 }
Kevin Enderbyb76d3862014-08-22 20:35:18 +00008271 if (f != 0 || flags == 0)
8272 outs() << format(" 0x%08" PRIx32, f);
8273 } else {
8274 outs() << format(" 0x%08" PRIx32, magic);
8275 outs() << format(" %7d", cputype);
8276 outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
8277 outs() << format(" 0x%02" PRIx32,
8278 (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
8279 outs() << format(" %10u", filetype);
8280 outs() << format(" %5u", ncmds);
8281 outs() << format(" %10u", sizeofcmds);
8282 outs() << format(" 0x%08" PRIx32, flags);
8283 }
8284 outs() << "\n";
8285}
8286
Kevin Enderby956366c2014-08-29 22:30:52 +00008287static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
8288 StringRef SegName, uint64_t vmaddr,
8289 uint64_t vmsize, uint64_t fileoff,
8290 uint64_t filesize, uint32_t maxprot,
8291 uint32_t initprot, uint32_t nsects,
8292 uint32_t flags, uint32_t object_size,
8293 bool verbose) {
8294 uint64_t expected_cmdsize;
8295 if (cmd == MachO::LC_SEGMENT) {
8296 outs() << " cmd LC_SEGMENT\n";
8297 expected_cmdsize = nsects;
8298 expected_cmdsize *= sizeof(struct MachO::section);
8299 expected_cmdsize += sizeof(struct MachO::segment_command);
8300 } else {
8301 outs() << " cmd LC_SEGMENT_64\n";
8302 expected_cmdsize = nsects;
8303 expected_cmdsize *= sizeof(struct MachO::section_64);
8304 expected_cmdsize += sizeof(struct MachO::segment_command_64);
8305 }
8306 outs() << " cmdsize " << cmdsize;
8307 if (cmdsize != expected_cmdsize)
8308 outs() << " Inconsistent size\n";
8309 else
8310 outs() << "\n";
8311 outs() << " segname " << SegName << "\n";
8312 if (cmd == MachO::LC_SEGMENT_64) {
8313 outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";
8314 outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";
8315 } else {
Kevin Enderbyadb7c432014-12-16 18:58:11 +00008316 outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";
8317 outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";
Kevin Enderby956366c2014-08-29 22:30:52 +00008318 }
8319 outs() << " fileoff " << fileoff;
8320 if (fileoff > object_size)
8321 outs() << " (past end of file)\n";
8322 else
8323 outs() << "\n";
8324 outs() << " filesize " << filesize;
8325 if (fileoff + filesize > object_size)
8326 outs() << " (past end of file)\n";
8327 else
8328 outs() << "\n";
8329 if (verbose) {
8330 if ((maxprot &
8331 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8332 MachO::VM_PROT_EXECUTE)) != 0)
8333 outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";
8334 else {
Davide Italiano37ff06a2015-09-02 16:53:25 +00008335 outs() << " maxprot ";
8336 outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-");
8337 outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8338 outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
Kevin Enderby956366c2014-08-29 22:30:52 +00008339 }
8340 if ((initprot &
8341 ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
8342 MachO::VM_PROT_EXECUTE)) != 0)
Kevin Enderby41c9c002016-10-21 18:22:35 +00008343 outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";
Kevin Enderby956366c2014-08-29 22:30:52 +00008344 else {
Kevin Enderby41c9c002016-10-21 18:22:35 +00008345 outs() << " initprot ";
Davide Italiano37ff06a2015-09-02 16:53:25 +00008346 outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-");
8347 outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-");
8348 outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n");
Kevin Enderby956366c2014-08-29 22:30:52 +00008349 }
8350 } else {
8351 outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";
8352 outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";
8353 }
8354 outs() << " nsects " << nsects << "\n";
8355 if (verbose) {
8356 outs() << " flags";
8357 if (flags == 0)
8358 outs() << " (none)\n";
8359 else {
8360 if (flags & MachO::SG_HIGHVM) {
8361 outs() << " HIGHVM";
8362 flags &= ~MachO::SG_HIGHVM;
8363 }
8364 if (flags & MachO::SG_FVMLIB) {
8365 outs() << " FVMLIB";
8366 flags &= ~MachO::SG_FVMLIB;
8367 }
8368 if (flags & MachO::SG_NORELOC) {
8369 outs() << " NORELOC";
8370 flags &= ~MachO::SG_NORELOC;
8371 }
8372 if (flags & MachO::SG_PROTECTED_VERSION_1) {
8373 outs() << " PROTECTED_VERSION_1";
8374 flags &= ~MachO::SG_PROTECTED_VERSION_1;
8375 }
8376 if (flags)
8377 outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
8378 else
8379 outs() << "\n";
8380 }
8381 } else {
8382 outs() << " flags " << format("0x%" PRIx32, flags) << "\n";
8383 }
8384}
8385
8386static void PrintSection(const char *sectname, const char *segname,
8387 uint64_t addr, uint64_t size, uint32_t offset,
8388 uint32_t align, uint32_t reloff, uint32_t nreloc,
8389 uint32_t flags, uint32_t reserved1, uint32_t reserved2,
8390 uint32_t cmd, const char *sg_segname,
8391 uint32_t filetype, uint32_t object_size,
8392 bool verbose) {
8393 outs() << "Section\n";
8394 outs() << " sectname " << format("%.16s\n", sectname);
8395 outs() << " segname " << format("%.16s", segname);
8396 if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)
8397 outs() << " (does not match segment)\n";
8398 else
8399 outs() << "\n";
8400 if (cmd == MachO::LC_SEGMENT_64) {
8401 outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";
8402 outs() << " size " << format("0x%016" PRIx64, size);
8403 } else {
Kevin Enderby75594b62014-12-16 21:00:25 +00008404 outs() << " addr " << format("0x%08" PRIx64, addr) << "\n";
8405 outs() << " size " << format("0x%08" PRIx64, size);
Kevin Enderby956366c2014-08-29 22:30:52 +00008406 }
8407 if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size)
8408 outs() << " (past end of file)\n";
8409 else
8410 outs() << "\n";
8411 outs() << " offset " << offset;
8412 if (offset > object_size)
8413 outs() << " (past end of file)\n";
8414 else
8415 outs() << "\n";
8416 uint32_t align_shifted = 1 << align;
8417 outs() << " align 2^" << align << " (" << align_shifted << ")\n";
8418 outs() << " reloff " << reloff;
8419 if (reloff > object_size)
8420 outs() << " (past end of file)\n";
8421 else
8422 outs() << "\n";
8423 outs() << " nreloc " << nreloc;
8424 if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
8425 outs() << " (past end of file)\n";
8426 else
8427 outs() << "\n";
8428 uint32_t section_type = flags & MachO::SECTION_TYPE;
8429 if (verbose) {
8430 outs() << " type";
8431 if (section_type == MachO::S_REGULAR)
8432 outs() << " S_REGULAR\n";
8433 else if (section_type == MachO::S_ZEROFILL)
8434 outs() << " S_ZEROFILL\n";
8435 else if (section_type == MachO::S_CSTRING_LITERALS)
8436 outs() << " S_CSTRING_LITERALS\n";
8437 else if (section_type == MachO::S_4BYTE_LITERALS)
8438 outs() << " S_4BYTE_LITERALS\n";
8439 else if (section_type == MachO::S_8BYTE_LITERALS)
8440 outs() << " S_8BYTE_LITERALS\n";
8441 else if (section_type == MachO::S_16BYTE_LITERALS)
8442 outs() << " S_16BYTE_LITERALS\n";
8443 else if (section_type == MachO::S_LITERAL_POINTERS)
8444 outs() << " S_LITERAL_POINTERS\n";
8445 else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
8446 outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
8447 else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
8448 outs() << " S_LAZY_SYMBOL_POINTERS\n";
8449 else if (section_type == MachO::S_SYMBOL_STUBS)
8450 outs() << " S_SYMBOL_STUBS\n";
8451 else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
8452 outs() << " S_MOD_INIT_FUNC_POINTERS\n";
8453 else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
8454 outs() << " S_MOD_TERM_FUNC_POINTERS\n";
8455 else if (section_type == MachO::S_COALESCED)
8456 outs() << " S_COALESCED\n";
8457 else if (section_type == MachO::S_INTERPOSING)
8458 outs() << " S_INTERPOSING\n";
8459 else if (section_type == MachO::S_DTRACE_DOF)
8460 outs() << " S_DTRACE_DOF\n";
8461 else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
8462 outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
8463 else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
8464 outs() << " S_THREAD_LOCAL_REGULAR\n";
8465 else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
8466 outs() << " S_THREAD_LOCAL_ZEROFILL\n";
8467 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
8468 outs() << " S_THREAD_LOCAL_VARIABLES\n";
8469 else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8470 outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
8471 else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
8472 outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
8473 else
8474 outs() << format("0x%08" PRIx32, section_type) << "\n";
8475 outs() << "attributes";
8476 uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
8477 if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
8478 outs() << " PURE_INSTRUCTIONS";
8479 if (section_attributes & MachO::S_ATTR_NO_TOC)
8480 outs() << " NO_TOC";
8481 if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
8482 outs() << " STRIP_STATIC_SYMS";
8483 if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
8484 outs() << " NO_DEAD_STRIP";
8485 if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
8486 outs() << " LIVE_SUPPORT";
8487 if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
8488 outs() << " SELF_MODIFYING_CODE";
8489 if (section_attributes & MachO::S_ATTR_DEBUG)
8490 outs() << " DEBUG";
8491 if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
8492 outs() << " SOME_INSTRUCTIONS";
8493 if (section_attributes & MachO::S_ATTR_EXT_RELOC)
8494 outs() << " EXT_RELOC";
8495 if (section_attributes & MachO::S_ATTR_LOC_RELOC)
8496 outs() << " LOC_RELOC";
8497 if (section_attributes == 0)
8498 outs() << " (none)";
8499 outs() << "\n";
8500 } else
8501 outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";
8502 outs() << " reserved1 " << reserved1;
8503 if (section_type == MachO::S_SYMBOL_STUBS ||
8504 section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
8505 section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
8506 section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
8507 section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
8508 outs() << " (index into indirect symbol table)\n";
8509 else
8510 outs() << "\n";
8511 outs() << " reserved2 " << reserved2;
8512 if (section_type == MachO::S_SYMBOL_STUBS)
8513 outs() << " (size of stubs)\n";
8514 else
8515 outs() << "\n";
8516}
8517
David Majnemer73cc6ff2014-11-13 19:48:56 +00008518static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
Kevin Enderby956366c2014-08-29 22:30:52 +00008519 uint32_t object_size) {
8520 outs() << " cmd LC_SYMTAB\n";
8521 outs() << " cmdsize " << st.cmdsize;
8522 if (st.cmdsize != sizeof(struct MachO::symtab_command))
8523 outs() << " Incorrect size\n";
8524 else
8525 outs() << "\n";
8526 outs() << " symoff " << st.symoff;
8527 if (st.symoff > object_size)
8528 outs() << " (past end of file)\n";
8529 else
8530 outs() << "\n";
8531 outs() << " nsyms " << st.nsyms;
8532 uint64_t big_size;
David Majnemer73cc6ff2014-11-13 19:48:56 +00008533 if (Is64Bit) {
Kevin Enderby956366c2014-08-29 22:30:52 +00008534 big_size = st.nsyms;
8535 big_size *= sizeof(struct MachO::nlist_64);
8536 big_size += st.symoff;
8537 if (big_size > object_size)
8538 outs() << " (past end of file)\n";
8539 else
8540 outs() << "\n";
8541 } else {
8542 big_size = st.nsyms;
8543 big_size *= sizeof(struct MachO::nlist);
8544 big_size += st.symoff;
8545 if (big_size > object_size)
8546 outs() << " (past end of file)\n";
8547 else
8548 outs() << "\n";
8549 }
8550 outs() << " stroff " << st.stroff;
8551 if (st.stroff > object_size)
8552 outs() << " (past end of file)\n";
8553 else
8554 outs() << "\n";
8555 outs() << " strsize " << st.strsize;
8556 big_size = st.stroff;
8557 big_size += st.strsize;
8558 if (big_size > object_size)
8559 outs() << " (past end of file)\n";
8560 else
8561 outs() << "\n";
8562}
8563
8564static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
8565 uint32_t nsyms, uint32_t object_size,
David Majnemer73cc6ff2014-11-13 19:48:56 +00008566 bool Is64Bit) {
Kevin Enderby956366c2014-08-29 22:30:52 +00008567 outs() << " cmd LC_DYSYMTAB\n";
8568 outs() << " cmdsize " << dyst.cmdsize;
8569 if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
8570 outs() << " Incorrect size\n";
8571 else
8572 outs() << "\n";
8573 outs() << " ilocalsym " << dyst.ilocalsym;
8574 if (dyst.ilocalsym > nsyms)
8575 outs() << " (greater than the number of symbols)\n";
8576 else
8577 outs() << "\n";
8578 outs() << " nlocalsym " << dyst.nlocalsym;
8579 uint64_t big_size;
8580 big_size = dyst.ilocalsym;
8581 big_size += dyst.nlocalsym;
8582 if (big_size > nsyms)
8583 outs() << " (past the end of the symbol table)\n";
8584 else
8585 outs() << "\n";
8586 outs() << " iextdefsym " << dyst.iextdefsym;
8587 if (dyst.iextdefsym > nsyms)
8588 outs() << " (greater than the number of symbols)\n";
8589 else
8590 outs() << "\n";
8591 outs() << " nextdefsym " << dyst.nextdefsym;
8592 big_size = dyst.iextdefsym;
8593 big_size += dyst.nextdefsym;
8594 if (big_size > nsyms)
8595 outs() << " (past the end of the symbol table)\n";
8596 else
8597 outs() << "\n";
8598 outs() << " iundefsym " << dyst.iundefsym;
8599 if (dyst.iundefsym > nsyms)
8600 outs() << " (greater than the number of symbols)\n";
8601 else
8602 outs() << "\n";
8603 outs() << " nundefsym " << dyst.nundefsym;
8604 big_size = dyst.iundefsym;
8605 big_size += dyst.nundefsym;
8606 if (big_size > nsyms)
8607 outs() << " (past the end of the symbol table)\n";
8608 else
8609 outs() << "\n";
8610 outs() << " tocoff " << dyst.tocoff;
8611 if (dyst.tocoff > object_size)
8612 outs() << " (past end of file)\n";
8613 else
8614 outs() << "\n";
8615 outs() << " ntoc " << dyst.ntoc;
8616 big_size = dyst.ntoc;
8617 big_size *= sizeof(struct MachO::dylib_table_of_contents);
8618 big_size += dyst.tocoff;
8619 if (big_size > object_size)
8620 outs() << " (past end of file)\n";
8621 else
8622 outs() << "\n";
8623 outs() << " modtaboff " << dyst.modtaboff;
8624 if (dyst.modtaboff > object_size)
8625 outs() << " (past end of file)\n";
8626 else
8627 outs() << "\n";
8628 outs() << " nmodtab " << dyst.nmodtab;
8629 uint64_t modtabend;
David Majnemer73cc6ff2014-11-13 19:48:56 +00008630 if (Is64Bit) {
Kevin Enderby956366c2014-08-29 22:30:52 +00008631 modtabend = dyst.nmodtab;
8632 modtabend *= sizeof(struct MachO::dylib_module_64);
8633 modtabend += dyst.modtaboff;
8634 } else {
8635 modtabend = dyst.nmodtab;
8636 modtabend *= sizeof(struct MachO::dylib_module);
8637 modtabend += dyst.modtaboff;
8638 }
8639 if (modtabend > object_size)
8640 outs() << " (past end of file)\n";
8641 else
8642 outs() << "\n";
8643 outs() << " extrefsymoff " << dyst.extrefsymoff;
8644 if (dyst.extrefsymoff > object_size)
8645 outs() << " (past end of file)\n";
8646 else
8647 outs() << "\n";
8648 outs() << " nextrefsyms " << dyst.nextrefsyms;
8649 big_size = dyst.nextrefsyms;
8650 big_size *= sizeof(struct MachO::dylib_reference);
8651 big_size += dyst.extrefsymoff;
8652 if (big_size > object_size)
8653 outs() << " (past end of file)\n";
8654 else
8655 outs() << "\n";
8656 outs() << " indirectsymoff " << dyst.indirectsymoff;
8657 if (dyst.indirectsymoff > object_size)
8658 outs() << " (past end of file)\n";
8659 else
8660 outs() << "\n";
8661 outs() << " nindirectsyms " << dyst.nindirectsyms;
8662 big_size = dyst.nindirectsyms;
8663 big_size *= sizeof(uint32_t);
8664 big_size += dyst.indirectsymoff;
8665 if (big_size > object_size)
8666 outs() << " (past end of file)\n";
8667 else
8668 outs() << "\n";
8669 outs() << " extreloff " << dyst.extreloff;
8670 if (dyst.extreloff > object_size)
8671 outs() << " (past end of file)\n";
8672 else
8673 outs() << "\n";
8674 outs() << " nextrel " << dyst.nextrel;
8675 big_size = dyst.nextrel;
8676 big_size *= sizeof(struct MachO::relocation_info);
8677 big_size += dyst.extreloff;
8678 if (big_size > object_size)
8679 outs() << " (past end of file)\n";
8680 else
8681 outs() << "\n";
8682 outs() << " locreloff " << dyst.locreloff;
8683 if (dyst.locreloff > object_size)
8684 outs() << " (past end of file)\n";
8685 else
8686 outs() << "\n";
8687 outs() << " nlocrel " << dyst.nlocrel;
8688 big_size = dyst.nlocrel;
8689 big_size *= sizeof(struct MachO::relocation_info);
8690 big_size += dyst.locreloff;
8691 if (big_size > object_size)
8692 outs() << " (past end of file)\n";
8693 else
8694 outs() << "\n";
8695}
8696
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008697static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
8698 uint32_t object_size) {
8699 if (dc.cmd == MachO::LC_DYLD_INFO)
8700 outs() << " cmd LC_DYLD_INFO\n";
8701 else
8702 outs() << " cmd LC_DYLD_INFO_ONLY\n";
8703 outs() << " cmdsize " << dc.cmdsize;
8704 if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
8705 outs() << " Incorrect size\n";
8706 else
8707 outs() << "\n";
8708 outs() << " rebase_off " << dc.rebase_off;
8709 if (dc.rebase_off > object_size)
8710 outs() << " (past end of file)\n";
8711 else
8712 outs() << "\n";
8713 outs() << " rebase_size " << dc.rebase_size;
8714 uint64_t big_size;
8715 big_size = dc.rebase_off;
8716 big_size += dc.rebase_size;
8717 if (big_size > object_size)
8718 outs() << " (past end of file)\n";
8719 else
8720 outs() << "\n";
8721 outs() << " bind_off " << dc.bind_off;
8722 if (dc.bind_off > object_size)
8723 outs() << " (past end of file)\n";
8724 else
8725 outs() << "\n";
8726 outs() << " bind_size " << dc.bind_size;
8727 big_size = dc.bind_off;
8728 big_size += dc.bind_size;
8729 if (big_size > object_size)
8730 outs() << " (past end of file)\n";
8731 else
8732 outs() << "\n";
8733 outs() << " weak_bind_off " << dc.weak_bind_off;
8734 if (dc.weak_bind_off > object_size)
8735 outs() << " (past end of file)\n";
8736 else
8737 outs() << "\n";
8738 outs() << " weak_bind_size " << dc.weak_bind_size;
8739 big_size = dc.weak_bind_off;
8740 big_size += dc.weak_bind_size;
8741 if (big_size > object_size)
8742 outs() << " (past end of file)\n";
8743 else
8744 outs() << "\n";
8745 outs() << " lazy_bind_off " << dc.lazy_bind_off;
8746 if (dc.lazy_bind_off > object_size)
8747 outs() << " (past end of file)\n";
8748 else
8749 outs() << "\n";
8750 outs() << " lazy_bind_size " << dc.lazy_bind_size;
8751 big_size = dc.lazy_bind_off;
8752 big_size += dc.lazy_bind_size;
8753 if (big_size > object_size)
8754 outs() << " (past end of file)\n";
8755 else
8756 outs() << "\n";
8757 outs() << " export_off " << dc.export_off;
8758 if (dc.export_off > object_size)
8759 outs() << " (past end of file)\n";
8760 else
8761 outs() << "\n";
8762 outs() << " export_size " << dc.export_size;
8763 big_size = dc.export_off;
8764 big_size += dc.export_size;
8765 if (big_size > object_size)
8766 outs() << " (past end of file)\n";
8767 else
8768 outs() << "\n";
8769}
8770
8771static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
8772 const char *Ptr) {
8773 if (dyld.cmd == MachO::LC_ID_DYLINKER)
8774 outs() << " cmd LC_ID_DYLINKER\n";
8775 else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
8776 outs() << " cmd LC_LOAD_DYLINKER\n";
8777 else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
8778 outs() << " cmd LC_DYLD_ENVIRONMENT\n";
8779 else
8780 outs() << " cmd ?(" << dyld.cmd << ")\n";
8781 outs() << " cmdsize " << dyld.cmdsize;
8782 if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
8783 outs() << " Incorrect size\n";
8784 else
8785 outs() << "\n";
8786 if (dyld.name >= dyld.cmdsize)
8787 outs() << " name ?(bad offset " << dyld.name << ")\n";
8788 else {
Kevin Enderbyb28ed012014-10-29 21:28:24 +00008789 const char *P = (const char *)(Ptr) + dyld.name;
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008790 outs() << " name " << P << " (offset " << dyld.name << ")\n";
8791 }
8792}
8793
8794static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
8795 outs() << " cmd LC_UUID\n";
8796 outs() << " cmdsize " << uuid.cmdsize;
8797 if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
8798 outs() << " Incorrect size\n";
8799 else
8800 outs() << "\n";
8801 outs() << " uuid ";
Davide Italianoc74277a2015-12-07 00:03:28 +00008802 for (int i = 0; i < 16; ++i) {
8803 outs() << format("%02" PRIX32, uuid.uuid[i]);
8804 if (i == 3 || i == 5 || i == 7 || i == 9)
8805 outs() << "-";
8806 }
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008807 outs() << "\n";
8808}
8809
Kevin Enderby66d51fc2015-01-08 00:25:24 +00008810static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) {
Jean-Daniel Dupas00cc1f52014-12-04 07:37:02 +00008811 outs() << " cmd LC_RPATH\n";
8812 outs() << " cmdsize " << rpath.cmdsize;
8813 if (rpath.cmdsize < sizeof(struct MachO::rpath_command))
8814 outs() << " Incorrect size\n";
8815 else
8816 outs() << "\n";
8817 if (rpath.path >= rpath.cmdsize)
8818 outs() << " path ?(bad offset " << rpath.path << ")\n";
8819 else {
8820 const char *P = (const char *)(Ptr) + rpath.path;
8821 outs() << " path " << P << " (offset " << rpath.path << ")\n";
8822 }
8823}
8824
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008825static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
Tim Northoverbfbfb122015-11-02 21:26:58 +00008826 StringRef LoadCmdName;
8827 switch (vd.cmd) {
8828 case MachO::LC_VERSION_MIN_MACOSX:
8829 LoadCmdName = "LC_VERSION_MIN_MACOSX";
8830 break;
8831 case MachO::LC_VERSION_MIN_IPHONEOS:
8832 LoadCmdName = "LC_VERSION_MIN_IPHONEOS";
8833 break;
8834 case MachO::LC_VERSION_MIN_TVOS:
8835 LoadCmdName = "LC_VERSION_MIN_TVOS";
8836 break;
8837 case MachO::LC_VERSION_MIN_WATCHOS:
8838 LoadCmdName = "LC_VERSION_MIN_WATCHOS";
8839 break;
8840 default:
8841 llvm_unreachable("Unknown version min load command");
8842 }
8843
8844 outs() << " cmd " << LoadCmdName << '\n';
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008845 outs() << " cmdsize " << vd.cmdsize;
8846 if (vd.cmdsize != sizeof(struct MachO::version_min_command))
8847 outs() << " Incorrect size\n";
8848 else
8849 outs() << "\n";
Davide Italiano56baef32015-08-26 12:26:11 +00008850 outs() << " version "
8851 << MachOObjectFile::getVersionMinMajor(vd, false) << "."
8852 << MachOObjectFile::getVersionMinMinor(vd, false);
8853 uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false);
8854 if (Update != 0)
8855 outs() << "." << Update;
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008856 outs() << "\n";
8857 if (vd.sdk == 0)
Kevin Enderby57538292014-12-17 01:01:30 +00008858 outs() << " sdk n/a";
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008859 else {
Davide Italiano56baef32015-08-26 12:26:11 +00008860 outs() << " sdk "
8861 << MachOObjectFile::getVersionMinMajor(vd, true) << "."
8862 << MachOObjectFile::getVersionMinMinor(vd, true);
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008863 }
Davide Italiano56baef32015-08-26 12:26:11 +00008864 Update = MachOObjectFile::getVersionMinUpdate(vd, true);
8865 if (Update != 0)
8866 outs() << "." << Update;
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008867 outs() << "\n";
8868}
8869
Kevin Enderbya4579c42017-01-19 17:36:31 +00008870static void PrintNoteLoadCommand(MachO::note_command Nt) {
8871 outs() << " cmd LC_NOTE\n";
8872 outs() << " cmdsize " << Nt.cmdsize;
8873 if (Nt.cmdsize != sizeof(struct MachO::note_command))
8874 outs() << " Incorrect size\n";
8875 else
8876 outs() << "\n";
8877 const char *d = Nt.data_owner;
8878 outs() << "data_owner " << format("%.16s\n", d);
8879 outs() << " offset " << Nt.offset << "\n";
8880 outs() << " size " << Nt.size << "\n";
8881}
8882
Steven Wu5b54a422017-01-23 20:07:55 +00008883static void PrintBuildToolVersion(MachO::build_tool_version bv) {
8884 outs() << " tool " << MachOObjectFile::getBuildTool(bv.tool) << "\n";
8885 outs() << " version " << MachOObjectFile::getVersionString(bv.version)
8886 << "\n";
8887}
8888
8889static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
8890 MachO::build_version_command bd) {
8891 outs() << " cmd LC_BUILD_VERSION\n";
8892 outs() << " cmdsize " << bd.cmdsize;
8893 if (bd.cmdsize !=
8894 sizeof(struct MachO::build_version_command) +
8895 bd.ntools * sizeof(struct MachO::build_tool_version))
8896 outs() << " Incorrect size\n";
8897 else
8898 outs() << "\n";
8899 outs() << " platform " << MachOObjectFile::getBuildPlatform(bd.platform)
8900 << "\n";
8901 if (bd.sdk)
8902 outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
8903 << "\n";
8904 else
8905 outs() << " sdk n/a\n";
8906 outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
8907 << "\n";
8908 outs() << " ntools " << bd.ntools << "\n";
8909 for (unsigned i = 0; i < bd.ntools; ++i) {
8910 MachO::build_tool_version bv = obj->getBuildToolVersion(i);
8911 PrintBuildToolVersion(bv);
8912 }
8913}
8914
Kevin Enderby8ae63c12014-09-04 16:54:47 +00008915static void PrintSourceVersionCommand(MachO::source_version_command sd) {
8916 outs() << " cmd LC_SOURCE_VERSION\n";
8917 outs() << " cmdsize " << sd.cmdsize;
8918 if (sd.cmdsize != sizeof(struct MachO::source_version_command))
8919 outs() << " Incorrect size\n";
8920 else
8921 outs() << "\n";
8922 uint64_t a = (sd.version >> 40) & 0xffffff;
8923 uint64_t b = (sd.version >> 30) & 0x3ff;
8924 uint64_t c = (sd.version >> 20) & 0x3ff;
8925 uint64_t d = (sd.version >> 10) & 0x3ff;
8926 uint64_t e = sd.version & 0x3ff;
8927 outs() << " version " << a << "." << b;
8928 if (e != 0)
8929 outs() << "." << c << "." << d << "." << e;
8930 else if (d != 0)
8931 outs() << "." << c << "." << d;
8932 else if (c != 0)
8933 outs() << "." << c;
8934 outs() << "\n";
8935}
8936
8937static void PrintEntryPointCommand(MachO::entry_point_command ep) {
8938 outs() << " cmd LC_MAIN\n";
8939 outs() << " cmdsize " << ep.cmdsize;
8940 if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
8941 outs() << " Incorrect size\n";
8942 else
8943 outs() << "\n";
8944 outs() << " entryoff " << ep.entryoff << "\n";
8945 outs() << " stacksize " << ep.stacksize << "\n";
8946}
8947
Kevin Enderby0804f4672014-12-16 23:25:52 +00008948static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec,
8949 uint32_t object_size) {
8950 outs() << " cmd LC_ENCRYPTION_INFO\n";
8951 outs() << " cmdsize " << ec.cmdsize;
8952 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command))
8953 outs() << " Incorrect size\n";
8954 else
8955 outs() << "\n";
8956 outs() << " cryptoff " << ec.cryptoff;
8957 if (ec.cryptoff > object_size)
8958 outs() << " (past end of file)\n";
8959 else
8960 outs() << "\n";
8961 outs() << " cryptsize " << ec.cryptsize;
8962 if (ec.cryptsize > object_size)
8963 outs() << " (past end of file)\n";
8964 else
8965 outs() << "\n";
8966 outs() << " cryptid " << ec.cryptid << "\n";
8967}
8968
Kevin Enderby57538292014-12-17 01:01:30 +00008969static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec,
Kevin Enderby66d51fc2015-01-08 00:25:24 +00008970 uint32_t object_size) {
Kevin Enderby57538292014-12-17 01:01:30 +00008971 outs() << " cmd LC_ENCRYPTION_INFO_64\n";
8972 outs() << " cmdsize " << ec.cmdsize;
8973 if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64))
8974 outs() << " Incorrect size\n";
8975 else
8976 outs() << "\n";
8977 outs() << " cryptoff " << ec.cryptoff;
8978 if (ec.cryptoff > object_size)
8979 outs() << " (past end of file)\n";
8980 else
8981 outs() << "\n";
8982 outs() << " cryptsize " << ec.cryptsize;
8983 if (ec.cryptsize > object_size)
8984 outs() << " (past end of file)\n";
8985 else
8986 outs() << "\n";
8987 outs() << " cryptid " << ec.cryptid << "\n";
8988 outs() << " pad " << ec.pad << "\n";
8989}
8990
Kevin Enderbyd0b6b7f2014-12-18 00:53:40 +00008991static void PrintLinkerOptionCommand(MachO::linker_option_command lo,
8992 const char *Ptr) {
8993 outs() << " cmd LC_LINKER_OPTION\n";
8994 outs() << " cmdsize " << lo.cmdsize;
8995 if (lo.cmdsize < sizeof(struct MachO::linker_option_command))
8996 outs() << " Incorrect size\n";
8997 else
8998 outs() << "\n";
8999 outs() << " count " << lo.count << "\n";
9000 const char *string = Ptr + sizeof(struct MachO::linker_option_command);
9001 uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command);
9002 uint32_t i = 0;
9003 while (left > 0) {
9004 while (*string == '\0' && left > 0) {
9005 string++;
9006 left--;
9007 }
9008 if (left > 0) {
9009 i++;
9010 outs() << " string #" << i << " " << format("%.*s\n", left, string);
David Majnemerd4449ed2014-12-20 08:24:43 +00009011 uint32_t NullPos = StringRef(string, left).find('\0');
9012 uint32_t len = std::min(NullPos, left) + 1;
Kevin Enderbyd0b6b7f2014-12-18 00:53:40 +00009013 string += len;
9014 left -= len;
9015 }
9016 }
9017 if (lo.count != i)
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009018 outs() << " count " << lo.count << " does not match number of strings "
9019 << i << "\n";
Kevin Enderbyd0b6b7f2014-12-18 00:53:40 +00009020}
9021
Kevin Enderbyb4b79312014-12-18 19:24:35 +00009022static void PrintSubFrameworkCommand(MachO::sub_framework_command sub,
9023 const char *Ptr) {
9024 outs() << " cmd LC_SUB_FRAMEWORK\n";
9025 outs() << " cmdsize " << sub.cmdsize;
9026 if (sub.cmdsize < sizeof(struct MachO::sub_framework_command))
9027 outs() << " Incorrect size\n";
9028 else
9029 outs() << "\n";
9030 if (sub.umbrella < sub.cmdsize) {
9031 const char *P = Ptr + sub.umbrella;
9032 outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n";
9033 } else {
9034 outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n";
9035 }
9036}
9037
Kevin Enderbya2bd8d92014-12-18 23:13:26 +00009038static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub,
9039 const char *Ptr) {
9040 outs() << " cmd LC_SUB_UMBRELLA\n";
9041 outs() << " cmdsize " << sub.cmdsize;
9042 if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command))
9043 outs() << " Incorrect size\n";
9044 else
9045 outs() << "\n";
9046 if (sub.sub_umbrella < sub.cmdsize) {
9047 const char *P = Ptr + sub.sub_umbrella;
9048 outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n";
9049 } else {
9050 outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n";
9051 }
9052}
9053
Kevin Enderby36c8d3a2014-12-19 19:48:16 +00009054static void PrintSubLibraryCommand(MachO::sub_library_command sub,
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009055 const char *Ptr) {
Kevin Enderby36c8d3a2014-12-19 19:48:16 +00009056 outs() << " cmd LC_SUB_LIBRARY\n";
9057 outs() << " cmdsize " << sub.cmdsize;
9058 if (sub.cmdsize < sizeof(struct MachO::sub_library_command))
9059 outs() << " Incorrect size\n";
9060 else
9061 outs() << "\n";
9062 if (sub.sub_library < sub.cmdsize) {
9063 const char *P = Ptr + sub.sub_library;
9064 outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n";
9065 } else {
9066 outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n";
9067 }
9068}
9069
Kevin Enderby186eac32014-12-19 21:06:24 +00009070static void PrintSubClientCommand(MachO::sub_client_command sub,
9071 const char *Ptr) {
9072 outs() << " cmd LC_SUB_CLIENT\n";
9073 outs() << " cmdsize " << sub.cmdsize;
9074 if (sub.cmdsize < sizeof(struct MachO::sub_client_command))
9075 outs() << " Incorrect size\n";
9076 else
9077 outs() << "\n";
9078 if (sub.client < sub.cmdsize) {
9079 const char *P = Ptr + sub.client;
9080 outs() << " client " << P << " (offset " << sub.client << ")\n";
9081 } else {
9082 outs() << " client ?(bad offset " << sub.client << ")\n";
9083 }
9084}
Kevin Enderby36c8d3a2014-12-19 19:48:16 +00009085
Kevin Enderby52e4ce42014-12-19 22:25:22 +00009086static void PrintRoutinesCommand(MachO::routines_command r) {
9087 outs() << " cmd LC_ROUTINES\n";
9088 outs() << " cmdsize " << r.cmdsize;
9089 if (r.cmdsize != sizeof(struct MachO::routines_command))
9090 outs() << " Incorrect size\n";
9091 else
9092 outs() << "\n";
9093 outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n";
9094 outs() << " init_module " << r.init_module << "\n";
9095 outs() << " reserved1 " << r.reserved1 << "\n";
9096 outs() << " reserved2 " << r.reserved2 << "\n";
9097 outs() << " reserved3 " << r.reserved3 << "\n";
9098 outs() << " reserved4 " << r.reserved4 << "\n";
9099 outs() << " reserved5 " << r.reserved5 << "\n";
9100 outs() << " reserved6 " << r.reserved6 << "\n";
9101}
9102
9103static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
9104 outs() << " cmd LC_ROUTINES_64\n";
9105 outs() << " cmdsize " << r.cmdsize;
9106 if (r.cmdsize != sizeof(struct MachO::routines_command_64))
9107 outs() << " Incorrect size\n";
9108 else
9109 outs() << "\n";
9110 outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n";
9111 outs() << " init_module " << r.init_module << "\n";
9112 outs() << " reserved1 " << r.reserved1 << "\n";
9113 outs() << " reserved2 " << r.reserved2 << "\n";
9114 outs() << " reserved3 " << r.reserved3 << "\n";
9115 outs() << " reserved4 " << r.reserved4 << "\n";
9116 outs() << " reserved5 " << r.reserved5 << "\n";
9117 outs() << " reserved6 " << r.reserved6 << "\n";
9118}
9119
Kevin Enderbyc3a035d2017-01-23 21:13:29 +00009120static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
9121 outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);
9122 outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);
9123 outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);
9124 outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";
9125 outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);
9126 outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);
9127 outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);
9128 outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";
9129 outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);
9130 outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);
9131 outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);
9132 outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";
9133 outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);
9134 outs() << " es " << format("0x%08" PRIx32, cpu32.es);
9135 outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);
9136 outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";
9137}
9138
Kevin Enderby48ef5342014-12-23 22:56:39 +00009139static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
9140 outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
9141 outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
9142 outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n";
9143 outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx);
9144 outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi);
9145 outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n";
9146 outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp);
9147 outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp);
9148 outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n";
9149 outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9);
9150 outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10);
9151 outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n";
9152 outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12);
9153 outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13);
9154 outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n";
9155 outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15);
9156 outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n";
9157 outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags);
9158 outs() << " cs " << format("0x%016" PRIx64, cpu64.cs);
9159 outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n";
9160 outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n";
9161}
9162
Kevin Enderby227df342014-12-23 23:43:59 +00009163static void Print_mmst_reg(MachO::mmst_reg_t &r) {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009164 uint32_t f;
9165 outs() << "\t mmst_reg ";
9166 for (f = 0; f < 10; f++)
9167 outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " ";
9168 outs() << "\n";
9169 outs() << "\t mmst_rsrv ";
9170 for (f = 0; f < 6; f++)
9171 outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " ";
9172 outs() << "\n";
9173}
9174
Kevin Enderbyaefb0032014-12-24 00:16:51 +00009175static void Print_xmm_reg(MachO::xmm_reg_t &r) {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009176 uint32_t f;
9177 outs() << "\t xmm_reg ";
9178 for (f = 0; f < 16; f++)
9179 outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " ";
9180 outs() << "\n";
9181}
9182
9183static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) {
9184 outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0];
9185 outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n";
9186 outs() << "\t control: invalid " << fpu.fpu_fcw.invalid;
9187 outs() << " denorm " << fpu.fpu_fcw.denorm;
9188 outs() << " zdiv " << fpu.fpu_fcw.zdiv;
9189 outs() << " ovrfl " << fpu.fpu_fcw.ovrfl;
9190 outs() << " undfl " << fpu.fpu_fcw.undfl;
9191 outs() << " precis " << fpu.fpu_fcw.precis << "\n";
9192 outs() << "\t\t pc ";
9193 if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B)
9194 outs() << "FP_PREC_24B ";
9195 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B)
9196 outs() << "FP_PREC_53B ";
9197 else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B)
9198 outs() << "FP_PREC_64B ";
9199 else
9200 outs() << fpu.fpu_fcw.pc << " ";
9201 outs() << "rc ";
9202 if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR)
9203 outs() << "FP_RND_NEAR ";
9204 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN)
9205 outs() << "FP_RND_DOWN ";
9206 else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP)
9207 outs() << "FP_RND_UP ";
9208 else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP)
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009209 outs() << "FP_CHOP ";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009210 outs() << "\n";
9211 outs() << "\t status: invalid " << fpu.fpu_fsw.invalid;
9212 outs() << " denorm " << fpu.fpu_fsw.denorm;
9213 outs() << " zdiv " << fpu.fpu_fsw.zdiv;
9214 outs() << " ovrfl " << fpu.fpu_fsw.ovrfl;
9215 outs() << " undfl " << fpu.fpu_fsw.undfl;
9216 outs() << " precis " << fpu.fpu_fsw.precis;
9217 outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n";
9218 outs() << "\t errsumm " << fpu.fpu_fsw.errsumm;
9219 outs() << " c0 " << fpu.fpu_fsw.c0;
9220 outs() << " c1 " << fpu.fpu_fsw.c1;
9221 outs() << " c2 " << fpu.fpu_fsw.c2;
9222 outs() << " tos " << fpu.fpu_fsw.tos;
9223 outs() << " c3 " << fpu.fpu_fsw.c3;
9224 outs() << " busy " << fpu.fpu_fsw.busy << "\n";
9225 outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw);
9226 outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1);
9227 outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop);
9228 outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n";
9229 outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs);
9230 outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2);
9231 outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp);
9232 outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n";
9233 outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3);
9234 outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr);
9235 outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask);
9236 outs() << "\n";
9237 outs() << "\t fpu_stmm0:\n";
9238 Print_mmst_reg(fpu.fpu_stmm0);
9239 outs() << "\t fpu_stmm1:\n";
9240 Print_mmst_reg(fpu.fpu_stmm1);
9241 outs() << "\t fpu_stmm2:\n";
9242 Print_mmst_reg(fpu.fpu_stmm2);
9243 outs() << "\t fpu_stmm3:\n";
9244 Print_mmst_reg(fpu.fpu_stmm3);
9245 outs() << "\t fpu_stmm4:\n";
9246 Print_mmst_reg(fpu.fpu_stmm4);
9247 outs() << "\t fpu_stmm5:\n";
9248 Print_mmst_reg(fpu.fpu_stmm5);
9249 outs() << "\t fpu_stmm6:\n";
9250 Print_mmst_reg(fpu.fpu_stmm6);
9251 outs() << "\t fpu_stmm7:\n";
9252 Print_mmst_reg(fpu.fpu_stmm7);
9253 outs() << "\t fpu_xmm0:\n";
9254 Print_xmm_reg(fpu.fpu_xmm0);
9255 outs() << "\t fpu_xmm1:\n";
9256 Print_xmm_reg(fpu.fpu_xmm1);
9257 outs() << "\t fpu_xmm2:\n";
9258 Print_xmm_reg(fpu.fpu_xmm2);
9259 outs() << "\t fpu_xmm3:\n";
9260 Print_xmm_reg(fpu.fpu_xmm3);
9261 outs() << "\t fpu_xmm4:\n";
9262 Print_xmm_reg(fpu.fpu_xmm4);
9263 outs() << "\t fpu_xmm5:\n";
9264 Print_xmm_reg(fpu.fpu_xmm5);
9265 outs() << "\t fpu_xmm6:\n";
9266 Print_xmm_reg(fpu.fpu_xmm6);
9267 outs() << "\t fpu_xmm7:\n";
9268 Print_xmm_reg(fpu.fpu_xmm7);
9269 outs() << "\t fpu_xmm8:\n";
9270 Print_xmm_reg(fpu.fpu_xmm8);
9271 outs() << "\t fpu_xmm9:\n";
9272 Print_xmm_reg(fpu.fpu_xmm9);
9273 outs() << "\t fpu_xmm10:\n";
9274 Print_xmm_reg(fpu.fpu_xmm10);
9275 outs() << "\t fpu_xmm11:\n";
9276 Print_xmm_reg(fpu.fpu_xmm11);
9277 outs() << "\t fpu_xmm12:\n";
9278 Print_xmm_reg(fpu.fpu_xmm12);
9279 outs() << "\t fpu_xmm13:\n";
9280 Print_xmm_reg(fpu.fpu_xmm13);
9281 outs() << "\t fpu_xmm14:\n";
9282 Print_xmm_reg(fpu.fpu_xmm14);
9283 outs() << "\t fpu_xmm15:\n";
9284 Print_xmm_reg(fpu.fpu_xmm15);
9285 outs() << "\t fpu_rsrv4:\n";
9286 for (uint32_t f = 0; f < 6; f++) {
9287 outs() << "\t ";
9288 for (uint32_t g = 0; g < 16; g++)
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009289 outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " ";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009290 outs() << "\n";
9291 }
9292 outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1);
9293 outs() << "\n";
9294}
9295
9296static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) {
9297 outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno);
9298 outs() << " err " << format("0x%08" PRIx32, exc64.err);
9299 outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n";
9300}
9301
Kevin Enderby41c9c002016-10-21 18:22:35 +00009302static void Print_arm_thread_state32_t(MachO::arm_thread_state32_t &cpu32) {
9303 outs() << "\t r0 " << format("0x%08" PRIx32, cpu32.r[0]);
9304 outs() << " r1 " << format("0x%08" PRIx32, cpu32.r[1]);
9305 outs() << " r2 " << format("0x%08" PRIx32, cpu32.r[2]);
9306 outs() << " r3 " << format("0x%08" PRIx32, cpu32.r[3]) << "\n";
9307 outs() << "\t r4 " << format("0x%08" PRIx32, cpu32.r[4]);
9308 outs() << " r5 " << format("0x%08" PRIx32, cpu32.r[5]);
9309 outs() << " r6 " << format("0x%08" PRIx32, cpu32.r[6]);
9310 outs() << " r7 " << format("0x%08" PRIx32, cpu32.r[7]) << "\n";
9311 outs() << "\t r8 " << format("0x%08" PRIx32, cpu32.r[8]);
9312 outs() << " r9 " << format("0x%08" PRIx32, cpu32.r[9]);
9313 outs() << " r10 " << format("0x%08" PRIx32, cpu32.r[10]);
9314 outs() << " r11 " << format("0x%08" PRIx32, cpu32.r[11]) << "\n";
9315 outs() << "\t r12 " << format("0x%08" PRIx32, cpu32.r[12]);
9316 outs() << " sp " << format("0x%08" PRIx32, cpu32.sp);
9317 outs() << " lr " << format("0x%08" PRIx32, cpu32.lr);
9318 outs() << " pc " << format("0x%08" PRIx32, cpu32.pc) << "\n";
9319 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu32.cpsr) << "\n";
9320}
9321
Kevin Enderby7747cb52016-11-03 20:51:28 +00009322static void Print_arm_thread_state64_t(MachO::arm_thread_state64_t &cpu64) {
9323 outs() << "\t x0 " << format("0x%016" PRIx64, cpu64.x[0]);
9324 outs() << " x1 " << format("0x%016" PRIx64, cpu64.x[1]);
9325 outs() << " x2 " << format("0x%016" PRIx64, cpu64.x[2]) << "\n";
9326 outs() << "\t x3 " << format("0x%016" PRIx64, cpu64.x[3]);
9327 outs() << " x4 " << format("0x%016" PRIx64, cpu64.x[4]);
9328 outs() << " x5 " << format("0x%016" PRIx64, cpu64.x[5]) << "\n";
9329 outs() << "\t x6 " << format("0x%016" PRIx64, cpu64.x[6]);
9330 outs() << " x7 " << format("0x%016" PRIx64, cpu64.x[7]);
9331 outs() << " x8 " << format("0x%016" PRIx64, cpu64.x[8]) << "\n";
9332 outs() << "\t x9 " << format("0x%016" PRIx64, cpu64.x[9]);
9333 outs() << " x10 " << format("0x%016" PRIx64, cpu64.x[10]);
9334 outs() << " x11 " << format("0x%016" PRIx64, cpu64.x[11]) << "\n";
9335 outs() << "\t x12 " << format("0x%016" PRIx64, cpu64.x[12]);
9336 outs() << " x13 " << format("0x%016" PRIx64, cpu64.x[13]);
9337 outs() << " x14 " << format("0x%016" PRIx64, cpu64.x[14]) << "\n";
9338 outs() << "\t x15 " << format("0x%016" PRIx64, cpu64.x[15]);
9339 outs() << " x16 " << format("0x%016" PRIx64, cpu64.x[16]);
9340 outs() << " x17 " << format("0x%016" PRIx64, cpu64.x[17]) << "\n";
9341 outs() << "\t x18 " << format("0x%016" PRIx64, cpu64.x[18]);
9342 outs() << " x19 " << format("0x%016" PRIx64, cpu64.x[19]);
9343 outs() << " x20 " << format("0x%016" PRIx64, cpu64.x[20]) << "\n";
9344 outs() << "\t x21 " << format("0x%016" PRIx64, cpu64.x[21]);
9345 outs() << " x22 " << format("0x%016" PRIx64, cpu64.x[22]);
9346 outs() << " x23 " << format("0x%016" PRIx64, cpu64.x[23]) << "\n";
9347 outs() << "\t x24 " << format("0x%016" PRIx64, cpu64.x[24]);
9348 outs() << " x25 " << format("0x%016" PRIx64, cpu64.x[25]);
9349 outs() << " x26 " << format("0x%016" PRIx64, cpu64.x[26]) << "\n";
9350 outs() << "\t x27 " << format("0x%016" PRIx64, cpu64.x[27]);
9351 outs() << " x28 " << format("0x%016" PRIx64, cpu64.x[28]);
9352 outs() << " fp " << format("0x%016" PRIx64, cpu64.fp) << "\n";
9353 outs() << "\t lr " << format("0x%016" PRIx64, cpu64.lr);
9354 outs() << " sp " << format("0x%016" PRIx64, cpu64.sp);
9355 outs() << " pc " << format("0x%016" PRIx64, cpu64.pc) << "\n";
9356 outs() << "\t cpsr " << format("0x%08" PRIx32, cpu64.cpsr) << "\n";
9357}
9358
Kevin Enderby48ef5342014-12-23 22:56:39 +00009359static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
9360 bool isLittleEndian, uint32_t cputype) {
9361 if (t.cmd == MachO::LC_THREAD)
9362 outs() << " cmd LC_THREAD\n";
9363 else if (t.cmd == MachO::LC_UNIXTHREAD)
9364 outs() << " cmd LC_UNIXTHREAD\n";
9365 else
9366 outs() << " cmd " << t.cmd << " (unknown)\n";
9367 outs() << " cmdsize " << t.cmdsize;
9368 if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t))
9369 outs() << " Incorrect size\n";
9370 else
9371 outs() << "\n";
9372
9373 const char *begin = Ptr + sizeof(struct MachO::thread_command);
9374 const char *end = Ptr + t.cmdsize;
9375 uint32_t flavor, count, left;
Kevin Enderbyc3a035d2017-01-23 21:13:29 +00009376 if (cputype == MachO::CPU_TYPE_I386) {
9377 while (begin < end) {
9378 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9379 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9380 begin += sizeof(uint32_t);
9381 } else {
9382 flavor = 0;
9383 begin = end;
9384 }
9385 if (isLittleEndian != sys::IsLittleEndianHost)
9386 sys::swapByteOrder(flavor);
9387 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9388 memcpy((char *)&count, begin, sizeof(uint32_t));
9389 begin += sizeof(uint32_t);
9390 } else {
9391 count = 0;
9392 begin = end;
9393 }
9394 if (isLittleEndian != sys::IsLittleEndianHost)
9395 sys::swapByteOrder(count);
9396 if (flavor == MachO::x86_THREAD_STATE32) {
9397 outs() << " flavor i386_THREAD_STATE\n";
9398 if (count == MachO::x86_THREAD_STATE32_COUNT)
9399 outs() << " count i386_THREAD_STATE_COUNT\n";
9400 else
9401 outs() << " count " << count
9402 << " (not x86_THREAD_STATE32_COUNT)\n";
9403 MachO::x86_thread_state32_t cpu32;
9404 left = end - begin;
9405 if (left >= sizeof(MachO::x86_thread_state32_t)) {
9406 memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));
9407 begin += sizeof(MachO::x86_thread_state32_t);
9408 } else {
9409 memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));
9410 memcpy(&cpu32, begin, left);
9411 begin += left;
9412 }
9413 if (isLittleEndian != sys::IsLittleEndianHost)
9414 swapStruct(cpu32);
9415 Print_x86_thread_state32_t(cpu32);
9416 } else if (flavor == MachO::x86_THREAD_STATE) {
9417 outs() << " flavor x86_THREAD_STATE\n";
9418 if (count == MachO::x86_THREAD_STATE_COUNT)
9419 outs() << " count x86_THREAD_STATE_COUNT\n";
9420 else
9421 outs() << " count " << count
9422 << " (not x86_THREAD_STATE_COUNT)\n";
9423 struct MachO::x86_thread_state_t ts;
9424 left = end - begin;
9425 if (left >= sizeof(MachO::x86_thread_state_t)) {
9426 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9427 begin += sizeof(MachO::x86_thread_state_t);
9428 } else {
9429 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9430 memcpy(&ts, begin, left);
9431 begin += left;
9432 }
9433 if (isLittleEndian != sys::IsLittleEndianHost)
9434 swapStruct(ts);
9435 if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
9436 outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
9437 if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
9438 outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
9439 else
9440 outs() << "tsh.count " << ts.tsh.count
9441 << " (not x86_THREAD_STATE32_COUNT\n";
9442 Print_x86_thread_state32_t(ts.uts.ts32);
9443 } else {
9444 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9445 << ts.tsh.count << "\n";
9446 }
9447 } else {
9448 outs() << " flavor " << flavor << " (unknown)\n";
9449 outs() << " count " << count << "\n";
9450 outs() << " state (unknown)\n";
9451 begin += count * sizeof(uint32_t);
9452 }
9453 }
9454 } else if (cputype == MachO::CPU_TYPE_X86_64) {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009455 while (begin < end) {
9456 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9457 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9458 begin += sizeof(uint32_t);
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009459 } else {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009460 flavor = 0;
9461 begin = end;
9462 }
9463 if (isLittleEndian != sys::IsLittleEndianHost)
9464 sys::swapByteOrder(flavor);
9465 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9466 memcpy((char *)&count, begin, sizeof(uint32_t));
9467 begin += sizeof(uint32_t);
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009468 } else {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009469 count = 0;
9470 begin = end;
9471 }
9472 if (isLittleEndian != sys::IsLittleEndianHost)
9473 sys::swapByteOrder(count);
9474 if (flavor == MachO::x86_THREAD_STATE64) {
9475 outs() << " flavor x86_THREAD_STATE64\n";
9476 if (count == MachO::x86_THREAD_STATE64_COUNT)
9477 outs() << " count x86_THREAD_STATE64_COUNT\n";
9478 else
9479 outs() << " count " << count
9480 << " (not x86_THREAD_STATE64_COUNT)\n";
9481 MachO::x86_thread_state64_t cpu64;
9482 left = end - begin;
9483 if (left >= sizeof(MachO::x86_thread_state64_t)) {
9484 memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t));
9485 begin += sizeof(MachO::x86_thread_state64_t);
9486 } else {
9487 memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t));
9488 memcpy(&cpu64, begin, left);
9489 begin += left;
9490 }
9491 if (isLittleEndian != sys::IsLittleEndianHost)
9492 swapStruct(cpu64);
9493 Print_x86_thread_state64_t(cpu64);
9494 } else if (flavor == MachO::x86_THREAD_STATE) {
9495 outs() << " flavor x86_THREAD_STATE\n";
9496 if (count == MachO::x86_THREAD_STATE_COUNT)
9497 outs() << " count x86_THREAD_STATE_COUNT\n";
9498 else
9499 outs() << " count " << count
9500 << " (not x86_THREAD_STATE_COUNT)\n";
9501 struct MachO::x86_thread_state_t ts;
9502 left = end - begin;
9503 if (left >= sizeof(MachO::x86_thread_state_t)) {
9504 memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
9505 begin += sizeof(MachO::x86_thread_state_t);
9506 } else {
9507 memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
9508 memcpy(&ts, begin, left);
9509 begin += left;
9510 }
9511 if (isLittleEndian != sys::IsLittleEndianHost)
9512 swapStruct(ts);
9513 if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) {
9514 outs() << "\t tsh.flavor x86_THREAD_STATE64 ";
9515 if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT)
9516 outs() << "tsh.count x86_THREAD_STATE64_COUNT\n";
9517 else
9518 outs() << "tsh.count " << ts.tsh.count
9519 << " (not x86_THREAD_STATE64_COUNT\n";
9520 Print_x86_thread_state64_t(ts.uts.ts64);
9521 } else {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009522 outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
9523 << ts.tsh.count << "\n";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009524 }
9525 } else if (flavor == MachO::x86_FLOAT_STATE) {
9526 outs() << " flavor x86_FLOAT_STATE\n";
9527 if (count == MachO::x86_FLOAT_STATE_COUNT)
9528 outs() << " count x86_FLOAT_STATE_COUNT\n";
9529 else
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009530 outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009531 struct MachO::x86_float_state_t fs;
9532 left = end - begin;
9533 if (left >= sizeof(MachO::x86_float_state_t)) {
9534 memcpy(&fs, begin, sizeof(MachO::x86_float_state_t));
9535 begin += sizeof(MachO::x86_float_state_t);
9536 } else {
9537 memset(&fs, '\0', sizeof(MachO::x86_float_state_t));
9538 memcpy(&fs, begin, left);
9539 begin += left;
9540 }
9541 if (isLittleEndian != sys::IsLittleEndianHost)
9542 swapStruct(fs);
9543 if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) {
9544 outs() << "\t fsh.flavor x86_FLOAT_STATE64 ";
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009545 if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT)
Kevin Enderby48ef5342014-12-23 22:56:39 +00009546 outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n";
9547 else
9548 outs() << "fsh.count " << fs.fsh.count
9549 << " (not x86_FLOAT_STATE64_COUNT\n";
9550 Print_x86_float_state_t(fs.ufs.fs64);
9551 } else {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009552 outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count "
9553 << fs.fsh.count << "\n";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009554 }
9555 } else if (flavor == MachO::x86_EXCEPTION_STATE) {
9556 outs() << " flavor x86_EXCEPTION_STATE\n";
9557 if (count == MachO::x86_EXCEPTION_STATE_COUNT)
9558 outs() << " count x86_EXCEPTION_STATE_COUNT\n";
9559 else
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009560 outs() << " count " << count
Kevin Enderby48ef5342014-12-23 22:56:39 +00009561 << " (not x86_EXCEPTION_STATE_COUNT)\n";
9562 struct MachO::x86_exception_state_t es;
9563 left = end - begin;
9564 if (left >= sizeof(MachO::x86_exception_state_t)) {
9565 memcpy(&es, begin, sizeof(MachO::x86_exception_state_t));
9566 begin += sizeof(MachO::x86_exception_state_t);
9567 } else {
9568 memset(&es, '\0', sizeof(MachO::x86_exception_state_t));
9569 memcpy(&es, begin, left);
9570 begin += left;
9571 }
9572 if (isLittleEndian != sys::IsLittleEndianHost)
9573 swapStruct(es);
9574 if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) {
9575 outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n";
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009576 if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT)
Kevin Enderby48ef5342014-12-23 22:56:39 +00009577 outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n";
9578 else
9579 outs() << "\t esh.count " << es.esh.count
9580 << " (not x86_EXCEPTION_STATE64_COUNT\n";
9581 Print_x86_exception_state_t(es.ues.es64);
9582 } else {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009583 outs() << "\t esh.flavor " << es.esh.flavor << " esh.count "
9584 << es.esh.count << "\n";
Kevin Enderby48ef5342014-12-23 22:56:39 +00009585 }
Kevin Enderby299cd892018-03-08 23:10:38 +00009586 } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
9587 outs() << " flavor x86_EXCEPTION_STATE64\n";
9588 if (count == MachO::x86_EXCEPTION_STATE64_COUNT)
9589 outs() << " count x86_EXCEPTION_STATE64_COUNT\n";
9590 else
9591 outs() << " count " << count
9592 << " (not x86_EXCEPTION_STATE64_COUNT)\n";
9593 struct MachO::x86_exception_state64_t es64;
9594 left = end - begin;
9595 if (left >= sizeof(MachO::x86_exception_state64_t)) {
9596 memcpy(&es64, begin, sizeof(MachO::x86_exception_state64_t));
9597 begin += sizeof(MachO::x86_exception_state64_t);
9598 } else {
9599 memset(&es64, '\0', sizeof(MachO::x86_exception_state64_t));
9600 memcpy(&es64, begin, left);
9601 begin += left;
9602 }
9603 if (isLittleEndian != sys::IsLittleEndianHost)
9604 swapStruct(es64);
9605 Print_x86_exception_state_t(es64);
Kevin Enderby48ef5342014-12-23 22:56:39 +00009606 } else {
9607 outs() << " flavor " << flavor << " (unknown)\n";
9608 outs() << " count " << count << "\n";
9609 outs() << " state (unknown)\n";
9610 begin += count * sizeof(uint32_t);
9611 }
9612 }
Kevin Enderby41c9c002016-10-21 18:22:35 +00009613 } else if (cputype == MachO::CPU_TYPE_ARM) {
9614 while (begin < end) {
9615 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9616 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9617 begin += sizeof(uint32_t);
9618 } else {
9619 flavor = 0;
9620 begin = end;
9621 }
9622 if (isLittleEndian != sys::IsLittleEndianHost)
9623 sys::swapByteOrder(flavor);
9624 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9625 memcpy((char *)&count, begin, sizeof(uint32_t));
9626 begin += sizeof(uint32_t);
9627 } else {
9628 count = 0;
9629 begin = end;
9630 }
9631 if (isLittleEndian != sys::IsLittleEndianHost)
9632 sys::swapByteOrder(count);
9633 if (flavor == MachO::ARM_THREAD_STATE) {
9634 outs() << " flavor ARM_THREAD_STATE\n";
9635 if (count == MachO::ARM_THREAD_STATE_COUNT)
9636 outs() << " count ARM_THREAD_STATE_COUNT\n";
9637 else
9638 outs() << " count " << count
9639 << " (not ARM_THREAD_STATE_COUNT)\n";
9640 MachO::arm_thread_state32_t cpu32;
9641 left = end - begin;
9642 if (left >= sizeof(MachO::arm_thread_state32_t)) {
9643 memcpy(&cpu32, begin, sizeof(MachO::arm_thread_state32_t));
9644 begin += sizeof(MachO::arm_thread_state32_t);
9645 } else {
9646 memset(&cpu32, '\0', sizeof(MachO::arm_thread_state32_t));
9647 memcpy(&cpu32, begin, left);
9648 begin += left;
9649 }
9650 if (isLittleEndian != sys::IsLittleEndianHost)
9651 swapStruct(cpu32);
9652 Print_arm_thread_state32_t(cpu32);
9653 } else {
9654 outs() << " flavor " << flavor << " (unknown)\n";
9655 outs() << " count " << count << "\n";
9656 outs() << " state (unknown)\n";
9657 begin += count * sizeof(uint32_t);
9658 }
9659 }
Kevin Enderby7747cb52016-11-03 20:51:28 +00009660 } else if (cputype == MachO::CPU_TYPE_ARM64) {
9661 while (begin < end) {
9662 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9663 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9664 begin += sizeof(uint32_t);
9665 } else {
9666 flavor = 0;
9667 begin = end;
9668 }
9669 if (isLittleEndian != sys::IsLittleEndianHost)
9670 sys::swapByteOrder(flavor);
9671 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9672 memcpy((char *)&count, begin, sizeof(uint32_t));
9673 begin += sizeof(uint32_t);
9674 } else {
9675 count = 0;
9676 begin = end;
9677 }
9678 if (isLittleEndian != sys::IsLittleEndianHost)
9679 sys::swapByteOrder(count);
9680 if (flavor == MachO::ARM_THREAD_STATE64) {
9681 outs() << " flavor ARM_THREAD_STATE64\n";
9682 if (count == MachO::ARM_THREAD_STATE64_COUNT)
9683 outs() << " count ARM_THREAD_STATE64_COUNT\n";
9684 else
9685 outs() << " count " << count
9686 << " (not ARM_THREAD_STATE64_COUNT)\n";
9687 MachO::arm_thread_state64_t cpu64;
9688 left = end - begin;
9689 if (left >= sizeof(MachO::arm_thread_state64_t)) {
9690 memcpy(&cpu64, begin, sizeof(MachO::arm_thread_state64_t));
9691 begin += sizeof(MachO::arm_thread_state64_t);
9692 } else {
9693 memset(&cpu64, '\0', sizeof(MachO::arm_thread_state64_t));
9694 memcpy(&cpu64, begin, left);
9695 begin += left;
9696 }
9697 if (isLittleEndian != sys::IsLittleEndianHost)
9698 swapStruct(cpu64);
9699 Print_arm_thread_state64_t(cpu64);
9700 } else {
9701 outs() << " flavor " << flavor << " (unknown)\n";
9702 outs() << " count " << count << "\n";
9703 outs() << " state (unknown)\n";
9704 begin += count * sizeof(uint32_t);
9705 }
9706 }
Kevin Enderby48ef5342014-12-23 22:56:39 +00009707 } else {
9708 while (begin < end) {
9709 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9710 memcpy((char *)&flavor, begin, sizeof(uint32_t));
9711 begin += sizeof(uint32_t);
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009712 } else {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009713 flavor = 0;
9714 begin = end;
9715 }
9716 if (isLittleEndian != sys::IsLittleEndianHost)
9717 sys::swapByteOrder(flavor);
9718 if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
9719 memcpy((char *)&count, begin, sizeof(uint32_t));
9720 begin += sizeof(uint32_t);
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009721 } else {
Kevin Enderby48ef5342014-12-23 22:56:39 +00009722 count = 0;
9723 begin = end;
9724 }
9725 if (isLittleEndian != sys::IsLittleEndianHost)
9726 sys::swapByteOrder(count);
9727 outs() << " flavor " << flavor << "\n";
9728 outs() << " count " << count << "\n";
9729 outs() << " state (Unknown cputype/cpusubtype)\n";
9730 begin += count * sizeof(uint32_t);
9731 }
9732 }
9733}
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009734
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009735static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) {
9736 if (dl.cmd == MachO::LC_ID_DYLIB)
9737 outs() << " cmd LC_ID_DYLIB\n";
9738 else if (dl.cmd == MachO::LC_LOAD_DYLIB)
9739 outs() << " cmd LC_LOAD_DYLIB\n";
9740 else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
9741 outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
9742 else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
9743 outs() << " cmd LC_REEXPORT_DYLIB\n";
9744 else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
9745 outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
9746 else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
9747 outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
9748 else
9749 outs() << " cmd " << dl.cmd << " (unknown)\n";
9750 outs() << " cmdsize " << dl.cmdsize;
9751 if (dl.cmdsize < sizeof(struct MachO::dylib_command))
9752 outs() << " Incorrect size\n";
9753 else
9754 outs() << "\n";
9755 if (dl.dylib.name < dl.cmdsize) {
Kevin Enderbyb28ed012014-10-29 21:28:24 +00009756 const char *P = (const char *)(Ptr) + dl.dylib.name;
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009757 outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
9758 } else {
9759 outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
9760 }
9761 outs() << " time stamp " << dl.dylib.timestamp << " ";
9762 time_t t = dl.dylib.timestamp;
9763 outs() << ctime(&t);
9764 outs() << " current version ";
9765 if (dl.dylib.current_version == 0xffffffff)
9766 outs() << "n/a\n";
9767 else
9768 outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
9769 << ((dl.dylib.current_version >> 8) & 0xff) << "."
9770 << (dl.dylib.current_version & 0xff) << "\n";
9771 outs() << "compatibility version ";
9772 if (dl.dylib.compatibility_version == 0xffffffff)
9773 outs() << "n/a\n";
9774 else
9775 outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
9776 << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
9777 << (dl.dylib.compatibility_version & 0xff) << "\n";
9778}
9779
9780static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
9781 uint32_t object_size) {
9782 if (ld.cmd == MachO::LC_CODE_SIGNATURE)
Kevin Enderby1be37a32016-04-28 21:07:20 +00009783 outs() << " cmd LC_CODE_SIGNATURE\n";
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009784 else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
9785 outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
9786 else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
9787 outs() << " cmd LC_FUNCTION_STARTS\n";
9788 else if (ld.cmd == MachO::LC_DATA_IN_CODE)
9789 outs() << " cmd LC_DATA_IN_CODE\n";
9790 else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
9791 outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
9792 else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
9793 outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
9794 else
9795 outs() << " cmd " << ld.cmd << " (?)\n";
9796 outs() << " cmdsize " << ld.cmdsize;
9797 if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
9798 outs() << " Incorrect size\n";
9799 else
9800 outs() << "\n";
9801 outs() << " dataoff " << ld.dataoff;
9802 if (ld.dataoff > object_size)
9803 outs() << " (past end of file)\n";
9804 else
9805 outs() << "\n";
9806 outs() << " datasize " << ld.datasize;
9807 uint64_t big_size = ld.dataoff;
9808 big_size += ld.datasize;
9809 if (big_size > object_size)
9810 outs() << " (past end of file)\n";
9811 else
9812 outs() << "\n";
9813}
9814
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00009815static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
9816 uint32_t cputype, bool verbose) {
Kevin Enderby956366c2014-08-29 22:30:52 +00009817 StringRef Buf = Obj->getData();
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00009818 unsigned Index = 0;
9819 for (const auto &Command : Obj->load_commands()) {
9820 outs() << "Load command " << Index++ << "\n";
Kevin Enderby956366c2014-08-29 22:30:52 +00009821 if (Command.C.cmd == MachO::LC_SEGMENT) {
9822 MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
9823 const char *sg_segname = SLC.segname;
9824 PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,
9825 SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,
9826 SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
9827 verbose);
9828 for (unsigned j = 0; j < SLC.nsects; j++) {
Kevin Enderbyc9713382014-12-16 01:14:45 +00009829 MachO::section S = Obj->getSection(Command, j);
Kevin Enderby956366c2014-08-29 22:30:52 +00009830 PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align,
9831 S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2,
9832 SLC.cmd, sg_segname, filetype, Buf.size(), verbose);
9833 }
9834 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
9835 MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);
9836 const char *sg_segname = SLC_64.segname;
9837 PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,
9838 SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,
9839 SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,
9840 SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);
9841 for (unsigned j = 0; j < SLC_64.nsects; j++) {
9842 MachO::section_64 S_64 = Obj->getSection64(Command, j);
9843 PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,
9844 S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,
9845 S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,
9846 sg_segname, filetype, Buf.size(), verbose);
9847 }
9848 } else if (Command.C.cmd == MachO::LC_SYMTAB) {
9849 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
David Majnemer73cc6ff2014-11-13 19:48:56 +00009850 PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());
Kevin Enderby956366c2014-08-29 22:30:52 +00009851 } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
9852 MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
9853 MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
David Majnemer73cc6ff2014-11-13 19:48:56 +00009854 PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),
9855 Obj->is64Bit());
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009856 } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
9857 Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
9858 MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);
9859 PrintDyldInfoLoadCommand(DyldInfo, Buf.size());
9860 } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
9861 Command.C.cmd == MachO::LC_ID_DYLINKER ||
9862 Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
9863 MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);
9864 PrintDyldLoadCommand(Dyld, Command.Ptr);
9865 } else if (Command.C.cmd == MachO::LC_UUID) {
9866 MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
9867 PrintUuidLoadCommand(Uuid);
Jean-Daniel Dupas00cc1f52014-12-04 07:37:02 +00009868 } else if (Command.C.cmd == MachO::LC_RPATH) {
9869 MachO::rpath_command Rpath = Obj->getRpathCommand(Command);
9870 PrintRpathLoadCommand(Rpath, Command.Ptr);
Kevin Enderby1ff0ecc2014-12-16 21:48:27 +00009871 } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX ||
Tim Northoverbfbfb122015-11-02 21:26:58 +00009872 Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS ||
9873 Command.C.cmd == MachO::LC_VERSION_MIN_TVOS ||
9874 Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009875 MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
9876 PrintVersionMinLoadCommand(Vd);
Kevin Enderbya4579c42017-01-19 17:36:31 +00009877 } else if (Command.C.cmd == MachO::LC_NOTE) {
9878 MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
9879 PrintNoteLoadCommand(Nt);
Steven Wu5b54a422017-01-23 20:07:55 +00009880 } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
9881 MachO::build_version_command Bv =
9882 Obj->getBuildVersionLoadCommand(Command);
9883 PrintBuildVersionLoadCommand(Obj, Bv);
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009884 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
9885 MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
9886 PrintSourceVersionCommand(Sd);
9887 } else if (Command.C.cmd == MachO::LC_MAIN) {
9888 MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command);
9889 PrintEntryPointCommand(Ep);
Kevin Enderby0804f4672014-12-16 23:25:52 +00009890 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009891 MachO::encryption_info_command Ei =
9892 Obj->getEncryptionInfoCommand(Command);
Kevin Enderby0804f4672014-12-16 23:25:52 +00009893 PrintEncryptionInfoCommand(Ei, Buf.size());
Kevin Enderby57538292014-12-17 01:01:30 +00009894 } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009895 MachO::encryption_info_command_64 Ei =
9896 Obj->getEncryptionInfoCommand64(Command);
Kevin Enderby57538292014-12-17 01:01:30 +00009897 PrintEncryptionInfoCommand64(Ei, Buf.size());
Kevin Enderbyd0b6b7f2014-12-18 00:53:40 +00009898 } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) {
Kevin Enderby66d51fc2015-01-08 00:25:24 +00009899 MachO::linker_option_command Lo =
9900 Obj->getLinkerOptionLoadCommand(Command);
Kevin Enderbyd0b6b7f2014-12-18 00:53:40 +00009901 PrintLinkerOptionCommand(Lo, Command.Ptr);
Kevin Enderbyb4b79312014-12-18 19:24:35 +00009902 } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) {
9903 MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command);
9904 PrintSubFrameworkCommand(Sf, Command.Ptr);
Kevin Enderbya2bd8d92014-12-18 23:13:26 +00009905 } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) {
9906 MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command);
9907 PrintSubUmbrellaCommand(Sf, Command.Ptr);
Kevin Enderby36c8d3a2014-12-19 19:48:16 +00009908 } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) {
9909 MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command);
9910 PrintSubLibraryCommand(Sl, Command.Ptr);
Kevin Enderby186eac32014-12-19 21:06:24 +00009911 } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) {
9912 MachO::sub_client_command Sc = Obj->getSubClientCommand(Command);
9913 PrintSubClientCommand(Sc, Command.Ptr);
Kevin Enderby52e4ce42014-12-19 22:25:22 +00009914 } else if (Command.C.cmd == MachO::LC_ROUTINES) {
9915 MachO::routines_command Rc = Obj->getRoutinesCommand(Command);
9916 PrintRoutinesCommand(Rc);
9917 } else if (Command.C.cmd == MachO::LC_ROUTINES_64) {
9918 MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command);
9919 PrintRoutinesCommand64(Rc);
Kevin Enderby48ef5342014-12-23 22:56:39 +00009920 } else if (Command.C.cmd == MachO::LC_THREAD ||
9921 Command.C.cmd == MachO::LC_UNIXTHREAD) {
9922 MachO::thread_command Tc = Obj->getThreadCommand(Command);
9923 PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype);
Nick Kledzik15558912014-10-16 18:58:20 +00009924 } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB ||
9925 Command.C.cmd == MachO::LC_ID_DYLIB ||
9926 Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
9927 Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
9928 Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
9929 Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
Kevin Enderby8ae63c12014-09-04 16:54:47 +00009930 MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);
9931 PrintDylibCommand(Dl, Command.Ptr);
9932 } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
9933 Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
9934 Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
9935 Command.C.cmd == MachO::LC_DATA_IN_CODE ||
9936 Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
9937 Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
9938 MachO::linkedit_data_command Ld =
9939 Obj->getLinkeditDataLoadCommand(Command);
9940 PrintLinkEditDataCommand(Ld, Buf.size());
Kevin Enderby956366c2014-08-29 22:30:52 +00009941 } else {
9942 outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)
9943 << ")\n";
9944 outs() << " cmdsize " << Command.C.cmdsize << "\n";
9945 // TODO: get and print the raw bytes of the load command.
9946 }
9947 // TODO: print all the other kinds of load commands.
Kevin Enderby956366c2014-08-29 22:30:52 +00009948 }
9949}
9950
Kevin Enderby0ae163f2016-01-13 00:25:36 +00009951static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
Kevin Enderbyb76d3862014-08-22 20:35:18 +00009952 if (Obj->is64Bit()) {
9953 MachO::mach_header_64 H_64;
9954 H_64 = Obj->getHeader64();
9955 PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
9956 H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
9957 } else {
9958 MachO::mach_header H;
9959 H = Obj->getHeader();
9960 PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
9961 H.sizeofcmds, H.flags, verbose);
9962 }
9963}
9964
9965void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
9966 const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
Kevin Enderby0ae163f2016-01-13 00:25:36 +00009967 PrintMachHeader(file, !NonVerbose);
9968}
9969
9970void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
9971 const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
Kevin Enderby956366c2014-08-29 22:30:52 +00009972 uint32_t filetype = 0;
9973 uint32_t cputype = 0;
Kevin Enderby0ae163f2016-01-13 00:25:36 +00009974 if (file->is64Bit()) {
9975 MachO::mach_header_64 H_64;
9976 H_64 = file->getHeader64();
9977 filetype = H_64.filetype;
9978 cputype = H_64.cputype;
9979 } else {
9980 MachO::mach_header H;
9981 H = file->getHeader();
9982 filetype = H.filetype;
9983 cputype = H.cputype;
9984 }
Alexey Samsonovd319c4f2015-06-03 22:19:36 +00009985 PrintLoadCommands(file, filetype, cputype, !NonVerbose);
Kevin Enderbyb76d3862014-08-22 20:35:18 +00009986}
Nick Kledzikd04bc352014-08-30 00:20:14 +00009987
9988//===----------------------------------------------------------------------===//
9989// export trie dumping
9990//===----------------------------------------------------------------------===//
9991
9992void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
Kevin Enderby0d5ec112017-06-19 21:23:07 +00009993 uint64_t BaseSegmentAddress = 0;
9994 for (const auto &Command : Obj->load_commands()) {
9995 if (Command.C.cmd == MachO::LC_SEGMENT) {
9996 MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);
9997 if (Seg.fileoff == 0 && Seg.filesize != 0) {
9998 BaseSegmentAddress = Seg.vmaddr;
9999 break;
10000 }
10001 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
10002 MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);
10003 if (Seg.fileoff == 0 && Seg.filesize != 0) {
10004 BaseSegmentAddress = Seg.vmaddr;
10005 break;
10006 }
10007 }
10008 }
Kevin Enderby3e95bd22017-07-20 23:08:41 +000010009 Error Err = Error::success();
Alexander Shaposhnikove5740342017-07-29 00:30:45 +000010010 for (const llvm::object::ExportEntry &Entry : Obj->exports(Err)) {
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010011 uint64_t Flags = Entry.flags();
Nick Kledzikd04bc352014-08-30 00:20:14 +000010012 bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
10013 bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
10014 bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10015 MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
10016 bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
10017 MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
10018 bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
10019 if (ReExport)
10020 outs() << "[re-export] ";
10021 else
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010022 outs() << format("0x%08llX ",
Kevin Enderby0d5ec112017-06-19 21:23:07 +000010023 Entry.address() + BaseSegmentAddress);
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010024 outs() << Entry.name();
Nick Kledzikd04bc352014-08-30 00:20:14 +000010025 if (WeakDef || ThreadLocal || Resolver || Abs) {
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010026 bool NeedsComma = false;
Nick Kledzik1d1ac4b2014-09-03 01:12:52 +000010027 outs() << " [";
Nick Kledzikd04bc352014-08-30 00:20:14 +000010028 if (WeakDef) {
10029 outs() << "weak_def";
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010030 NeedsComma = true;
Nick Kledzikd04bc352014-08-30 00:20:14 +000010031 }
10032 if (ThreadLocal) {
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010033 if (NeedsComma)
Nick Kledzikd04bc352014-08-30 00:20:14 +000010034 outs() << ", ";
10035 outs() << "per-thread";
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010036 NeedsComma = true;
Nick Kledzikd04bc352014-08-30 00:20:14 +000010037 }
10038 if (Abs) {
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010039 if (NeedsComma)
Nick Kledzikd04bc352014-08-30 00:20:14 +000010040 outs() << ", ";
10041 outs() << "absolute";
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010042 NeedsComma = true;
Nick Kledzikd04bc352014-08-30 00:20:14 +000010043 }
10044 if (Resolver) {
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010045 if (NeedsComma)
Nick Kledzikd04bc352014-08-30 00:20:14 +000010046 outs() << ", ";
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010047 outs() << format("resolver=0x%08llX", Entry.other());
10048 NeedsComma = true;
Nick Kledzikd04bc352014-08-30 00:20:14 +000010049 }
10050 outs() << "]";
10051 }
10052 if (ReExport) {
10053 StringRef DylibName = "unknown";
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010054 int Ordinal = Entry.other() - 1;
10055 Obj->getLibraryShortNameByIndex(Ordinal, DylibName);
10056 if (Entry.otherName().empty())
Nick Kledzikd04bc352014-08-30 00:20:14 +000010057 outs() << " (from " << DylibName << ")";
10058 else
Nick Kledzikac7cbdc2014-09-02 18:50:24 +000010059 outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
Nick Kledzikd04bc352014-08-30 00:20:14 +000010060 }
10061 outs() << "\n";
10062 }
Kevin Enderby3e95bd22017-07-20 23:08:41 +000010063 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010064 report_error(std::move(Err), Obj->getFileName());
Nick Kledzikd04bc352014-08-30 00:20:14 +000010065}
Nick Kledzikac431442014-09-12 21:34:15 +000010066
Nick Kledzikac431442014-09-12 21:34:15 +000010067//===----------------------------------------------------------------------===//
10068// rebase table dumping
10069//===----------------------------------------------------------------------===//
10070
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010071void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) {
Nick Kledzikac431442014-09-12 21:34:15 +000010072 outs() << "segment section address type\n";
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010073 Error Err = Error::success();
10074 for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
10075 StringRef SegmentName = Entry.segmentName();
10076 StringRef SectionName = Entry.sectionName();
10077 uint64_t Address = Entry.address();
Nick Kledzikac431442014-09-12 21:34:15 +000010078
10079 // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010080 outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
10081 SegmentName.str().c_str(), SectionName.str().c_str(),
10082 Address, Entry.typeName().str().c_str());
Nick Kledzikac431442014-09-12 21:34:15 +000010083 }
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010084 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010085 report_error(std::move(Err), Obj->getFileName());
Nick Kledzikac431442014-09-12 21:34:15 +000010086}
Nick Kledzik56ebef42014-09-16 01:41:51 +000010087
10088static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
10089 StringRef DylibName;
10090 switch (Ordinal) {
10091 case MachO::BIND_SPECIAL_DYLIB_SELF:
10092 return "this-image";
10093 case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
10094 return "main-executable";
10095 case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
10096 return "flat-namespace";
10097 default:
Nick Kledzikabd29872014-09-16 22:03:13 +000010098 if (Ordinal > 0) {
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010099 std::error_code EC =
10100 Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);
Nick Kledzikabd29872014-09-16 22:03:13 +000010101 if (EC)
Nick Kledzik51d2c2b2014-10-14 23:29:38 +000010102 return "<<bad library ordinal>>";
Nick Kledzikabd29872014-09-16 22:03:13 +000010103 return DylibName;
10104 }
Nick Kledzik56ebef42014-09-16 01:41:51 +000010105 }
Nick Kledzikabd29872014-09-16 22:03:13 +000010106 return "<<unknown special ordinal>>";
Nick Kledzik56ebef42014-09-16 01:41:51 +000010107}
10108
10109//===----------------------------------------------------------------------===//
10110// bind table dumping
10111//===----------------------------------------------------------------------===//
10112
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010113void llvm::printMachOBindTable(object::MachOObjectFile *Obj) {
Nick Kledzik56ebef42014-09-16 01:41:51 +000010114 // Build table of sections so names can used in final output.
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010115 outs() << "segment section address type "
10116 "addend dylib symbol\n";
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010117 Error Err = Error::success();
10118 for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010119 StringRef SegmentName = Entry.segmentName();
10120 StringRef SectionName = Entry.sectionName();
10121 uint64_t Address = Entry.address();
Nick Kledzik56ebef42014-09-16 01:41:51 +000010122
10123 // Table lines look like:
10124 // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010125 StringRef Attr;
Nick Kledzik56ebef42014-09-16 01:41:51 +000010126 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010127 Attr = " (weak_import)";
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010128 outs() << left_justify(SegmentName, 8) << " "
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010129 << left_justify(SectionName, 18) << " "
10130 << format_hex(Address, 10, true) << " "
10131 << left_justify(Entry.typeName(), 8) << " "
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010132 << format_decimal(Entry.addend(), 8) << " "
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010133 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010134 << Entry.symbolName() << Attr << "\n";
Nick Kledzik56ebef42014-09-16 01:41:51 +000010135 }
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010136 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010137 report_error(std::move(Err), Obj->getFileName());
Nick Kledzik56ebef42014-09-16 01:41:51 +000010138}
10139
10140//===----------------------------------------------------------------------===//
10141// lazy bind table dumping
10142//===----------------------------------------------------------------------===//
10143
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010144void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) {
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010145 outs() << "segment section address "
10146 "dylib symbol\n";
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010147 Error Err = Error::success();
10148 for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010149 StringRef SegmentName = Entry.segmentName();
10150 StringRef SectionName = Entry.sectionName();
10151 uint64_t Address = Entry.address();
Nick Kledzik56ebef42014-09-16 01:41:51 +000010152
10153 // Table lines look like:
10154 // __DATA __got 0x00012010 libSystem ___stack_chk_guard
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010155 outs() << left_justify(SegmentName, 8) << " "
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010156 << left_justify(SectionName, 18) << " "
10157 << format_hex(Address, 10, true) << " "
10158 << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
Nick Kledzik56ebef42014-09-16 01:41:51 +000010159 << Entry.symbolName() << "\n";
10160 }
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010161 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010162 report_error(std::move(Err), Obj->getFileName());
Nick Kledzik56ebef42014-09-16 01:41:51 +000010163}
10164
Nick Kledzik56ebef42014-09-16 01:41:51 +000010165//===----------------------------------------------------------------------===//
10166// weak bind table dumping
10167//===----------------------------------------------------------------------===//
10168
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010169void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) {
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010170 outs() << "segment section address "
10171 "type addend symbol\n";
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010172 Error Err = Error::success();
10173 for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
Nick Kledzik56ebef42014-09-16 01:41:51 +000010174 // Strong symbols don't have a location to update.
10175 if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010176 outs() << " strong "
Nick Kledzik56ebef42014-09-16 01:41:51 +000010177 << Entry.symbolName() << "\n";
10178 continue;
10179 }
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010180 StringRef SegmentName = Entry.segmentName();
10181 StringRef SectionName = Entry.sectionName();
10182 uint64_t Address = Entry.address();
Nick Kledzik56ebef42014-09-16 01:41:51 +000010183
10184 // Table lines look like:
10185 // __DATA __data 0x00001000 pointer 0 _foo
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010186 outs() << left_justify(SegmentName, 8) << " "
Nick Kledzik5ffacc12014-09-30 00:19:58 +000010187 << left_justify(SectionName, 18) << " "
10188 << format_hex(Address, 10, true) << " "
10189 << left_justify(Entry.typeName(), 8) << " "
Kevin Enderbyb28ed012014-10-29 21:28:24 +000010190 << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
10191 << "\n";
Nick Kledzik56ebef42014-09-16 01:41:51 +000010192 }
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010193 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010194 report_error(std::move(Err), Obj->getFileName());
Nick Kledzik56ebef42014-09-16 01:41:51 +000010195}
10196
Kevin Enderby6f326ce2014-10-23 19:37:31 +000010197// get_dyld_bind_info_symbolname() is used for disassembly and passed an
10198// address, ReferenceValue, in the Mach-O file and looks in the dyld bind
10199// information for that address. If the address is found its binding symbol
10200// name is returned. If not nullptr is returned.
10201static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
10202 struct DisassembleInfo *info) {
Kevin Enderby078be602014-10-23 19:53:12 +000010203 if (info->bindtable == nullptr) {
Saleem Abdulrasool1d84d9a2017-01-08 19:14:15 +000010204 info->bindtable = llvm::make_unique<SymbolAddressMap>();
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010205 Error Err = Error::success();
10206 for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
Kevin Enderbya8d256c2017-03-20 19:46:55 +000010207 uint64_t Address = Entry.address();
Kevin Enderby6f326ce2014-10-23 19:37:31 +000010208 StringRef name = Entry.symbolName();
10209 if (!name.empty())
Saleem Abdulrasool1d84d9a2017-01-08 19:14:15 +000010210 (*info->bindtable)[Address] = name;
Kevin Enderby6f326ce2014-10-23 19:37:31 +000010211 }
Kevin Enderbyfeb63b92017-02-28 21:47:07 +000010212 if (Err)
Fangrui Songe7834bd2019-04-07 08:19:55 +000010213 report_error(std::move(Err), info->O->getFileName());
Kevin Enderby6f326ce2014-10-23 19:37:31 +000010214 }
Saleem Abdulrasool1d84d9a2017-01-08 19:14:15 +000010215 auto name = info->bindtable->lookup(ReferenceValue);
10216 return !name.empty() ? name.data() : nullptr;
Kevin Enderby6f326ce2014-10-23 19:37:31 +000010217}
Michael Trent1854ecc2017-12-05 07:50:00 +000010218