MachOObjectFile.cpp revision 291e767dcf19d60b8e774114efc6e10f2e022844
1//===- MachOObjectFile.cpp - Mach-O object file binding ---------*- C++ -*-===//
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 defines the MachOObjectFile class, which binds the MachOObject
11// class to the generic ObjectFile wrapper.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/Triple.h"
16#include "llvm/Object/MachOFormat.h"
17#include "llvm/Object/MachOObject.h"
18#include "llvm/Object/ObjectFile.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/MachO.h"
21
22#include <cctype>
23#include <cstring>
24#include <limits>
25
26using namespace llvm;
27using namespace object;
28
29namespace llvm {
30
31typedef MachOObject::LoadCommandInfo LoadCommandInfo;
32
33class MachOObjectFile : public ObjectFile {
34public:
35  MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, error_code &ec)
36    : ObjectFile(Binary::isMachO, Object, ec),
37      MachOObj(MOO),
38      RegisteredStringTable(std::numeric_limits<uint32_t>::max()) {}
39
40  virtual symbol_iterator begin_symbols() const;
41  virtual symbol_iterator end_symbols() const;
42  virtual section_iterator begin_sections() const;
43  virtual section_iterator end_sections() const;
44
45  virtual uint8_t getBytesInAddress() const;
46  virtual StringRef getFileFormatName() const;
47  virtual unsigned getArch() const;
48
49protected:
50  virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;
51  virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const;
52  virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const;
53  virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const;
54  virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const;
55  virtual error_code isSymbolInternal(DataRefImpl Symb, bool &Res) const;
56
57  virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const;
58  virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const;
59  virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const;
60  virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const;
61  virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const;
62  virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const;
63
64private:
65  MachOObject *MachOObj;
66  mutable uint32_t RegisteredStringTable;
67
68  void moveToNextSection(DataRefImpl &DRI) const;
69  void getSymbolTableEntry(DataRefImpl DRI,
70                           InMemoryStruct<macho::SymbolTableEntry> &Res) const;
71  void moveToNextSymbol(DataRefImpl &DRI) const;
72  void getSection(DataRefImpl DRI, InMemoryStruct<macho::Section> &Res) const;
73  void getSection64(DataRefImpl DRI,
74                    InMemoryStruct<macho::Section64> &Res) const;
75};
76
77ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) {
78  error_code ec;
79  std::string Err;
80  MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err);
81  if (!MachOObj)
82    return NULL;
83  return new MachOObjectFile(Buffer, MachOObj, ec);
84}
85
86/*===-- Symbols -----------------------------------------------------------===*/
87
88void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const {
89  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
90  while (DRI.d.a < LoadCommandCount) {
91    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
92    if (LCI.Command.Type == macho::LCT_Symtab) {
93      InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
94      MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
95      if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries)
96        return;
97    }
98
99    DRI.d.a++;
100    DRI.d.b = 0;
101  }
102}
103
104void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI,
105    InMemoryStruct<macho::SymbolTableEntry> &Res) const {
106  InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
107  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
108  MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
109
110  if (RegisteredStringTable != DRI.d.a) {
111    MachOObj->RegisterStringTable(*SymtabLoadCmd);
112    RegisteredStringTable = DRI.d.a;
113  }
114
115  MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b,
116                                 Res);
117}
118
119
120error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI,
121                                          SymbolRef &Result) const {
122  DRI.d.b++;
123  moveToNextSymbol(DRI);
124  Result = SymbolRef(DRI, this);
125  return object_error::success;
126}
127
128error_code MachOObjectFile::getSymbolName(DataRefImpl DRI,
129                                          StringRef &Result) const {
130  InMemoryStruct<macho::SymbolTableEntry> Entry;
131  getSymbolTableEntry(DRI, Entry);
132  Result = MachOObj->getStringAtIndex(Entry->StringIndex);
133  return object_error::success;
134}
135
136error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI,
137                                             uint64_t &Result) const {
138  InMemoryStruct<macho::SymbolTableEntry> Entry;
139  getSymbolTableEntry(DRI, Entry);
140  Result = Entry->Value;
141  return object_error::success;
142}
143
144error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI,
145                                          uint64_t &Result) const {
146  Result = UnknownAddressOrSize;
147  return object_error::success;
148}
149
150error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI,
151                                                char &Result) const {
152  InMemoryStruct<macho::SymbolTableEntry> Entry;
153  getSymbolTableEntry(DRI, Entry);
154
155  char Char;
156  switch (Entry->Type & macho::STF_TypeMask) {
157    case macho::STT_Undefined:
158      Char = 'u';
159      break;
160    case macho::STT_Absolute:
161    case macho::STT_Section:
162      Char = 's';
163      break;
164    default:
165      Char = '?';
166      break;
167  }
168
169  if (Entry->Flags & (macho::STF_External | macho::STF_PrivateExtern))
170    Char = toupper(Char);
171  Result = Char;
172  return object_error::success;
173}
174
175error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI,
176                                             bool &Result) const {
177  InMemoryStruct<macho::SymbolTableEntry> Entry;
178  getSymbolTableEntry(DRI, Entry);
179  Result = Entry->Flags & macho::STF_StabsEntryMask;
180  return object_error::success;
181}
182
183ObjectFile::symbol_iterator MachOObjectFile::begin_symbols() const {
184  // DRI.d.a = segment number; DRI.d.b = symbol index.
185  DataRefImpl DRI;
186  DRI.d.a = DRI.d.b = 0;
187  moveToNextSymbol(DRI);
188  return symbol_iterator(SymbolRef(DRI, this));
189}
190
191ObjectFile::symbol_iterator MachOObjectFile::end_symbols() const {
192  DataRefImpl DRI;
193  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
194  DRI.d.b = 0;
195  return symbol_iterator(SymbolRef(DRI, this));
196}
197
198
199/*===-- Sections ----------------------------------------------------------===*/
200
201void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const {
202  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
203  while (DRI.d.a < LoadCommandCount) {
204    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
205    if (LCI.Command.Type == macho::LCT_Segment) {
206      InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd;
207      MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd);
208      if (DRI.d.b < SegmentLoadCmd->NumSections)
209        return;
210    } else if (LCI.Command.Type == macho::LCT_Segment64) {
211      InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd;
212      MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd);
213      if (DRI.d.b < Segment64LoadCmd->NumSections)
214        return;
215    }
216
217    DRI.d.a++;
218    DRI.d.b = 0;
219  }
220}
221
222error_code MachOObjectFile::getSectionNext(DataRefImpl DRI,
223                                           SectionRef &Result) const {
224  DRI.d.b++;
225  moveToNextSection(DRI);
226  Result = SectionRef(DRI, this);
227  return object_error::success;
228}
229
230void
231MachOObjectFile::getSection(DataRefImpl DRI,
232                            InMemoryStruct<macho::Section> &Res) const {
233  InMemoryStruct<macho::SegmentLoadCommand> SLC;
234  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
235  MachOObj->ReadSegmentLoadCommand(LCI, SLC);
236  MachOObj->ReadSection(LCI, DRI.d.b, Res);
237}
238
239void
240MachOObjectFile::getSection64(DataRefImpl DRI,
241                            InMemoryStruct<macho::Section64> &Res) const {
242  InMemoryStruct<macho::Segment64LoadCommand> SLC;
243  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
244  MachOObj->ReadSegment64LoadCommand(LCI, SLC);
245  MachOObj->ReadSection64(LCI, DRI.d.b, Res);
246}
247
248static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) {
249  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
250  if (LCI.Command.Type == macho::LCT_Segment64)
251    return true;
252  assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type.");
253  return false;
254}
255
256error_code MachOObjectFile::getSectionName(DataRefImpl DRI,
257                                           StringRef &Result) const {
258  // FIXME: thread safety.
259  static char result[34];
260  if (is64BitLoadCommand(MachOObj, DRI)) {
261    InMemoryStruct<macho::Segment64LoadCommand> SLC;
262    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
263    MachOObj->ReadSegment64LoadCommand(LCI, SLC);
264    InMemoryStruct<macho::Section64> Sect;
265    MachOObj->ReadSection64(LCI, DRI.d.b, Sect);
266
267    strcpy(result, Sect->SegmentName);
268    strcat(result, ",");
269    strcat(result, Sect->Name);
270  } else {
271    InMemoryStruct<macho::SegmentLoadCommand> SLC;
272    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
273    MachOObj->ReadSegmentLoadCommand(LCI, SLC);
274    InMemoryStruct<macho::Section> Sect;
275    MachOObj->ReadSection(LCI, DRI.d.b, Sect);
276
277    strcpy(result, Sect->SegmentName);
278    strcat(result, ",");
279    strcat(result, Sect->Name);
280  }
281  Result = StringRef(result);
282  return object_error::success;
283}
284
285error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI,
286                                              uint64_t &Result) const {
287  if (is64BitLoadCommand(MachOObj, DRI)) {
288    InMemoryStruct<macho::Section64> Sect;
289    getSection64(DRI, Sect);
290    Result = Sect->Address;
291  } else {
292    InMemoryStruct<macho::Section> Sect;
293    getSection(DRI, Sect);
294    Result = Sect->Address;
295  }
296  return object_error::success;
297}
298
299error_code MachOObjectFile::getSectionSize(DataRefImpl DRI,
300                                           uint64_t &Result) const {
301  if (is64BitLoadCommand(MachOObj, DRI)) {
302    InMemoryStruct<macho::Section64> Sect;
303    getSection64(DRI, Sect);
304    Result = Sect->Size;
305  } else {
306    InMemoryStruct<macho::Section> Sect;
307    getSection(DRI, Sect);
308    Result = Sect->Size;
309  }
310  return object_error::success;
311}
312
313error_code MachOObjectFile::getSectionContents(DataRefImpl DRI,
314                                               StringRef &Result) const {
315  if (is64BitLoadCommand(MachOObj, DRI)) {
316    InMemoryStruct<macho::Section64> Sect;
317    getSection64(DRI, Sect);
318    Result = MachOObj->getData(Sect->Offset, Sect->Size);
319  } else {
320    InMemoryStruct<macho::Section> Sect;
321    getSection(DRI, Sect);
322    Result = MachOObj->getData(Sect->Offset, Sect->Size);
323  }
324  return object_error::success;
325}
326
327error_code MachOObjectFile::isSectionText(DataRefImpl DRI,
328                                          bool &Result) const {
329  if (is64BitLoadCommand(MachOObj, DRI)) {
330    InMemoryStruct<macho::Section64> Sect;
331    getSection64(DRI, Sect);
332    Result = !strcmp(Sect->Name, "__text");
333  } else {
334    InMemoryStruct<macho::Section> Sect;
335    getSection(DRI, Sect);
336    Result = !strcmp(Sect->Name, "__text");
337  }
338  return object_error::success;
339}
340
341ObjectFile::section_iterator MachOObjectFile::begin_sections() const {
342  DataRefImpl DRI;
343  DRI.d.a = DRI.d.b = 0;
344  moveToNextSection(DRI);
345  return section_iterator(SectionRef(DRI, this));
346}
347
348ObjectFile::section_iterator MachOObjectFile::end_sections() const {
349  DataRefImpl DRI;
350  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
351  DRI.d.b = 0;
352  return section_iterator(SectionRef(DRI, this));
353}
354
355/*===-- Miscellaneous -----------------------------------------------------===*/
356
357uint8_t MachOObjectFile::getBytesInAddress() const {
358  return MachOObj->is64Bit() ? 8 : 4;
359}
360
361StringRef MachOObjectFile::getFileFormatName() const {
362  if (!MachOObj->is64Bit()) {
363    switch (MachOObj->getHeader().CPUType) {
364    case llvm::MachO::CPUTypeI386:
365      return "Mach-O 32-bit i386";
366    case llvm::MachO::CPUTypeARM:
367      return "Mach-O arm";
368    case llvm::MachO::CPUTypePowerPC:
369      return "Mach-O 32-bit ppc";
370    default:
371      assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 &&
372             "64-bit object file when we're not 64-bit?");
373      return "Mach-O 32-bit unknown";
374    }
375  }
376
377  switch (MachOObj->getHeader().CPUType) {
378  case llvm::MachO::CPUTypeX86_64:
379    return "Mach-O 64-bit x86-64";
380  case llvm::MachO::CPUTypePowerPC64:
381    return "Mach-O 64-bit ppc64";
382  default:
383    assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 &&
384           "32-bit object file when we're 64-bit?");
385    return "Mach-O 64-bit unknown";
386  }
387}
388
389unsigned MachOObjectFile::getArch() const {
390  switch (MachOObj->getHeader().CPUType) {
391  case llvm::MachO::CPUTypeI386:
392    return Triple::x86;
393  case llvm::MachO::CPUTypeX86_64:
394    return Triple::x86_64;
395  case llvm::MachO::CPUTypeARM:
396    return Triple::arm;
397  case llvm::MachO::CPUTypePowerPC:
398    return Triple::ppc;
399  case llvm::MachO::CPUTypePowerPC64:
400    return Triple::ppc64;
401  default:
402    return Triple::UnknownArch;
403  }
404}
405
406} // end namespace llvm
407
408