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