LLVM API Documentation
00001 //===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the MachOUniversalBinary class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "llvm/Object/MachOUniversal.h" 00015 #include "llvm/Object/MachO.h" 00016 #include "llvm/Object/ObjectFile.h" 00017 #include "llvm/Object/Archive.h" 00018 #include "llvm/Support/Casting.h" 00019 #include "llvm/Support/Host.h" 00020 #include "llvm/Support/MemoryBuffer.h" 00021 00022 using namespace llvm; 00023 using namespace object; 00024 00025 template<typename T> 00026 static void SwapStruct(T &Value); 00027 00028 template<> 00029 void SwapStruct(MachO::fat_header &H) { 00030 sys::swapByteOrder(H.magic); 00031 sys::swapByteOrder(H.nfat_arch); 00032 } 00033 00034 template<> 00035 void SwapStruct(MachO::fat_arch &H) { 00036 sys::swapByteOrder(H.cputype); 00037 sys::swapByteOrder(H.cpusubtype); 00038 sys::swapByteOrder(H.offset); 00039 sys::swapByteOrder(H.size); 00040 sys::swapByteOrder(H.align); 00041 } 00042 00043 template<typename T> 00044 static T getUniversalBinaryStruct(const char *Ptr) { 00045 T Res; 00046 memcpy(&Res, Ptr, sizeof(T)); 00047 // Universal binary headers have big-endian byte order. 00048 if (sys::IsLittleEndianHost) 00049 SwapStruct(Res); 00050 return Res; 00051 } 00052 00053 MachOUniversalBinary::ObjectForArch::ObjectForArch( 00054 const MachOUniversalBinary *Parent, uint32_t Index) 00055 : Parent(Parent), Index(Index) { 00056 if (!Parent || Index >= Parent->getNumberOfObjects()) { 00057 clear(); 00058 } else { 00059 // Parse object header. 00060 StringRef ParentData = Parent->getData(); 00061 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) + 00062 Index * sizeof(MachO::fat_arch); 00063 Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos); 00064 if (ParentData.size() < Header.offset + Header.size) { 00065 clear(); 00066 } 00067 } 00068 } 00069 00070 ErrorOr<std::unique_ptr<ObjectFile>> 00071 MachOUniversalBinary::ObjectForArch::getAsObjectFile() const { 00072 if (Parent) { 00073 StringRef ParentData = Parent->getData(); 00074 StringRef ObjectData = ParentData.substr(Header.offset, Header.size); 00075 StringRef ObjectName = Parent->getFileName(); 00076 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 00077 return ObjectFile::createMachOObjectFile(ObjBuffer); 00078 } 00079 return object_error::parse_failed; 00080 } 00081 00082 std::error_code MachOUniversalBinary::ObjectForArch::getAsArchive( 00083 std::unique_ptr<Archive> &Result) const { 00084 if (Parent) { 00085 StringRef ParentData = Parent->getData(); 00086 StringRef ObjectData = ParentData.substr(Header.offset, Header.size); 00087 StringRef ObjectName = Parent->getFileName(); 00088 MemoryBufferRef ObjBuffer(ObjectData, ObjectName); 00089 ErrorOr<std::unique_ptr<Archive>> Obj = Archive::create(ObjBuffer); 00090 if (std::error_code EC = Obj.getError()) 00091 return EC; 00092 Result = std::move(Obj.get()); 00093 return object_error::success; 00094 } 00095 return object_error::parse_failed; 00096 } 00097 00098 void MachOUniversalBinary::anchor() { } 00099 00100 ErrorOr<std::unique_ptr<MachOUniversalBinary>> 00101 MachOUniversalBinary::create(MemoryBufferRef Source) { 00102 std::error_code EC; 00103 std::unique_ptr<MachOUniversalBinary> Ret( 00104 new MachOUniversalBinary(Source, EC)); 00105 if (EC) 00106 return EC; 00107 return std::move(Ret); 00108 } 00109 00110 MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, 00111 std::error_code &ec) 00112 : Binary(Binary::ID_MachOUniversalBinary, Source), NumberOfObjects(0) { 00113 if (Data.getBufferSize() < sizeof(MachO::fat_header)) { 00114 ec = object_error::invalid_file_type; 00115 return; 00116 } 00117 // Check for magic value and sufficient header size. 00118 StringRef Buf = getData(); 00119 MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin()); 00120 NumberOfObjects = H.nfat_arch; 00121 uint32_t MinSize = sizeof(MachO::fat_header) + 00122 sizeof(MachO::fat_arch) * NumberOfObjects; 00123 if (H.magic != MachO::FAT_MAGIC || Buf.size() < MinSize) { 00124 ec = object_error::parse_failed; 00125 return; 00126 } 00127 ec = object_error::success; 00128 } 00129 00130 static bool getCTMForArch(Triple::ArchType Arch, MachO::CPUType &CTM) { 00131 switch (Arch) { 00132 case Triple::x86: CTM = MachO::CPU_TYPE_I386; return true; 00133 case Triple::x86_64: CTM = MachO::CPU_TYPE_X86_64; return true; 00134 case Triple::arm: CTM = MachO::CPU_TYPE_ARM; return true; 00135 case Triple::sparc: CTM = MachO::CPU_TYPE_SPARC; return true; 00136 case Triple::ppc: CTM = MachO::CPU_TYPE_POWERPC; return true; 00137 case Triple::ppc64: CTM = MachO::CPU_TYPE_POWERPC64; return true; 00138 default: return false; 00139 } 00140 } 00141 00142 ErrorOr<std::unique_ptr<ObjectFile>> 00143 MachOUniversalBinary::getObjectForArch(Triple::ArchType Arch) const { 00144 MachO::CPUType CTM; 00145 if (!getCTMForArch(Arch, CTM)) 00146 return object_error::arch_not_found; 00147 for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) { 00148 if (I->getCPUType() == static_cast<uint32_t>(CTM)) 00149 return I->getAsObjectFile(); 00150 } 00151 return object_error::arch_not_found; 00152 }