• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ADT/SmallVector.h"
13 #include "llvm/Support/DataExtractor.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/Host.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/Support/SwapByteOrder.h"
19 
20 using namespace llvm;
21 using namespace llvm::object;
22 
23 /* Translation Utilities */
24 
25 template<typename T>
SwapValue(T & Value)26 static void SwapValue(T &Value) {
27   Value = sys::SwapByteOrder(Value);
28 }
29 
30 template<typename T>
31 static void SwapStruct(T &Value);
32 
33 template<typename T>
ReadInMemoryStruct(const MachOObject & MOO,StringRef Buffer,uint64_t Base,InMemoryStruct<T> & Res)34 static void ReadInMemoryStruct(const MachOObject &MOO,
35                                StringRef Buffer, uint64_t Base,
36                                InMemoryStruct<T> &Res) {
37   typedef T struct_type;
38   uint64_t Size = sizeof(struct_type);
39 
40   // Check that the buffer contains the expected data.
41   if (Base + Size >  Buffer.size()) {
42     Res = 0;
43     return;
44   }
45 
46   // Check whether we can return a direct pointer.
47   struct_type *Ptr = (struct_type *) (Buffer.data() + Base);
48   if (!MOO.isSwappedEndian()) {
49     Res = Ptr;
50     return;
51   }
52 
53   // Otherwise, copy the struct and translate the values.
54   Res = *Ptr;
55   SwapStruct(*Res);
56 }
57 
58 /* *** */
59 
MachOObject(MemoryBuffer * Buffer_,bool IsLittleEndian_,bool Is64Bit_)60 MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_,
61                          bool Is64Bit_)
62   : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_),
63     IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()),
64     HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) {
65   // Load the common header.
66   memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header));
67   if (IsSwappedEndian) {
68     SwapValue(Header.Magic);
69     SwapValue(Header.CPUType);
70     SwapValue(Header.CPUSubtype);
71     SwapValue(Header.FileType);
72     SwapValue(Header.NumLoadCommands);
73     SwapValue(Header.SizeOfLoadCommands);
74     SwapValue(Header.Flags);
75   }
76 
77   if (is64Bit()) {
78     memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header),
79            sizeof(Header64Ext));
80     if (IsSwappedEndian) {
81       SwapValue(Header64Ext.Reserved);
82     }
83   }
84 
85   // Create the load command array if sane.
86   if (getHeader().NumLoadCommands < (1 << 20))
87     LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands];
88 }
89 
~MachOObject()90 MachOObject::~MachOObject() {
91   delete [] LoadCommands;
92 }
93 
LoadFromBuffer(MemoryBuffer * Buffer,std::string * ErrorStr)94 MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer,
95                                          std::string *ErrorStr) {
96   // First, check the magic value and initialize the basic object info.
97   bool IsLittleEndian = false, Is64Bit = false;
98   StringRef Magic = Buffer->getBuffer().slice(0, 4);
99   if (Magic == "\xFE\xED\xFA\xCE") {
100   }  else if (Magic == "\xCE\xFA\xED\xFE") {
101     IsLittleEndian = true;
102   } else if (Magic == "\xFE\xED\xFA\xCF") {
103     Is64Bit = true;
104   } else if (Magic == "\xCF\xFA\xED\xFE") {
105     IsLittleEndian = true;
106     Is64Bit = true;
107   } else {
108     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)";
109     return 0;
110   }
111 
112   // Ensure that the at least the full header is present.
113   unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size;
114   if (Buffer->getBufferSize() < HeaderSize) {
115     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)";
116     return 0;
117   }
118 
119   OwningPtr<MachOObject> Object(new MachOObject(Buffer, IsLittleEndian,
120                                                 Is64Bit));
121 
122   // Check for bogus number of load commands.
123   if (Object->getHeader().NumLoadCommands >= (1 << 20)) {
124     if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)";
125     return 0;
126   }
127 
128   if (ErrorStr) *ErrorStr = "";
129   return Object.take();
130 }
131 
getData(size_t Offset,size_t Size) const132 StringRef MachOObject::getData(size_t Offset, size_t Size) const {
133   return Buffer->getBuffer().substr(Offset,Size);
134 }
135 
RegisterStringTable(macho::SymtabLoadCommand & SLC)136 void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) {
137   HasStringTable = true;
138   StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset,
139                                            SLC.StringTableSize);
140 }
141 
142 const MachOObject::LoadCommandInfo &
getLoadCommandInfo(unsigned Index) const143 MachOObject::getLoadCommandInfo(unsigned Index) const {
144   assert(Index < getHeader().NumLoadCommands && "Invalid index!");
145 
146   // Load the command, if necessary.
147   if (Index >= NumLoadedCommands) {
148     uint64_t Offset;
149     if (Index == 0) {
150       Offset = getHeaderSize();
151     } else {
152       const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1);
153       Offset = Prev.Offset + Prev.Command.Size;
154     }
155 
156     LoadCommandInfo &Info = LoadCommands[Index];
157     memcpy(&Info.Command, Buffer->getBuffer().data() + Offset,
158            sizeof(macho::LoadCommand));
159     if (IsSwappedEndian) {
160       SwapValue(Info.Command.Type);
161       SwapValue(Info.Command.Size);
162     }
163     Info.Offset = Offset;
164     NumLoadedCommands = Index + 1;
165   }
166 
167   return LoadCommands[Index];
168 }
169 
170 template<>
SwapStruct(macho::SegmentLoadCommand & Value)171 void SwapStruct(macho::SegmentLoadCommand &Value) {
172   SwapValue(Value.Type);
173   SwapValue(Value.Size);
174   SwapValue(Value.VMAddress);
175   SwapValue(Value.VMSize);
176   SwapValue(Value.FileOffset);
177   SwapValue(Value.FileSize);
178   SwapValue(Value.MaxVMProtection);
179   SwapValue(Value.InitialVMProtection);
180   SwapValue(Value.NumSections);
181   SwapValue(Value.Flags);
182 }
ReadSegmentLoadCommand(const LoadCommandInfo & LCI,InMemoryStruct<macho::SegmentLoadCommand> & Res) const183 void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI,
184                          InMemoryStruct<macho::SegmentLoadCommand> &Res) const {
185   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
186 }
187 
188 template<>
SwapStruct(macho::Segment64LoadCommand & Value)189 void SwapStruct(macho::Segment64LoadCommand &Value) {
190   SwapValue(Value.Type);
191   SwapValue(Value.Size);
192   SwapValue(Value.VMAddress);
193   SwapValue(Value.VMSize);
194   SwapValue(Value.FileOffset);
195   SwapValue(Value.FileSize);
196   SwapValue(Value.MaxVMProtection);
197   SwapValue(Value.InitialVMProtection);
198   SwapValue(Value.NumSections);
199   SwapValue(Value.Flags);
200 }
ReadSegment64LoadCommand(const LoadCommandInfo & LCI,InMemoryStruct<macho::Segment64LoadCommand> & Res) const201 void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI,
202                        InMemoryStruct<macho::Segment64LoadCommand> &Res) const {
203   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
204 }
205 
206 template<>
SwapStruct(macho::SymtabLoadCommand & Value)207 void SwapStruct(macho::SymtabLoadCommand &Value) {
208   SwapValue(Value.Type);
209   SwapValue(Value.Size);
210   SwapValue(Value.SymbolTableOffset);
211   SwapValue(Value.NumSymbolTableEntries);
212   SwapValue(Value.StringTableOffset);
213   SwapValue(Value.StringTableSize);
214 }
ReadSymtabLoadCommand(const LoadCommandInfo & LCI,InMemoryStruct<macho::SymtabLoadCommand> & Res) const215 void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI,
216                           InMemoryStruct<macho::SymtabLoadCommand> &Res) const {
217   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
218 }
219 
220 template<>
SwapStruct(macho::DysymtabLoadCommand & Value)221 void SwapStruct(macho::DysymtabLoadCommand &Value) {
222   SwapValue(Value.Type);
223   SwapValue(Value.Size);
224   SwapValue(Value.LocalSymbolsIndex);
225   SwapValue(Value.NumLocalSymbols);
226   SwapValue(Value.ExternalSymbolsIndex);
227   SwapValue(Value.NumExternalSymbols);
228   SwapValue(Value.UndefinedSymbolsIndex);
229   SwapValue(Value.NumUndefinedSymbols);
230   SwapValue(Value.TOCOffset);
231   SwapValue(Value.NumTOCEntries);
232   SwapValue(Value.ModuleTableOffset);
233   SwapValue(Value.NumModuleTableEntries);
234   SwapValue(Value.ReferenceSymbolTableOffset);
235   SwapValue(Value.NumReferencedSymbolTableEntries);
236   SwapValue(Value.IndirectSymbolTableOffset);
237   SwapValue(Value.NumIndirectSymbolTableEntries);
238   SwapValue(Value.ExternalRelocationTableOffset);
239   SwapValue(Value.NumExternalRelocationTableEntries);
240   SwapValue(Value.LocalRelocationTableOffset);
241   SwapValue(Value.NumLocalRelocationTableEntries);
242 }
ReadDysymtabLoadCommand(const LoadCommandInfo & LCI,InMemoryStruct<macho::DysymtabLoadCommand> & Res) const243 void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI,
244                         InMemoryStruct<macho::DysymtabLoadCommand> &Res) const {
245   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
246 }
247 
248 template<>
SwapStruct(macho::LinkeditDataLoadCommand & Value)249 void SwapStruct(macho::LinkeditDataLoadCommand &Value) {
250   SwapValue(Value.Type);
251   SwapValue(Value.Size);
252   SwapValue(Value.DataOffset);
253   SwapValue(Value.DataSize);
254 }
ReadLinkeditDataLoadCommand(const LoadCommandInfo & LCI,InMemoryStruct<macho::LinkeditDataLoadCommand> & Res) const255 void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI,
256                     InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const {
257   ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res);
258 }
259 
260 template<>
SwapStruct(macho::IndirectSymbolTableEntry & Value)261 void SwapStruct(macho::IndirectSymbolTableEntry &Value) {
262   SwapValue(Value.Index);
263 }
264 void
ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand & DLC,unsigned Index,InMemoryStruct<macho::IndirectSymbolTableEntry> & Res) const265 MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC,
266                                           unsigned Index,
267                    InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const {
268   uint64_t Offset = (DLC.IndirectSymbolTableOffset +
269                      Index * sizeof(macho::IndirectSymbolTableEntry));
270   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
271 }
272 
273 
274 template<>
SwapStruct(macho::Section & Value)275 void SwapStruct(macho::Section &Value) {
276   SwapValue(Value.Address);
277   SwapValue(Value.Size);
278   SwapValue(Value.Offset);
279   SwapValue(Value.Align);
280   SwapValue(Value.RelocationTableOffset);
281   SwapValue(Value.NumRelocationTableEntries);
282   SwapValue(Value.Flags);
283   SwapValue(Value.Reserved1);
284   SwapValue(Value.Reserved2);
285 }
ReadSection(const LoadCommandInfo & LCI,unsigned Index,InMemoryStruct<macho::Section> & Res) const286 void MachOObject::ReadSection(const LoadCommandInfo &LCI,
287                               unsigned Index,
288                               InMemoryStruct<macho::Section> &Res) const {
289   assert(LCI.Command.Type == macho::LCT_Segment &&
290          "Unexpected load command info!");
291   uint64_t Offset = (LCI.Offset + sizeof(macho::SegmentLoadCommand) +
292                      Index * sizeof(macho::Section));
293   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
294 }
295 
296 template<>
SwapStruct(macho::Section64 & Value)297 void SwapStruct(macho::Section64 &Value) {
298   SwapValue(Value.Address);
299   SwapValue(Value.Size);
300   SwapValue(Value.Offset);
301   SwapValue(Value.Align);
302   SwapValue(Value.RelocationTableOffset);
303   SwapValue(Value.NumRelocationTableEntries);
304   SwapValue(Value.Flags);
305   SwapValue(Value.Reserved1);
306   SwapValue(Value.Reserved2);
307   SwapValue(Value.Reserved3);
308 }
ReadSection64(const LoadCommandInfo & LCI,unsigned Index,InMemoryStruct<macho::Section64> & Res) const309 void MachOObject::ReadSection64(const LoadCommandInfo &LCI,
310                                 unsigned Index,
311                                 InMemoryStruct<macho::Section64> &Res) const {
312   assert(LCI.Command.Type == macho::LCT_Segment64 &&
313          "Unexpected load command info!");
314   uint64_t Offset = (LCI.Offset + sizeof(macho::Segment64LoadCommand) +
315                      Index * sizeof(macho::Section64));
316   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
317 }
318 
319 template<>
SwapStruct(macho::RelocationEntry & Value)320 void SwapStruct(macho::RelocationEntry &Value) {
321   SwapValue(Value.Word0);
322   SwapValue(Value.Word1);
323 }
ReadRelocationEntry(uint64_t RelocationTableOffset,unsigned Index,InMemoryStruct<macho::RelocationEntry> & Res) const324 void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset,
325                                       unsigned Index,
326                             InMemoryStruct<macho::RelocationEntry> &Res) const {
327   uint64_t Offset = (RelocationTableOffset +
328                      Index * sizeof(macho::RelocationEntry));
329   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
330 }
331 
332 template<>
SwapStruct(macho::SymbolTableEntry & Value)333 void SwapStruct(macho::SymbolTableEntry &Value) {
334   SwapValue(Value.StringIndex);
335   SwapValue(Value.Flags);
336   SwapValue(Value.Value);
337 }
ReadSymbolTableEntry(uint64_t SymbolTableOffset,unsigned Index,InMemoryStruct<macho::SymbolTableEntry> & Res) const338 void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset,
339                                        unsigned Index,
340                            InMemoryStruct<macho::SymbolTableEntry> &Res) const {
341   uint64_t Offset = (SymbolTableOffset +
342                      Index * sizeof(macho::SymbolTableEntry));
343   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
344 }
345 
346 template<>
SwapStruct(macho::Symbol64TableEntry & Value)347 void SwapStruct(macho::Symbol64TableEntry &Value) {
348   SwapValue(Value.StringIndex);
349   SwapValue(Value.Flags);
350   SwapValue(Value.Value);
351 }
ReadSymbol64TableEntry(uint64_t SymbolTableOffset,unsigned Index,InMemoryStruct<macho::Symbol64TableEntry> & Res) const352 void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset,
353                                        unsigned Index,
354                          InMemoryStruct<macho::Symbol64TableEntry> &Res) const {
355   uint64_t Offset = (SymbolTableOffset +
356                      Index * sizeof(macho::Symbol64TableEntry));
357   ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res);
358 }
359 
360 
ReadULEB128s(uint64_t Index,SmallVectorImpl<uint64_t> & Out) const361 void MachOObject::ReadULEB128s(uint64_t Index,
362                                SmallVectorImpl<uint64_t> &Out) const {
363   DataExtractor extractor(Buffer->getBuffer(), true, 0);
364 
365   uint32_t offset = Index;
366   uint64_t data = 0;
367   while (uint64_t delta = extractor.getULEB128(&offset)) {
368     data += delta;
369     Out.push_back(data);
370   }
371 }
372 
373 /* ** */
374 // Object Dumping Facilities
dump() const375 void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; }
dumpHeader() const376 void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; }
377 
printHeader(raw_ostream & O) const378 void MachOObject::printHeader(raw_ostream &O) const {
379   O << "('cputype', " << Header.CPUType << ")\n";
380   O << "('cpusubtype', " << Header.CPUSubtype << ")\n";
381   O << "('filetype', " << Header.FileType << ")\n";
382   O << "('num_load_commands', " << Header.NumLoadCommands << ")\n";
383   O << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n";
384   O << "('flag', " << Header.Flags << ")\n";
385 
386   // Print extended header if 64-bit.
387   if (is64Bit())
388     O << "('reserved', " << Header64Ext.Reserved << ")\n";
389 }
390 
print(raw_ostream & O) const391 void MachOObject::print(raw_ostream &O) const {
392   O << "Header:\n";
393   printHeader(O);
394   O << "Load Commands:\n";
395 
396   O << "Buffer:\n";
397 }
398