MachODumper.cpp revision 335f1d46d82a4d6b5a7317ccc73178a47b62fc25
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::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  const llvm::object::MachOObjectFile *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 MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(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 MachOObjectFile *Obj,
161                       DataRefImpl DRI,
162                       MachOSection &Section) {
163  if (Obj->is64Bit()) {
164    const MachOFormat::Section<true> *Sect = Obj->getSection64(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 MachOFormat::Section<false> *Sect = Obj->getSection(DRI);
177
178    Section.Address     = Sect->Address;
179    Section.Size        = Sect->Size;
180    Section.Offset      = Sect->Offset;
181    Section.Alignment   = Sect->Align;
182    Section.RelocationTableOffset = Sect->RelocationTableOffset;
183    Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries;
184    Section.Flags       = Sect->Flags;
185    Section.Reserved1   = Sect->Reserved1;
186    Section.Reserved2   = Sect->Reserved2;
187  }
188}
189
190static void getSymbol(const MachOObjectFile *Obj,
191                      DataRefImpl DRI,
192                      MachOSymbol &Symbol) {
193  if (Obj->is64Bit()) {
194    const MachOFormat::SymbolTableEntry<true> *Entry =
195      Obj->getSymbol64TableEntry(DRI);
196    Symbol.StringIndex  = Entry->StringIndex;
197    Symbol.Type         = Entry->Type;
198    Symbol.SectionIndex = Entry->SectionIndex;
199    Symbol.Flags        = Entry->Flags;
200    Symbol.Value        = Entry->Value;
201  } else {
202    const MachOFormat::SymbolTableEntry<false> *Entry =
203      Obj->getSymbolTableEntry(DRI);
204    Symbol.StringIndex  = Entry->StringIndex;
205    Symbol.Type         = Entry->Type;
206    Symbol.SectionIndex = Entry->SectionIndex;
207    Symbol.Flags        = Entry->Flags;
208    Symbol.Value        = Entry->Value;
209  }
210}
211
212void MachODumper::printFileHeaders() {
213  W.startLine() << "FileHeaders not implemented.\n";
214}
215
216void MachODumper::printSections() {
217  ListScope Group(W, "Sections");
218
219  int SectionIndex = -1;
220  error_code EC;
221  for (section_iterator SecI = Obj->begin_sections(),
222                        SecE = Obj->end_sections();
223                        SecI != SecE; SecI.increment(EC)) {
224    if (error(EC)) break;
225
226    ++SectionIndex;
227
228    MachOSection Section;
229    getSection(Obj, SecI->getRawDataRefImpl(), Section);
230    DataRefImpl DR = SecI->getRawDataRefImpl();
231
232    StringRef Name;
233    if (error(SecI->getName(Name)))
234        Name = "";
235
236    ArrayRef<char> RawName = Obj->getSectionRawName(DR);
237    StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
238    ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);
239
240    DictScope SectionD(W, "Section");
241    W.printNumber("Index", SectionIndex);
242    W.printBinary("Name", Name, RawName);
243    W.printBinary("Segment", SegmentName, RawSegmentName);
244    W.printHex   ("Address", Section.Address);
245    W.printHex   ("Size", Section.Size);
246    W.printNumber("Offset", Section.Offset);
247    W.printNumber("Alignment", Section.Alignment);
248    W.printHex   ("RelocationOffset", Section.RelocationTableOffset);
249    W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
250    W.printEnum  ("Type", Section.Flags & 0xFF,
251                  makeArrayRef(MachOSectionAttributes));
252    W.printFlags ("Attributes", Section.Flags >> 8,
253                  makeArrayRef(MachOSectionAttributes));
254    W.printHex   ("Reserved1", Section.Reserved1);
255    W.printHex   ("Reserved2", Section.Reserved2);
256
257    if (opts::SectionRelocations) {
258      ListScope D(W, "Relocations");
259      for (relocation_iterator RelI = SecI->begin_relocations(),
260                               RelE = SecI->end_relocations();
261                               RelI != RelE; RelI.increment(EC)) {
262        if (error(EC)) break;
263
264        printRelocation(SecI, RelI);
265      }
266    }
267
268    if (opts::SectionSymbols) {
269      ListScope D(W, "Symbols");
270      for (symbol_iterator SymI = Obj->begin_symbols(),
271                           SymE = Obj->end_symbols();
272                           SymI != SymE; SymI.increment(EC)) {
273        if (error(EC)) break;
274
275        bool Contained = false;
276        if (SecI->containsSymbol(*SymI, Contained) || !Contained)
277          continue;
278
279        printSymbol(SymI);
280      }
281    }
282
283    if (opts::SectionData) {
284      StringRef Data;
285      if (error(SecI->getContents(Data))) break;
286
287      W.printBinaryBlock("SectionData", Data);
288    }
289  }
290}
291
292void MachODumper::printRelocations() {
293  ListScope D(W, "Relocations");
294
295  error_code EC;
296  for (section_iterator SecI = Obj->begin_sections(),
297                        SecE = Obj->end_sections();
298                        SecI != SecE; SecI.increment(EC)) {
299    if (error(EC)) break;
300
301    StringRef Name;
302    if (error(SecI->getName(Name)))
303      continue;
304
305    bool PrintedGroup = false;
306    for (relocation_iterator RelI = SecI->begin_relocations(),
307                             RelE = SecI->end_relocations();
308                             RelI != RelE; RelI.increment(EC)) {
309      if (error(EC)) break;
310
311      if (!PrintedGroup) {
312        W.startLine() << "Section " << Name << " {\n";
313        W.indent();
314        PrintedGroup = true;
315      }
316
317      printRelocation(SecI, RelI);
318    }
319
320    if (PrintedGroup) {
321      W.unindent();
322      W.startLine() << "}\n";
323    }
324  }
325}
326
327void MachODumper::printRelocation(section_iterator SecI,
328                                  relocation_iterator RelI) {
329  uint64_t Offset;
330  SmallString<32> RelocName;
331  int64_t Info;
332  StringRef SymbolName;
333  SymbolRef Symbol;
334  if (error(RelI->getOffset(Offset))) return;
335  if (error(RelI->getTypeName(RelocName))) return;
336  if (error(RelI->getAdditionalInfo(Info))) return;
337  if (error(RelI->getSymbol(Symbol))) return;
338  if (error(Symbol.getName(SymbolName))) return;
339
340  raw_ostream& OS = W.startLine();
341  OS << W.hex(Offset)
342     << " " << RelocName
343     << " " << (SymbolName.size() > 0 ? SymbolName : "-")
344     << " " << W.hex(Info)
345     << "\n";
346}
347
348void MachODumper::printSymbols() {
349  ListScope Group(W, "Symbols");
350
351  error_code EC;
352  for (symbol_iterator SymI = Obj->begin_symbols(),
353                       SymE = Obj->end_symbols();
354                       SymI != SymE; SymI.increment(EC)) {
355    if (error(EC)) break;
356
357    printSymbol(SymI);
358  }
359}
360
361void MachODumper::printDynamicSymbols() {
362  ListScope Group(W, "DynamicSymbols");
363}
364
365void MachODumper::printSymbol(symbol_iterator SymI) {
366  error_code EC;
367
368  StringRef SymbolName;
369  if (SymI->getName(SymbolName))
370    SymbolName = "";
371
372  MachOSymbol Symbol;
373  getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol);
374
375  StringRef SectionName;
376  section_iterator SecI(Obj->end_sections());
377  if (error(SymI->getSection(SecI)) ||
378      error(SecI->getName(SectionName)))
379    SectionName = "";
380
381  DictScope D(W, "Symbol");
382  W.printNumber("Name", SymbolName, Symbol.StringIndex);
383  if (Symbol.Type & N_STAB) {
384    W.printHex ("Type", "SymDebugTable", Symbol.Type);
385  } else {
386    W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes));
387  }
388  W.printHex   ("Section", SectionName, Symbol.SectionIndex);
389  W.printEnum  ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
390                  makeArrayRef(MachOSymbolRefTypes));
391  W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
392                  makeArrayRef(MachOSymbolFlags));
393  W.printHex   ("Value", Symbol.Value);
394}
395
396void MachODumper::printUnwindInfo() {
397  W.startLine() << "UnwindInfo not implemented.\n";
398}
399