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