Unbreak build for newer GCCs.
[oota-llvm.git] / lib / Object / MachOObject.cpp
1 //===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===//
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 #include "llvm/Object/MachOObject.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/System/Host.h"
14 #include "llvm/System/SwapByteOrder.h"
15
16 using namespace llvm;
17 using namespace llvm::object;
18
19 /* Translation Utilities */
20
21 template<typename T>
22 static void SwapValue(T &Value) {
23   Value = sys::SwapByteOrder(Value);
24 }
25
26 template<typename T>
27 static void SwapStruct(T &Value);
28
29 template<typename T>
30 static void ReadInMemoryStruct(const MachOObject &MOO,
31                                StringRef Buffer, uint64_t Base,
32                                InMemoryStruct<T> &Res) {
33   typedef T struct_type;
34   uint64_t Size = sizeof(struct_type);
35
36   // Check that the buffer contains the expected data.
37   if (Base + Size >  Buffer.size()) {
38     Res = 0;
39     return;
40   }
41
42   // Check whether we can return a direct pointer.
43   struct_type *Ptr = (struct_type *) (Buffer.data() + Base);
44   if (!MOO.isSwappedEndian()) {
45     Res = Ptr;
46     return;
47   }
48
49   // Otherwise, copy the struct and translate the values.
50   Res = *Ptr;
51   SwapStruct(*Res);
52 }
53
54 /* *** */
55
56 MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_,
57                          bool Is64Bit_)
58   : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_),
59     IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()),
60     LoadCommands(0), NumLoadedCommands(0) {
61   // Load the common header.
62   memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header));
63   if (IsSwappedEndian) {
64     SwapValue(Header.Magic);
65     SwapValue(Header.CPUType);
66     SwapValue(Header.CPUSubtype);
67     SwapValue(Header.FileType);
68     SwapValue(Header.NumLoadCommands);
69     SwapValue(Header.SizeOfLoadCommands);
70     SwapValue(Header.Flags);
71   }
72
73   if (is64Bit()) {
74     memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header),
75            sizeof(Header64Ext));
76     if (IsSwappedEndian) {
77       SwapValue(Header64Ext.Reserved);
78     }
79   }
80
81   // Create the load command array if sane.
82   if (getHeader().NumLoadCommands < (1 << 20))
83     LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands];
84 }
85
86 MachOObject::~MachOObject() {
87   delete LoadCommands;
88 }
89
90 MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer,
91                                          std::string *ErrorStr) {
92   // First, check the magic value and initialize the basic object info.
93   bool IsLittleEndian = false, Is64Bit = false;
94   StringRef Magic = Buffer->getBuffer().slice(0, 4);
95   if (Magic == "\xFE\xED\xFA\xCE") {
96   }  else if (Magic == "\xCE\xFA\xED\xFE") {
97     IsLittleEndian = true;
98   } else if (Magic == "\xFE\xED\xFA\xCF") {
99     Is64Bit = true;
100   } else if (Magic == "\xCF\xFA\xED\xFE") {
101     IsLittleEndian = true;
102     Is64Bit = true;
103   } else {
104     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)";
105     return 0;
106   }
107
108   // Ensure that the at least the full header is present.
109   unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size;
110   if (Buffer->getBufferSize() < HeaderSize) {
111     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)";
112     return 0;
113   }
114
115   OwningPtr<MachOObject> Object(new MachOObject(Buffer, IsLittleEndian,
116                                                 Is64Bit));
117
118   // Check for bogus number of load commands.
119   if (Object->getHeader().NumLoadCommands >= (1 << 20)) {
120     if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)";
121     return 0;
122   }
123
124   if (ErrorStr) *ErrorStr = "";
125   return Object.take();
126 }
127
128 const MachOObject::LoadCommandInfo &
129 MachOObject::getLoadCommandInfo(unsigned Index) const {
130   assert(Index < getHeader().NumLoadCommands && "Invalid index!");
131
132   // Load the command, if necessary.
133   if (Index >= NumLoadedCommands) {
134     uint64_t Offset;
135     if (Index == 0) {
136       Offset = getHeaderSize();
137     } else {
138       const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1);
139       Offset = Prev.Offset + Prev.Command.Size;
140     }
141
142     LoadCommandInfo &Info = LoadCommands[Index];
143     memcpy(&Info.Command, Buffer->getBuffer().data() + Offset,
144            sizeof(macho::LoadCommand));
145     if (IsSwappedEndian) {
146       SwapValue(Info.Command.Type);
147       SwapValue(Info.Command.Size);
148     }
149     Info.Offset = Offset;
150     NumLoadedCommands = Index + 1;
151   }
152
153   return LoadCommands[Index];
154 }
155
156 template<>
157 void SwapStruct(macho::SegmentLoadCommand &Value) {
158   SwapValue(Value.Type);
159   SwapValue(Value.Size);
160   SwapValue(Value.VMAddress);
161   SwapValue(Value.VMSize);
162   SwapValue(Value.FileOffset);
163   SwapValue(Value.FileSize);
164   SwapValue(Value.MaxVMProtection);
165   SwapValue(Value.InitialVMProtection);
166   SwapValue(Value.NumSections);
167   SwapValue(Value.Flags);
168 }
169 void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI,
170                          InMemoryStruct<macho::SegmentLoadCommand> &Res) const {
171   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
172 }
173
174 template<>
175 void SwapStruct(macho::Segment64LoadCommand &Value) {
176   SwapValue(Value.Type);
177   SwapValue(Value.Size);
178   SwapValue(Value.VMAddress);
179   SwapValue(Value.VMSize);
180   SwapValue(Value.FileOffset);
181   SwapValue(Value.FileSize);
182   SwapValue(Value.MaxVMProtection);
183   SwapValue(Value.InitialVMProtection);
184   SwapValue(Value.NumSections);
185   SwapValue(Value.Flags);
186 }
187 void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI,
188                        InMemoryStruct<macho::Segment64LoadCommand> &Res) const {
189   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
190 }
191
192 template<>
193 void SwapStruct(macho::SymtabLoadCommand &Value) {
194   SwapValue(Value.Type);
195   SwapValue(Value.Size);
196   SwapValue(Value.SymbolTableOffset);
197   SwapValue(Value.NumSymbolTableEntries);
198   SwapValue(Value.StringTableOffset);
199   SwapValue(Value.StringTableSize);
200 }
201 void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI,
202                           InMemoryStruct<macho::SymtabLoadCommand> &Res) const {
203   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
204 }
205
206 template<>
207 void SwapStruct(macho::DysymtabLoadCommand &Value) {
208   SwapValue(Value.Type);
209   SwapValue(Value.Size);
210   SwapValue(Value.LocalSymbolIndex);
211   SwapValue(Value.NumLocalSymbols);
212   SwapValue(Value.ExternalSymbolsIndex);
213   SwapValue(Value.NumExternalSymbols);
214   SwapValue(Value.UndefinedSymbolsIndex);
215   SwapValue(Value.NumUndefinedSymbols);
216   SwapValue(Value.TOCOffset);
217   SwapValue(Value.NumTOCEntries);
218   SwapValue(Value.ModuleTableOffset);
219   SwapValue(Value.NumModuleTableEntries);
220   SwapValue(Value.ReferenceSymbolTableOffset);
221   SwapValue(Value.NumReferencedSymbolTableEntries);
222   SwapValue(Value.IndirectSymbolTableOffset);
223   SwapValue(Value.NumIndirectSymbolTableEntries);
224   SwapValue(Value.ExternalRelocationTableOffset);
225   SwapValue(Value.NumExternalRelocationTableEntries);
226   SwapValue(Value.LocalRelocationTableOffset);
227   SwapValue(Value.NumLocalRelocationTableEntries);
228 }
229 void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI,
230                         InMemoryStruct<macho::DysymtabLoadCommand> &Res) const {
231   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
232 }