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