#ifndef __IMAGELOADER__
#define __IMAGELOADER__
#include <sys/types.h>
#include <mach/mach_time.h> // struct mach_timebase_info
#include <mach/mach_init.h> // struct mach_thread_self
#include <stdint.h>
#include <vector>
#include <set>
#include "mach-o/dyld_images.h"
#include "mach-o/dyld_priv.h"
#define SPLIT_SEG_SHARED_REGION_SUPPORT 0
#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__)
#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__)
#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__)
#define IMAGE_NOTIFY_SUPPORT 0
#define RECURSIVE_INITIALIZER_LOCK 1
#define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
namespace dyld {
extern __attribute__((noreturn)) void throwf(const char* format, ...) __attribute__((format(printf, 1, 2)));
extern void log(const char* format, ...) __attribute__((format(printf, 1, 2)));
extern void warn(const char* format, ...) __attribute__((format(printf, 1, 2)));
extern const char* mkstringf(const char* format, ...) __attribute__((format(printf, 1, 2)));
};
struct ProgramVars
{
const void* mh;
int* NXArgcPtr;
const char*** NXArgvPtr;
const char*** environPtr;
const char** __prognamePtr;
};
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 PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding };
enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers };
enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion, kSharedRegionIsSharedCache };
struct Symbol;
struct MappedRegion {
uintptr_t address;
size_t size;
};
struct RPathChain {
RPathChain(const RPathChain* n, std::vector<const char*>* p) : next(n), paths(p) {};
const RPathChain* next;
std::vector<const char*>* paths;
};
struct DOFInfo {
void* dof;
const mach_header* imageHeader;
const char* imageShortName;
};
struct LinkContext {
ImageLoader* (*loadLibrary)(const char* libraryName, bool search, bool findDLL, const char* origin, const RPathChain* rpaths);
void (*terminationRecorder)(ImageLoader* image);
bool (*flatExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
bool (*coalescedExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
void (*undefinedHandler)(const char* name);
#if IMAGE_NOTIFY_SUPPORT
void (*addImageNeedingNotification)(ImageLoader* image);
void (*notifyAdding)(const ImageLoader* const * images, unsigned int count);
#endif
MappedRegion* (*getAllMappedRegions)(MappedRegion*);
void * (*bindingHandler)(const char *, const char *, void *);
void (*notifySingle)(dyld_image_states, const struct mach_header*, const char* path, time_t modDate);
void (*notifyBatch)(dyld_image_states state);
void (*removeImage)(ImageLoader* image);
void (*registerDOFs)(const std::vector<DOFInfo>& dofs);
void (*clearAllDepths)();
unsigned int (*imageCount)();
void (*notifySharedCacheInvalid)();
#if __i386__
void (*makeSharedCacheImportSegmentsWritable)(bool writable);
#endif
void (*setNewProgramVars)(const ProgramVars&);
#if SUPPORT_OLD_CRT_INITIALIZATION
void (*setRunInitialzersOldWay)();
#endif
BindingOptions bindingOptions;
int argc;
const char** argv;
const char** envp;
const char** apple;
const char* progname;
ProgramVars programVars;
ImageLoader* mainExecutable;
const char* imageSuffix;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
bool dyldLoadedAtSameAddressNeededBySharedCache;
bool preFetchDisabled;
bool prebinding;
bool bindFlat;
bool linkingMainExecutable;
bool startedInitializingMainExecutable;
bool verboseOpts;
bool verboseEnv;
bool verboseMapping;
bool verboseRebase;
bool verboseBind;
bool verboseInit;
bool verboseDOF;
bool verbosePrebinding;
bool verboseWarnings;
};
virtual ~ImageLoader();
void link(const LinkContext& context, bool forceLazysBound, bool preflight, const RPathChain& loaderRPaths);
void runInitializers(const LinkContext& context);
void bindAllLazyPointers(const LinkContext& context, bool recursive);
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();
bool leaveMapped() { return fLeaveMapped; }
virtual bool containsAddress(const void* addr) const;
virtual bool overlapsWithAddressRange(const void* start, const void* end) const;
void getMappedRegions(MappedRegion*& region) const;
time_t lastModified() const;
virtual void* getMain() const = 0;
virtual const struct mach_header* machHeader() const = 0;
virtual uintptr_t getSlide() const = 0;
virtual const void* getEnd() const = 0;
virtual bool hasCoalescedExports() const = 0;
virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) const = 0;
virtual uintptr_t getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor=NULL) 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, const LinkContext& context, const ImageLoader** foundIn) const;
virtual const Symbol* findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const 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;
#if IMAGE_NOTIFY_SUPPORT
virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) = 0;
#endif
virtual bool needsInitialization() = 0;
#if IMAGE_NOTIFY_SUPPORT
virtual bool hasImageNotification() = 0;
#endif
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;
virtual void getRPaths(const LinkContext& context, std::vector<const char*>&) const = 0;
dyld_image_states getState() { return (dyld_image_states)fState; }
int compare(const ImageLoader* right) const;
void incrementDlopenReferenceCount() { ++fDlopenReferenceCount; }
bool decrementDlopenReferenceCount();
void printReferenceCounts();
uint32_t referenceCount() const { return fDlopenReferenceCount + fStaticReferenceCount + fDynamicReferenceCount; }
bool neverUnload() const { return fNeverUnload; }
void setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
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 setPathUnowned(const char* path);
void setLogicalPath(const char* path);
void clearDepth() { fDepth = 0; }
void setBeingRemoved() { fBeingRemoved = true; }
bool isBeingRemoved() const { return fBeingRemoved; }
void setAddFuncNotified() { fAddFuncNotified = true; }
bool addFuncNotified() const { return fAddFuncNotified; }
protected:
struct DependentLibrary;
public:
friend class iterator;
class iterator
{
public:
iterator& operator++() { ++fLocation; return *this; }
bool operator!=(const iterator& it) const { return (it.fLocation != this->fLocation); }
ImageLoader* operator*() const { return fLocation->image; }
private:
friend class ImageLoader;
iterator(DependentLibrary* loc) : fLocation(loc) {}
DependentLibrary* fLocation;
};
iterator beginDependents() { return iterator(fLibraries); }
iterator endDependents() { return iterator(&fLibraries[fLibrariesCount]); }
friend class Segment;
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 {
uint32_t checksum;
uint32_t minVersion;
uint32_t maxVersion;
};
struct DependentLibrary {
ImageLoader* image;
uint32_t required : 1,
checksumMatches : 1,
isReExported : 1,
isSubFramework : 1;
};
struct DependentLibraryInfo {
const char* name;
LibraryInfo info;
bool required;
bool reExported;
};
class SegmentIterator
{
public:
SegmentIterator& operator++(); bool operator!=(const SegmentIterator& it) const { return (it.fLocation != this->fLocation); }
class Segment* operator*() const { return fLocation; }
SegmentIterator(class Segment* loc) : fLocation(loc) {}
private:
class Segment* fLocation;
};
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
typedef void (*Terminator)(void);
void recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths);
void recursiveUnLoadMappedLibraries(const LinkContext& context);
unsigned int recursiveUpdateDepth(unsigned int maxDepth);
void recursiveValidate(const LinkContext& context);
void recursiveRebase(const LinkContext& context);
void recursiveBind(const LinkContext& context, bool forceLazysBound);
void recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
#if IMAGE_NOTIFY_SUPPORT
void recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages);
#endif
void recursiveInitialization(const LinkContext& context, mach_port_t this_thread);
virtual uint32_t doGetDependentLibraryCount() = 0;
virtual void doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
virtual LibraryInfo doGetLibraryInfo() = 0;
virtual void doRebase(const LinkContext& context) = 0;
virtual void doBind(const LinkContext& context, bool forceLazysBound) = 0;
virtual void doBindJustLazies(const LinkContext& context) = 0;
virtual void doUpdateMappingPermissions(const LinkContext& context) = 0;
virtual void doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
virtual void doInitialization(const LinkContext& context) = 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;
void setMapped(const LinkContext& context);
void addDynamicReference(const ImageLoader* target);
virtual SegmentIterator beginSegments() const = 0;
virtual SegmentIterator endSegments() const = 0;
static uint32_t fgImagesWithUsedPrebinding;
static uint32_t fgImagesUsedFromSharedCache;
static uint32_t fgImagesRequiringNoFixups;
static uint32_t fgTotalRebaseFixups;
static uint32_t fgTotalBindFixups;
static uint32_t fgTotalBindSymbolsResolved;
static uint32_t fgTotalBindImageSearches;
static uint32_t fgTotalLazyBindFixups;
static uint32_t fgTotalPossibleLazyBindFixups;
static uint32_t fgTotalSegmentsMapped;
static uint64_t fgTotalBytesMapped;
static uint64_t fgTotalBytesPreFetched;
static uint64_t fgTotalLoadLibrariesTime;
static uint64_t fgTotalRebaseTime;
static uint64_t fgTotalBindTime;
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;
DependentLibrary* fLibraries;
uint32_t fLibrariesCount;
uint32_t fPathHash;
uint32_t fDlopenReferenceCount; uint32_t fStaticReferenceCount; uint32_t fDynamicReferenceCount; std::set<const ImageLoader*>* fDynamicReferences;
private:
#if RECURSIVE_INITIALIZER_LOCK
struct recursive_lock {
recursive_lock(mach_port_t t) : thread(t), count(0) {}
mach_port_t thread;
int count;
};
void recursiveSpinLock(recursive_lock&);
void recursiveSpinUnLock();
#endif
void init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate);
intptr_t assignSegmentAddresses(const LinkContext& context);
const ImageLoader::Symbol* findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart,
const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
uint16_t fDepth;
uint16_t fLoadOrder;
uint32_t fState : 8,
fAllLibraryChecksumsAndLoadAddressesMatch : 1,
fLeaveMapped : 1, fNeverUnload : 1, fHideSymbols : 1, fMatchByInstallName : 1, fRegisteredDOF : 1,
#if IMAGE_NOTIFY_SUPPORT
fAnnounced : 1,
#endif
fAllLazyPointersBound : 1,
fBeingRemoved : 1,
fAddFuncNotified : 1,
fPathOwnedByImage : 1;
#if RECURSIVE_INITIALIZER_LOCK
recursive_lock* fInitializerRecursiveLock;
#else
uint32_t fInitializerLock;
#endif
static uint16_t fgLoadOrdinal;
};
class Segment {
public:
virtual ~Segment() {}
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 uintptr_t getActualLoadAddress(const ImageLoader*) = 0;
virtual uintptr_t getPreferredLoadAddress() = 0;
virtual void unmap(const ImageLoader*) = 0;
virtual Segment* next(Segment*) = 0;
#if __i386__
virtual bool readOnlyImportStubs() = 0;
#endif
protected:
Segment() {}
Segment(const Segment&);
void operator=(const Segment&);
virtual bool hasPreferredLoadAddress() = 0;
virtual void map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
static bool reserveAddressRange(uintptr_t start, size_t length);
static uintptr_t reserveAnAddressRange(size_t length, const class ImageLoader::LinkContext& context);
static uintptr_t fgNextPIEDylibAddress;
private:
void setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image);
void map(const void* memoryImage, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
void tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image);
friend class ImageLoader;
friend class ImageLoaderMachO;
};
inline ImageLoader::SegmentIterator& ImageLoader::SegmentIterator::operator++() { fLocation = fLocation->next(fLocation); return *this; }
#endif