mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
0c3b9888f7
The reason we need to search by name rather than by Triple::ArchType is to handle subarchitecture correclty. There is no different ArchType for the x86_64h architecture (it identifies itself as x86_64), or for the various ARM subarches. The only way to get to the subarch slice in an universal binary is to search by name. This issue led to hard to debug and transient symbolication failures in Asan tests (it mostly works, because the files are very similar). This also affects the Profiling infrastucture as it is the other user of that API. Reviewers: samsonov, bogner Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D10604 llvm-svn: 240339
137 lines
4.3 KiB
C++
137 lines
4.3 KiB
C++
//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the MachOUniversalBinary class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Object/MachOUniversal.h"
|
|
#include "llvm/Object/Archive.h"
|
|
#include "llvm/Object/MachO.h"
|
|
#include "llvm/Object/ObjectFile.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
using namespace llvm;
|
|
using namespace object;
|
|
|
|
template<typename T>
|
|
static void SwapStruct(T &Value);
|
|
|
|
template<>
|
|
void SwapStruct(MachO::fat_header &H) {
|
|
sys::swapByteOrder(H.magic);
|
|
sys::swapByteOrder(H.nfat_arch);
|
|
}
|
|
|
|
template<>
|
|
void SwapStruct(MachO::fat_arch &H) {
|
|
sys::swapByteOrder(H.cputype);
|
|
sys::swapByteOrder(H.cpusubtype);
|
|
sys::swapByteOrder(H.offset);
|
|
sys::swapByteOrder(H.size);
|
|
sys::swapByteOrder(H.align);
|
|
}
|
|
|
|
template<typename T>
|
|
static T getUniversalBinaryStruct(const char *Ptr) {
|
|
T Res;
|
|
memcpy(&Res, Ptr, sizeof(T));
|
|
// Universal binary headers have big-endian byte order.
|
|
if (sys::IsLittleEndianHost)
|
|
SwapStruct(Res);
|
|
return Res;
|
|
}
|
|
|
|
MachOUniversalBinary::ObjectForArch::ObjectForArch(
|
|
const MachOUniversalBinary *Parent, uint32_t Index)
|
|
: Parent(Parent), Index(Index) {
|
|
if (!Parent || Index >= Parent->getNumberOfObjects()) {
|
|
clear();
|
|
} else {
|
|
// Parse object header.
|
|
StringRef ParentData = Parent->getData();
|
|
const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
|
|
Index * sizeof(MachO::fat_arch);
|
|
Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
|
|
if (ParentData.size() < Header.offset + Header.size) {
|
|
clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<MachOObjectFile>>
|
|
MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
|
|
if (Parent) {
|
|
StringRef ParentData = Parent->getData();
|
|
StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
|
|
StringRef ObjectName = Parent->getFileName();
|
|
MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
|
|
return ObjectFile::createMachOObjectFile(ObjBuffer);
|
|
}
|
|
return object_error::parse_failed;
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<Archive>>
|
|
MachOUniversalBinary::ObjectForArch::getAsArchive() const {
|
|
if (!Parent)
|
|
return object_error::parse_failed;
|
|
|
|
StringRef ParentData = Parent->getData();
|
|
StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
|
|
StringRef ObjectName = Parent->getFileName();
|
|
MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
|
|
return Archive::create(ObjBuffer);
|
|
}
|
|
|
|
void MachOUniversalBinary::anchor() { }
|
|
|
|
ErrorOr<std::unique_ptr<MachOUniversalBinary>>
|
|
MachOUniversalBinary::create(MemoryBufferRef Source) {
|
|
std::error_code EC;
|
|
std::unique_ptr<MachOUniversalBinary> Ret(
|
|
new MachOUniversalBinary(Source, EC));
|
|
if (EC)
|
|
return EC;
|
|
return std::move(Ret);
|
|
}
|
|
|
|
MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source,
|
|
std::error_code &ec)
|
|
: Binary(Binary::ID_MachOUniversalBinary, Source), NumberOfObjects(0) {
|
|
if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
|
|
ec = object_error::invalid_file_type;
|
|
return;
|
|
}
|
|
// Check for magic value and sufficient header size.
|
|
StringRef Buf = getData();
|
|
MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
|
|
NumberOfObjects = H.nfat_arch;
|
|
uint32_t MinSize = sizeof(MachO::fat_header) +
|
|
sizeof(MachO::fat_arch) * NumberOfObjects;
|
|
if (H.magic != MachO::FAT_MAGIC || Buf.size() < MinSize) {
|
|
ec = object_error::parse_failed;
|
|
return;
|
|
}
|
|
ec = std::error_code();
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<MachOObjectFile>>
|
|
MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
|
|
if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
|
|
return object_error::arch_not_found;
|
|
|
|
for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) {
|
|
if (I->getArchTypeName() == ArchName)
|
|
return I->getAsObjectFile();
|
|
}
|
|
return object_error::arch_not_found;
|
|
}
|