#ifndef DyldSharedCache_h
#define DyldSharedCache_h
#include <TargetConditionals.h>
#include <uuid/uuid.h>
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
#include <sys/types.h>
#endif
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
#include <set>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#endif
#include "dyld_cache_format.h"
#include "Diagnostics.h"
#include "MachOAnalyzer.h"
#include "Closure.h"
#include "JSON.h"
namespace objc_opt {
struct objc_opt_t;
}
class VIS_HIDDEN DyldSharedCache
{
public:
#if BUILDING_CACHE_BUILDER
enum CodeSigningDigestMode
{
SHA256only = 0,
SHA1only = 1,
Agile = 2
};
enum class LocalSymbolsMode {
keep,
unmap,
strip
};
struct CreateOptions
{
std::string outputFilePath;
std::string outputMapFilePath;
const dyld3::GradedArchs* archs;
dyld3::Platform platform;
LocalSymbolsMode localSymbolMode;
bool optimizeStubs;
bool optimizeDyldDlopens;
bool optimizeDyldLaunches;
CodeSigningDigestMode codeSigningDigestMode;
bool dylibsRemovedDuringMastering;
bool inodesAreSameAsRuntime;
bool cacheSupportsASLR;
bool forSimulator;
bool isLocallyBuiltCache;
bool verbose;
bool evictLeafDylibsOnOverflow;
std::unordered_map<std::string, unsigned> dylibOrdering;
std::unordered_map<std::string, unsigned> dirtyDataSegmentOrdering;
dyld3::json::Node objcOptimizations;
std::string loggingPrefix;
};
struct MappedMachO
{
MappedMachO()
: mh(nullptr), length(0), isSetUID(false), protectedBySIP(false), sliceFileOffset(0), modTime(0), inode(0) { }
MappedMachO(const std::string& path, const dyld3::MachOAnalyzer* p, size_t l, bool isu, bool sip, uint64_t o, uint64_t m, uint64_t i)
: runtimePath(path), mh(p), length(l), isSetUID(isu), protectedBySIP(sip), sliceFileOffset(o), modTime(m), inode(i) { }
std::string runtimePath;
const dyld3::MachOAnalyzer* mh;
size_t length;
uint64_t isSetUID : 1,
protectedBySIP : 1,
sliceFileOffset : 62;
uint64_t modTime; uint64_t inode; };
struct CreateResults
{
std::string errorMessage;
std::set<std::string> warnings;
std::set<const dyld3::MachOAnalyzer*> evictions;
bool agileSignature = false;
std::string cdHashFirst;
std::string cdHashSecond;
};
struct FileAlias
{
std::string realPath;
std::string aliasPath;
};
static bool verifySelfContained(std::vector<MappedMachO>& dylibsToCache,
std::unordered_set<std::string>& badZippered,
MappedMachO (^loader)(const std::string& runtimePath, Diagnostics& diag), std::vector<std::pair<DyldSharedCache::MappedMachO, std::set<std::string>>>& excluded);
static CreateResults create(const CreateOptions& options,
const dyld3::closure::FileSystem& fileSystem,
const std::vector<MappedMachO>& dylibsToCache,
const std::vector<MappedMachO>& otherOsDylibs,
const std::vector<MappedMachO>& osExecutables);
std::string mapFile() const;
#endif // BUILDING_CACHE_BUILDER
const char* archName() const;
dyld3::Platform platform() const;
void forEachImage(void (^handler)(const mach_header* mh, const char* installName)) const;
bool hasImagePath(const char* dylibPath, uint32_t& imageIndex) const;
bool isOverridablePath(const char* dylibPath) const;
bool hasNonOverridablePath(const char* dylibPath) const;
const bool hasLocalSymbolsInfo() const;
uint64_t getCodeSignAddress() const;
bool findMachHeaderImageIndex(const mach_header* mh, uint32_t& imageIndex) const;
void forEachImageEntry(void (^handler)(const char* path, uint64_t mTime, uint64_t inode)) const;
const mach_header* getIndexedImageEntry(uint32_t index, uint64_t& mTime, uint64_t& node) const;
void forEachDylibPath(void (^handler)(const char* dylibPath, uint32_t index)) const;
const char* getIndexedImagePath(uint32_t index) const;
#if BUILDING_LIBDYLD
const char* getCanonicalPath(const char* path) const;
#endif
void forEachImageTextSegment(void (^handler)(uint64_t loadAddressUnslid, uint64_t textSegmentSize, const uuid_t dylibUUID, const char* installName, bool& stop)) const;
void forEachRegion(void (^handler)(const void* content, uint64_t vmAddr, uint64_t size,
uint32_t initProt, uint32_t maxProt, uint64_t flags)) const;
const void* getLocalNlistEntries() const;
const uint32_t getLocalNlistCount() const;
const char* getLocalStrings() const;
const uint32_t getLocalStringsSize() const;
void forEachLocalSymbolEntry(void (^handler)(uint32_t dylibOffset, uint32_t nlistStartIndex, uint32_t nlistCount, bool& stop)) const;
bool inCache(const void* addr, size_t length, bool& readOnly) const;
bool isAlias(const char* path) const;
uint64_t unslidLoadAddress() const;
void getUUID(uuid_t uuid) const;
uint64_t mappedSize() const;
const dyld3::closure::LaunchClosure* findClosure(const char* executablePath) const;
void forEachLaunchClosure(void (^handler)(const char* executableRuntimePath, const dyld3::closure::LaunchClosure* closure)) const;
void forEachDlopenImage(void (^handler)(const char* runtimePath, const dyld3::closure::Image* image)) const;
const dyld3::closure::ImageArray* cachedDylibsImageArray() const;
const dyld3::closure::ImageArray* otherOSImageArray() const;
const dyld3::closure::Image* findDlopenOtherImage(const char* path) const;
const dyld_cache_slide_info* legacyCacheSlideInfo() const;
const dyld_cache_mapping_info* legacyCacheDataRegionMapping() const;
const uint8_t* legacyCacheDataRegionBuffer() const;
const objc_opt::objc_opt_t* objcOpt() const;
const void* objcOptPtrs() const;
bool hasSlideInfo() const;
void forEachSlideInfo(void (^handler)(uint64_t mappingStartAddress, uint64_t mappingSize,
const uint8_t* mappingPagesStart,
uint64_t slideInfoOffset, uint64_t slideInfoSize,
const dyld_cache_slide_info* slideInfoHeader)) const;
bool addressInText(uint32_t cacheOffset, uint32_t* index) const;
uint32_t patchableExportCount(uint32_t imageIndex) const;
void forEachPatchableExport(uint32_t imageIndex, void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const;
void forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t cacheOffsetOfImpl,
void (^handler)(dyld_cache_patchable_location patchLocation)) const;
static uint64_t getAddend(const dyld_cache_patchable_location& loc) {
uint64_t unsingedAddend = loc.addend;
int64_t signedAddend = (int64_t)unsingedAddend;
signedAddend = (signedAddend << 52) >> 52;
return (uint64_t)signedAddend;
}
static const char* keyName(const dyld_cache_patchable_location& patchLocation) {
dyld3::MachOLoaded::ChainedFixupPointerOnDisk dummy;
dummy.arm64e.authRebase.auth = 1;
dummy.arm64e.authRebase.bind = 0;
dummy.arm64e.authRebase.key = patchLocation.key;
return dummy.arm64e.keyName();
}
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
typedef void (*DataConstLogFunc)(const char*, ...) __attribute__((format(printf, 1, 2)));
void changeDataConstPermissions(mach_port_t machTask, uint32_t permissions, DataConstLogFunc logFunc) const;
struct DataConstLazyScopedWriter {
DataConstLazyScopedWriter(const DyldSharedCache* cache, mach_port_t machTask, DataConstLogFunc logFunc);
~DataConstLazyScopedWriter();
DataConstLazyScopedWriter() = delete;
DataConstLazyScopedWriter(const DataConstLazyScopedWriter&) = delete;
DataConstLazyScopedWriter(DataConstLazyScopedWriter&&) = delete;
DataConstLazyScopedWriter& operator=(const DataConstLazyScopedWriter&) = delete;
DataConstLazyScopedWriter& operator=(DataConstLazyScopedWriter&&) = delete;
void makeWriteable();
const DyldSharedCache* cache = nullptr;
mach_port_t machTask = MACH_PORT_NULL;
DataConstLogFunc logFunc = nullptr;
bool wasMadeWritable = false;
};
struct DataConstScopedWriter {
DataConstScopedWriter(const DyldSharedCache* cache, mach_port_t machTask, DataConstLogFunc logFunc);
~DataConstScopedWriter() = default;
DataConstScopedWriter() = delete;
DataConstScopedWriter(const DataConstScopedWriter&) = delete;
DataConstScopedWriter(DataConstScopedWriter&&) = delete;
DataConstScopedWriter& operator=(const DataConstScopedWriter&) = delete;
DataConstScopedWriter& operator=(DataConstScopedWriter&&) = delete;
DataConstLazyScopedWriter writer;
};
#endif
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
std::string generateJSONMap(const char* disposition) const;
std::string generateJSONDependents() const;
#endif
enum class ConstantClasses {
cfStringAtomSize = 32
};
std::pair<const void*, uint64_t> getObjCConstantRange() const;
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
dyld3::MachOAnalyzer::VMAddrConverter makeVMAddrConverter(bool contentRebased) const;
#endif
dyld_cache_header header;
static const uint32_t MaxMappings = 8;
private:
template<typename T>
const T getAddrField(uint64_t addr) const;
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
void fillMachOAnalyzersMap(std::unordered_map<std::string,dyld3::MachOAnalyzer*> & dylibAnalyzers) const;
void computeReverseDependencyMapForDylib(std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap, const std::unordered_map<std::string,dyld3::MachOAnalyzer*> & dylibAnalyzers, const std::string &loadPath) const;
void computeReverseDependencyMap(std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap) const;
void findDependentsRecursively(std::unordered_map<std::string, std::set<std::string>> &transitiveDependents, const std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap, std::set<std::string> & visited, const std::string &loadPath) const;
void computeTransitiveDependents(std::unordered_map<std::string, std::set<std::string>> & transitiveDependents) const;
#endif
};
#endif