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 template<typename T> 26 static void SwapStruct(T &Value); 27 28 template<> 29 void SwapStruct(MachO::fat_header &H) { 30 sys::swapByteOrder(H.magic); 31 sys::swapByteOrder(H.nfat_arch); 32 } 33 34 template<> 35 void SwapStruct(MachO::fat_arch &H) { 36 sys::swapByteOrder(H.cputype); 37 sys::swapByteOrder(H.cpusubtype); 38 sys::swapByteOrder(H.offset); 39 sys::swapByteOrder(H.size); 40 sys::swapByteOrder(H.align); 41 } 42 43 template<> 44 void SwapStruct(MachO::fat_arch_64 &H) { 45 sys::swapByteOrder(H.cputype); 46 sys::swapByteOrder(H.cpusubtype); 47 sys::swapByteOrder(H.offset); 48 sys::swapByteOrder(H.size); 49 sys::swapByteOrder(H.align); 50 sys::swapByteOrder(H.reserved); 51 } 52 53 template<typename T> 54 static T getUniversalBinaryStruct(const char *Ptr) { 55 T Res; 56 memcpy(&Res, Ptr, sizeof(T)); 57 // Universal binary headers have big-endian byte order. 58 if (sys::IsLittleEndianHost) 59 SwapStruct(Res); 60 return Res; 61 } 62 63 MachOUniversalBinary::ObjectForArch::ObjectForArch( 64 const MachOUniversalBinary *Parent, uint32_t Index) 65 : Parent(Parent), Index(Index) { 66 if (!Parent || Index >= Parent->getNumberOfObjects()) { 67 clear(); 68 } else { 69 // Parse object header. 70 StringRef ParentData = Parent->getData(); 71 if (Parent->getMagic() == MachO::FAT_MAGIC) { 72 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) + 73 Index * sizeof(MachO::fat_arch); 74 Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos); 75 if (ParentData.size() < Header.offset + Header.size) { 76 clear(); 77 } 78 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 79 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) + 80 Index * sizeof(MachO::fat_arch_64); 81 Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos); 82 if (ParentData.size() < Header64.offset + Header64.size) { 83 clear(); 84 } 85 } 86 } 87 } 88 89 Expected<std::unique_ptr<MachOObjectFile>> 90 MachOUniversalBinary::ObjectForArch::getAsObjectFile() const { 91 if (!Parent) 92 return errorCodeToError(object_error::parse_failed); 93 94 StringRef ParentData = Parent->getData(); 95 StringRef ObjectData; 96 if (Parent->getMagic() == MachO::FAT_MAGIC) 97 ObjectData = ParentData.substr(Header.offset, Header.size); 98 else // Parent->getMagic() == MachO::FAT_MAGIC_64 99 ObjectData = ParentData.substr(Header64.offset, Header64.size); 100 StringRef ObjectName = Parent->getFileName(); 101 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 102 return ObjectFile::createMachOObjectFile(ObjBuffer); 103 } 104 105 ErrorOr<std::unique_ptr<Archive>> 106 MachOUniversalBinary::ObjectForArch::getAsArchive() const { 107 if (!Parent) 108 return object_error::parse_failed; 109 110 StringRef ParentData = Parent->getData(); 111 StringRef ObjectData; 112 if (Parent->getMagic() == MachO::FAT_MAGIC) 113 ObjectData = ParentData.substr(Header.offset, Header.size); 114 else // Parent->getMagic() == MachO::FAT_MAGIC_64 115 ObjectData = ParentData.substr(Header64.offset, Header64.size); 116 StringRef ObjectName = Parent->getFileName(); 117 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 118 return Archive::create(ObjBuffer); 119 } 120 121 void MachOUniversalBinary::anchor() { } 122 123 ErrorOr<std::unique_ptr<MachOUniversalBinary>> 124 MachOUniversalBinary::create(MemoryBufferRef Source) { 125 std::error_code EC; 126 std::unique_ptr<MachOUniversalBinary> Ret( 127 new MachOUniversalBinary(Source, EC)); 128 if (EC) 129 return EC; 130 return std::move(Ret); 131 } 132 133 MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, 134 std::error_code &ec) 135 : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0), 136 NumberOfObjects(0) { 137 if (Data.getBufferSize() < sizeof(MachO::fat_header)) { 138 ec = object_error::invalid_file_type; 139 return; 140 } 141 // Check for magic value and sufficient header size. 142 StringRef Buf = getData(); 143 MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin()); 144 Magic = H.magic; 145 NumberOfObjects = H.nfat_arch; 146 uint32_t MinSize = sizeof(MachO::fat_header); 147 if (Magic == MachO::FAT_MAGIC) 148 MinSize += sizeof(MachO::fat_arch) * NumberOfObjects; 149 else if (Magic == MachO::FAT_MAGIC_64) 150 MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects; 151 else { 152 ec = object_error::parse_failed; 153 return; 154 } 155 if (Buf.size() < MinSize) { 156 ec = object_error::parse_failed; 157 return; 158 } 159 ec = std::error_code(); 160 } 161 162 Expected<std::unique_ptr<MachOObjectFile>> 163 MachOUniversalBinary::getObjectForArch(StringRef ArchName) const { 164 if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch) 165 return errorCodeToError(object_error::arch_not_found); 166 167 for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) { 168 if (I->getArchTypeName() == ArchName) 169 return I->getAsObjectFile(); 170 } 171 return errorCodeToError(object_error::arch_not_found); 172 } 173