1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the MachO-specific dumper for llvm-readobj.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm-readobj.h"
15#include "Error.h"
16#include "ObjDumper.h"
17#include "StreamWriter.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/Object/MachO.h"
21#include "llvm/Support/Casting.h"
22
23using namespace llvm;
24using namespace object;
25
26namespace {
27
28class MachODumper : public ObjDumper {
29public:
30  MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
31    : ObjDumper(Writer)
32    , Obj(Obj) { }
33
34  virtual void printFileHeaders() override;
35  virtual void printSections() override;
36  virtual void printRelocations() override;
37  virtual void printSymbols() override;
38  virtual void printDynamicSymbols() override;
39  virtual void printUnwindInfo() override;
40
41private:
42  void printSymbol(const SymbolRef &Symbol);
43
44  void printRelocation(const RelocationRef &Reloc);
45
46  void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc);
47
48  void printSections(const MachOObjectFile *Obj);
49
50  const MachOObjectFile *Obj;
51};
52
53} // namespace
54
55
56namespace llvm {
57
58std::error_code createMachODumper(const object::ObjectFile *Obj,
59                                  StreamWriter &Writer,
60                                  std::unique_ptr<ObjDumper> &Result) {
61  const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
62  if (!MachOObj)
63    return readobj_error::unsupported_obj_file_format;
64
65  Result.reset(new MachODumper(MachOObj, Writer));
66  return readobj_error::success;
67}
68
69} // namespace llvm
70
71
72static const EnumEntry<unsigned> MachOSectionTypes[] = {
73  { "Regular"                        , 0x00 },
74  { "ZeroFill"                       , 0x01 },
75  { "CStringLiterals"                , 0x02 },
76  { "4ByteLiterals"                  , 0x03 },
77  { "8ByteLiterals"                  , 0x04 },
78  { "LiteralPointers"                , 0x05 },
79  { "NonLazySymbolPointers"          , 0x06 },
80  { "LazySymbolPointers"             , 0x07 },
81  { "SymbolStubs"                    , 0x08 },
82  { "ModInitFuncs"                   , 0x09 },
83  { "ModTermFuncs"                   , 0x0A },
84  { "Coalesced"                      , 0x0B },
85  { "GBZeroFill"                     , 0x0C },
86  { "Interposing"                    , 0x0D },
87  { "16ByteLiterals"                 , 0x0E },
88  { "DTraceDOF"                      , 0x0F },
89  { "LazyDylibSymbolPoints"          , 0x10 },
90  { "ThreadLocalRegular"             , 0x11 },
91  { "ThreadLocalZerofill"            , 0x12 },
92  { "ThreadLocalVariables"           , 0x13 },
93  { "ThreadLocalVariablePointers"    , 0x14 },
94  { "ThreadLocalInitFunctionPointers", 0x15 }
95};
96
97static const EnumEntry<unsigned> MachOSectionAttributes[] = {
98  { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },
99  { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ },
100  { "SomeInstructions" , 1 <<  2 /*S_ATTR_SOME_INSTRUCTIONS  */ },
101  { "Debug"            , 1 << 17 /*S_ATTR_DEBUG              */ },
102  { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
103  { "LiveSupport"      , 1 << 19 /*S_ATTR_LIVE_SUPPORT       */ },
104  { "NoDeadStrip"      , 1 << 20 /*S_ATTR_NO_DEAD_STRIP      */ },
105  { "StripStaticSyms"  , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS  */ },
106  { "NoTOC"            , 1 << 22 /*S_ATTR_NO_TOC             */ },
107  { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS  */ },
108};
109
110static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
111  { "UndefinedNonLazy",                     0 },
112  { "ReferenceFlagUndefinedLazy",           1 },
113  { "ReferenceFlagDefined",                 2 },
114  { "ReferenceFlagPrivateDefined",          3 },
115  { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
116  { "ReferenceFlagPrivateUndefinedLazy",    5 }
117};
118
119static const EnumEntry<unsigned> MachOSymbolFlags[] = {
120  { "ReferencedDynamically", 0x10 },
121  { "NoDeadStrip",           0x20 },
122  { "WeakRef",               0x40 },
123  { "WeakDef",               0x80 }
124};
125
126static const EnumEntry<unsigned> MachOSymbolTypes[] = {
127  { "Undef",           0x0 },
128  { "Abs",             0x2 },
129  { "Indirect",        0xA },
130  { "PreboundUndef",   0xC },
131  { "Section",         0xE }
132};
133
134namespace {
135  struct MachOSection {
136    ArrayRef<char> Name;
137    ArrayRef<char> SegmentName;
138    uint64_t Address;
139    uint64_t Size;
140    uint32_t Offset;
141    uint32_t Alignment;
142    uint32_t RelocationTableOffset;
143    uint32_t NumRelocationTableEntries;
144    uint32_t Flags;
145    uint32_t Reserved1;
146    uint32_t Reserved2;
147  };
148
149  struct MachOSymbol {
150    uint32_t StringIndex;
151    uint8_t Type;
152    uint8_t SectionIndex;
153    uint16_t Flags;
154    uint64_t Value;
155  };
156}
157
158static void getSection(const MachOObjectFile *Obj,
159                       DataRefImpl Sec,
160                       MachOSection &Section) {
161  if (!Obj->is64Bit()) {
162    MachO::section Sect = Obj->getSection(Sec);
163    Section.Address     = Sect.addr;
164    Section.Size        = Sect.size;
165    Section.Offset      = Sect.offset;
166    Section.Alignment   = Sect.align;
167    Section.RelocationTableOffset = Sect.reloff;
168    Section.NumRelocationTableEntries = Sect.nreloc;
169    Section.Flags       = Sect.flags;
170    Section.Reserved1   = Sect.reserved1;
171    Section.Reserved2   = Sect.reserved2;
172    return;
173  }
174  MachO::section_64 Sect = Obj->getSection64(Sec);
175  Section.Address     = Sect.addr;
176  Section.Size        = Sect.size;
177  Section.Offset      = Sect.offset;
178  Section.Alignment   = Sect.align;
179  Section.RelocationTableOffset = Sect.reloff;
180  Section.NumRelocationTableEntries = Sect.nreloc;
181  Section.Flags       = Sect.flags;
182  Section.Reserved1   = Sect.reserved1;
183  Section.Reserved2   = Sect.reserved2;
184}
185
186
187static void getSymbol(const MachOObjectFile *Obj,
188                      DataRefImpl DRI,
189                      MachOSymbol &Symbol) {
190  if (!Obj->is64Bit()) {
191    MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
192    Symbol.StringIndex  = Entry.n_strx;
193    Symbol.Type         = Entry.n_type;
194    Symbol.SectionIndex = Entry.n_sect;
195    Symbol.Flags        = Entry.n_desc;
196    Symbol.Value        = Entry.n_value;
197    return;
198  }
199  MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
200  Symbol.StringIndex  = Entry.n_strx;
201  Symbol.Type         = Entry.n_type;
202  Symbol.SectionIndex = Entry.n_sect;
203  Symbol.Flags        = Entry.n_desc;
204  Symbol.Value        = Entry.n_value;
205}
206
207void MachODumper::printFileHeaders() {
208  W.startLine() << "FileHeaders not implemented.\n";
209}
210
211void MachODumper::printSections() {
212  return printSections(Obj);
213}
214
215void MachODumper::printSections(const MachOObjectFile *Obj) {
216  ListScope Group(W, "Sections");
217
218  int SectionIndex = -1;
219  for (const SectionRef &Section : Obj->sections()) {
220    ++SectionIndex;
221
222    MachOSection MOSection;
223    getSection(Obj, Section.getRawDataRefImpl(), MOSection);
224    DataRefImpl DR = Section.getRawDataRefImpl();
225
226    StringRef Name;
227    if (error(Section.getName(Name)))
228      Name = "";
229
230    ArrayRef<char> RawName = Obj->getSectionRawName(DR);
231    StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
232    ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);
233
234    DictScope SectionD(W, "Section");
235    W.printNumber("Index", SectionIndex);
236    W.printBinary("Name", Name, RawName);
237    W.printBinary("Segment", SegmentName, RawSegmentName);
238    W.printHex("Address", MOSection.Address);
239    W.printHex("Size", MOSection.Size);
240    W.printNumber("Offset", MOSection.Offset);
241    W.printNumber("Alignment", MOSection.Alignment);
242    W.printHex("RelocationOffset", MOSection.RelocationTableOffset);
243    W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries);
244    W.printEnum("Type", MOSection.Flags & 0xFF,
245                makeArrayRef(MachOSectionAttributes));
246    W.printFlags("Attributes", MOSection.Flags >> 8,
247                 makeArrayRef(MachOSectionAttributes));
248    W.printHex("Reserved1", MOSection.Reserved1);
249    W.printHex("Reserved2", MOSection.Reserved2);
250
251    if (opts::SectionRelocations) {
252      ListScope D(W, "Relocations");
253      for (const RelocationRef &Reloc : Section.relocations())
254        printRelocation(Reloc);
255    }
256
257    if (opts::SectionSymbols) {
258      ListScope D(W, "Symbols");
259      for (const SymbolRef &Symbol : Obj->symbols()) {
260        bool Contained = false;
261        if (Section.containsSymbol(Symbol, Contained) || !Contained)
262          continue;
263
264        printSymbol(Symbol);
265      }
266    }
267
268    if (opts::SectionData) {
269      StringRef Data;
270      if (error(Section.getContents(Data)))
271        break;
272
273      W.printBinaryBlock("SectionData", Data);
274    }
275  }
276}
277
278void MachODumper::printRelocations() {
279  ListScope D(W, "Relocations");
280
281  std::error_code EC;
282  for (const SectionRef &Section : Obj->sections()) {
283    StringRef Name;
284    if (error(Section.getName(Name)))
285      continue;
286
287    bool PrintedGroup = false;
288    for (const RelocationRef &Reloc : Section.relocations()) {
289      if (!PrintedGroup) {
290        W.startLine() << "Section " << Name << " {\n";
291        W.indent();
292        PrintedGroup = true;
293      }
294
295      printRelocation(Reloc);
296    }
297
298    if (PrintedGroup) {
299      W.unindent();
300      W.startLine() << "}\n";
301    }
302  }
303}
304
305void MachODumper::printRelocation(const RelocationRef &Reloc) {
306  return printRelocation(Obj, Reloc);
307}
308
309void MachODumper::printRelocation(const MachOObjectFile *Obj,
310                                  const RelocationRef &Reloc) {
311  uint64_t Offset;
312  SmallString<32> RelocName;
313  if (error(Reloc.getOffset(Offset)))
314    return;
315  if (error(Reloc.getTypeName(RelocName)))
316    return;
317
318  DataRefImpl DR = Reloc.getRawDataRefImpl();
319  MachO::any_relocation_info RE = Obj->getRelocation(DR);
320  bool IsScattered = Obj->isRelocationScattered(RE);
321  SmallString<32> SymbolNameOrOffset("0x");
322  if (IsScattered) {
323    // Scattered relocations don't really have an associated symbol
324    // for some reason, even if one exists in the symtab at the correct address.
325    SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE));
326  } else {
327    symbol_iterator Symbol = Reloc.getSymbol();
328    if (Symbol != Obj->symbol_end()) {
329      StringRef SymbolName;
330      if (error(Symbol->getName(SymbolName)))
331        return;
332      SymbolNameOrOffset = SymbolName;
333    } else
334      SymbolNameOrOffset += utohexstr(Obj->getPlainRelocationSymbolNum(RE));
335  }
336
337  if (opts::ExpandRelocs) {
338    DictScope Group(W, "Relocation");
339    W.printHex("Offset", Offset);
340    W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
341    W.printNumber("Length", Obj->getAnyRelocationLength(RE));
342    if (IsScattered)
343      W.printString("Extern", StringRef("N/A"));
344    else
345      W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
346    W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
347    W.printString("Symbol", SymbolNameOrOffset);
348    W.printNumber("Scattered", IsScattered);
349  } else {
350    raw_ostream& OS = W.startLine();
351    OS << W.hex(Offset)
352       << " " << Obj->getAnyRelocationPCRel(RE)
353       << " " << Obj->getAnyRelocationLength(RE);
354    if (IsScattered)
355      OS << " n/a";
356    else
357      OS << " " << Obj->getPlainRelocationExternal(RE);
358    OS << " " << RelocName
359       << " " << IsScattered
360       << " " << SymbolNameOrOffset
361       << "\n";
362  }
363}
364
365void MachODumper::printSymbols() {
366  ListScope Group(W, "Symbols");
367
368  for (const SymbolRef &Symbol : Obj->symbols()) {
369    printSymbol(Symbol);
370  }
371}
372
373void MachODumper::printDynamicSymbols() {
374  ListScope Group(W, "DynamicSymbols");
375}
376
377void MachODumper::printSymbol(const SymbolRef &Symbol) {
378  StringRef SymbolName;
379  if (Symbol.getName(SymbolName))
380    SymbolName = "";
381
382  MachOSymbol MOSymbol;
383  getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol);
384
385  StringRef SectionName = "";
386  section_iterator SecI(Obj->section_begin());
387  if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end())
388    error(SecI->getName(SectionName));
389
390  DictScope D(W, "Symbol");
391  W.printNumber("Name", SymbolName, MOSymbol.StringIndex);
392  if (MOSymbol.Type & MachO::N_STAB) {
393    W.printHex("Type", "SymDebugTable", MOSymbol.Type);
394  } else {
395    if (MOSymbol.Type & MachO::N_PEXT)
396      W.startLine() << "PrivateExtern\n";
397    if (MOSymbol.Type & MachO::N_EXT)
398      W.startLine() << "Extern\n";
399    W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE),
400                makeArrayRef(MachOSymbolTypes));
401  }
402  W.printHex("Section", SectionName, MOSymbol.SectionIndex);
403  W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0xF),
404              makeArrayRef(MachOSymbolRefTypes));
405  W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0xF),
406               makeArrayRef(MachOSymbolFlags));
407  W.printHex("Value", MOSymbol.Value);
408}
409
410void MachODumper::printUnwindInfo() {
411  W.startLine() << "UnwindInfo not implemented.\n";
412}
413