mirror of
https://github.com/darlinghq/darling-dyld.git
synced 2024-11-23 12:29:44 +00:00
291 lines
16 KiB
C++
291 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
|
|
#ifndef __ALL_IMAGES_H__
|
|
#define __ALL_IMAGES_H__
|
|
|
|
#include <mach-o/loader.h>
|
|
#include <pthread.h>
|
|
#include <os/lock_private.h>
|
|
#include <mach-o/dyld_priv.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include "Closure.h"
|
|
#include "Loading.h"
|
|
#include "MachOLoaded.h"
|
|
#include "DyldSharedCache.h"
|
|
#include "PointerAuth.h"
|
|
|
|
|
|
#if TARGET_OS_OSX
|
|
// only in macOS and deprecated
|
|
struct VIS_HIDDEN OFIInfo
|
|
{
|
|
const char* path; // = nullptr;
|
|
const void* memSource; // = nullptr;
|
|
size_t memLength; // = 0;
|
|
const dyld3::MachOLoaded* loadAddress; // = nullptr;
|
|
uint64_t imageNum; // = 0;
|
|
};
|
|
#endif
|
|
|
|
namespace dyld3 {
|
|
|
|
class VIS_HIDDEN AllImages
|
|
{
|
|
public:
|
|
typedef void (*NotifyFunc)(const mach_header* mh, intptr_t slide);
|
|
typedef void (*LoadNotifyFunc)(const mach_header* mh, const char* path, bool unloadable);
|
|
typedef void (*BulkLoadNotifier)(unsigned count, const mach_header* mhs[], const char* paths[]);
|
|
typedef void (*MainFunc)(void);
|
|
|
|
void init(const closure::LaunchClosure* closure, const DyldSharedCache* dyldCacheLoadAddress, const char* dyldCachePath,
|
|
const Array<LoadedImage>& initialImages);
|
|
void setRestrictions(bool allowAtPaths, bool allowEnvPaths);
|
|
void setHasCacheOverrides(bool someCacheImageOverriden);
|
|
bool hasCacheOverrides() const;
|
|
void setMainPath(const char* path);
|
|
void setLaunchMode(uint32_t flags);
|
|
void applyInitialImages();
|
|
|
|
void addImages(const Array<LoadedImage>& newImages);
|
|
void removeImages(const Array<LoadedImage>& unloadImages);
|
|
void runImageNotifiers(const Array<LoadedImage>& newImages);
|
|
void runImageCallbacks(const Array<LoadedImage>& newImages);
|
|
void applyInterposingToDyldCache(const closure::Closure* closure, mach_port_t mach_task_self);
|
|
void runStartupInitialzers();
|
|
void runInitialzersBottomUp(const closure::Image* topImage);
|
|
void runLibSystemInitializer(LoadedImage& libSystem);
|
|
|
|
uint32_t count() const;
|
|
|
|
void forEachImage(void (^handler)(const LoadedImage& loadedImage, bool& stop)) const;
|
|
const MachOLoaded* findDependent(const MachOLoaded* mh, uint32_t depIndex);
|
|
void visitDependentsTopDown(const LoadedImage& start, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const;
|
|
void infoForImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const;
|
|
bool infoForImageMappedAt(const void* addr, const MachOLoaded** ml, uint64_t* textSize, const char** path) const;
|
|
void infoForNonCachedImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const;
|
|
void infoForImageWithLoadAddress(const MachOLoaded*, void (^handler)(const LoadedImage& foundImage)) const;
|
|
const char* pathForImageMappedAt(const void* addr) const;
|
|
const char* imagePathByIndex(uint32_t index) const;
|
|
const mach_header* imageLoadAddressByIndex(uint32_t index) const;
|
|
bool immutableMemory(const void* addr, size_t length) const;
|
|
void* interposeValue(void* value) const;
|
|
|
|
bool hasInsertedOrInterposingLibraries() const;
|
|
bool isRestricted() const;
|
|
const MachOLoaded* mainExecutable() const;
|
|
const closure::Image* mainExecutableImage() const;
|
|
const void* cacheLoadAddress() const { return _dyldCacheAddress; }
|
|
const char* dyldCachePath() const { return _dyldCachePath; }
|
|
bool dyldCacheHasPath(const char* path) const;
|
|
const char* imagePath(const closure::Image*) const;
|
|
dyld_platform_t platform() const;
|
|
const GradedArchs& archs() const;
|
|
uint32_t launchMode() const { return _launchMode; }
|
|
|
|
const Array<const closure::ImageArray*>& imagesArrays();
|
|
|
|
void incRefCount(const mach_header* loadAddress);
|
|
void decRefCount(const mach_header* loadAddress);
|
|
|
|
void addLoadNotifier(NotifyFunc);
|
|
void addUnloadNotifier(NotifyFunc);
|
|
void setObjCNotifiers(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped);
|
|
void notifyObjCUnmap(const char* path, const struct mach_header* mh);
|
|
void addLoadNotifier(LoadNotifyFunc);
|
|
void addBulkLoadNotifier(BulkLoadNotifier);
|
|
|
|
|
|
void setOldAllImageInfo(dyld_all_image_infos* old) { _oldAllImageInfos = old; }
|
|
dyld_all_image_infos* oldAllImageInfo() const { return _oldAllImageInfos;}
|
|
void notifyMonitorMain();
|
|
void notifyMonitorLoads(const Array<LoadedImage>& newImages);
|
|
void notifyMonitorUnloads(const Array<LoadedImage>& unloadingImages);
|
|
|
|
#if TARGET_OS_OSX
|
|
NSObjectFileImage addNSObjectFileImage(const OFIInfo&);
|
|
void removeNSObjectFileImage(NSObjectFileImage);
|
|
bool forNSObjectFileImage(NSObjectFileImage imageHandle,
|
|
void (^handler)(OFIInfo& image));
|
|
#endif
|
|
|
|
const char* getObjCSelector(const char* selName) const;
|
|
void forEachObjCClass(const char* className,
|
|
void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const;
|
|
void forEachObjCProtocol(const char* protocolName,
|
|
void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) const;
|
|
|
|
MainFunc getDriverkitMain();
|
|
void setDriverkitMain(MainFunc mainFunc);
|
|
|
|
const MachOLoaded* dlopen(Diagnostics& diag, const char* path, bool rtldNoLoad, bool rtldLocal, bool rtldNoDelete,
|
|
bool forceBindLazies, bool fromOFI, const void* callerAddress,
|
|
bool canUsePrebuiltSharedCacheClosure = true);
|
|
|
|
struct ProgramVars
|
|
{
|
|
const void* mh;
|
|
int* NXArgcPtr;
|
|
const char*** NXArgvPtr;
|
|
const char*** environPtr;
|
|
const char** __prognamePtr;
|
|
};
|
|
void setProgramVars(ProgramVars* vars, bool keysOff, bool platformBinariesOnly);
|
|
|
|
// Note these are to be used exclusively by forking
|
|
void takeLockBeforeFork();
|
|
void releaseLockInForkParent();
|
|
void resetLockInForkChild();
|
|
|
|
private:
|
|
friend class Reaper;
|
|
|
|
struct DlopenCount {
|
|
const mach_header* loadAddress;
|
|
uintptr_t refCount;
|
|
};
|
|
|
|
//
|
|
// The ImmutableRanges structure is used to make dyld_is_memory_immutable()
|
|
// fast and lock free. The table contains just ranges that are immutable,
|
|
// which means they are non-writable and will never be unloaded.
|
|
// This means the table is only every appended to. No entries are ever removed
|
|
// or changed. This makes it easier to be lock-less. The array fields
|
|
// all start as zero. Entries are only appended with the writer lock,
|
|
// so we don't need to worry about multiple writers colliding. And when
|
|
// appending, the end field is set before the start field. Readers
|
|
// of this structure just walk down the array and quit at the first
|
|
// start field that is zero.
|
|
//
|
|
struct ImmutableRanges {
|
|
std::atomic<ImmutableRanges*> next;
|
|
uintptr_t arraySize;
|
|
struct {
|
|
std::atomic<uintptr_t> start;
|
|
std::atomic<uintptr_t> end;
|
|
} array[2]; // programs with only main-exe and dyld cache fit in here
|
|
};
|
|
|
|
const MachOLoaded* loadImage(Diagnostics& diag, const char* path,
|
|
closure::ImageNum topImageNum, const closure::DlopenClosure* newClosure,
|
|
bool rtldLocal, bool rtldNoDelete, bool rtldNow, bool fromOFI,
|
|
const void* callerAddress);
|
|
|
|
|
|
typedef void (*Initializer)(int argc, const char* argv[], char* envp[], const char* apple[], const ProgramVars* vars);
|
|
typedef const Array<LoadedImage> StartImageArray;
|
|
|
|
void runInitialzersInImage(const mach_header* imageLoadAddress, const closure::Image* image);
|
|
void mirrorToOldAllImageInfos();
|
|
void garbageCollectImages();
|
|
void breadthFirstRecurseDependents(Array<closure::ImageNum>& visited, const LoadedImage& nodeLi, bool& stop, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const;
|
|
void appendToImagesArray(const closure::ImageArray* newArray);
|
|
void withReadLock(void (^work)()) const;
|
|
void withWriteLock(void (^work)());
|
|
void withNotifiersLock(void (^work)()) const;
|
|
bool findImage(const mach_header* loadAddress, LoadedImage& foundImage) const;
|
|
bool findImageNum(closure::ImageNum imageNum, LoadedImage& foundImage) const;
|
|
LoadedImage findImageNum(closure::ImageNum num, uint32_t& indexHint);
|
|
bool swapImageState(closure::ImageNum num, uint32_t& indexHint, LoadedImage::State expectedCurrentState, LoadedImage::State newState);
|
|
void runAllInitializersInImage(const closure::Image* image, const MachOLoaded* ml);
|
|
void recomputeBounds();
|
|
void runAllStaticTerminators();
|
|
uintptr_t resolveTarget(closure::Image::ResolvedSymbolTarget target) const;
|
|
void addImmutableRange(uintptr_t start, uintptr_t end);
|
|
|
|
static void runAllStaticTerminatorsHelper(void*);
|
|
|
|
typedef closure::ImageArray ImageArray;
|
|
|
|
typedef const closure::LaunchClosure* __ptrauth_dyld_address_auth MainClosurePtrType;
|
|
|
|
MainClosurePtrType _mainClosure = nullptr;
|
|
const DyldSharedCache* _dyldCacheAddress = nullptr;
|
|
const char* _dyldCachePath = nullptr;
|
|
uint64_t _dyldCacheSlide = 0;
|
|
StartImageArray* _initialImages = nullptr;
|
|
const char* _mainExeOverridePath = nullptr;
|
|
_dyld_objc_notify_mapped _objcNotifyMapped = nullptr;
|
|
_dyld_objc_notify_init _objcNotifyInit = nullptr;
|
|
_dyld_objc_notify_unmapped _objcNotifyUnmapped = nullptr;
|
|
ProgramVars* _programVars = nullptr;
|
|
dyld_all_image_infos* _oldAllImageInfos = nullptr;
|
|
dyld_image_info* _oldAllImageArray = nullptr;
|
|
dyld_uuid_info* _oldUUIDArray = nullptr;
|
|
const GradedArchs* _archs = nullptr;
|
|
ImmutableRanges _immutableRanges = { nullptr, 2 };
|
|
uint32_t _oldArrayAllocCount = 0;
|
|
uint32_t _oldUUIDAllocCount = 0;
|
|
closure::ImageNum _nextImageNum = 0;
|
|
int32_t _gcCount = 0;
|
|
bool _processDOFs = false;
|
|
bool _allowAtPaths = false;
|
|
bool _allowEnvPaths = false;
|
|
bool _someImageOverridden = false;
|
|
uint32_t _launchMode = 0;
|
|
uintptr_t _lowestNonCached = 0;
|
|
uintptr_t _highestNonCached = UINTPTR_MAX;
|
|
|
|
MainFunc _driverkitMain = nullptr;
|
|
#ifdef OS_UNFAIR_RECURSIVE_LOCK_INIT
|
|
mutable os_unfair_recursive_lock _globalLock = OS_UNFAIR_RECURSIVE_LOCK_INIT;
|
|
#else
|
|
mutable pthread_mutex_t _globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
|
|
#endif
|
|
GrowableArray<const ImageArray*, 4, 4> _imagesArrays;
|
|
GrowableArray<NotifyFunc, 4, 4> _loadNotifiers;
|
|
GrowableArray<NotifyFunc, 4, 4> _unloadNotifiers;
|
|
GrowableArray<LoadNotifyFunc, 4, 4> _loadNotifiers2;
|
|
GrowableArray<BulkLoadNotifier, 2, 2> _loadBulkNotifiers;
|
|
GrowableArray<DlopenCount, 4, 4> _dlopenRefCounts;
|
|
GrowableArray<LoadedImage, 16> _loadedImages;
|
|
#if TARGET_OS_OSX
|
|
uint64_t _nextObjectFileImageNum = 0;
|
|
GrowableArray<OFIInfo, 4, 1> _objectFileImages;
|
|
#endif
|
|
|
|
// ObjC selectors
|
|
// This is an array of the base addresses of sections containing selector strings
|
|
GrowableArray<uintptr_t, 4, 4> _objcSelectorHashTableImages;
|
|
const closure::ObjCSelectorOpt* _objcSelectorHashTable = nullptr;
|
|
|
|
// ObjC classes
|
|
// This is an array of the base addresses of (name vmaddr, data vmaddr) pairs of sections in each image
|
|
GrowableArray<std::pair<uintptr_t, uintptr_t>, 4, 4> _objcClassHashTableImages;
|
|
const closure::ObjCClassOpt* _objcClassHashTable = nullptr;
|
|
const closure::ObjCClassDuplicatesOpt* _objcClassDuplicatesHashTable = nullptr;
|
|
const closure::ObjCClassOpt* _objcProtocolHashTable = nullptr;
|
|
const objc_opt::objc_opt_t* _dyldCacheObjCOpt = nullptr;
|
|
};
|
|
|
|
extern AllImages gAllImages;
|
|
|
|
|
|
} // dyld3
|
|
|
|
|
|
#endif // __ALL_IMAGES_H__
|