MachODumper.cpp revision 261991
1249259Sdim//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file implements the MachO-specific dumper for llvm-readobj.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#include "llvm-readobj.h"
15249259Sdim#include "Error.h"
16249259Sdim#include "ObjDumper.h"
17249259Sdim#include "StreamWriter.h"
18249259Sdim
19249259Sdim#include "llvm/ADT/SmallString.h"
20249259Sdim#include "llvm/Object/MachO.h"
21249259Sdim#include "llvm/Support/Casting.h"
22249259Sdim
23249259Sdimusing namespace llvm;
24249259Sdimusing namespace object;
25249259Sdim
26249259Sdimnamespace {
27249259Sdim
28249259Sdimclass MachODumper : public ObjDumper {
29249259Sdimpublic:
30251662Sdim  MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
31249259Sdim    : ObjDumper(Writer)
32249259Sdim    , Obj(Obj) { }
33249259Sdim
34249259Sdim  virtual void printFileHeaders() LLVM_OVERRIDE;
35249259Sdim  virtual void printSections() LLVM_OVERRIDE;
36249259Sdim  virtual void printRelocations() LLVM_OVERRIDE;
37249259Sdim  virtual void printSymbols() LLVM_OVERRIDE;
38249259Sdim  virtual void printDynamicSymbols() LLVM_OVERRIDE;
39249259Sdim  virtual void printUnwindInfo() LLVM_OVERRIDE;
40249259Sdim
41249259Sdimprivate:
42249259Sdim  void printSymbol(symbol_iterator SymI);
43249259Sdim
44249259Sdim  void printRelocation(section_iterator SecI, relocation_iterator RelI);
45249259Sdim
46251662Sdim  void printRelocation(const MachOObjectFile *Obj,
47251662Sdim                       section_iterator SecI, relocation_iterator RelI);
48251662Sdim
49251662Sdim  void printSections(const MachOObjectFile *Obj);
50251662Sdim
51251662Sdim  const MachOObjectFile *Obj;
52249259Sdim};
53249259Sdim
54249259Sdim} // namespace
55249259Sdim
56249259Sdim
57249259Sdimnamespace llvm {
58249259Sdim
59249259Sdimerror_code createMachODumper(const object::ObjectFile *Obj,
60249259Sdim                             StreamWriter& Writer,
61249259Sdim                             OwningPtr<ObjDumper> &Result) {
62249259Sdim  const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
63249259Sdim  if (!MachOObj)
64249259Sdim    return readobj_error::unsupported_obj_file_format;
65249259Sdim
66249259Sdim  Result.reset(new MachODumper(MachOObj, Writer));
67249259Sdim  return readobj_error::success;
68249259Sdim}
69249259Sdim
70249259Sdim} // namespace llvm
71249259Sdim
72249259Sdim
73249259Sdimstatic const EnumEntry<unsigned> MachOSectionTypes[] = {
74249259Sdim  { "Regular"                        , 0x00 },
75249259Sdim  { "ZeroFill"                       , 0x01 },
76249259Sdim  { "CStringLiterals"                , 0x02 },
77249259Sdim  { "4ByteLiterals"                  , 0x03 },
78249259Sdim  { "8ByteLiterals"                  , 0x04 },
79249259Sdim  { "LiteralPointers"                , 0x05 },
80249259Sdim  { "NonLazySymbolPointers"          , 0x06 },
81249259Sdim  { "LazySymbolPointers"             , 0x07 },
82249259Sdim  { "SymbolStubs"                    , 0x08 },
83249259Sdim  { "ModInitFuncs"                   , 0x09 },
84249259Sdim  { "ModTermFuncs"                   , 0x0A },
85249259Sdim  { "Coalesced"                      , 0x0B },
86249259Sdim  { "GBZeroFill"                     , 0x0C },
87249259Sdim  { "Interposing"                    , 0x0D },
88249259Sdim  { "16ByteLiterals"                 , 0x0E },
89249259Sdim  { "DTraceDOF"                      , 0x0F },
90249259Sdim  { "LazyDylibSymbolPoints"          , 0x10 },
91249259Sdim  { "ThreadLocalRegular"             , 0x11 },
92249259Sdim  { "ThreadLocalZerofill"            , 0x12 },
93249259Sdim  { "ThreadLocalVariables"           , 0x13 },
94249259Sdim  { "ThreadLocalVariablePointers"    , 0x14 },
95249259Sdim  { "ThreadLocalInitFunctionPointers", 0x15 }
96249259Sdim};
97249259Sdim
98249259Sdimstatic const EnumEntry<unsigned> MachOSectionAttributes[] = {
99249259Sdim  { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },
100249259Sdim  { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ },
101249259Sdim  { "SomeInstructions" , 1 <<  2 /*S_ATTR_SOME_INSTRUCTIONS  */ },
102249259Sdim  { "Debug"            , 1 << 17 /*S_ATTR_DEBUG              */ },
103249259Sdim  { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
104249259Sdim  { "LiveSupport"      , 1 << 19 /*S_ATTR_LIVE_SUPPORT       */ },
105249259Sdim  { "NoDeadStrip"      , 1 << 20 /*S_ATTR_NO_DEAD_STRIP      */ },
106249259Sdim  { "StripStaticSyms"  , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS  */ },
107249259Sdim  { "NoTOC"            , 1 << 22 /*S_ATTR_NO_TOC             */ },
108249259Sdim  { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS  */ },
109249259Sdim};
110249259Sdim
111249259Sdimstatic const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
112249259Sdim  { "UndefinedNonLazy",                     0 },
113249259Sdim  { "ReferenceFlagUndefinedLazy",           1 },
114249259Sdim  { "ReferenceFlagDefined",                 2 },
115249259Sdim  { "ReferenceFlagPrivateDefined",          3 },
116249259Sdim  { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
117249259Sdim  { "ReferenceFlagPrivateUndefinedLazy",    5 }
118249259Sdim};
119249259Sdim
120249259Sdimstatic const EnumEntry<unsigned> MachOSymbolFlags[] = {
121249259Sdim  { "ReferencedDynamically", 0x10 },
122249259Sdim  { "NoDeadStrip",           0x20 },
123249259Sdim  { "WeakRef",               0x40 },
124249259Sdim  { "WeakDef",               0x80 }
125249259Sdim};
126249259Sdim
127249259Sdimstatic const EnumEntry<unsigned> MachOSymbolTypes[] = {
128249259Sdim  { "Undef",           0x0 },
129249259Sdim  { "External",        0x1 },
130249259Sdim  { "Abs",             0x2 },
131249259Sdim  { "Indirect",        0xA },
132249259Sdim  { "PreboundUndef",   0xC },
133249259Sdim  { "Section",         0xE },
134249259Sdim  { "PrivateExternal", 0x10 }
135249259Sdim};
136249259Sdim
137249259Sdimnamespace {
138249259Sdim  enum {
139249259Sdim    N_STAB = 0xE0
140249259Sdim  };
141249259Sdim
142249259Sdim  struct MachOSection {
143249259Sdim    ArrayRef<char> Name;
144249259Sdim    ArrayRef<char> SegmentName;
145249259Sdim    uint64_t Address;
146249259Sdim    uint64_t Size;
147249259Sdim    uint32_t Offset;
148249259Sdim    uint32_t Alignment;
149249259Sdim    uint32_t RelocationTableOffset;
150249259Sdim    uint32_t NumRelocationTableEntries;
151249259Sdim    uint32_t Flags;
152249259Sdim    uint32_t Reserved1;
153249259Sdim    uint32_t Reserved2;
154249259Sdim  };
155249259Sdim
156249259Sdim  struct MachOSymbol {
157249259Sdim    uint32_t StringIndex;
158249259Sdim    uint8_t Type;
159249259Sdim    uint8_t SectionIndex;
160249259Sdim    uint16_t Flags;
161249259Sdim    uint64_t Value;
162249259Sdim  };
163249259Sdim}
164249259Sdim
165251662Sdimstatic void getSection(const MachOObjectFile *Obj,
166251662Sdim                       DataRefImpl Sec,
167249259Sdim                       MachOSection &Section) {
168251662Sdim  if (!Obj->is64Bit()) {
169261991Sdim    MachO::section Sect = Obj->getSection(Sec);
170261991Sdim    Section.Address     = Sect.addr;
171261991Sdim    Section.Size        = Sect.size;
172261991Sdim    Section.Offset      = Sect.offset;
173261991Sdim    Section.Alignment   = Sect.align;
174261991Sdim    Section.RelocationTableOffset = Sect.reloff;
175261991Sdim    Section.NumRelocationTableEntries = Sect.nreloc;
176261991Sdim    Section.Flags       = Sect.flags;
177261991Sdim    Section.Reserved1   = Sect.reserved1;
178261991Sdim    Section.Reserved2   = Sect.reserved2;
179251662Sdim    return;
180249259Sdim  }
181261991Sdim  MachO::section_64 Sect = Obj->getSection64(Sec);
182261991Sdim  Section.Address     = Sect.addr;
183261991Sdim  Section.Size        = Sect.size;
184261991Sdim  Section.Offset      = Sect.offset;
185261991Sdim  Section.Alignment   = Sect.align;
186261991Sdim  Section.RelocationTableOffset = Sect.reloff;
187261991Sdim  Section.NumRelocationTableEntries = Sect.nreloc;
188261991Sdim  Section.Flags       = Sect.flags;
189261991Sdim  Section.Reserved1   = Sect.reserved1;
190261991Sdim  Section.Reserved2   = Sect.reserved2;
191249259Sdim}
192249259Sdim
193249259Sdim
194251662Sdimstatic void getSymbol(const MachOObjectFile *Obj,
195249259Sdim                      DataRefImpl DRI,
196249259Sdim                      MachOSymbol &Symbol) {
197251662Sdim  if (!Obj->is64Bit()) {
198261991Sdim    MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
199261991Sdim    Symbol.StringIndex  = Entry.n_strx;
200261991Sdim    Symbol.Type         = Entry.n_type;
201261991Sdim    Symbol.SectionIndex = Entry.n_sect;
202261991Sdim    Symbol.Flags        = Entry.n_desc;
203261991Sdim    Symbol.Value        = Entry.n_value;
204251662Sdim    return;
205249259Sdim  }
206261991Sdim  MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
207261991Sdim  Symbol.StringIndex  = Entry.n_strx;
208261991Sdim  Symbol.Type         = Entry.n_type;
209261991Sdim  Symbol.SectionIndex = Entry.n_sect;
210261991Sdim  Symbol.Flags        = Entry.n_desc;
211261991Sdim  Symbol.Value        = Entry.n_value;
212249259Sdim}
213249259Sdim
214249259Sdimvoid MachODumper::printFileHeaders() {
215249259Sdim  W.startLine() << "FileHeaders not implemented.\n";
216249259Sdim}
217249259Sdim
218249259Sdimvoid MachODumper::printSections() {
219251662Sdim  return printSections(Obj);
220251662Sdim}
221251662Sdim
222251662Sdimvoid MachODumper::printSections(const MachOObjectFile *Obj) {
223249259Sdim  ListScope Group(W, "Sections");
224249259Sdim
225249259Sdim  int SectionIndex = -1;
226249259Sdim  error_code EC;
227249259Sdim  for (section_iterator SecI = Obj->begin_sections(),
228249259Sdim                        SecE = Obj->end_sections();
229249259Sdim                        SecI != SecE; SecI.increment(EC)) {
230249259Sdim    if (error(EC)) break;
231249259Sdim
232249259Sdim    ++SectionIndex;
233249259Sdim
234251662Sdim    MachOSection Section;
235251662Sdim    getSection(Obj, SecI->getRawDataRefImpl(), Section);
236251662Sdim    DataRefImpl DR = SecI->getRawDataRefImpl();
237249259Sdim
238249259Sdim    StringRef Name;
239249259Sdim    if (error(SecI->getName(Name)))
240249259Sdim        Name = "";
241249259Sdim
242251662Sdim    ArrayRef<char> RawName = Obj->getSectionRawName(DR);
243251662Sdim    StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
244251662Sdim    ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);
245251662Sdim
246249259Sdim    DictScope SectionD(W, "Section");
247249259Sdim    W.printNumber("Index", SectionIndex);
248251662Sdim    W.printBinary("Name", Name, RawName);
249251662Sdim    W.printBinary("Segment", SegmentName, RawSegmentName);
250249259Sdim    W.printHex   ("Address", Section.Address);
251249259Sdim    W.printHex   ("Size", Section.Size);
252249259Sdim    W.printNumber("Offset", Section.Offset);
253249259Sdim    W.printNumber("Alignment", Section.Alignment);
254249259Sdim    W.printHex   ("RelocationOffset", Section.RelocationTableOffset);
255249259Sdim    W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
256249259Sdim    W.printEnum  ("Type", Section.Flags & 0xFF,
257249259Sdim                  makeArrayRef(MachOSectionAttributes));
258249259Sdim    W.printFlags ("Attributes", Section.Flags >> 8,
259249259Sdim                  makeArrayRef(MachOSectionAttributes));
260249259Sdim    W.printHex   ("Reserved1", Section.Reserved1);
261249259Sdim    W.printHex   ("Reserved2", Section.Reserved2);
262249259Sdim
263249259Sdim    if (opts::SectionRelocations) {
264249259Sdim      ListScope D(W, "Relocations");
265249259Sdim      for (relocation_iterator RelI = SecI->begin_relocations(),
266249259Sdim                               RelE = SecI->end_relocations();
267249259Sdim                               RelI != RelE; RelI.increment(EC)) {
268249259Sdim        if (error(EC)) break;
269249259Sdim
270249259Sdim        printRelocation(SecI, RelI);
271249259Sdim      }
272249259Sdim    }
273249259Sdim
274249259Sdim    if (opts::SectionSymbols) {
275249259Sdim      ListScope D(W, "Symbols");
276249259Sdim      for (symbol_iterator SymI = Obj->begin_symbols(),
277249259Sdim                           SymE = Obj->end_symbols();
278249259Sdim                           SymI != SymE; SymI.increment(EC)) {
279249259Sdim        if (error(EC)) break;
280249259Sdim
281249259Sdim        bool Contained = false;
282249259Sdim        if (SecI->containsSymbol(*SymI, Contained) || !Contained)
283249259Sdim          continue;
284249259Sdim
285249259Sdim        printSymbol(SymI);
286249259Sdim      }
287249259Sdim    }
288249259Sdim
289249259Sdim    if (opts::SectionData) {
290249259Sdim      StringRef Data;
291249259Sdim      if (error(SecI->getContents(Data))) break;
292249259Sdim
293249259Sdim      W.printBinaryBlock("SectionData", Data);
294249259Sdim    }
295249259Sdim  }
296249259Sdim}
297249259Sdim
298249259Sdimvoid MachODumper::printRelocations() {
299249259Sdim  ListScope D(W, "Relocations");
300249259Sdim
301249259Sdim  error_code EC;
302249259Sdim  for (section_iterator SecI = Obj->begin_sections(),
303249259Sdim                        SecE = Obj->end_sections();
304249259Sdim                        SecI != SecE; SecI.increment(EC)) {
305249259Sdim    if (error(EC)) break;
306249259Sdim
307249259Sdim    StringRef Name;
308249259Sdim    if (error(SecI->getName(Name)))
309249259Sdim      continue;
310249259Sdim
311249259Sdim    bool PrintedGroup = false;
312249259Sdim    for (relocation_iterator RelI = SecI->begin_relocations(),
313249259Sdim                             RelE = SecI->end_relocations();
314249259Sdim                             RelI != RelE; RelI.increment(EC)) {
315249259Sdim      if (error(EC)) break;
316249259Sdim
317249259Sdim      if (!PrintedGroup) {
318249259Sdim        W.startLine() << "Section " << Name << " {\n";
319249259Sdim        W.indent();
320249259Sdim        PrintedGroup = true;
321249259Sdim      }
322249259Sdim
323249259Sdim      printRelocation(SecI, RelI);
324249259Sdim    }
325249259Sdim
326249259Sdim    if (PrintedGroup) {
327249259Sdim      W.unindent();
328249259Sdim      W.startLine() << "}\n";
329249259Sdim    }
330249259Sdim  }
331249259Sdim}
332249259Sdim
333249259Sdimvoid MachODumper::printRelocation(section_iterator SecI,
334249259Sdim                                  relocation_iterator RelI) {
335251662Sdim  return printRelocation(Obj, SecI, RelI);
336251662Sdim}
337251662Sdim
338251662Sdimvoid MachODumper::printRelocation(const MachOObjectFile *Obj,
339251662Sdim                                  section_iterator SecI,
340251662Sdim                                  relocation_iterator RelI) {
341249259Sdim  uint64_t Offset;
342249259Sdim  SmallString<32> RelocName;
343249259Sdim  StringRef SymbolName;
344249259Sdim  if (error(RelI->getOffset(Offset))) return;
345249259Sdim  if (error(RelI->getTypeName(RelocName))) return;
346261991Sdim  symbol_iterator Symbol = RelI->getSymbol();
347261991Sdim  if (Symbol != Obj->end_symbols() &&
348261991Sdim      error(Symbol->getName(SymbolName)))
349251662Sdim    return;
350249259Sdim
351251662Sdim  DataRefImpl DR = RelI->getRawDataRefImpl();
352261991Sdim  MachO::any_relocation_info RE = Obj->getRelocation(DR);
353251662Sdim  bool IsScattered = Obj->isRelocationScattered(RE);
354251662Sdim
355251662Sdim  if (opts::ExpandRelocs) {
356251662Sdim    DictScope Group(W, "Relocation");
357251662Sdim    W.printHex("Offset", Offset);
358251662Sdim    W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
359251662Sdim    W.printNumber("Length", Obj->getAnyRelocationLength(RE));
360251662Sdim    if (IsScattered)
361251662Sdim      W.printString("Extern", StringRef("N/A"));
362251662Sdim    else
363251662Sdim      W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
364251662Sdim    W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
365251662Sdim    W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
366251662Sdim    W.printNumber("Scattered", IsScattered);
367251662Sdim  } else {
368251662Sdim    raw_ostream& OS = W.startLine();
369251662Sdim    OS << W.hex(Offset)
370251662Sdim       << " " << Obj->getAnyRelocationPCRel(RE)
371251662Sdim       << " " << Obj->getAnyRelocationLength(RE);
372251662Sdim    if (IsScattered)
373251662Sdim      OS << " n/a";
374251662Sdim    else
375251662Sdim      OS << " " << Obj->getPlainRelocationExternal(RE);
376251662Sdim    OS << " " << RelocName
377251662Sdim       << " " << IsScattered
378251662Sdim       << " " << (SymbolName.size() > 0 ? SymbolName : "-")
379251662Sdim       << "\n";
380251662Sdim  }
381249259Sdim}
382249259Sdim
383249259Sdimvoid MachODumper::printSymbols() {
384249259Sdim  ListScope Group(W, "Symbols");
385249259Sdim
386249259Sdim  error_code EC;
387249259Sdim  for (symbol_iterator SymI = Obj->begin_symbols(),
388249259Sdim                       SymE = Obj->end_symbols();
389249259Sdim                       SymI != SymE; SymI.increment(EC)) {
390249259Sdim    if (error(EC)) break;
391249259Sdim
392249259Sdim    printSymbol(SymI);
393249259Sdim  }
394249259Sdim}
395249259Sdim
396249259Sdimvoid MachODumper::printDynamicSymbols() {
397249259Sdim  ListScope Group(W, "DynamicSymbols");
398249259Sdim}
399249259Sdim
400249259Sdimvoid MachODumper::printSymbol(symbol_iterator SymI) {
401249259Sdim  StringRef SymbolName;
402249259Sdim  if (SymI->getName(SymbolName))
403249259Sdim    SymbolName = "";
404249259Sdim
405249259Sdim  MachOSymbol Symbol;
406251662Sdim  getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol);
407249259Sdim
408251662Sdim  StringRef SectionName = "";
409249259Sdim  section_iterator SecI(Obj->end_sections());
410251662Sdim  if (!error(SymI->getSection(SecI)) &&
411251662Sdim      SecI != Obj->end_sections())
412251662Sdim      error(SecI->getName(SectionName));
413249259Sdim
414249259Sdim  DictScope D(W, "Symbol");
415249259Sdim  W.printNumber("Name", SymbolName, Symbol.StringIndex);
416249259Sdim  if (Symbol.Type & N_STAB) {
417249259Sdim    W.printHex ("Type", "SymDebugTable", Symbol.Type);
418249259Sdim  } else {
419249259Sdim    W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes));
420249259Sdim  }
421249259Sdim  W.printHex   ("Section", SectionName, Symbol.SectionIndex);
422249259Sdim  W.printEnum  ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
423249259Sdim                  makeArrayRef(MachOSymbolRefTypes));
424249259Sdim  W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
425249259Sdim                  makeArrayRef(MachOSymbolFlags));
426249259Sdim  W.printHex   ("Value", Symbol.Value);
427249259Sdim}
428249259Sdim
429249259Sdimvoid MachODumper::printUnwindInfo() {
430249259Sdim  W.startLine() << "UnwindInfo not implemented.\n";
431249259Sdim}
432