blob: 5085efde5ecfbeece709c9122bc355b32ae549d4 [file] [log] [blame]
Alexey Samsonove6388e62013-06-18 15:03:28 +00001//===- MachOUniversal.cpp - Mach-O universal binary -------------*- 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 MachOUniversalBinary class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Object/MachOUniversal.h"
Alexey Samsonove6388e62013-06-18 15:03:28 +000015#include "llvm/Object/MachO.h"
16#include "llvm/Object/ObjectFile.h"
Kevin Enderbye858a652014-05-14 21:18:50 +000017#include "llvm/Object/Archive.h"
Alexey Samsonove6388e62013-06-18 15:03:28 +000018#include "llvm/Support/Casting.h"
19#include "llvm/Support/Host.h"
20#include "llvm/Support/MemoryBuffer.h"
21
22using namespace llvm;
23using namespace object;
24
25template<typename T>
26static void SwapValue(T &Value) {
27 Value = sys::SwapByteOrder(Value);
28}
29
30template<typename T>
31static void SwapStruct(T &Value);
32
33template<>
Charles Davis8bdfafd2013-09-01 04:28:48 +000034void SwapStruct(MachO::fat_header &H) {
35 SwapValue(H.magic);
36 SwapValue(H.nfat_arch);
Alexey Samsonove6388e62013-06-18 15:03:28 +000037}
38
39template<>
Charles Davis8bdfafd2013-09-01 04:28:48 +000040void SwapStruct(MachO::fat_arch &H) {
41 SwapValue(H.cputype);
42 SwapValue(H.cpusubtype);
43 SwapValue(H.offset);
44 SwapValue(H.size);
45 SwapValue(H.align);
Alexey Samsonove6388e62013-06-18 15:03:28 +000046}
47
48template<typename T>
49static T getUniversalBinaryStruct(const char *Ptr) {
50 T Res;
51 memcpy(&Res, Ptr, sizeof(T));
52 // Universal binary headers have big-endian byte order.
53 if (sys::IsLittleEndianHost)
54 SwapStruct(Res);
55 return Res;
56}
57
58MachOUniversalBinary::ObjectForArch::ObjectForArch(
59 const MachOUniversalBinary *Parent, uint32_t Index)
60 : Parent(Parent), Index(Index) {
Craig Topper2617dcc2014-04-15 06:32:26 +000061 if (!Parent || Index > Parent->getNumberOfObjects()) {
Alexey Samsonove6388e62013-06-18 15:03:28 +000062 clear();
63 } else {
64 // Parse object header.
65 StringRef ParentData = Parent->getData();
Charles Davis8bdfafd2013-09-01 04:28:48 +000066 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
67 Index * sizeof(MachO::fat_arch);
68 Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
69 if (ParentData.size() < Header.offset + Header.size) {
Alexey Samsonove6388e62013-06-18 15:03:28 +000070 clear();
71 }
72 }
73}
74
75error_code MachOUniversalBinary::ObjectForArch::getAsObjectFile(
Ahmed Charles56440fd2014-03-06 05:51:42 +000076 std::unique_ptr<ObjectFile> &Result) const {
Alexey Samsonove6388e62013-06-18 15:03:28 +000077 if (Parent) {
78 StringRef ParentData = Parent->getData();
Charles Davis8bdfafd2013-09-01 04:28:48 +000079 StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
NAKAMURA Takumidb1bf3f2013-06-19 09:55:05 +000080 std::string ObjectName =
81 Parent->getFileName().str() + ":" +
Charles Davis8bdfafd2013-09-01 04:28:48 +000082 Triple::getArchTypeName(MachOObjectFile::getArch(Header.cputype));
Alexey Samsonove6388e62013-06-18 15:03:28 +000083 MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer(
NAKAMURA Takumidb1bf3f2013-06-19 09:55:05 +000084 ObjectData, ObjectName, false);
Rafael Espindola692410e2014-01-21 23:06:54 +000085 ErrorOr<ObjectFile *> Obj = ObjectFile::createMachOObjectFile(ObjBuffer);
86 if (error_code EC = Obj.getError())
87 return EC;
88 Result.reset(Obj.get());
89 return object_error::success;
Alexey Samsonove6388e62013-06-18 15:03:28 +000090 }
91 return object_error::parse_failed;
92}
93
Kevin Enderbye858a652014-05-14 21:18:50 +000094error_code MachOUniversalBinary::ObjectForArch::getAsArchive(
95 std::unique_ptr<Archive> &Result) const {
96 if (Parent) {
97 StringRef ParentData = Parent->getData();
98 StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
99 std::string ObjectName =
100 Parent->getFileName().str() + ":" +
101 Triple::getArchTypeName(MachOObjectFile::getArch(Header.cputype));
102 MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer(
103 ObjectData, ObjectName, false);
104 ErrorOr<Archive *> Obj = Archive::create(ObjBuffer);
105 if (error_code EC = Obj.getError())
106 return EC;
107 Result.reset(Obj.get());
108 return object_error::success;
109 }
110 return object_error::parse_failed;
111}
112
Alexey Samsonove6388e62013-06-18 15:03:28 +0000113void MachOUniversalBinary::anchor() { }
114
Rafael Espindola692410e2014-01-21 23:06:54 +0000115ErrorOr<MachOUniversalBinary *>
116MachOUniversalBinary::create(MemoryBuffer *Source) {
117 error_code EC;
Ahmed Charles56440fd2014-03-06 05:51:42 +0000118 std::unique_ptr<MachOUniversalBinary> Ret(
119 new MachOUniversalBinary(Source, EC));
Rafael Espindola692410e2014-01-21 23:06:54 +0000120 if (EC)
121 return EC;
Ahmed Charles96c9d952014-03-05 10:19:29 +0000122 return Ret.release();
Rafael Espindola692410e2014-01-21 23:06:54 +0000123}
124
Alexey Samsonove6388e62013-06-18 15:03:28 +0000125MachOUniversalBinary::MachOUniversalBinary(MemoryBuffer *Source,
126 error_code &ec)
127 : Binary(Binary::ID_MachOUniversalBinary, Source),
128 NumberOfObjects(0) {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000129 if (Source->getBufferSize() < sizeof(MachO::fat_header)) {
Alexey Samsonove6388e62013-06-18 15:03:28 +0000130 ec = object_error::invalid_file_type;
131 return;
132 }
133 // Check for magic value and sufficient header size.
134 StringRef Buf = getData();
Charles Davis8bdfafd2013-09-01 04:28:48 +0000135 MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
136 NumberOfObjects = H.nfat_arch;
137 uint32_t MinSize = sizeof(MachO::fat_header) +
138 sizeof(MachO::fat_arch) * NumberOfObjects;
139 if (H.magic != MachO::FAT_MAGIC || Buf.size() < MinSize) {
Alexey Samsonove6388e62013-06-18 15:03:28 +0000140 ec = object_error::parse_failed;
141 return;
142 }
143 ec = object_error::success;
144}
145
Charles Davis8bdfafd2013-09-01 04:28:48 +0000146static bool getCTMForArch(Triple::ArchType Arch, MachO::CPUType &CTM) {
Alexey Samsonove6388e62013-06-18 15:03:28 +0000147 switch (Arch) {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000148 case Triple::x86: CTM = MachO::CPU_TYPE_I386; return true;
149 case Triple::x86_64: CTM = MachO::CPU_TYPE_X86_64; return true;
150 case Triple::arm: CTM = MachO::CPU_TYPE_ARM; return true;
151 case Triple::sparc: CTM = MachO::CPU_TYPE_SPARC; return true;
152 case Triple::ppc: CTM = MachO::CPU_TYPE_POWERPC; return true;
153 case Triple::ppc64: CTM = MachO::CPU_TYPE_POWERPC64; return true;
Alexey Samsonove6388e62013-06-18 15:03:28 +0000154 default: return false;
155 }
156}
157
Ahmed Charles56440fd2014-03-06 05:51:42 +0000158error_code MachOUniversalBinary::getObjectForArch(
159 Triple::ArchType Arch, std::unique_ptr<ObjectFile> &Result) const {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000160 MachO::CPUType CTM;
Alexey Samsonove6388e62013-06-18 15:03:28 +0000161 if (!getCTMForArch(Arch, CTM))
162 return object_error::arch_not_found;
163 for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) {
164 if (I->getCPUType() == static_cast<uint32_t>(CTM))
165 return I->getAsObjectFile(Result);
166 }
167 return object_error::arch_not_found;
168}