2022-04-19 03:33:29 +00:00
|
|
|
/*
|
|
|
|
* 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 __DYLD_LOADING_H__
|
|
|
|
#define __DYLD_LOADING_H__
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <mach/mach.h>
|
|
|
|
#include <_simple.h>
|
|
|
|
|
|
|
|
#include "Closure.h"
|
|
|
|
#include "MachOLoaded.h"
|
2022-04-20 03:09:17 +00:00
|
|
|
#include "MachOAnalyzerSet.h"
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
namespace objc_opt {
|
|
|
|
struct objc_clsopt_t;
|
|
|
|
struct objc_selopt_t;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace dyld3 {
|
|
|
|
|
2022-04-20 03:09:17 +00:00
|
|
|
class RootsChecker;
|
|
|
|
|
|
|
|
struct LaunchErrorInfo
|
|
|
|
{
|
|
|
|
uintptr_t kind;
|
|
|
|
const char* clientOfDylibPath;
|
|
|
|
const char* targetDylibPath;
|
|
|
|
const char* symbol;
|
|
|
|
};
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Tuple of info about a loaded image. Contains the loaded address, Image*, and state.
|
|
|
|
//
|
|
|
|
class VIS_HIDDEN LoadedImage {
|
|
|
|
public:
|
|
|
|
enum class State { unmapped=0, mapped=1, fixedUp=2, beingInited=3, inited=4 };
|
|
|
|
|
|
|
|
static LoadedImage make(const closure::Image* img) { LoadedImage result; result._image = img; return result; }
|
|
|
|
static LoadedImage make(const closure::Image* img, const MachOLoaded* mh)
|
|
|
|
{ LoadedImage result; result._image = img; result.setLoadedAddress(mh); return result; }
|
|
|
|
|
|
|
|
const closure::Image* image() const { return _image; }
|
|
|
|
const MachOLoaded* loadedAddress() const { return (MachOLoaded*)(_loadAddr & (-4096)); }
|
|
|
|
void setLoadedAddress(const MachOLoaded* a) { _loadAddr |= ((uintptr_t)a & (-4096)); }
|
|
|
|
State state() const { return (State)(asBits().state); }
|
|
|
|
void setState(State s) { asBits().state = (int)s; }
|
|
|
|
bool hideFromFlatSearch() const { return asBits().hide; }
|
|
|
|
void setHideFromFlatSearch(bool h) { asBits().hide = h; }
|
|
|
|
bool leaveMapped() const { return asBits().leaveMapped; }
|
|
|
|
void markLeaveMapped() { asBits().leaveMapped = true; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
// since loaded MachO files are always page aligned, that means at least low 12-bits are always zero
|
|
|
|
// so we don't need to record the low 12 bits, instead those bits hold various flags in the _loadeAddr field
|
|
|
|
struct AddrBits {
|
|
|
|
uintptr_t state : 3,
|
|
|
|
hide : 1,
|
|
|
|
leaveMapped : 1,
|
|
|
|
extra : 7,
|
|
|
|
#if __LP64__
|
|
|
|
addr : 52;
|
|
|
|
#else
|
|
|
|
addr : 20;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
AddrBits& asBits() { return *((AddrBits*)&_loadAddr); }
|
|
|
|
const AddrBits& asBits() const { return *((AddrBits*)&_loadAddr); }
|
|
|
|
|
|
|
|
// Note: this must be statically initializable so as to not cause static initializers
|
|
|
|
const closure::Image* _image = nullptr;
|
|
|
|
uintptr_t _loadAddr = 0; // really AddrBits
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Utility class to recursively load dependents
|
|
|
|
//
|
2022-04-20 03:09:17 +00:00
|
|
|
class VIS_HIDDEN Loader : public MachOAnalyzerSet {
|
2022-04-19 03:33:29 +00:00
|
|
|
public:
|
|
|
|
typedef bool (*LogFunc)(const char*, ...) __attribute__((format(printf, 1, 2)));
|
|
|
|
|
|
|
|
Loader(const Array<LoadedImage>& existingImages, Array<LoadedImage>& newImagesStorage,
|
|
|
|
const void* cacheAddress, const Array<const dyld3::closure::ImageArray*>& imagesArrays,
|
|
|
|
const closure::ObjCSelectorOpt* selOpt, const Array<closure::Image::ObjCSelectorImage>& selImages,
|
2022-04-20 03:09:17 +00:00
|
|
|
const RootsChecker& rootsChecker, dyld3::Platform platform,
|
|
|
|
LogFunc log_loads, LogFunc log_segments, LogFunc log_fixups, LogFunc log_dofs,
|
|
|
|
bool allowMissingLazies=false, dyld3::LaunchErrorInfo* launchErrorInfo=nullptr);
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
void addImage(const LoadedImage&);
|
|
|
|
void completeAllDependents(Diagnostics& diag, bool& someCacheImageOverridden);
|
2022-04-20 03:09:17 +00:00
|
|
|
void mapAndFixupAllImages(Diagnostics& diag, bool processDOFs, bool fromOFI, bool* closureOutOfDate, bool* recoverable);
|
2022-04-19 03:33:29 +00:00
|
|
|
uintptr_t resolveTarget(closure::Image::ResolvedSymbolTarget target);
|
2022-04-20 03:09:17 +00:00
|
|
|
LoadedImage* findImage(closure::ImageNum targetImageNum) const;
|
|
|
|
void forEachImage(void (^handler)(const LoadedImage& li, bool& stop)) const;
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
static void unmapImage(LoadedImage& info);
|
|
|
|
static bool dtraceUserProbesEnabled();
|
|
|
|
static void vmAccountingSetSuspended(bool suspend, LogFunc);
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
struct ImageOverride
|
|
|
|
{
|
|
|
|
closure::ImageNum inCache;
|
|
|
|
closure::ImageNum replacement;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DOFInfo {
|
|
|
|
const void* dof;
|
|
|
|
const mach_header* imageHeader;
|
|
|
|
const char* imageShortName;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if BUILDING_DYLD
|
|
|
|
struct LaunchImagesCache {
|
|
|
|
LoadedImage* findImage(closure::ImageNum targetImageNum,
|
|
|
|
Array<LoadedImage>& images) const;
|
2022-04-20 03:09:17 +00:00
|
|
|
void tryAddImage(closure::ImageNum targetImageNum, uint64_t allImagesIndex) const;
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
static const uint64_t _cacheSize = 128;
|
|
|
|
static const closure::ImageNum _firstImageNum = closure::kFirstLaunchClosureImageNum;
|
|
|
|
static const closure::ImageNum _lastImageNum = closure::kFirstLaunchClosureImageNum + _cacheSize;
|
|
|
|
|
|
|
|
// Note, the cache stores "indices + 1" into the _allImages array.
|
|
|
|
// 0 means we haven't cached an entry yet
|
|
|
|
uint32_t _cacheStorage[_cacheSize] = { 0 };
|
2022-04-20 03:09:17 +00:00
|
|
|
mutable Array<uint32_t> _imageIndices = { &_cacheStorage[0], _cacheSize, _cacheSize };
|
2022-04-19 03:33:29 +00:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2022-04-20 03:09:17 +00:00
|
|
|
void mapImage(Diagnostics& diag, LoadedImage& info, bool fromOFI, bool* closureOutOfDate);
|
2022-04-19 03:33:29 +00:00
|
|
|
void applyFixupsToImage(Diagnostics& diag, LoadedImage& info);
|
|
|
|
void registerDOFs(const Array<DOFInfo>& dofs);
|
|
|
|
void setSegmentProtects(const LoadedImage& info, bool write);
|
|
|
|
bool sandboxBlockedMmap(const char* path);
|
|
|
|
bool sandboxBlockedOpen(const char* path);
|
|
|
|
bool sandboxBlockedStat(const char* path);
|
|
|
|
bool sandboxBlocked(const char* path, const char* kind);
|
2022-04-20 03:09:17 +00:00
|
|
|
void unmapAllImages();
|
|
|
|
|
|
|
|
// MachOAnalyzerSet support
|
|
|
|
void mas_forEachImage(void (^handler)(const WrappedMachO& anImage, bool hidden, bool& stop)) const override;
|
|
|
|
void mas_mainExecutable(WrappedMachO& anImage) const override;
|
|
|
|
void* mas_dyldCache() const override;
|
|
|
|
bool wmo_dependent(const WrappedMachO* image, uint32_t depIndex, WrappedMachO& childObj, bool& missingWeakDylib) const override;
|
|
|
|
const char* wmo_path(const WrappedMachO* image) const override;
|
|
|
|
bool wmo_missingSymbolResolver(const WrappedMachO* fromWmo, bool weakImport, bool lazyBind, const char* symbolName, const char* expectedInDylibPath, const char* clientPath, FixupTarget& target) const override;
|
|
|
|
|
2022-04-19 03:33:29 +00:00
|
|
|
|
|
|
|
const Array<LoadedImage>& _existingImages;
|
|
|
|
Array<LoadedImage>& _newImages;
|
|
|
|
const Array<const closure::ImageArray*>& _imagesArrays;
|
|
|
|
const void* _dyldCacheAddress;
|
|
|
|
const objc_opt::objc_selopt_t* _dyldCacheSelectorOpt;
|
|
|
|
const closure::ObjCSelectorOpt* _closureSelectorOpt;
|
|
|
|
const Array<closure::Image::ObjCSelectorImage>& _closureSelectorImages;
|
2022-04-20 03:09:17 +00:00
|
|
|
const RootsChecker& _rootsChecker;
|
2022-04-19 03:33:29 +00:00
|
|
|
#if BUILDING_DYLD
|
|
|
|
LaunchImagesCache _launchImagesCache;
|
|
|
|
#endif
|
2022-04-20 03:09:17 +00:00
|
|
|
bool _allowMissingLazies;
|
|
|
|
dyld3::Platform _platform;
|
2022-04-19 03:33:29 +00:00
|
|
|
LogFunc _logLoads;
|
|
|
|
LogFunc _logSegments;
|
|
|
|
LogFunc _logFixups;
|
|
|
|
LogFunc _logDofs;
|
2022-04-20 03:09:17 +00:00
|
|
|
dyld3::LaunchErrorInfo* _launchErrorInfo;
|
2022-04-19 03:33:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
|
|
|
|
bool internalInstall();
|
|
|
|
#endif
|
|
|
|
#if BUILDING_DYLD
|
|
|
|
void forEachLineInFile(const char* path, void (^lineHandler)(const char* line, bool& stop));
|
|
|
|
void forEachLineInFile(const char* buffer, size_t bufferLen, void (^lineHandler)(const char* line, bool& stop));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace dyld3
|
|
|
|
|
|
|
|
#endif // __DYLD_LOADING_H__
|
|
|
|
|
|
|
|
|