1 //===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/Object/MachOObject.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/Support/Host.h"
14 #include "llvm/Support/SwapByteOrder.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "llvm/Support/Debug.h"
19 using namespace llvm::object
;
21 /* Translation Utilities */
24 static void SwapValue(T
&Value
) {
25 Value
= sys::SwapByteOrder(Value
);
29 static void SwapStruct(T
&Value
);
32 static void ReadInMemoryStruct(const MachOObject
&MOO
,
33 StringRef Buffer
, uint64_t Base
,
34 InMemoryStruct
<T
> &Res
) {
35 typedef T struct_type
;
36 uint64_t Size
= sizeof(struct_type
);
38 // Check that the buffer contains the expected data.
39 if (Base
+ Size
> Buffer
.size()) {
44 // Check whether we can return a direct pointer.
45 struct_type
*Ptr
= (struct_type
*) (Buffer
.data() + Base
);
46 if (!MOO
.isSwappedEndian()) {
51 // Otherwise, copy the struct and translate the values.
58 MachOObject::MachOObject(MemoryBuffer
*Buffer_
, bool IsLittleEndian_
,
60 : Buffer(Buffer_
), IsLittleEndian(IsLittleEndian_
), Is64Bit(Is64Bit_
),
61 IsSwappedEndian(IsLittleEndian
!= sys::isLittleEndianHost()),
62 HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) {
63 // Load the common header.
64 memcpy(&Header
, Buffer
->getBuffer().data(), sizeof(Header
));
65 if (IsSwappedEndian
) {
66 SwapValue(Header
.Magic
);
67 SwapValue(Header
.CPUType
);
68 SwapValue(Header
.CPUSubtype
);
69 SwapValue(Header
.FileType
);
70 SwapValue(Header
.NumLoadCommands
);
71 SwapValue(Header
.SizeOfLoadCommands
);
72 SwapValue(Header
.Flags
);
76 memcpy(&Header64Ext
, Buffer
->getBuffer().data() + sizeof(Header
),
78 if (IsSwappedEndian
) {
79 SwapValue(Header64Ext
.Reserved
);
83 // Create the load command array if sane.
84 if (getHeader().NumLoadCommands
< (1 << 20))
85 LoadCommands
= new LoadCommandInfo
[getHeader().NumLoadCommands
];
88 MachOObject::~MachOObject() {
89 delete [] LoadCommands
;
92 MachOObject
*MachOObject::LoadFromBuffer(MemoryBuffer
*Buffer
,
93 std::string
*ErrorStr
) {
94 // First, check the magic value and initialize the basic object info.
95 bool IsLittleEndian
= false, Is64Bit
= false;
96 StringRef Magic
= Buffer
->getBuffer().slice(0, 4);
97 if (Magic
== "\xFE\xED\xFA\xCE") {
98 } else if (Magic
== "\xCE\xFA\xED\xFE") {
99 IsLittleEndian
= true;
100 } else if (Magic
== "\xFE\xED\xFA\xCF") {
102 } else if (Magic
== "\xCF\xFA\xED\xFE") {
103 IsLittleEndian
= true;
106 if (ErrorStr
) *ErrorStr
= "not a Mach object file (invalid magic)";
110 // Ensure that the at least the full header is present.
111 unsigned HeaderSize
= Is64Bit
? macho::Header64Size
: macho::Header32Size
;
112 if (Buffer
->getBufferSize() < HeaderSize
) {
113 if (ErrorStr
) *ErrorStr
= "not a Mach object file (invalid header)";
117 OwningPtr
<MachOObject
> Object(new MachOObject(Buffer
, IsLittleEndian
,
120 // Check for bogus number of load commands.
121 if (Object
->getHeader().NumLoadCommands
>= (1 << 20)) {
122 if (ErrorStr
) *ErrorStr
= "not a Mach object file (unreasonable header)";
126 if (ErrorStr
) *ErrorStr
= "";
127 return Object
.take();
130 StringRef
MachOObject::getData(size_t Offset
, size_t Size
) const {
131 return Buffer
->getBuffer().substr(Offset
,Size
);
134 void MachOObject::RegisterStringTable(macho::SymtabLoadCommand
&SLC
) {
135 HasStringTable
= true;
136 StringTable
= Buffer
->getBuffer().substr(SLC
.StringTableOffset
,
137 SLC
.StringTableSize
);
140 const MachOObject::LoadCommandInfo
&
141 MachOObject::getLoadCommandInfo(unsigned Index
) const {
142 assert(Index
< getHeader().NumLoadCommands
&& "Invalid index!");
144 // Load the command, if necessary.
145 if (Index
>= NumLoadedCommands
) {
148 Offset
= getHeaderSize();
150 const LoadCommandInfo
&Prev
= getLoadCommandInfo(Index
- 1);
151 Offset
= Prev
.Offset
+ Prev
.Command
.Size
;
154 LoadCommandInfo
&Info
= LoadCommands
[Index
];
155 memcpy(&Info
.Command
, Buffer
->getBuffer().data() + Offset
,
156 sizeof(macho::LoadCommand
));
157 if (IsSwappedEndian
) {
158 SwapValue(Info
.Command
.Type
);
159 SwapValue(Info
.Command
.Size
);
161 Info
.Offset
= Offset
;
162 NumLoadedCommands
= Index
+ 1;
165 return LoadCommands
[Index
];
169 void SwapStruct(macho::SegmentLoadCommand
&Value
) {
170 SwapValue(Value
.Type
);
171 SwapValue(Value
.Size
);
172 SwapValue(Value
.VMAddress
);
173 SwapValue(Value
.VMSize
);
174 SwapValue(Value
.FileOffset
);
175 SwapValue(Value
.FileSize
);
176 SwapValue(Value
.MaxVMProtection
);
177 SwapValue(Value
.InitialVMProtection
);
178 SwapValue(Value
.NumSections
);
179 SwapValue(Value
.Flags
);
181 void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo
&LCI
,
182 InMemoryStruct
<macho::SegmentLoadCommand
> &Res
) const {
183 ReadInMemoryStruct(*this, Buffer
->getBuffer(), LCI
.Offset
, Res
);
187 void SwapStruct(macho::Segment64LoadCommand
&Value
) {
188 SwapValue(Value
.Type
);
189 SwapValue(Value
.Size
);
190 SwapValue(Value
.VMAddress
);
191 SwapValue(Value
.VMSize
);
192 SwapValue(Value
.FileOffset
);
193 SwapValue(Value
.FileSize
);
194 SwapValue(Value
.MaxVMProtection
);
195 SwapValue(Value
.InitialVMProtection
);
196 SwapValue(Value
.NumSections
);
197 SwapValue(Value
.Flags
);
199 void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo
&LCI
,
200 InMemoryStruct
<macho::Segment64LoadCommand
> &Res
) const {
201 ReadInMemoryStruct(*this, Buffer
->getBuffer(), LCI
.Offset
, Res
);
205 void SwapStruct(macho::SymtabLoadCommand
&Value
) {
206 SwapValue(Value
.Type
);
207 SwapValue(Value
.Size
);
208 SwapValue(Value
.SymbolTableOffset
);
209 SwapValue(Value
.NumSymbolTableEntries
);
210 SwapValue(Value
.StringTableOffset
);
211 SwapValue(Value
.StringTableSize
);
213 void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo
&LCI
,
214 InMemoryStruct
<macho::SymtabLoadCommand
> &Res
) const {
215 ReadInMemoryStruct(*this, Buffer
->getBuffer(), LCI
.Offset
, Res
);
219 void SwapStruct(macho::DysymtabLoadCommand
&Value
) {
220 SwapValue(Value
.Type
);
221 SwapValue(Value
.Size
);
222 SwapValue(Value
.LocalSymbolsIndex
);
223 SwapValue(Value
.NumLocalSymbols
);
224 SwapValue(Value
.ExternalSymbolsIndex
);
225 SwapValue(Value
.NumExternalSymbols
);
226 SwapValue(Value
.UndefinedSymbolsIndex
);
227 SwapValue(Value
.NumUndefinedSymbols
);
228 SwapValue(Value
.TOCOffset
);
229 SwapValue(Value
.NumTOCEntries
);
230 SwapValue(Value
.ModuleTableOffset
);
231 SwapValue(Value
.NumModuleTableEntries
);
232 SwapValue(Value
.ReferenceSymbolTableOffset
);
233 SwapValue(Value
.NumReferencedSymbolTableEntries
);
234 SwapValue(Value
.IndirectSymbolTableOffset
);
235 SwapValue(Value
.NumIndirectSymbolTableEntries
);
236 SwapValue(Value
.ExternalRelocationTableOffset
);
237 SwapValue(Value
.NumExternalRelocationTableEntries
);
238 SwapValue(Value
.LocalRelocationTableOffset
);
239 SwapValue(Value
.NumLocalRelocationTableEntries
);
241 void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo
&LCI
,
242 InMemoryStruct
<macho::DysymtabLoadCommand
> &Res
) const {
243 ReadInMemoryStruct(*this, Buffer
->getBuffer(), LCI
.Offset
, Res
);
247 void SwapStruct(macho::IndirectSymbolTableEntry
&Value
) {
248 SwapValue(Value
.Index
);
251 MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand
&DLC
,
253 InMemoryStruct
<macho::IndirectSymbolTableEntry
> &Res
) const {
254 uint64_t Offset
= (DLC
.IndirectSymbolTableOffset
+
255 Index
* sizeof(macho::IndirectSymbolTableEntry
));
256 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
261 void SwapStruct(macho::Section
&Value
) {
262 SwapValue(Value
.Address
);
263 SwapValue(Value
.Size
);
264 SwapValue(Value
.Offset
);
265 SwapValue(Value
.Align
);
266 SwapValue(Value
.RelocationTableOffset
);
267 SwapValue(Value
.NumRelocationTableEntries
);
268 SwapValue(Value
.Flags
);
269 SwapValue(Value
.Reserved1
);
270 SwapValue(Value
.Reserved2
);
272 void MachOObject::ReadSection(const LoadCommandInfo
&LCI
,
274 InMemoryStruct
<macho::Section
> &Res
) const {
275 assert(LCI
.Command
.Type
== macho::LCT_Segment
&&
276 "Unexpected load command info!");
277 uint64_t Offset
= (LCI
.Offset
+ sizeof(macho::SegmentLoadCommand
) +
278 Index
* sizeof(macho::Section
));
279 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
283 void SwapStruct(macho::Section64
&Value
) {
284 SwapValue(Value
.Address
);
285 SwapValue(Value
.Size
);
286 SwapValue(Value
.Offset
);
287 SwapValue(Value
.Align
);
288 SwapValue(Value
.RelocationTableOffset
);
289 SwapValue(Value
.NumRelocationTableEntries
);
290 SwapValue(Value
.Flags
);
291 SwapValue(Value
.Reserved1
);
292 SwapValue(Value
.Reserved2
);
293 SwapValue(Value
.Reserved3
);
295 void MachOObject::ReadSection64(const LoadCommandInfo
&LCI
,
297 InMemoryStruct
<macho::Section64
> &Res
) const {
298 assert(LCI
.Command
.Type
== macho::LCT_Segment64
&&
299 "Unexpected load command info!");
300 uint64_t Offset
= (LCI
.Offset
+ sizeof(macho::Segment64LoadCommand
) +
301 Index
* sizeof(macho::Section64
));
302 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
306 void SwapStruct(macho::RelocationEntry
&Value
) {
307 SwapValue(Value
.Word0
);
308 SwapValue(Value
.Word1
);
310 void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset
,
312 InMemoryStruct
<macho::RelocationEntry
> &Res
) const {
313 uint64_t Offset
= (RelocationTableOffset
+
314 Index
* sizeof(macho::RelocationEntry
));
315 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
319 void SwapStruct(macho::SymbolTableEntry
&Value
) {
320 SwapValue(Value
.StringIndex
);
321 SwapValue(Value
.Flags
);
322 SwapValue(Value
.Value
);
324 void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset
,
326 InMemoryStruct
<macho::SymbolTableEntry
> &Res
) const {
327 uint64_t Offset
= (SymbolTableOffset
+
328 Index
* sizeof(macho::SymbolTableEntry
));
329 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
333 void SwapStruct(macho::Symbol64TableEntry
&Value
) {
334 SwapValue(Value
.StringIndex
);
335 SwapValue(Value
.Flags
);
336 SwapValue(Value
.Value
);
338 void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset
,
340 InMemoryStruct
<macho::Symbol64TableEntry
> &Res
) const {
341 uint64_t Offset
= (SymbolTableOffset
+
342 Index
* sizeof(macho::Symbol64TableEntry
));
343 ReadInMemoryStruct(*this, Buffer
->getBuffer(), Offset
, Res
);
347 // Object Dumping Facilities
348 void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; }
349 void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; }
351 void MachOObject::printHeader(raw_ostream
&O
) const {
352 O
<< "('cputype', " << Header
.CPUType
<< ")\n";
353 O
<< "('cpusubtype', " << Header
.CPUSubtype
<< ")\n";
354 O
<< "('filetype', " << Header
.FileType
<< ")\n";
355 O
<< "('num_load_commands', " << Header
.NumLoadCommands
<< ")\n";
356 O
<< "('load_commands_size', " << Header
.SizeOfLoadCommands
<< ")\n";
357 O
<< "('flag', " << Header
.Flags
<< ")\n";
359 // Print extended header if 64-bit.
361 O
<< "('reserved', " << Header64Ext
.Reserved
<< ")\n";
364 void MachOObject::print(raw_ostream
&O
) const {
367 O
<< "Load Commands:\n";