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