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