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 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); 30 } 31 32 template<typename T> 33 static T getUniversalBinaryStruct(const char *Ptr) { 34 T Res; 35 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 MachOUniversalBinary::ObjectForArch::ObjectForArch( 43 const MachOUniversalBinary *Parent, uint32_t Index) 44 : Parent(Parent), Index(Index) { 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 if (ParentData.size() < Header.offset + Header.size) { 55 clear(); 56 } 57 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 58 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) + 59 Index * sizeof(MachO::fat_arch_64); 60 Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos); 61 if (ParentData.size() < Header64.offset + Header64.size) { 62 clear(); 63 } 64 } 65 } 66 } 67 68 Expected<std::unique_ptr<MachOObjectFile>> 69 MachOUniversalBinary::ObjectForArch::getAsObjectFile() const { 70 if (!Parent) 71 report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() " 72 "called when Parent is a nullptr"); 73 74 StringRef ParentData = Parent->getData(); 75 StringRef ObjectData; 76 uint32_t cputype; 77 if (Parent->getMagic() == MachO::FAT_MAGIC) { 78 ObjectData = ParentData.substr(Header.offset, Header.size); 79 cputype = Header.cputype; 80 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 81 ObjectData = ParentData.substr(Header64.offset, Header64.size); 82 cputype = Header64.cputype; 83 } 84 StringRef ObjectName = Parent->getFileName(); 85 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 86 return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index); 87 } 88 89 Expected<std::unique_ptr<Archive>> 90 MachOUniversalBinary::ObjectForArch::getAsArchive() const { 91 if (!Parent) 92 report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() " 93 "called when Parent is a nullptr"); 94 95 StringRef ParentData = Parent->getData(); 96 StringRef ObjectData; 97 if (Parent->getMagic() == MachO::FAT_MAGIC) 98 ObjectData = ParentData.substr(Header.offset, Header.size); 99 else // Parent->getMagic() == MachO::FAT_MAGIC_64 100 ObjectData = ParentData.substr(Header64.offset, Header64.size); 101 StringRef ObjectName = Parent->getFileName(); 102 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 103 return Archive::create(ObjBuffer); 104 } 105 106 void MachOUniversalBinary::anchor() { } 107 108 Expected<std::unique_ptr<MachOUniversalBinary>> 109 MachOUniversalBinary::create(MemoryBufferRef Source) { 110 Error Err = Error::success(); 111 std::unique_ptr<MachOUniversalBinary> Ret( 112 new MachOUniversalBinary(Source, Err)); 113 if (Err) 114 return std::move(Err); 115 return std::move(Ret); 116 } 117 118 MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err) 119 : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0), 120 NumberOfObjects(0) { 121 ErrorAsOutParameter ErrAsOutParam(&Err); 122 if (Data.getBufferSize() < sizeof(MachO::fat_header)) { 123 Err = make_error<GenericBinaryError>("File too small to be a Mach-O " 124 "universal file", 125 object_error::invalid_file_type); 126 return; 127 } 128 // Check for magic value and sufficient header size. 129 StringRef Buf = getData(); 130 MachO::fat_header H = 131 getUniversalBinaryStruct<MachO::fat_header>(Buf.begin()); 132 Magic = H.magic; 133 NumberOfObjects = H.nfat_arch; 134 uint32_t MinSize = sizeof(MachO::fat_header); 135 if (Magic == MachO::FAT_MAGIC) 136 MinSize += sizeof(MachO::fat_arch) * NumberOfObjects; 137 else if (Magic == MachO::FAT_MAGIC_64) 138 MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects; 139 else { 140 Err = malformedError("bad magic number"); 141 return; 142 } 143 if (Buf.size() < MinSize) { 144 Err = malformedError("fat_arch" + 145 Twine(Magic == MachO::FAT_MAGIC ? "" : "_64") + 146 " structs would extend past the end of the file"); 147 return; 148 } 149 Err = Error::success(); 150 } 151 152 Expected<std::unique_ptr<MachOObjectFile>> 153 MachOUniversalBinary::getObjectForArch(StringRef ArchName) const { 154 if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch) 155 return make_error<GenericBinaryError>("Unknown architecture " 156 "named: " + 157 ArchName, 158 object_error::arch_not_found); 159 160 for (auto &Obj : objects()) 161 if (Obj.getArchTypeName() == ArchName) 162 return Obj.getAsObjectFile(); 163 return make_error<GenericBinaryError>("fat file does not " 164 "contain " + 165 ArchName, 166 object_error::arch_not_found); 167 } 168