mirror of
https://github.com/darlinghq/darling-dyld.git
synced 2024-11-23 04:19:41 +00:00
298 lines
12 KiB
C++
298 lines
12 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 MachOFile_h
|
|
#define MachOFile_h
|
|
|
|
#include <mach-o/loader.h>
|
|
#include <mach-o/fat.h>
|
|
#include <uuid/uuid.h>
|
|
|
|
#include "Diagnostics.h"
|
|
#include "SupportedArchs.h"
|
|
#include <mach-o/fixup-chains.h>
|
|
#include <mach-o/loader.h>
|
|
|
|
// needed until dyld builds with a newer SDK
|
|
#ifndef CPU_SUBTYPE_ARM64E
|
|
#define CPU_SUBTYPE_ARM64E 2
|
|
#endif
|
|
#ifndef CPU_TYPE_ARM64_32
|
|
#define CPU_TYPE_ARM64_32 0x0200000C
|
|
#endif
|
|
#ifndef CPU_SUBTYPE_ARM64_32_V8
|
|
#define CPU_SUBTYPE_ARM64_32_V8 1
|
|
#endif
|
|
#ifndef BIND_OPCODE_THREADED
|
|
#define BIND_OPCODE_THREADED 0xD0
|
|
#endif
|
|
#ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
|
|
#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00
|
|
#endif
|
|
#ifndef BIND_SUBOPCODE_THREADED_APPLY
|
|
#define BIND_SUBOPCODE_THREADED_APPLY 0x01
|
|
#endif
|
|
#ifndef BIND_SPECIAL_DYLIB_WEAK_LOOKUP
|
|
#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP (-3)
|
|
#endif
|
|
#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
|
|
#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
|
|
#endif
|
|
#ifndef SG_READ_ONLY
|
|
#define SG_READ_ONLY 0x10
|
|
#endif
|
|
|
|
#ifndef LC_DYLD_EXPORTS_TRIE
|
|
#define LC_DYLD_EXPORTS_TRIE 0x80000033
|
|
#endif
|
|
#ifndef LC_DYLD_CHAINED_FIXUPS
|
|
#define LC_DYLD_CHAINED_FIXUPS 0x80000034
|
|
#endif
|
|
|
|
#ifndef S_INIT_FUNC_OFFSETS
|
|
#define S_INIT_FUNC_OFFSETS 0x16
|
|
#endif
|
|
|
|
#ifndef MH_FILESET
|
|
#define MH_FILESET 0xc /* set of mach-o's */
|
|
#endif
|
|
|
|
namespace dyld3 {
|
|
|
|
// replacements for posix that handle EINTR
|
|
int stat(const char* path, struct stat* buf) VIS_HIDDEN;
|
|
int open(const char* path, int flag, int other) VIS_HIDDEN;
|
|
|
|
|
|
/// Returns true if (addLHS + addRHS) > b, or if the add overflowed
|
|
template<typename T>
|
|
inline bool greaterThanAddOrOverflow(uint32_t addLHS, uint32_t addRHS, T b) {
|
|
return (addLHS > b) || (addRHS > (b-addLHS));
|
|
}
|
|
|
|
/// Returns true if (addLHS + addRHS) > b, or if the add overflowed
|
|
template<typename T>
|
|
inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) {
|
|
return (addLHS > b) || (addRHS > (b-addLHS));
|
|
}
|
|
|
|
|
|
// Note, this should match PLATFORM_* values in <mach-o/loader.h>
|
|
enum class Platform {
|
|
unknown = 0,
|
|
macOS = 1, // PLATFORM_MACOS
|
|
iOS = 2, // PLATFORM_IOS
|
|
tvOS = 3, // PLATFORM_TVOS
|
|
watchOS = 4, // PLATFORM_WATCHOS
|
|
bridgeOS = 5, // PLATFORM_BRIDGEOS
|
|
iOSMac = 6, // PLATFORM_MACCATALYST
|
|
iOS_simulator = 7, // PLATFORM_IOSSIMULATOR
|
|
tvOS_simulator = 8, // PLATFORM_TVOSSIMULATOR
|
|
watchOS_simulator = 9, // PLATFORM_WATCHOSSIMULATOR
|
|
driverKit = 10, // PLATFORM_DRIVERKIT
|
|
};
|
|
|
|
struct MachOFile; // forward ref
|
|
|
|
// A prioritized list of architectures
|
|
class VIS_HIDDEN GradedArchs {
|
|
public:
|
|
// never construct new ones - just use existing static instances
|
|
GradedArchs() = delete;
|
|
GradedArchs(const GradedArchs&) = delete;
|
|
|
|
static const GradedArchs& forCurrentOS(bool keysOff, bool platformBinariesOnly);
|
|
static const GradedArchs& forName(const char* archName, bool keysOff = false);
|
|
|
|
|
|
int grade(uint32_t cputype, uint32_t cpusubtype, bool platformBinariesOnly) const;
|
|
const char* name() const;
|
|
|
|
// pre-built lists for existing hardware
|
|
static const GradedArchs i386; // 32-bit Mac
|
|
static const GradedArchs x86_64; // older Mac
|
|
static const GradedArchs x86_64h; // haswell Mac
|
|
static const GradedArchs arm64; // A11 or earlier iPhone or iPad
|
|
#if SUPPORT_ARCH_arm64e
|
|
static const GradedArchs arm64e; // A12 or later iPhone or iPad
|
|
static const GradedArchs arm64e_keysoff; // A12 running with signing keys disabled
|
|
static const GradedArchs arm64e_pb; // macOS Apple Silicon running platform binary
|
|
static const GradedArchs arm64e_keysoff_pb; // macOS Apple Silicon running with signing keys disabled
|
|
#endif
|
|
static const GradedArchs armv7k; // watch thru series 3
|
|
static const GradedArchs armv7s; // deprecated
|
|
static const GradedArchs armv7; // deprecated
|
|
#if SUPPORT_ARCH_arm64_32
|
|
static const GradedArchs arm64_32; // watch series 4 and later
|
|
#endif
|
|
|
|
// private:
|
|
// should be private, but compiler won't statically initialize static members above
|
|
struct CpuGrade { uint32_t type; uint32_t subtype; bool osBinary; uint16_t grade; };
|
|
const CpuGrade _orderedCpuTypes[3]; // zero terminated
|
|
};
|
|
|
|
|
|
// A file read/mapped into memory
|
|
struct VIS_HIDDEN FatFile : fat_header
|
|
{
|
|
static const FatFile* isFatFile(const void* fileContent);
|
|
void forEachSlice(Diagnostics& diag, uint64_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop)) const;
|
|
bool isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, bool osBinary, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const;
|
|
|
|
private:
|
|
bool isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex,
|
|
uint32_t sliceCpuType, uint32_t sliceCpuSubType, uint64_t sliceOffset, uint64_t sliceLen) const;
|
|
};
|
|
|
|
|
|
// A mach-o file read/mapped into memory
|
|
// Only info from mach_header or load commands is accessible (no LINKEDIT info)
|
|
struct VIS_HIDDEN MachOFile : mach_header
|
|
{
|
|
static const char* archName(uint32_t cputype, uint32_t cpusubtype);
|
|
static const char* platformName(Platform platform);
|
|
static uint32_t cpuTypeFromArchName(const char* archName);
|
|
static uint32_t cpuSubtypeFromArchName(const char* archName);
|
|
static void packedVersionToString(uint32_t packedVersion, char versionString[32]);
|
|
static const char* currentArchName();
|
|
static Platform currentPlatform();
|
|
static uint64_t read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
|
|
static int64_t read_sleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
|
|
static bool isSimulatorPlatform(Platform platform);
|
|
static bool isSharedCacheEligiblePath(const char* path);
|
|
|
|
bool hasMachOMagic() const;
|
|
bool isMachO(Diagnostics& diag, uint64_t fileSize) const;
|
|
bool isDylib() const;
|
|
bool isBundle() const;
|
|
bool isMainExecutable() const;
|
|
bool isDynamicExecutable() const;
|
|
bool isStaticExecutable() const;
|
|
bool isKextBundle() const;
|
|
bool isFileSet() const;
|
|
bool isPreload() const;
|
|
bool isPIE() const;
|
|
bool isArch(const char* archName) const;
|
|
const char* archName() const;
|
|
bool is64() const;
|
|
uint32_t maskedCpuSubtype() const;
|
|
size_t machHeaderSize() const;
|
|
uint32_t pointerSize() const;
|
|
bool uses16KPages() const;
|
|
bool builtForPlatform(Platform, bool onlyOnePlatform=false) const;
|
|
bool loadableIntoProcess(Platform processPlatform, const char* path) const;
|
|
bool isZippered() const;
|
|
bool inDyldCache() const;
|
|
bool getUuid(uuid_t uuid) const;
|
|
bool hasWeakDefs() const;
|
|
bool hasThreadLocalVariables() const;
|
|
bool getDylibInstallName(const char** installName, uint32_t* compatVersion, uint32_t* currentVersion) const;
|
|
void forEachSupportedPlatform(void (^callback)(Platform platform, uint32_t minOS, uint32_t sdk)) const;
|
|
const char* installName() const; // returns nullptr is no install name
|
|
void forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const;
|
|
bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const;
|
|
#if BUILDING_APP_CACHE_UTIL
|
|
bool canBePlacedInKernelCollection(const char* path, void (^failureReason)(const char*)) const;
|
|
#endif
|
|
bool canHavePrecomputedDlopenClosure(const char* path, void (^failureReason)(const char*)) const;
|
|
bool canBeFairPlayEncrypted() const;
|
|
bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
|
|
bool allowsAlternatePlatform() const;
|
|
bool hasChainedFixups() const;
|
|
bool hasChainedFixupsLoadCommand() const;
|
|
void forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const;
|
|
bool enforceCompatVersion() const;
|
|
bool hasInterposingTuples() const;
|
|
|
|
const thread_command* unixThreadLoadCommand() const;
|
|
uint32_t entryAddrRegisterIndexForThreadCmd() const;
|
|
uint64_t entryAddrFromThreadCmd(const thread_command* cmd) const;
|
|
|
|
struct SegmentInfo
|
|
{
|
|
uint64_t fileOffset;
|
|
uint64_t fileSize;
|
|
uint64_t vmAddr;
|
|
uint64_t vmSize;
|
|
uint64_t sizeOfSections;
|
|
const char* segName;
|
|
uint32_t loadCommandOffset;
|
|
uint32_t protections;
|
|
uint32_t textRelocs : 1, // segment has text relocs (i386 only)
|
|
readOnlyData : 1,
|
|
isProtected : 1, // segment is protected
|
|
segIndex : 13,
|
|
p2align : 16;
|
|
bool readable() const { return protections & VM_PROT_READ; }
|
|
bool writable() const { return protections & VM_PROT_WRITE; }
|
|
bool executable() const { return protections & VM_PROT_EXECUTE; }
|
|
};
|
|
|
|
struct SectionInfo
|
|
{
|
|
SegmentInfo segInfo;
|
|
uint64_t sectAddr;
|
|
uint64_t sectSize;
|
|
const char* sectName;
|
|
uint32_t sectFileOffset;
|
|
uint32_t sectFlags;
|
|
uint32_t sectAlignP2;
|
|
uint32_t reserved1;
|
|
uint32_t reserved2;
|
|
};
|
|
|
|
void forEachSegment(void (^callback)(const SegmentInfo& info, bool& stop)) const;
|
|
void forEachSection(void (^callback)(const SectionInfo& sectInfo, bool malformedSectionRange, bool& stop)) const;
|
|
|
|
protected:
|
|
bool hasMachOBigEndianMagic() const;
|
|
void forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const;
|
|
void removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop));
|
|
bool hasLoadCommand(uint32_t) const;
|
|
|
|
const encryption_info_command* findFairPlayEncryptionLoadCommand() const;
|
|
|
|
struct ArchInfo
|
|
{
|
|
const char* name;
|
|
uint32_t cputype;
|
|
uint32_t cpusubtype;
|
|
};
|
|
static const ArchInfo _s_archInfos[];
|
|
|
|
struct PlatformInfo
|
|
{
|
|
const char* name;
|
|
Platform platform;
|
|
uint32_t loadCommand;
|
|
};
|
|
static const PlatformInfo _s_platformInfos[];
|
|
};
|
|
|
|
|
|
} // namespace dyld3
|
|
|
|
#endif /* MachOFile_h */
|