1 //===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
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 // This file defines the MachOUniversalBinary class.
12 //===----------------------------------------------------------------------===//
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"
23 using namespace object
;
26 malformedError(Twine Msg
) {
27 std::string StringMsg
= "truncated or malformed fat file (" + Msg
.str() + ")";
28 return make_error
<GenericBinaryError
>(std::move(StringMsg
),
29 object_error::parse_failed
);
33 static T
getUniversalBinaryStruct(const char *Ptr
) {
35 memcpy(&Res
, Ptr
, sizeof(T
));
36 // Universal binary headers have big-endian byte order.
37 if (sys::IsLittleEndianHost
)
42 MachOUniversalBinary::ObjectForArch::ObjectForArch(
43 const MachOUniversalBinary
*Parent
, uint32_t Index
)
44 : Parent(Parent
), Index(Index
) {
45 // The iterators use Parent as a nullptr and an Index+1 == NumberOfObjects.
46 if (!Parent
|| Index
>= Parent
->getNumberOfObjects()) {
49 // Parse object header.
50 StringRef ParentData
= Parent
->getData();
51 if (Parent
->getMagic() == MachO::FAT_MAGIC
) {
52 const char *HeaderPos
= ParentData
.begin() + sizeof(MachO::fat_header
) +
53 Index
* sizeof(MachO::fat_arch
);
54 Header
= getUniversalBinaryStruct
<MachO::fat_arch
>(HeaderPos
);
55 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
56 const char *HeaderPos
= ParentData
.begin() + sizeof(MachO::fat_header
) +
57 Index
* sizeof(MachO::fat_arch_64
);
58 Header64
= getUniversalBinaryStruct
<MachO::fat_arch_64
>(HeaderPos
);
63 Expected
<std::unique_ptr
<MachOObjectFile
>>
64 MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
66 report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() "
67 "called when Parent is a nullptr");
69 StringRef ParentData
= Parent
->getData();
72 if (Parent
->getMagic() == MachO::FAT_MAGIC
) {
73 ObjectData
= ParentData
.substr(Header
.offset
, Header
.size
);
74 cputype
= Header
.cputype
;
75 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
76 ObjectData
= ParentData
.substr(Header64
.offset
, Header64
.size
);
77 cputype
= Header64
.cputype
;
79 StringRef ObjectName
= Parent
->getFileName();
80 MemoryBufferRef
ObjBuffer(ObjectData
, ObjectName
);
81 return ObjectFile::createMachOObjectFile(ObjBuffer
, cputype
, Index
);
84 Expected
<std::unique_ptr
<Archive
>>
85 MachOUniversalBinary::ObjectForArch::getAsArchive() const {
87 report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() "
88 "called when Parent is a nullptr");
90 StringRef ParentData
= Parent
->getData();
92 if (Parent
->getMagic() == MachO::FAT_MAGIC
)
93 ObjectData
= ParentData
.substr(Header
.offset
, Header
.size
);
94 else // Parent->getMagic() == MachO::FAT_MAGIC_64
95 ObjectData
= ParentData
.substr(Header64
.offset
, Header64
.size
);
96 StringRef ObjectName
= Parent
->getFileName();
97 MemoryBufferRef
ObjBuffer(ObjectData
, ObjectName
);
98 return Archive::create(ObjBuffer
);
101 void MachOUniversalBinary::anchor() { }
103 Expected
<std::unique_ptr
<MachOUniversalBinary
>>
104 MachOUniversalBinary::create(MemoryBufferRef Source
) {
105 Error Err
= Error::success();
106 std::unique_ptr
<MachOUniversalBinary
> Ret(
107 new MachOUniversalBinary(Source
, Err
));
109 return std::move(Err
);
110 return std::move(Ret
);
113 MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source
, Error
&Err
)
114 : Binary(Binary::ID_MachOUniversalBinary
, Source
), Magic(0),
116 ErrorAsOutParameter
ErrAsOutParam(&Err
);
117 if (Data
.getBufferSize() < sizeof(MachO::fat_header
)) {
118 Err
= make_error
<GenericBinaryError
>("File too small to be a Mach-O "
120 object_error::invalid_file_type
);
123 // Check for magic value and sufficient header size.
124 StringRef Buf
= getData();
125 MachO::fat_header H
=
126 getUniversalBinaryStruct
<MachO::fat_header
>(Buf
.begin());
128 NumberOfObjects
= H
.nfat_arch
;
129 if (NumberOfObjects
== 0) {
130 Err
= malformedError("contains zero architecture types");
133 uint32_t MinSize
= sizeof(MachO::fat_header
);
134 if (Magic
== MachO::FAT_MAGIC
)
135 MinSize
+= sizeof(MachO::fat_arch
) * NumberOfObjects
;
136 else if (Magic
== MachO::FAT_MAGIC_64
)
137 MinSize
+= sizeof(MachO::fat_arch_64
) * NumberOfObjects
;
139 Err
= malformedError("bad magic number");
142 if (Buf
.size() < MinSize
) {
143 Err
= malformedError("fat_arch" +
144 Twine(Magic
== MachO::FAT_MAGIC
? "" : "_64") +
145 " structs would extend past the end of the file");
148 for (uint32_t i
= 0; i
< NumberOfObjects
; i
++) {
149 ObjectForArch
A(this, i
);
150 uint64_t bigSize
= A
.getOffset();
151 bigSize
+= A
.getSize();
152 if (bigSize
> Buf
.size()) {
153 Err
= malformedError("offset plus size of cputype (" +
154 Twine(A
.getCPUType()) + ") cpusubtype (" +
155 Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) +
156 ") extends past the end of the file");
159 #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
160 if (A
.getAlign() > MAXSECTALIGN
) {
161 Err
= malformedError("align (2^" + Twine(A
.getAlign()) + ") too large "
162 "for cputype (" + Twine(A
.getCPUType()) + ") cpusubtype (" +
163 Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) +
164 ") (maximum 2^" + Twine(MAXSECTALIGN
) + ")");
167 if(A
.getOffset() % (1 << A
.getAlign()) != 0){
168 Err
= malformedError("offset: " + Twine(A
.getOffset()) +
169 " for cputype (" + Twine(A
.getCPUType()) + ") cpusubtype (" +
170 Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) +
171 ") not aligned on it's alignment (2^" + Twine(A
.getAlign()) + ")");
174 if (A
.getOffset() < MinSize
) {
175 Err
= malformedError("cputype (" + Twine(A
.getCPUType()) + ") "
176 "cpusubtype (" + Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) +
177 ") offset " + Twine(A
.getOffset()) + " overlaps universal headers");
181 for (uint32_t i
= 0; i
< NumberOfObjects
; i
++) {
182 ObjectForArch
A(this, i
);
183 for (uint32_t j
= i
+ 1; j
< NumberOfObjects
; j
++) {
184 ObjectForArch
B(this, j
);
185 if (A
.getCPUType() == B
.getCPUType() &&
186 (A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) ==
187 (B
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
)) {
188 Err
= malformedError("contains two of the same architecture (cputype "
189 "(" + Twine(A
.getCPUType()) + ") cpusubtype (" +
190 Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) + "))");
193 if ((A
.getOffset() >= B
.getOffset() &&
194 A
.getOffset() < B
.getOffset() + B
.getSize()) ||
195 (A
.getOffset() + A
.getSize() > B
.getOffset() &&
196 A
.getOffset() + A
.getSize() < B
.getOffset() + B
.getSize()) ||
197 (A
.getOffset() <= B
.getOffset() &&
198 A
.getOffset() + A
.getSize() >= B
.getOffset() + B
.getSize())) {
199 Err
= malformedError("cputype (" + Twine(A
.getCPUType()) + ") "
200 "cpusubtype (" + Twine(A
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
) +
201 ") at offset " + Twine(A
.getOffset()) + " with a size of " +
202 Twine(A
.getSize()) + ", overlaps cputype (" + Twine(B
.getCPUType()) +
203 ") cpusubtype (" + Twine(B
.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK
)
204 + ") at offset " + Twine(B
.getOffset()) + " with a size of "
205 + Twine(B
.getSize()));
210 Err
= Error::success();
213 Expected
<std::unique_ptr
<MachOObjectFile
>>
214 MachOUniversalBinary::getObjectForArch(StringRef ArchName
) const {
215 if (Triple(ArchName
).getArch() == Triple::ArchType::UnknownArch
)
216 return make_error
<GenericBinaryError
>("Unknown architecture "
219 object_error::arch_not_found
);
221 for (auto &Obj
: objects())
222 if (Obj
.getArchFlagName() == ArchName
)
223 return Obj
.getAsObjectFile();
224 return make_error
<GenericBinaryError
>("fat file does not "
227 object_error::arch_not_found
);