#include "dyldcache.h"
static const uint16_t bigEndian = 0x1200;
static const uint16_t littleEndian = 0x0012;
const DYLDCache::ArchType DYLDCache::architectures[] = {
{ CPU_TYPE_X86_64, CPU_SUBTYPE_MULTIPLE, "dyld_v1 x86_64", "x86_64", littleEndian },
{ CPU_TYPE_X86, CPU_SUBTYPE_MULTIPLE, "dyld_v1 i386", "i386", littleEndian },
{ CPU_TYPE_POWERPC, CPU_SUBTYPE_MULTIPLE, "dyld_v1 ppc", "rosetta", bigEndian },
{ CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, "dyld_v1 armv6", "armv6", littleEndian },
{ CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, "dyld_v1 armv7", "armv7", littleEndian },
{ 0 }
};
const DYLDCache::ArchType DYLDCache::defaultArchitecture =
{ 0, 0, "dyld_v1 default", "unknown", littleEndian };
std::string DYLDCache::pathFor(const Architecture &arch)
{
for (const ArchType *it = architectures; it->cpu; it++)
if (arch.matches(it->architecture()))
return it->path();
UnixError::throwMe(ENOEXEC);
}
const DYLDCache::ArchType *DYLDCache::matchArchitecture(const dyld_cache_header &header)
{
for (const ArchType *arch = architectures; arch->cpu; arch++)
if (!strcmp(header.magic, arch->magic))
return arch;
if (!strncmp(header.magic, "dyld_v1 ", 8))
return &defaultArchitecture;
return NULL;
}
DYLDCache::DYLDCache(const std::string &path)
{
this->open(path);
mLength = this->fileSize();
mBase = this->mmap(PROT_READ, mLength);
mHeader = at<dyld_cache_header>(0);
if ((mArch = matchArchitecture(*mHeader)) == NULL)
UnixError::throwMe(ENOEXEC);
mFlip = *((const uint8_t *)&mArch->order) != 0x12;
mSigStart = (size_t)flip(mHeader->codeSignatureOffset);
mSigLength = (size_t)flip(mHeader->codeSignatureSize);
size_t sigEnd = mSigStart + mSigLength;
if (mSigStart > sigEnd || sigEnd > mLength)
UnixError::throwMe(ENOEXEC);
}
DYLDCache::~DYLDCache()
{
::munmap((void *)mBase, mLength);
}
bool DYLDCache::validate(UnixPlusPlus::FileDesc &fd)
{
dyld_cache_header header;
return fd.read(&header, sizeof(header), 0) == sizeof(header)
&& matchArchitecture(header) != NULL;
}
DYLDCache::Mapping DYLDCache::mapping(unsigned ix) const
{
assert(ix < this->mappingCount());
return Mapping(*this, flip(mHeader->mappingOffset) + ix * sizeof(shared_file_mapping_np));
}
DYLDCache::Image DYLDCache::image(unsigned ix) const
{
assert(ix < this->imageCount());
return Image(*this, flip(mHeader->imagesOffset) + ix * sizeof(dyld_cache_image_info));
}
DYLDCache::Mapping DYLDCache::findMap(uint64_t address) const
{
for (unsigned ix = 0; ix < mappingCount(); ix++) {
Mapping map = this->mapping(ix);
if (map.contains(address))
return map;
}
UnixError::throwMe(EINVAL);
}
uint64_t DYLDCache::mapAddress(uint64_t address) const
{
Mapping map = this->findMap(address);
return (address - map.address()) + map.offset();
}