]> git.saurik.com Git - apple/dyld.git/blob - dyld3/MachOFile.h
dyld-851.27.tar.gz
[apple/dyld.git] / dyld3 / MachOFile.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef MachOFile_h
26 #define MachOFile_h
27
28 #include <mach-o/loader.h>
29 #include <mach-o/fat.h>
30 #include <uuid/uuid.h>
31
32 #include "Diagnostics.h"
33 #include "SupportedArchs.h"
34 #include <mach-o/fixup-chains.h>
35 #include <mach-o/loader.h>
36
37 // needed until dyld builds with a newer SDK
38 #ifndef CPU_SUBTYPE_ARM64E
39 #define CPU_SUBTYPE_ARM64E 2
40 #endif
41 #ifndef CPU_TYPE_ARM64_32
42 #define CPU_TYPE_ARM64_32 0x0200000C
43 #endif
44 #ifndef CPU_SUBTYPE_ARM64_32_V8
45 #define CPU_SUBTYPE_ARM64_32_V8 1
46 #endif
47 #ifndef BIND_OPCODE_THREADED
48 #define BIND_OPCODE_THREADED 0xD0
49 #endif
50 #ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
51 #define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00
52 #endif
53 #ifndef BIND_SUBOPCODE_THREADED_APPLY
54 #define BIND_SUBOPCODE_THREADED_APPLY 0x01
55 #endif
56 #ifndef BIND_SPECIAL_DYLIB_WEAK_LOOKUP
57 #define BIND_SPECIAL_DYLIB_WEAK_LOOKUP (-3)
58 #endif
59 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
60 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
61 #endif
62 #ifndef SG_READ_ONLY
63 #define SG_READ_ONLY 0x10
64 #endif
65
66 #ifndef LC_DYLD_EXPORTS_TRIE
67 #define LC_DYLD_EXPORTS_TRIE 0x80000033
68 #endif
69 #ifndef LC_DYLD_CHAINED_FIXUPS
70 #define LC_DYLD_CHAINED_FIXUPS 0x80000034
71 #endif
72
73 #ifndef S_INIT_FUNC_OFFSETS
74 #define S_INIT_FUNC_OFFSETS 0x16
75 #endif
76
77 #ifndef MH_FILESET
78 #define MH_FILESET 0xc /* set of mach-o's */
79 #endif
80
81 namespace dyld3 {
82
83 // replacements for posix that handle EINTR
84 int stat(const char* path, struct stat* buf) VIS_HIDDEN;
85 int open(const char* path, int flag, int other) VIS_HIDDEN;
86
87
88 /// Returns true if (addLHS + addRHS) > b, or if the add overflowed
89 template<typename T>
90 inline bool greaterThanAddOrOverflow(uint32_t addLHS, uint32_t addRHS, T b) {
91 return (addLHS > b) || (addRHS > (b-addLHS));
92 }
93
94 /// Returns true if (addLHS + addRHS) > b, or if the add overflowed
95 template<typename T>
96 inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) {
97 return (addLHS > b) || (addRHS > (b-addLHS));
98 }
99
100
101 // Note, this should match PLATFORM_* values in <mach-o/loader.h>
102 enum class Platform {
103 unknown = 0,
104 macOS = 1, // PLATFORM_MACOS
105 iOS = 2, // PLATFORM_IOS
106 tvOS = 3, // PLATFORM_TVOS
107 watchOS = 4, // PLATFORM_WATCHOS
108 bridgeOS = 5, // PLATFORM_BRIDGEOS
109 iOSMac = 6, // PLATFORM_MACCATALYST
110 iOS_simulator = 7, // PLATFORM_IOSSIMULATOR
111 tvOS_simulator = 8, // PLATFORM_TVOSSIMULATOR
112 watchOS_simulator = 9, // PLATFORM_WATCHOSSIMULATOR
113 driverKit = 10, // PLATFORM_DRIVERKIT
114 };
115
116 struct MachOFile; // forward ref
117
118 // A prioritized list of architectures
119 class VIS_HIDDEN GradedArchs {
120 public:
121 // never construct new ones - just use existing static instances
122 GradedArchs() = delete;
123 GradedArchs(const GradedArchs&) = delete;
124
125 static const GradedArchs& forCurrentOS(bool keysOff, bool platformBinariesOnly);
126 static const GradedArchs& forName(const char* archName, bool keysOff = false);
127
128
129 int grade(uint32_t cputype, uint32_t cpusubtype, bool platformBinariesOnly) const;
130 const char* name() const;
131
132 // pre-built lists for existing hardware
133 static const GradedArchs i386; // 32-bit Mac
134 static const GradedArchs x86_64; // older Mac
135 static const GradedArchs x86_64h; // haswell Mac
136 static const GradedArchs arm64; // A11 or earlier iPhone or iPad
137 #if SUPPORT_ARCH_arm64e
138 static const GradedArchs arm64e; // A12 or later iPhone or iPad
139 static const GradedArchs arm64e_keysoff; // A12 running with signing keys disabled
140 static const GradedArchs arm64e_pb; // macOS Apple Silicon running platform binary
141 static const GradedArchs arm64e_keysoff_pb; // macOS Apple Silicon running with signing keys disabled
142 #endif
143 static const GradedArchs armv7k; // watch thru series 3
144 static const GradedArchs armv7s; // deprecated
145 static const GradedArchs armv7; // deprecated
146 #if SUPPORT_ARCH_arm64_32
147 static const GradedArchs arm64_32; // watch series 4 and later
148 #endif
149
150 // private:
151 // should be private, but compiler won't statically initialize static members above
152 struct CpuGrade { uint32_t type; uint32_t subtype; bool osBinary; uint16_t grade; };
153 const CpuGrade _orderedCpuTypes[3]; // zero terminated
154 };
155
156
157 // A file read/mapped into memory
158 struct VIS_HIDDEN FatFile : fat_header
159 {
160 static const FatFile* isFatFile(const void* fileContent);
161 void forEachSlice(Diagnostics& diag, uint64_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop)) const;
162 bool isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, bool osBinary, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const;
163
164 private:
165 bool isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex,
166 uint32_t sliceCpuType, uint32_t sliceCpuSubType, uint64_t sliceOffset, uint64_t sliceLen) const;
167 };
168
169
170 // A mach-o file read/mapped into memory
171 // Only info from mach_header or load commands is accessible (no LINKEDIT info)
172 struct VIS_HIDDEN MachOFile : mach_header
173 {
174 static const char* archName(uint32_t cputype, uint32_t cpusubtype);
175 static const char* platformName(Platform platform);
176 static uint32_t cpuTypeFromArchName(const char* archName);
177 static uint32_t cpuSubtypeFromArchName(const char* archName);
178 static void packedVersionToString(uint32_t packedVersion, char versionString[32]);
179 static const char* currentArchName();
180 static Platform currentPlatform();
181 static uint64_t read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
182 static int64_t read_sleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
183 static bool isSimulatorPlatform(Platform platform);
184 static bool isSharedCacheEligiblePath(const char* path);
185
186 bool hasMachOMagic() const;
187 bool isMachO(Diagnostics& diag, uint64_t fileSize) const;
188 bool isDylib() const;
189 bool isBundle() const;
190 bool isMainExecutable() const;
191 bool isDynamicExecutable() const;
192 bool isStaticExecutable() const;
193 bool isKextBundle() const;
194 bool isFileSet() const;
195 bool isPreload() const;
196 bool isPIE() const;
197 bool isArch(const char* archName) const;
198 const char* archName() const;
199 bool is64() const;
200 uint32_t maskedCpuSubtype() const;
201 size_t machHeaderSize() const;
202 uint32_t pointerSize() const;
203 bool uses16KPages() const;
204 bool builtForPlatform(Platform, bool onlyOnePlatform=false) const;
205 bool loadableIntoProcess(Platform processPlatform, const char* path) const;
206 bool isZippered() const;
207 bool inDyldCache() const;
208 bool getUuid(uuid_t uuid) const;
209 bool hasWeakDefs() const;
210 bool hasThreadLocalVariables() const;
211 bool getDylibInstallName(const char** installName, uint32_t* compatVersion, uint32_t* currentVersion) const;
212 void forEachSupportedPlatform(void (^callback)(Platform platform, uint32_t minOS, uint32_t sdk)) const;
213 const char* installName() const; // returns nullptr is no install name
214 void forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const;
215 bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const;
216 #if BUILDING_APP_CACHE_UTIL
217 bool canBePlacedInKernelCollection(const char* path, void (^failureReason)(const char*)) const;
218 #endif
219 bool canHavePrecomputedDlopenClosure(const char* path, void (^failureReason)(const char*)) const;
220 bool canBeFairPlayEncrypted() const;
221 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
222 bool allowsAlternatePlatform() const;
223 bool hasChainedFixups() const;
224 bool hasChainedFixupsLoadCommand() const;
225 void forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const;
226 bool enforceCompatVersion() const;
227 bool hasInterposingTuples() const;
228
229 const thread_command* unixThreadLoadCommand() const;
230 uint32_t entryAddrRegisterIndexForThreadCmd() const;
231 uint64_t entryAddrFromThreadCmd(const thread_command* cmd) const;
232
233 struct SegmentInfo
234 {
235 uint64_t fileOffset;
236 uint64_t fileSize;
237 uint64_t vmAddr;
238 uint64_t vmSize;
239 uint64_t sizeOfSections;
240 const char* segName;
241 uint32_t loadCommandOffset;
242 uint32_t protections;
243 uint32_t textRelocs : 1, // segment has text relocs (i386 only)
244 readOnlyData : 1,
245 isProtected : 1, // segment is protected
246 segIndex : 13,
247 p2align : 16;
248 bool readable() const { return protections & VM_PROT_READ; }
249 bool writable() const { return protections & VM_PROT_WRITE; }
250 bool executable() const { return protections & VM_PROT_EXECUTE; }
251 };
252
253 struct SectionInfo
254 {
255 SegmentInfo segInfo;
256 uint64_t sectAddr;
257 uint64_t sectSize;
258 const char* sectName;
259 uint32_t sectFileOffset;
260 uint32_t sectFlags;
261 uint32_t sectAlignP2;
262 uint32_t reserved1;
263 uint32_t reserved2;
264 };
265
266 void forEachSegment(void (^callback)(const SegmentInfo& info, bool& stop)) const;
267 void forEachSection(void (^callback)(const SectionInfo& sectInfo, bool malformedSectionRange, bool& stop)) const;
268
269 protected:
270 bool hasMachOBigEndianMagic() const;
271 void forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const;
272 void removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop));
273 bool hasLoadCommand(uint32_t) const;
274
275 const encryption_info_command* findFairPlayEncryptionLoadCommand() const;
276
277 struct ArchInfo
278 {
279 const char* name;
280 uint32_t cputype;
281 uint32_t cpusubtype;
282 };
283 static const ArchInfo _s_archInfos[];
284
285 struct PlatformInfo
286 {
287 const char* name;
288 Platform platform;
289 uint32_t loadCommand;
290 };
291 static const PlatformInfo _s_platformInfos[];
292 };
293
294
295 } // namespace dyld3
296
297 #endif /* MachOFile_h */