Object/Mach-O: Add header and load command information.
[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 template<typename T>
20 static void SwapValue(T &Value) {
21   Value = sys::SwapByteOrder(Value);
22 }
23
24 MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_,
25                          bool Is64Bit_)
26   : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_),
27     IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()),
28     LoadCommands(0), NumLoadedCommands(0) {
29   // Load the common header.
30   memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header));
31   if (IsSwappedEndian) {
32     SwapValue(Header.Magic);
33     SwapValue(Header.CPUType);
34     SwapValue(Header.CPUSubtype);
35     SwapValue(Header.FileType);
36     SwapValue(Header.NumLoadCommands);
37     SwapValue(Header.SizeOfLoadCommands);
38     SwapValue(Header.Flags);
39   }
40
41   if (is64Bit()) {
42     memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header),
43            sizeof(Header64Ext));
44     if (IsSwappedEndian) {
45       SwapValue(Header64Ext.Reserved);
46     }
47   }
48
49   // Create the load command array if sane.
50   if (getHeader().NumLoadCommands < (1 << 20))
51     LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands];
52 }
53
54 MachOObject::~MachOObject() {
55   delete LoadCommands;
56 }
57
58 MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer,
59                                          std::string *ErrorStr) {
60   // First, check the magic value and initialize the basic object info.
61   bool IsLittleEndian = false, Is64Bit = false;
62   StringRef Magic = Buffer->getBuffer().slice(0, 4);
63   if (Magic == "\xFE\xED\xFA\xCE") {
64   }  else if (Magic == "\xCE\xFA\xED\xFE") {
65     IsLittleEndian = true;
66   } else if (Magic == "\xFE\xED\xFA\xCF") {
67     Is64Bit = true;
68   } else if (Magic == "\xCF\xFA\xED\xFE") {
69     IsLittleEndian = true;
70     Is64Bit = true;
71   } else {
72     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)";
73     return 0;
74   }
75
76   // Ensure that the at least the full header is present.
77   unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size;
78   if (Buffer->getBufferSize() < HeaderSize) {
79     if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)";
80     return 0;
81   }
82
83   OwningPtr<MachOObject> Object(new MachOObject(Buffer, IsLittleEndian,
84                                                 Is64Bit));
85
86   // Check for bogus number of load commands.
87   if (Object->getHeader().NumLoadCommands >= (1 << 20)) {
88     if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)";
89     return 0;
90   }
91
92   if (ErrorStr) *ErrorStr = "";
93   return Object.take();
94 }
95
96 const MachOObject::LoadCommandInfo &
97 MachOObject::getLoadCommandInfo(unsigned Index) const {
98   assert(Index < getHeader().NumLoadCommands && "Invalid index!");
99
100   // Load the command, if necessary.
101   if (Index >= NumLoadedCommands) {
102     uint64_t Offset;
103     if (Index == 0) {
104       Offset = getHeaderSize();
105     } else {
106       const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1);
107       Offset = Prev.Offset + Prev.Command.Size;
108     }
109
110     LoadCommandInfo &Info = LoadCommands[Index];
111     memcpy(&Info.Command, Buffer->getBuffer().data() + Offset,
112            sizeof(macho::LoadCommand));
113     if (IsSwappedEndian) {
114       SwapValue(Info.Command.Type);
115       SwapValue(Info.Command.Size);
116     }
117     Info.Offset = Offset;
118     NumLoadedCommands = Index + 1;
119   }
120
121   return LoadCommands[Index];
122 }