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