#ifndef __IMAGELOADER__
#define __IMAGELOADER__
#include <sys/types.h>
#include <mach/mach_time.h> // struct mach_timebase_info
#include <stdint.h>
#include <vector>
#include <set>
#include "mach-o/dyld_gdb.h"
__attribute__((noreturn)) void throwf(const char* format, ...);
class ImageLoader {
public:
typedef uint32_t DefinitionFlags;
static const DefinitionFlags kNoDefinitionOptions = 0;
static const DefinitionFlags kWeakDefinition = 1;
typedef uint32_t ReferenceFlags;
static const ReferenceFlags kNoReferenceOptions = 0;
static const ReferenceFlags kWeakReference = 1;
static const ReferenceFlags kTentativeDefinition = 2;
enum BindingLaziness { kNonLazyOnly, kLazyAndNonLazy, kLazyOnly, kLazyOnlyNoDependents };
enum InitializerRunning { kDontRunInitializers, kRunInitializers, kDontRunInitializersButTellObjc };
enum PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding };
enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers };
enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion };
struct Symbol;
struct MappedRegion {
uintptr_t address;
size_t size;
};
typedef std::vector<MappedRegion> RegionsVector;
struct LinkContext {
ImageLoader* (*loadLibrary)(const char* libraryName, bool search, const char* origin, const char* rpath[]);
uint32_t (*imageNotification)(ImageLoader* image, uint32_t startIndex);
void (*terminationRecorder)(ImageLoader* image);
bool (*flatExportFinder)(const char* name, const Symbol** sym, ImageLoader** image);
bool (*coalescedExportFinder)(const char* name, const Symbol** sym, ImageLoader** image);
void (*undefinedHandler)(const char* name);
void (*addImageNeedingNotification)(ImageLoader* image);
void (*notifyAdding)(std::vector<ImageLoader*>& images);
void (*getAllMappedRegions)(RegionsVector&);
void * (*bindingHandler)(const char *, const char *, void *);
BindingOptions bindingOptions;
int argc;
const char** argv;
const char** envp;
const char** apple;
ImageLoader* mainExecutable;
const char* imageSuffix;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
bool bindFlat;
bool slideAndPackDylibs;
bool verboseOpts;
bool verboseEnv;
bool verboseMapping;
bool verboseRebase;
bool verboseBind;
bool verboseInit;
bool verbosePrebinding;
bool verboseWarnings;
};
virtual ~ImageLoader();
void link(const LinkContext& context, BindingLaziness mode, InitializerRunning inits, uint32_t notifyCount);
void runInitializers(const LinkContext& context);
void runNotification(const LinkContext& context, uint32_t notifyCount);
bool statMatch(const struct stat& stat_buf) const;
const char* getShortName() const;
const char* getPath() const { return fPath; }
uint32_t getPathHash() const { return fPathHash; }
const char* getLogicalPath() const;
virtual const char* getInstallPath() const = 0;
bool matchInstallPath() const;
void setMatchInstallPath(bool);
uint64_t getOffsetInFatFile() const;
void setHideExports(bool hide = true);
bool hasHiddenExports() const;
bool isLinked() const;
void setLeaveMapped();
virtual bool containsAddress(const void* addr) const;
void addMappedRegions(RegionsVector& regions) const;
time_t lastModified();
uint64_t reprebind(const LinkContext& context, time_t timestamp);
void reprebindCommit(const LinkContext& context, bool commit, bool unmapOld);
virtual void* getMain() const = 0;
virtual const struct mach_header* machHeader() const = 0;
virtual uintptr_t getSlide() const = 0;
virtual const void* getBaseAddress() const = 0;
virtual bool hasCoalescedExports() const = 0;
virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const = 0;
virtual uintptr_t getExportedSymbolAddress(const Symbol* sym) const = 0;
virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const = 0;
virtual const char* getExportedSymbolName(const Symbol* sym) const = 0;
virtual uint32_t getExportedSymbolCount() const = 0;
virtual const Symbol* getIndexedExportedSymbol(uint32_t index) const = 0;
virtual const Symbol* findExportedSymbolInDependentImages(const char* name, ImageLoader** foundIn) const;
virtual const Symbol* findExportedSymbolInImageOrDependentImages(const char* name, ImageLoader** foundIn) const;
virtual uint32_t getImportedSymbolCount() const = 0;
virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const = 0;
virtual ReferenceFlags geImportedSymbolInfo(const Symbol* sym) const = 0;
virtual const char* getImportedSymbolName(const Symbol* sym) const = 0;
virtual bool isBundle() const = 0;
virtual bool isDylib() const = 0;
virtual bool forceFlat() const = 0;
virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
virtual void doTermination(const LinkContext& context) = 0;
virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) = 0;
virtual bool needsInitialization() = 0;
virtual bool hasImageNotification() = 0;
virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) = 0;
virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) = 0;
virtual bool isPrebindable() const = 0;
virtual bool usablePrebinding(const LinkContext& context) const = 0;
void incrementReferenceCount();
bool decrementReferenceCount();
static void printStatistics(unsigned int imageCount);
static void addSuffix(const char* path, const char* suffix, char* result);
static uint32_t hash(const char*);
void setPath(const char* path); void setLogicalPath(const char* path);
protected:
ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info);
ImageLoader(const char* moduleName);
ImageLoader(const ImageLoader&);
void operator=(const ImageLoader&);
struct LibraryInfo {
uint64_t checksum;
uint32_t minVersion;
uint32_t maxVersion;
};
struct DependentLibrary {
const char* name;
ImageLoader* image;
LibraryInfo info;
bool required;
bool checksumMatches;
bool isReExported;
bool isSubFramework;
};
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[],const char* apple[]);
typedef void (*Terminator)(void);
void recursiveLoadLibraries(const LinkContext& context);
void recursiveRebase(const LinkContext& context);
void recursiveBind(const LinkContext& context, BindingLaziness bindness);
void recursiveImageAnnouncement(const LinkContext& context, std::vector<ImageLoader*>& newImages);
void recursiveImageNotification(const LinkContext& context, uint32_t addImageCount);
void recursiveInitialization(const LinkContext& context);
virtual void instantiateSegments(const uint8_t* fileData) = 0;
virtual uint32_t doGetDependentLibraryCount() = 0;
virtual void doGetDependentLibraries(DependentLibrary libs[]) = 0;
virtual LibraryInfo doGetLibraryInfo() = 0;
virtual void doRebase(const LinkContext& context) = 0;
virtual void doBind(const LinkContext& context, BindingLaziness bindness) = 0;
virtual void doInitialization(const LinkContext& context) = 0;
virtual void doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind) = 0;
virtual bool needsTermination() = 0;
virtual bool segmentsMustSlideTogether() const = 0;
virtual bool segmentsCanSlide() const = 0;
virtual void setSlide(intptr_t slide) = 0;
virtual void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
virtual void mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
bool allDependentLibrariesAsWhenPreBound() const;
virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
virtual void prebindUnmap(const LinkContext& context) = 0;
static uint32_t fgImagesWithUsedPrebinding;
static uint32_t fgTotalRebaseFixups;
static uint32_t fgTotalBindFixups;
static uint32_t fgTotalLazyBindFixups;
static uint32_t fgTotalPossibleLazyBindFixups;
static uint64_t fgTotalLoadLibrariesTime;
static uint64_t fgTotalRebaseTime;
static uint64_t fgTotalBindTime;
static uint64_t fgTotalNotifyTime;
static uint64_t fgTotalInitTime;
static uintptr_t fgNextSplitSegAddress;
const char* fPath;
const char* fLogicalPath; dev_t fDevice;
ino_t fInode;
time_t fLastModified;
uint64_t fOffsetInFatFile;
std::vector<class Segment*> fSegments;
DependentLibrary* fLibraries;
uint32_t fLibrariesCount;
uint32_t fPathHash;
uint32_t fReferenceCount;
bool fAllLibraryChecksumsAndLoadAddressesMatch;
bool fLeaveMapped;
private:
void init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate);
intptr_t assignSegmentAddresses(const LinkContext& context);
uint64_t copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize);
const ImageLoader::Symbol* findExportedSymbolInDependentImagesExcept(const char* name, std::set<const ImageLoader*>& dontSearchImages, ImageLoader** foundIn) const;
bool fHideSymbols; bool fMatchByInstallName; bool fLibrariesLoaded;
bool fBased;
bool fBoundAllNonLazy;
bool fBoundAllLazy;
bool fAnnounced;
bool fInitialized;
uint16_t fNextAddImageIndex;
};
class Segment {
public:
virtual ~Segment() {}
virtual const ImageLoader* getImage() = 0;
virtual const char* getName() = 0;
virtual uintptr_t getSize() = 0;
virtual uintptr_t getFileSize() = 0;
virtual bool hasTrailingZeroFill();
virtual uintptr_t getFileOffset() = 0;
virtual bool readable() = 0;
virtual bool writeable() = 0;
virtual bool executable() = 0;
virtual bool unaccessible() = 0;
virtual bool hasFixUps() = 0;
virtual uintptr_t getActualLoadAddress() = 0;
virtual uintptr_t getPreferredLoadAddress() = 0;
virtual void setUnMapWhenDestructed(bool unmap) = 0;
protected:
Segment() {}
Segment(const Segment&);
void operator=(const Segment&);
virtual bool hasPreferredLoadAddress() = 0;
static bool reserveAddressRange(uintptr_t start, size_t length);
static uintptr_t reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context);
static uintptr_t fgNextNonSplitSegAddress;
private:
void map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader::LinkContext& context);
void map(const void* memoryImage, intptr_t slide, const ImageLoader::LinkContext& context);
void setPermissions();
void tempWritable();
friend class ImageLoader;
friend class ImageLoaderMachO;
};
#endif