MachOObjectFile.cpp revision 6256b03674f4d50d1c035aa3ecba45df1345ea79
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
21#include <cctype>
22#include <cstring>
23#include <limits>
24
25using namespace llvm;
26using namespace object;
27
28namespace llvm {
29
30typedef MachOObject::LoadCommandInfo LoadCommandInfo;
31
32class MachOObjectFile : public ObjectFile {
33public:
34  MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO)
35    : ObjectFile(Object),
36      MachOObj(MOO),
37      RegisteredStringTable(std::numeric_limits<uint32_t>::max()) {}
38
39  virtual symbol_iterator begin_symbols() const;
40  virtual symbol_iterator end_symbols() const;
41  virtual section_iterator begin_sections() const;
42  virtual section_iterator end_sections() const;
43
44  virtual uint8_t getBytesInAddress() const;
45  virtual StringRef getFileFormatName() const;
46  virtual unsigned getArch() const;
47
48protected:
49  virtual SymbolRef getSymbolNext(DataRefImpl Symb) const;
50  virtual StringRef getSymbolName(DataRefImpl Symb) const;
51  virtual uint64_t  getSymbolAddress(DataRefImpl Symb) const;
52  virtual uint64_t  getSymbolSize(DataRefImpl Symb) const;
53  virtual char      getSymbolNMTypeChar(DataRefImpl Symb) const;
54  virtual bool      isSymbolInternal(DataRefImpl Symb) const;
55
56  virtual SectionRef getSectionNext(DataRefImpl Sec) const;
57  virtual StringRef  getSectionName(DataRefImpl Sec) const;
58  virtual uint64_t   getSectionAddress(DataRefImpl Sec) const;
59  virtual uint64_t   getSectionSize(DataRefImpl Sec) const;
60  virtual StringRef  getSectionContents(DataRefImpl Sec) const;
61  virtual bool       isSectionText(DataRefImpl Sec) const;
62
63private:
64  MachOObject *MachOObj;
65  mutable uint32_t RegisteredStringTable;
66
67  void moveToNextSection(DataRefImpl &DRI) const;
68  void getSymbolTableEntry(DataRefImpl DRI,
69                           InMemoryStruct<macho::SymbolTableEntry> &Res) const;
70  void moveToNextSymbol(DataRefImpl &DRI) const;
71  void getSection(DataRefImpl DRI, InMemoryStruct<macho::Section> &Res) const;
72};
73
74ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) {
75  std::string Err;
76  MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err);
77  if (!MachOObj)
78    return NULL;
79  return new MachOObjectFile(Buffer, MachOObj);
80}
81
82/*===-- Symbols -----------------------------------------------------------===*/
83
84void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const {
85  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
86  while (DRI.d.a < LoadCommandCount) {
87    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
88    if (LCI.Command.Type == macho::LCT_Symtab) {
89      InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
90      MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
91      if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries)
92        return;
93    }
94
95    DRI.d.a++;
96    DRI.d.b = 0;
97  }
98}
99
100void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI,
101    InMemoryStruct<macho::SymbolTableEntry> &Res) const {
102  InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
103  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
104  MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
105
106  if (RegisteredStringTable != DRI.d.a) {
107    MachOObj->RegisterStringTable(*SymtabLoadCmd);
108    RegisteredStringTable = DRI.d.a;
109  }
110
111  MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b,
112                                 Res);
113}
114
115
116SymbolRef MachOObjectFile::getSymbolNext(DataRefImpl DRI) const {
117  DRI.d.b++;
118  moveToNextSymbol(DRI);
119  return SymbolRef(DRI, this);
120}
121
122StringRef MachOObjectFile::getSymbolName(DataRefImpl DRI) const {
123  InMemoryStruct<macho::SymbolTableEntry> Entry;
124  getSymbolTableEntry(DRI, Entry);
125  return MachOObj->getStringAtIndex(Entry->StringIndex);
126}
127
128uint64_t MachOObjectFile::getSymbolAddress(DataRefImpl DRI) const {
129  InMemoryStruct<macho::SymbolTableEntry> Entry;
130  getSymbolTableEntry(DRI, Entry);
131  return Entry->Value;
132}
133
134uint64_t MachOObjectFile::getSymbolSize(DataRefImpl DRI) const {
135  return UnknownAddressOrSize;
136}
137
138char MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI) const {
139  InMemoryStruct<macho::SymbolTableEntry> Entry;
140  getSymbolTableEntry(DRI, Entry);
141
142  char Char;
143  switch (Entry->Type & macho::STF_TypeMask) {
144    case macho::STT_Undefined:
145      Char = 'u';
146      break;
147    case macho::STT_Absolute:
148    case macho::STT_Section:
149      Char = 's';
150      break;
151    default:
152      Char = '?';
153      break;
154  }
155
156  if (Entry->Flags & (macho::STF_External | macho::STF_PrivateExtern))
157    Char = toupper(Char);
158  return Char;
159}
160
161bool MachOObjectFile::isSymbolInternal(DataRefImpl DRI) const {
162  InMemoryStruct<macho::SymbolTableEntry> Entry;
163  getSymbolTableEntry(DRI, Entry);
164  return Entry->Flags & macho::STF_StabsEntryMask;
165}
166
167ObjectFile::symbol_iterator MachOObjectFile::begin_symbols() const {
168  // DRI.d.a = segment number; DRI.d.b = symbol index.
169  DataRefImpl DRI;
170  DRI.d.a = DRI.d.b = 0;
171  moveToNextSymbol(DRI);
172  return symbol_iterator(SymbolRef(DRI, this));
173}
174
175ObjectFile::symbol_iterator MachOObjectFile::end_symbols() const {
176  DataRefImpl DRI;
177  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
178  DRI.d.b = 0;
179  return symbol_iterator(SymbolRef(DRI, this));
180}
181
182
183/*===-- Sections ----------------------------------------------------------===*/
184
185void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const {
186  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
187  while (DRI.d.a < LoadCommandCount) {
188    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
189    if (LCI.Command.Type == macho::LCT_Segment) {
190      InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd;
191      MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd);
192      if (DRI.d.b < SegmentLoadCmd->NumSections)
193        return;
194    } else if (LCI.Command.Type == macho::LCT_Segment64) {
195      InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd;
196      MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd);
197      if (DRI.d.b < Segment64LoadCmd->NumSections)
198        return;
199    }
200
201    DRI.d.a++;
202    DRI.d.b = 0;
203  }
204}
205
206SectionRef MachOObjectFile::getSectionNext(DataRefImpl DRI) const {
207  DRI.d.b++;
208  moveToNextSection(DRI);
209  return SectionRef(DRI, this);
210}
211
212void
213MachOObjectFile::getSection(DataRefImpl DRI,
214                            InMemoryStruct<macho::Section> &Res) const {
215  InMemoryStruct<macho::SegmentLoadCommand> SLC;
216  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
217  MachOObj->ReadSegmentLoadCommand(LCI, SLC);
218  MachOObj->ReadSection(LCI, DRI.d.b, Res);
219}
220
221StringRef MachOObjectFile::getSectionName(DataRefImpl DRI) const {
222  InMemoryStruct<macho::SegmentLoadCommand> SLC;
223  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
224  MachOObj->ReadSegmentLoadCommand(LCI, SLC);
225  InMemoryStruct<macho::Section> Sect;
226  MachOObj->ReadSection(LCI, DRI.d.b, Sect);
227
228  static char Result[34];
229  strcpy(Result, SLC->Name);
230  strcat(Result, ",");
231  strcat(Result, Sect->Name);
232  return StringRef(Result);
233}
234
235uint64_t MachOObjectFile::getSectionAddress(DataRefImpl DRI) const {
236  InMemoryStruct<macho::Section> Sect;
237  getSection(DRI, Sect);
238  return Sect->Address;
239}
240
241uint64_t MachOObjectFile::getSectionSize(DataRefImpl DRI) const {
242  InMemoryStruct<macho::Section> Sect;
243  getSection(DRI, Sect);
244  return Sect->Size;
245}
246
247StringRef MachOObjectFile::getSectionContents(DataRefImpl DRI) const {
248  InMemoryStruct<macho::Section> Sect;
249  getSection(DRI, Sect);
250  return MachOObj->getData(Sect->Offset, Sect->Size);
251}
252
253bool MachOObjectFile::isSectionText(DataRefImpl DRI) const {
254  InMemoryStruct<macho::SegmentLoadCommand> SLC;
255  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
256  MachOObj->ReadSegmentLoadCommand(LCI, SLC);
257  return !strcmp(SLC->Name, "__TEXT");
258}
259
260ObjectFile::section_iterator MachOObjectFile::begin_sections() const {
261  DataRefImpl DRI;
262  DRI.d.a = DRI.d.b = 0;
263  moveToNextSection(DRI);
264  return section_iterator(SectionRef(DRI, this));
265}
266
267ObjectFile::section_iterator MachOObjectFile::end_sections() const {
268  DataRefImpl DRI;
269  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
270  DRI.d.b = 0;
271  return section_iterator(SectionRef(DRI, this));
272}
273
274/*===-- Miscellaneous -----------------------------------------------------===*/
275
276uint8_t MachOObjectFile::getBytesInAddress() const {
277  return MachOObj->is64Bit() ? 8 : 4;
278}
279
280StringRef MachOObjectFile::getFileFormatName() const {
281  if (!MachOObj->is64Bit()) {
282    switch (MachOObj->getHeader().CPUType) {
283    case 0x00000007:
284      return "MACHO32-i386";
285    case 0x01000007:
286      return "MACHO32-x86-64";
287    case 0x0000000c:
288      return "MACHO32-arm";
289    case 0x00000012:
290      return "MACHO32-ppc";
291    case 0x01000012:
292      return "MACHO32-ppc64";
293    }
294  }
295
296  switch (MachOObj->getHeader().CPUType) {
297  case 0x00000007:
298    return "MACHO64-i386";
299  case 0x01000007:
300    return "MACHO64-x86-64";
301  case 0x0000000c:
302    return "MACHO64-arm";
303  case 0x00000012:
304    return "MACHO64-ppc";
305  case 0x01000012:
306    return "MACHO64-ppc64";
307  default:
308    return "MACHO64-unknown";
309  }
310}
311
312unsigned MachOObjectFile::getArch() const {
313  switch (MachOObj->getHeader().CPUType) {
314  case 0x00000007:
315    return Triple::x86;
316  case 0x01000007:
317    return Triple::x86_64;
318  case 0x0000000c:
319    return Triple::arm;
320  case 0x00000012:
321    return Triple::ppc;
322  case 0x01000012:
323    return Triple::ppc64;
324  default:
325    return Triple::UnknownArch;
326  }
327}
328
329} // end namespace llvm
330
331