Add an ObjectFile implementation for mach-o.
[oota-llvm.git] / lib / Object / MachOObjectFile.cpp
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
25 using namespace llvm;
26 using namespace object;
27
28 namespace llvm {
29
30 typedef MachOObject::LoadCommandInfo LoadCommandInfo;
31
32 class MachOObjectFile : public ObjectFile {
33 public:
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
48 protected:
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
63 private:
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
74 ObjectFile *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
84 void 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
100 void 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
116 SymbolRef MachOObjectFile::getSymbolNext(DataRefImpl DRI) const {
117   DRI.d.b++;
118   moveToNextSymbol(DRI);
119   return SymbolRef(DRI, this);
120 }
121
122 StringRef MachOObjectFile::getSymbolName(DataRefImpl DRI) const {
123   InMemoryStruct<macho::SymbolTableEntry> Entry;
124   getSymbolTableEntry(DRI, Entry);
125   return MachOObj->getStringAtIndex(Entry->StringIndex);
126 }
127
128 uint64_t MachOObjectFile::getSymbolAddress(DataRefImpl DRI) const {
129   InMemoryStruct<macho::SymbolTableEntry> Entry;
130   getSymbolTableEntry(DRI, Entry);
131   return Entry->Value;
132 }
133
134 uint64_t MachOObjectFile::getSymbolSize(DataRefImpl DRI) const {
135   return UnknownAddressOrSize;
136 }
137
138 char 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
161 bool MachOObjectFile::isSymbolInternal(DataRefImpl DRI) const {
162   InMemoryStruct<macho::SymbolTableEntry> Entry;
163   getSymbolTableEntry(DRI, Entry);
164   return Entry->Flags & macho::STF_StabsEntryMask;
165 }
166
167 ObjectFile::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
175 ObjectFile::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
185 void 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
206 SectionRef MachOObjectFile::getSectionNext(DataRefImpl DRI) const {
207   DRI.d.b++;
208   moveToNextSection(DRI);
209   return SectionRef(DRI, this);
210 }
211
212 void
213 MachOObjectFile::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
221 StringRef 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
235 uint64_t MachOObjectFile::getSectionAddress(DataRefImpl DRI) const {
236   InMemoryStruct<macho::Section> Sect;
237   getSection(DRI, Sect);
238   return Sect->Address;
239 }
240
241 uint64_t MachOObjectFile::getSectionSize(DataRefImpl DRI) const {
242   InMemoryStruct<macho::Section> Sect;
243   getSection(DRI, Sect);
244   return Sect->Size;
245 }
246
247 StringRef MachOObjectFile::getSectionContents(DataRefImpl DRI) const {
248   InMemoryStruct<macho::Section> Sect;
249   getSection(DRI, Sect);
250   return MachOObj->getData(Sect->Offset, Sect->Size);
251 }
252
253 bool 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
260 ObjectFile::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
267 ObjectFile::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
276 uint8_t MachOObjectFile::getBytesInAddress() const {
277   return MachOObj->is64Bit() ? 8 : 4;
278 }
279
280 StringRef 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
312 unsigned 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