LLVM  10.0.0svn
MachOUniversal.cpp
Go to the documentation of this file.
1 //===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the MachOUniversalBinary class.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/Object/Archive.h"
15 #include "llvm/Object/MachO.h"
16 #include "llvm/Object/ObjectFile.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/Host.h"
20 
21 using namespace llvm;
22 using namespace object;
23 
24 static Error
26  std::string StringMsg = "truncated or malformed fat file (" + Msg.str() + ")";
27  return make_error<GenericBinaryError>(std::move(StringMsg),
29 }
30 
31 template<typename T>
32 static T getUniversalBinaryStruct(const char *Ptr) {
33  T Res;
34  memcpy(&Res, Ptr, sizeof(T));
35  // Universal binary headers have big-endian byte order.
37  swapStruct(Res);
38  return Res;
39 }
40 
42  const MachOUniversalBinary *Parent, uint32_t Index)
43  : Parent(Parent), Index(Index) {
44  // The iterators use Parent as a nullptr and an Index+1 == NumberOfObjects.
45  if (!Parent || Index >= Parent->getNumberOfObjects()) {
46  clear();
47  } else {
48  // Parse object header.
49  StringRef ParentData = Parent->getData();
50  if (Parent->getMagic() == MachO::FAT_MAGIC) {
51  const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
52  Index * sizeof(MachO::fat_arch);
53  Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
54  } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
55  const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
56  Index * sizeof(MachO::fat_arch_64);
57  Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
58  }
59  }
60 }
61 
64  if (!Parent)
65  report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() "
66  "called when Parent is a nullptr");
67 
68  StringRef ParentData = Parent->getData();
69  StringRef ObjectData;
70  uint32_t cputype;
71  if (Parent->getMagic() == MachO::FAT_MAGIC) {
72  ObjectData = ParentData.substr(Header.offset, Header.size);
73  cputype = Header.cputype;
74  } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
75  ObjectData = ParentData.substr(Header64.offset, Header64.size);
76  cputype = Header64.cputype;
77  }
78  StringRef ObjectName = Parent->getFileName();
79  MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
80  return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index);
81 }
82 
85  if (!Parent)
86  report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() "
87  "called when Parent is a nullptr");
88 
89  StringRef ParentData = Parent->getData();
90  StringRef ObjectData;
91  if (Parent->getMagic() == MachO::FAT_MAGIC)
92  ObjectData = ParentData.substr(Header.offset, Header.size);
93  else // Parent->getMagic() == MachO::FAT_MAGIC_64
94  ObjectData = ParentData.substr(Header64.offset, Header64.size);
95  StringRef ObjectName = Parent->getFileName();
96  MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
97  return Archive::create(ObjBuffer);
98 }
99 
100 void MachOUniversalBinary::anchor() { }
101 
104  Error Err = Error::success();
105  std::unique_ptr<MachOUniversalBinary> Ret(
106  new MachOUniversalBinary(Source, Err));
107  if (Err)
108  return std::move(Err);
109  return std::move(Ret);
110 }
111 
113  : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
114  NumberOfObjects(0) {
115  ErrorAsOutParameter ErrAsOutParam(&Err);
116  if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
117  Err = make_error<GenericBinaryError>("File too small to be a Mach-O "
118  "universal file",
120  return;
121  }
122  // Check for magic value and sufficient header size.
123  StringRef Buf = getData();
125  getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
126  Magic = H.magic;
127  NumberOfObjects = H.nfat_arch;
128  if (NumberOfObjects == 0) {
129  Err = malformedError("contains zero architecture types");
130  return;
131  }
132  uint32_t MinSize = sizeof(MachO::fat_header);
133  if (Magic == MachO::FAT_MAGIC)
134  MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
135  else if (Magic == MachO::FAT_MAGIC_64)
136  MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
137  else {
138  Err = malformedError("bad magic number");
139  return;
140  }
141  if (Buf.size() < MinSize) {
142  Err = malformedError("fat_arch" +
143  Twine(Magic == MachO::FAT_MAGIC ? "" : "_64") +
144  " structs would extend past the end of the file");
145  return;
146  }
147  for (uint32_t i = 0; i < NumberOfObjects; i++) {
148  ObjectForArch A(this, i);
149  uint64_t bigSize = A.getOffset();
150  bigSize += A.getSize();
151  if (bigSize > Buf.size()) {
152  Err = malformedError("offset plus size of cputype (" +
153  Twine(A.getCPUType()) + ") cpusubtype (" +
154  Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
155  ") extends past the end of the file");
156  return;
157  }
158 
159  if (A.getAlign() > MaxSectionAlignment) {
160  Err = malformedError("align (2^" + Twine(A.getAlign()) +
161  ") too large for cputype (" + Twine(A.getCPUType()) +
162  ") cpusubtype (" +
163  Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
164  ") (maximum 2^" + Twine(MaxSectionAlignment) + ")");
165  return;
166  }
167  if(A.getOffset() % (1ull << 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()) + ")");
172  return;
173  }
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");
178  return;
179  }
180  }
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) + "))");
191  return;
192  }
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()));
206  return;
207  }
208  }
209  }
210  Err = Error::success();
211 }
212 
215  if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
216  return make_error<GenericBinaryError>("Unknown architecture "
217  "named: " +
218  ArchName,
220  for (const auto &Obj : objects())
221  if (Obj.getArchFlagName() == ArchName)
222  return Obj;
223  return make_error<GenericBinaryError>("fat file does not "
224  "contain " +
225  ArchName,
227 }
228 
232  if (!O)
233  return O.takeError();
234  return O->getAsObjectFile();
235 }
236 
240  if (!O)
241  return O.takeError();
242  return O->getAsArchive();
243 }
void swapStruct(fat_header &mh)
Definition: MachO.h:1002
static T getUniversalBinaryStruct(const char *Ptr)
Expected< std::unique_ptr< Archive > > getAsArchive() const
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
StringRef getFileName() const
Definition: Binary.cpp:42
uint32_t nfat_arch
Definition: MachO.h:928
Expected< std::unique_ptr< Archive > > getArchiveForArch(StringRef ArchName) const
ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index)
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
static Error malformedError(Twine Msg)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:592
static const bool IsLittleEndianHost
Definition: SwapByteOrder.h:54
Expected< std::unique_ptr< MachOObjectFile > > getAsObjectFile() const
MachOUniversalBinary(MemoryBufferRef Souce, Error &Err)
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
static Expected< std::unique_ptr< Archive > > create(MemoryBufferRef Source)
Definition: Archive.cpp:530
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Expected< ObjectForArch > getObjectForArch(StringRef ArchName) const
size_t getBufferSize() const
Definition: MemoryBuffer.h:278
Expected< std::unique_ptr< MachOObjectFile > > getMachOObjectForArch(StringRef ArchName) const
#define H(x, y, z)
Definition: MD5.cpp:57
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:43
static const char *const Magic
Definition: Archive.cpp:41
static Expected< std::unique_ptr< MachOUniversalBinary > > create(MemoryBufferRef Source)
iterator_range< object_iterator > objects() const
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
static Expected< std::unique_ptr< MachOObjectFile > > createMachOObjectFile(MemoryBufferRef Object, uint32_t UniversalCputype=0, uint32_t UniversalIndex=0)
static constexpr uint32_t MaxSectionAlignment
MemoryBufferRef Data
Definition: Binary.h:37
uint32_t cputype
Definition: MachO.h:932
Helper for Errors used as out-parameters.
Definition: Error.h:1055
iterator begin() const
Definition: StringRef.h:115
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
uint32_t offset
Definition: MachO.h:934
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
StringRef getData() const
Definition: Binary.cpp:40