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