#ifndef CacheBuilder_h
#define CacheBuilder_h
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include "DyldSharedCache.h"
#include "Diagnostics.h"
#include "ImageProxy.h"
namespace dyld3 {
namespace launch_cache {
namespace binary_format {
struct ImageGroup;
struct Closure;
}
}
}
struct CacheBuilder {
CacheBuilder(const DyldSharedCache::CreateOptions& options);
void build(const std::vector<DyldSharedCache::MappedMachO>& dylibsToCache,
const std::vector<DyldSharedCache::MappedMachO>& otherOsDylibs,
const std::vector<DyldSharedCache::MappedMachO>& osExecutables);
void deleteBuffer();
const DyldSharedCache* buffer() { return _buffer; }
size_t bufferSize() { return (size_t)_allocatedBufferSize; }
std::string errorMessage();
const std::set<std::string> warnings();
const std::set<const mach_header*> evictions();
const bool agileSignature();
const std::string cdHashFirst();
const std::string cdHashSecond();
struct SegmentMappingInfo {
const void* srcSegment;
const char* segName;
uint64_t dstCacheAddress;
uint32_t dstCacheOffset;
uint32_t dstCacheSegmentSize;
uint32_t copySegmentSize;
uint32_t srcSegmentIndex;
};
private:
typedef std::unordered_map<const mach_header*, std::vector<SegmentMappingInfo>> SegmentMapping;
struct ArchLayout
{
uint64_t sharedMemoryStart;
uint64_t sharedMemorySize;
uint64_t sharedRegionPadding;
uint64_t pointerDeltaMask;
const char* archName;
uint32_t branchPoolTextSize;
uint32_t branchPoolLinkEditSize;
uint32_t branchReach;
uint8_t sharedRegionAlignP2;
bool sharedRegionsAreDiscontiguous;
bool is64;
};
static const ArchLayout _s_archLayout[];
static const char* const _s_neverStubEliminate[];
std::vector<DyldSharedCache::MappedMachO> makeSortedDylibs(const std::vector<DyldSharedCache::MappedMachO>& dylibs, const std::unordered_map<std::string, unsigned> sortOrder);
SegmentMapping assignSegmentAddresses(const std::vector<DyldSharedCache::MappedMachO>& dylibs, struct dyld_cache_mapping_info regions[3]);
bool cacheOverflow(const dyld_cache_mapping_info regions[3]);
void adjustImageForNewSegmentLocations(const std::vector<uint64_t>& segNewStartAddresses,
const std::vector<uint64_t>& segCacheFileOffsets,
const std::vector<uint64_t>& segCacheSizes, std::vector<void*>& pointersForASLR);
void fipsSign();
void codeSign();
uint64_t pathHash(const char* path);
void writeCacheHeader(const struct dyld_cache_mapping_info regions[3], const std::vector<DyldSharedCache::MappedMachO>& dylibs, const SegmentMapping&);
void copyRawSegments(const std::vector<DyldSharedCache::MappedMachO>& dylibs, const SegmentMapping& mapping);
void adjustAllImagesForNewSegmentLocations(const std::vector<DyldSharedCache::MappedMachO>& dylibs, const SegmentMapping& mapping);
void bindAllImagesInCacheFile(const dyld_cache_mapping_info regions[3]);
void writeSlideInfoV1();
void recomputeCacheUUID(void);
void findDylibAndSegment(const void* contentPtr, std::string& dylibName, std::string& segName);
void addCachedDylibsImageGroup(dyld3::ImageProxyGroup*);
void addCachedOtherDylibsImageGroup(dyld3::ImageProxyGroup*);
void addClosures(const std::map<std::string, const dyld3::launch_cache::binary_format::Closure*>& closures);
template <typename P> void writeSlideInfoV2();
template <typename P> bool makeRebaseChain(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const struct dyld_cache_slide_info2* info);
template <typename P> void addPageStarts(uint8_t* pageContent, const bool bitmap[], const struct dyld_cache_slide_info2* info,
std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
const DyldSharedCache::CreateOptions& _options;
DyldSharedCache* _buffer;
Diagnostics _diagnostics;
std::set<const mach_header*> _evictions;
const ArchLayout* _archLayout;
uint32_t _aliasCount;
uint64_t _slideInfoFileOffset;
uint64_t _slideInfoBufferSizeAllocated;
uint64_t _allocatedBufferSize;
uint64_t _currentFileSize;
uint64_t _vmSize;
std::unordered_map<std::string, uint32_t> _dataDirtySegsOrder;
std::vector<void*> _pointersForASLR;
dyld3::ImageProxyGroup::PatchTable _patchTable;
std::vector<uint64_t> _branchPoolStarts;
uint64_t _branchPoolsLinkEditStartAddr;
uint8_t _cdHashFirst[20];
uint8_t _cdHashSecond[20];
};
void adjustDylibSegments(DyldSharedCache* cache, bool is64, mach_header* mhInCache, const std::vector<CacheBuilder::SegmentMappingInfo>& mappingInfo, std::vector<void*>& pointersForASLR, Diagnostics& diag);
uint64_t optimizeLinkedit(DyldSharedCache* cache, bool is64, bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets, Diagnostics& diag, dyld_cache_local_symbols_info** localsInfo);
void bypassStubs(DyldSharedCache* cache, const std::vector<uint64_t>& branchPoolStartAddrs, const char* const alwaysUsesStubsTo[], Diagnostics& diag);
void optimizeObjC(DyldSharedCache* cache, bool is64, bool customerCache, std::vector<void*>& pointersForASLR, Diagnostics& diag);
inline uint64_t align(uint64_t addr, uint8_t p2)
{
uint64_t mask = (1 << p2);
return (addr + mask - 1) & (-mask);
}
#endif