#ifndef Closures_h
#define Closures_h
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <uuid/uuid.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
#include "Diagnostics.h"
#include "Array.h"
#include "MachOLoaded.h"
#include "SupportedArchs.h"
namespace dyld3 {
namespace closure {
enum { kFormatVersion = 10 };
typedef uint32_t ImageNum;
const ImageNum kFirstDyldCacheImageNum = 0x00000001;
const ImageNum kLastDyldCacheImageNum = 0x00000FFF;
const ImageNum kFirstOtherOSImageNum = 0x00001001;
const ImageNum kLastOtherOSImageNum = 0x00001FFF;
const ImageNum kFirstLaunchClosureImageNum = 0x00002000;
const ImageNum kMissingWeakLinkedImage = 0x0FFFFFFF;
struct VIS_HIDDEN TypedBytes
{
uint32_t type : 8,
payloadLength : 24;
enum class Type {
launchClosure = 1, imageArray = 2, image = 3, dlopenClosure = 4,
imageFlags = 7, pathWithHash = 8, fileInodeAndTime = 9, cdHash = 10, uuid = 11, mappingInfo = 12, diskSegment = 13, cacheSegment = 14, dependents = 15, initOffsets = 16, dofOffsets = 17, codeSignLoc = 18, fairPlayLoc = 19, rebaseFixups = 20, bindFixups = 21, cachePatchInfo = 22, textFixups = 23, imageOverride = 24, initBefores = 25, chainedFixupsStarts = 26, chainedFixupsTargets = 27,
closureFlags = 32, dyldCacheUUID = 33, missingFiles = 34,
envVar = 35, topImage = 36, libDyldEntry = 37, libSystemNum = 38, bootUUID = 39, mainEntry = 40, startEntry = 41, cacheOverrides = 42, interposeTuples = 43, };
const void* payload() const;
void* payload();
};
struct VIS_HIDDEN ContainerTypedBytes : TypedBytes
{
void forEachAttribute(void (^callback)(const TypedBytes* typedBytes, bool& stop)) const;
void forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const;
const void* findAttributePayload(Type requestedType, uint32_t* payloadSize=nullptr) const;
private:
const TypedBytes* first() const;
const TypedBytes* next(const TypedBytes*) const;
};
struct VIS_HIDDEN Image : ContainerTypedBytes
{
enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
size_t size() const;
ImageNum imageNum() const;
bool representsImageNum(ImageNum num) const; uint32_t maxLoadCount() const;
const char* path() const;
const char* leafName() const;
bool getUuid(uuid_t) const;
bool isInvalid() const;
bool inDyldCache() const;
bool hasObjC() const;
bool hasInitializers() const;
bool isBundle() const;
bool isDylib() const;
bool isExecutable() const;
bool hasWeakDefs() const;
bool mayHavePlusLoads() const;
bool is64() const;
bool neverUnload() const;
bool cwdMustBeThisDir() const;
bool isPlatformBinary() const;
bool overridableDylib() const;
bool hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const;
bool hasCdHash(uint8_t cdHash[20]) const;
void forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const;
void forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const;
ImageNum dependentImageNum(uint32_t depIndex) const;
bool containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions=nullptr) const;
void forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
void forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const;
void forEachDOF(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
bool hasPathWithHash(const char* path, uint32_t hash) const;
bool isOverrideOfDyldCacheImage(ImageNum& cacheImageNum) const;
uint64_t textSize() const;
union ResolvedSymbolTarget
{
enum Kinds { kindRebase, kindSharedCache, kindImage, kindAbsolute };
struct Rebase {
uint64_t kind : 2, unused : 62; };
struct SharedCache {
uint64_t kind : 2, offset : 62;
};
struct Image {
uint64_t kind : 2, imageNum : 22, offset : 40;
};
struct Absolute {
uint64_t kind : 2, value : 62; };
Rebase rebase;
SharedCache sharedCache;
Image image;
Absolute absolute;
uint64_t raw;
bool operator==(const ResolvedSymbolTarget& rhs) const {
return (raw == rhs.raw);
}
bool operator!=(const ResolvedSymbolTarget& rhs) const {
return (raw != rhs.raw);
}
};
typedef MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
uint32_t cacheOffset() const;
uint32_t patchStartIndex() const;
uint32_t patchCount() const;
void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
uint64_t vmSizeToMap() const;
uint64_t sliceOffsetInFile() const;
bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
void forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
void (^chainedFixupStart)(uint64_t imageOffsetStart, const Array<ResolvedSymbolTarget>& targets, bool& stop)) const;
void forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
static void forEachChainedFixup(void* imageLoadAddress, uint64_t imageOffsetChainStart,
void (^chainedFixupStart)(uint64_t* fixupLoc, ChainedFixupPointerOnDisk fixupInfo, bool& stop));
static_assert(sizeof(ResolvedSymbolTarget) == 8, "Overflow in size of SymbolTargetLocation");
static uint32_t hashFunction(const char*);
struct PatchableExport
{
struct PatchLocation
{
uint64_t cacheOffset : 32,
addend : 12, authenticated : 1,
usesAddressDiversity : 1,
key : 2,
discriminator : 16;
PatchLocation(size_t cacheOffset, uint64_t addend);
PatchLocation(size_t cacheOffset, uint64_t addend, dyld3::MachOLoaded::ChainedFixupPointerOnDisk authInfo);
uint64_t getAddend() const {
uint64_t unsingedAddend = addend;
int64_t signedAddend = (int64_t)unsingedAddend;
signedAddend = (signedAddend << 52) >> 52;
return (uint64_t)signedAddend;
}
const char* keyName() const;
bool operator==(const PatchLocation& other) const {
return this->cacheOffset == other.cacheOffset;
}
};
uint32_t cacheOffsetOfImpl;
uint32_t patchLocationsCount;
PatchLocation patchLocations[];
};
uint32_t patchableExportCount() const;
void forEachPatchableExport(void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const;
void forEachPatchableUseOfExport(uint32_t cacheOffsetOfImpl, void (^handler)(PatchableExport::PatchLocation patchLocation)) const;
private:
friend struct Closure;
friend class ImageWriter;
friend class ClosureBuilder;
friend class LaunchClosureWriter;
uint32_t pageSize() const;
struct Flags
{
uint64_t imageNum : 16,
maxLoadCount : 12,
isInvalid : 1, has16KBpages : 1,
is64 : 1,
hasObjC : 1,
mayHavePlusLoads : 1,
isEncrypted : 1, hasWeakDefs : 1,
neverUnload : 1,
cwdSameAsThis : 1, isPlatformBinary : 1, isBundle : 1,
isDylib : 1,
isExecutable : 1,
overridableDylib : 1, inDyldCache : 1,
padding : 21;
};
const Flags& getFlags() const;
struct PathAndHash
{
uint32_t hash;
char path[];
};
struct DiskSegment
{
uint64_t filePageCount : 30,
vmPageCount : 30,
permissions : 3,
paddingNotSeg : 1;
};
struct DyldCacheSegment
{
uint64_t cacheOffset : 32,
size : 28,
permissions : 4;
};
struct CodeSignatureLocation
{
uint32_t fileOffset;
uint32_t fileSize;
};
struct FileInfo
{
uint64_t inode;
uint64_t modTime;
};
struct FairPlayRange
{
uint32_t textPageCount : 28,
textStartPage : 4;
};
struct MappingInfo
{
uint32_t totalVmPages;
uint32_t sliceOffsetIn4K;
};
struct LinkedImage {
LinkedImage() : imgNum(0), linkKind(0) {
}
LinkedImage(LinkKind k, ImageNum num) : imgNum(num), linkKind((uint32_t)k) {
assert((num & 0xC0000000) == 0);
}
LinkKind kind() const { return (LinkKind)linkKind; }
ImageNum imageNum() const { return imgNum; }
void clearKind() { linkKind = 0; }
bool operator==(const LinkedImage& rhs) const {
return (linkKind == rhs.linkKind) && (imgNum == rhs.imgNum);
}
bool operator!=(const LinkedImage& rhs) const {
return (linkKind != rhs.linkKind) || (imgNum != rhs.imgNum);
}
private:
uint32_t imgNum : 30,
linkKind : 2; };
const Array<LinkedImage> dependentsArray() const;
struct RebasePattern
{
uint32_t repeatCount : 20,
contigCount : 8, skipCount : 4; };
const Array<RebasePattern> rebaseFixups() const;
struct BindPattern
{
Image::ResolvedSymbolTarget target;
uint64_t startVmOffset : 40, skipCount : 8,
repeatCount : 16;
};
const Array<BindPattern> bindFixups() const;
struct TextFixupPattern
{
Image::ResolvedSymbolTarget target;
uint32_t startVmOffset;
uint16_t repeatCount;
uint16_t skipCount;
};
const Array<TextFixupPattern> textFixups() const;
const Array<uint64_t> chainedStarts() const;
const Array<Image::ResolvedSymbolTarget> chainedTargets() const;
};
struct VIS_HIDDEN ImageArray : public TypedBytes
{
size_t size() const;
size_t startImageNum() const;
uint32_t imageCount() const;
void forEachImage(void (^callback)(const Image* image, bool& stop)) const;
bool hasPath(const char* path, ImageNum& num) const;
const Image* imageForNum(ImageNum) const;
static const Image* findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum);
private:
friend class ImageArrayWriter;
uint32_t firstImageNum;
uint32_t count;
uint32_t offsets[];
};
struct InterposingTuple
{
Image::ResolvedSymbolTarget stockImplementation;
Image::ResolvedSymbolTarget newImplementation;
};
struct VIS_HIDDEN Closure : public ContainerTypedBytes
{
size_t size() const;
const ImageArray* images() const;
ImageNum topImage() const;
void deallocate() const;
friend class ClosureWriter;
struct PatchEntry
{
ImageNum overriddenDylibInCache;
uint32_t exportCacheOffset;
Image::ResolvedSymbolTarget replacement;
};
void forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const;
};
struct VIS_HIDDEN LaunchClosure : public Closure
{
bool builtAgainstDyldCache(uuid_t cacheUUID) const;
const char* bootUUID() const;
void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
ImageNum libSystemImageNum() const;
void libDyldEntry(Image::ResolvedSymbolTarget& loc) const;
bool mainEntry(Image::ResolvedSymbolTarget& mainLoc) const;
bool startEntry(Image::ResolvedSymbolTarget& startLoc) const;
uint32_t initialLoadCount() const;
void forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const;
bool usedAtPaths() const;
bool usedFallbackPaths() const;
private:
friend class LaunchClosureWriter;
struct Flags
{
uint32_t usedAtPaths : 1,
usedFallbackPaths : 1,
initImageCount : 16,
padding : 14;
};
const Flags& getFlags() const;
};
struct VIS_HIDDEN DlopenClosure : public Closure
{
};
} }
#endif // Closures_h