Line data Source code
1 : //===- 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"
15 : #include "llvm/Object/Archive.h"
16 : #include "llvm/Object/MachO.h"
17 : #include "llvm/Object/ObjectFile.h"
18 : #include "llvm/Support/Casting.h"
19 : #include "llvm/Support/Host.h"
20 : #include "llvm/Support/MemoryBuffer.h"
21 :
22 : using namespace llvm;
23 : using namespace object;
24 :
25 : static Error
26 467 : malformedError(Twine Msg) {
27 934 : std::string StringMsg = "truncated or malformed fat file (" + Msg.str() + ")";
28 : return make_error<GenericBinaryError>(std::move(StringMsg),
29 467 : object_error::parse_failed);
30 : }
31 :
32 : template<typename T>
33 : static T getUniversalBinaryStruct(const char *Ptr) {
34 : T Res;
35 1492 : memcpy(&Res, Ptr, sizeof(T));
36 : // Universal binary headers have big-endian byte order.
37 : if (sys::IsLittleEndianHost)
38 : swapStruct(Res);
39 : return Res;
40 : }
41 :
42 1100 : MachOUniversalBinary::ObjectForArch::ObjectForArch(
43 1100 : const MachOUniversalBinary *Parent, uint32_t Index)
44 1100 : : Parent(Parent), Index(Index) {
45 : // The iterators use Parent as a nullptr and an Index+1 == NumberOfObjects.
46 1100 : if (!Parent || Index >= Parent->getNumberOfObjects()) {
47 : clear();
48 : } else {
49 : // Parse object header.
50 932 : StringRef ParentData = Parent->getData();
51 932 : if (Parent->getMagic() == MachO::FAT_MAGIC) {
52 909 : const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
53 909 : Index * sizeof(MachO::fat_arch);
54 909 : Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
55 : } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
56 23 : const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
57 23 : Index * sizeof(MachO::fat_arch_64);
58 23 : Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
59 : }
60 : }
61 1100 : }
62 :
63 : Expected<std::unique_ptr<MachOObjectFile>>
64 101 : MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
65 101 : if (!Parent)
66 0 : report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() "
67 : "called when Parent is a nullptr");
68 :
69 101 : StringRef ParentData = Parent->getData();
70 : StringRef ObjectData;
71 : uint32_t cputype;
72 101 : if (Parent->getMagic() == MachO::FAT_MAGIC) {
73 96 : ObjectData = ParentData.substr(Header.offset, Header.size);
74 96 : cputype = Header.cputype;
75 : } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
76 5 : ObjectData = ParentData.substr(Header64.offset, Header64.size);
77 5 : cputype = Header64.cputype;
78 : }
79 101 : StringRef ObjectName = Parent->getFileName();
80 : MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
81 101 : return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index);
82 : }
83 :
84 : Expected<std::unique_ptr<Archive>>
85 52 : MachOUniversalBinary::ObjectForArch::getAsArchive() const {
86 52 : if (!Parent)
87 0 : report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() "
88 : "called when Parent is a nullptr");
89 :
90 52 : StringRef ParentData = Parent->getData();
91 : StringRef ObjectData;
92 52 : if (Parent->getMagic() == MachO::FAT_MAGIC)
93 100 : ObjectData = ParentData.substr(Header.offset, Header.size);
94 : else // Parent->getMagic() == MachO::FAT_MAGIC_64
95 4 : ObjectData = ParentData.substr(Header64.offset, Header64.size);
96 52 : StringRef ObjectName = Parent->getFileName();
97 : MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
98 52 : return Archive::create(ObjBuffer);
99 : }
100 :
101 0 : void MachOUniversalBinary::anchor() { }
102 :
103 : Expected<std::unique_ptr<MachOUniversalBinary>>
104 560 : MachOUniversalBinary::create(MemoryBufferRef Source) {
105 : Error Err = Error::success();
106 : std::unique_ptr<MachOUniversalBinary> Ret(
107 560 : new MachOUniversalBinary(Source, Err));
108 560 : if (Err)
109 : return std::move(Err);
110 : return std::move(Ret);
111 : }
112 :
113 560 : MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err)
114 : : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
115 560 : NumberOfObjects(0) {
116 : ErrorAsOutParameter ErrAsOutParam(&Err);
117 560 : if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
118 : Err = make_error<GenericBinaryError>("File too small to be a Mach-O "
119 : "universal file",
120 : object_error::invalid_file_type);
121 0 : return;
122 : }
123 : // Check for magic value and sufficient header size.
124 560 : StringRef Buf = getData();
125 : MachO::fat_header H =
126 560 : getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
127 560 : Magic = H.magic;
128 560 : NumberOfObjects = H.nfat_arch;
129 560 : if (NumberOfObjects == 0) {
130 1 : Err = malformedError("contains zero architecture types");
131 1 : return;
132 : }
133 : uint32_t MinSize = sizeof(MachO::fat_header);
134 559 : if (Magic == MachO::FAT_MAGIC)
135 96 : MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
136 463 : else if (Magic == MachO::FAT_MAGIC_64)
137 4 : MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
138 : else {
139 459 : Err = malformedError("bad magic number");
140 459 : return;
141 : }
142 100 : if (Buf.size() < MinSize) {
143 1 : Err = malformedError("fat_arch" +
144 1 : Twine(Magic == MachO::FAT_MAGIC ? "" : "_64") +
145 : " structs would extend past the end of the file");
146 1 : return;
147 : }
148 340 : for (uint32_t i = 0; i < NumberOfObjects; i++) {
149 245 : ObjectForArch A(this, i);
150 245 : uint64_t bigSize = A.getOffset();
151 245 : bigSize += A.getSize();
152 245 : if (bigSize > Buf.size()) {
153 1 : Err = malformedError("offset plus size of cputype (" +
154 2 : Twine(A.getCPUType()) + ") cpusubtype (" +
155 1 : Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
156 : ") extends past the end of the file");
157 4 : return;
158 : }
159 : #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
160 244 : if (A.getAlign() > MAXSECTALIGN) {
161 1 : Err = malformedError("align (2^" + Twine(A.getAlign()) + ") too large "
162 2 : "for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
163 1 : Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
164 2 : ") (maximum 2^" + Twine(MAXSECTALIGN) + ")");
165 1 : return;
166 : }
167 243 : if(A.getOffset() % (1 << A.getAlign()) != 0){
168 1 : Err = malformedError("offset: " + Twine(A.getOffset()) +
169 2 : " for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
170 1 : Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
171 2 : ") not aligned on it's alignment (2^" + Twine(A.getAlign()) + ")");
172 1 : return;
173 : }
174 242 : if (A.getOffset() < MinSize) {
175 1 : Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
176 1 : "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
177 2 : ") offset " + Twine(A.getOffset()) + " overlaps universal headers");
178 1 : return;
179 : }
180 : }
181 331 : for (uint32_t i = 0; i < NumberOfObjects; i++) {
182 238 : ObjectForArch A(this, i);
183 452 : for (uint32_t j = i + 1; j < NumberOfObjects; j++) {
184 216 : ObjectForArch B(this, j);
185 216 : if (A.getCPUType() == B.getCPUType() &&
186 63 : (A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) ==
187 : (B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)) {
188 1 : Err = malformedError("contains two of the same architecture (cputype "
189 1 : "(" + Twine(A.getCPUType()) + ") cpusubtype (" +
190 1 : Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) + "))");
191 2 : return;
192 : }
193 32 : if ((A.getOffset() >= B.getOffset() &&
194 32 : A.getOffset() < B.getOffset() + B.getSize()) ||
195 215 : (A.getOffset() + A.getSize() > B.getOffset() &&
196 430 : A.getOffset() + A.getSize() < B.getOffset() + B.getSize()) ||
197 182 : (A.getOffset() <= B.getOffset() &&
198 182 : A.getOffset() + A.getSize() >= B.getOffset() + B.getSize())) {
199 1 : Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
200 1 : "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
201 2 : ") at offset " + Twine(A.getOffset()) + " with a size of " +
202 2 : Twine(A.getSize()) + ", overlaps cputype (" + Twine(B.getCPUType()) +
203 1 : ") cpusubtype (" + Twine(B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)
204 2 : + ") at offset " + Twine(B.getOffset()) + " with a size of "
205 1 : + Twine(B.getSize()));
206 1 : return;
207 : }
208 : }
209 : }
210 : Err = Error::success();
211 : }
212 :
213 : Expected<std::unique_ptr<MachOObjectFile>>
214 15 : MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
215 15 : if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
216 : return make_error<GenericBinaryError>("Unknown architecture "
217 1 : "named: " +
218 : ArchName,
219 : object_error::arch_not_found);
220 :
221 28 : for (auto &Obj : objects())
222 54 : if (Obj.getArchFlagName() == ArchName)
223 13 : return Obj.getAsObjectFile();
224 : return make_error<GenericBinaryError>("fat file does not "
225 1 : "contain " +
226 : ArchName,
227 : object_error::arch_not_found);
228 : }
|