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