]> git.saurik.com Git - apple/dyld.git/blob - dyld3/MachOParser.h
dyld-519.2.2.tar.gz
[apple/dyld.git] / dyld3 / MachOParser.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 MachOParser_h
26 #define MachOParser_h
27
28 #include <stdint.h>
29 #include <uuid/uuid.h>
30 #include <mach-o/loader.h>
31
32 #include <array>
33 #include <string>
34 #include <vector>
35
36 #include "Diagnostics.h"
37
38
39 #define BIND_TYPE_IMPORT_JMP_REL32 4
40
41 namespace dyld3 {
42
43 // Note, this should make PLATFORM_* values in <mach-o/loader.h>
44 enum class Platform {
45 unknown = 0,
46 macOS = 1,
47 iOS = 2,
48 tvOS = 3,
49 watchOS = 4,
50 bridgeOS = 5
51 };
52
53 struct VIS_HIDDEN UUID {
54 UUID() {}
55 UUID(const UUID& other) { uuid_copy(&_bytes[0], &other._bytes[0]); }
56 UUID(const uuid_t other_uuid) { uuid_copy(&_bytes[0], other_uuid); }
57 bool operator<(const UUID& other) const { return uuid_compare(&_bytes[0], &other._bytes[0]) < 0; }
58 bool operator==(const UUID& other) const { return uuid_compare(&_bytes[0], &other._bytes[0]) == 0; }
59 bool operator!=(const UUID& other) const { return !(*this == other); }
60
61 size_t hash() const
62 {
63 size_t retval = 0;
64 for (auto i = 0; i < 16 / sizeof(size_t); ++i) {
65 retval ^= ((size_t*)(&_bytes[0]))[i];
66 }
67 return retval;
68 }
69 const unsigned char* get() const { return &_bytes[0]; };
70 private:
71 std::array<unsigned char, 16> _bytes;
72 };
73
74 class VIS_HIDDEN MachOParser
75 {
76 public:
77 #if !DYLD_IN_PROCESS
78 static bool isValidMachO(Diagnostics& diag, const std::string& archName, Platform platform, const void* fileContent, size_t fileLength, const std::string& pathOpened, bool ignoreMainExecutables);
79 static bool isArch(const mach_header* mh, const std::string& archName);
80 static std::string archName(uint32_t cputype, uint32_t cpusubtype);
81 static std::string platformName(Platform platform);
82 static std::string versionString(uint32_t packedVersion);
83 static uint32_t cpuTypeFromArchName(const std::string& archName);
84 static uint32_t cpuSubtypeFromArchName(const std::string& archName);
85 #else
86 static bool isMachO(Diagnostics& diag, const void* fileContent, size_t fileLength);
87 static bool wellFormedMachHeaderAndLoadCommands(const mach_header* mh);
88 #endif
89 MachOParser(const mach_header* mh, bool dyldCacheIsRaw=false);
90 bool valid(Diagnostics& diag);
91
92 const mach_header* header() const;
93 uint32_t fileType() const;
94 std::string archName() const;
95 bool is64() const;
96 bool inDyldCache() const;
97 bool hasThreadLocalVariables() const;
98 Platform platform() const;
99 uint64_t preferredLoadAddress() const;
100 UUID uuid() const;
101 bool getUuid(uuid_t uuid) const;
102 bool getPlatformAndVersion(Platform* platform, uint32_t* minOS, uint32_t* sdk) const;
103 bool isSimulatorBinary() const;
104 bool getDylibInstallName(const char** installName, uint32_t* compatVersion, uint32_t* currentVersion) const;
105 const char* installName() const;
106 uint32_t dependentDylibCount() const;
107 const char* dependentDylibLoadPath(uint32_t depIndex) const;
108 void forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const;
109 void forEachSection(void (^callback)(const char* segName, const char* sectionName, uint32_t flags, const void* content, size_t size, bool illegalSectionSize, bool& stop)) const;
110 void forEachSegment(void (^callback)(const char* segName, uint32_t fileOffset, uint32_t fileSize, uint64_t vmAddr, uint64_t vmSize, uint8_t protections, bool& stop)) const;
111 void forEachGlobalSymbol(Diagnostics& diag, void (^callback)(const char* symbolName, uint64_t n_value, uint8_t n_type, uint8_t n_sect, uint16_t n_desc, bool& stop)) const;
112 void forEachLocalSymbol(Diagnostics& diag, void (^callback)(const char* symbolName, uint64_t n_value, uint8_t n_type, uint8_t n_sect, uint16_t n_desc, bool& stop)) const;
113 void forEachRPath(void (^callback)(const char* rPath, bool& stop)) const;
114 void forEachSection(void (^callback)(const char* segName, const char* sectionName, uint32_t flags, uint64_t addr, const void* content,
115 uint64_t size, uint32_t alignP2, uint32_t reserved1, uint32_t reserved2, bool illegalSectionSize, bool& stop)) const;
116
117 struct FoundSymbol {
118 enum class Kind { headerOffset, absolute, resolverOffset };
119 Kind kind;
120 bool isThreadLocal;
121 const mach_header* foundInDylib;
122 void* foundExtra;
123 uint64_t value;
124 uint32_t resolverFuncOffset;
125 const char* foundSymbolName;
126 };
127
128 typedef bool (^DependentFinder)(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra);
129
130 bool findExportedSymbol(Diagnostics& diag, const char* symbolName, void* extra, FoundSymbol& foundInfo, DependentFinder finder) const;
131 bool findClosestSymbol(uint64_t unSlidAddr, const char** symbolName, uint64_t* symbolUnslidAddr) const;
132 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size);
133
134 #if DYLD_IN_PROCESS
135 intptr_t getSlide() const;
136 bool hasExportedSymbol(const char* symbolName, DependentFinder finder, void** result) const;
137 bool findClosestSymbol(const void* addr, const char** symbolName, const void** symbolAddress) const;
138 const char* segmentName(uint32_t segIndex) const;
139 #else
140
141 bool uses16KPages() const;
142 bool hasObjC() const;
143 bool hasWeakDefs() const;
144 bool isEncrypted() const;
145 bool hasPlusLoadMethod(Diagnostics& diag) const;
146 bool hasInitializer(Diagnostics& diag) const;
147 bool getCDHash(uint8_t cdHash[20]);
148 bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size);
149 bool usesLibraryValidation() const;
150 bool isRestricted() const;
151 bool getEntry(uint32_t& offset, bool& usesCRT);
152 bool canBePlacedInDyldCache(const std::string& path) const;
153 bool canBePlacedInDyldCache(const std::string& path, std::set<std::string>& reasons) const;
154 bool isDynamicExecutable() const;
155 bool isSlideable() const;
156 void forEachInitializer(Diagnostics& diag, void (^callback)(uint32_t offset)) const;
157 void forEachDOFSection(Diagnostics& diag, void (^callback)(uint32_t offset)) const;
158 uint32_t segmentCount() const;
159 void forEachExportedSymbol(Diagnostics diag, void (^callback)(const char* symbolName, uint64_t imageOffset, bool isReExport, bool& stop)) const;
160 void forEachSegment(void (^callback)(const char* segName, uint32_t fileOffset, uint32_t fileSize, uint64_t vmAddr, uint64_t vmSize, uint8_t protections, uint32_t segIndex, uint64_t sizeOfSections, uint8_t p2align, bool& stop)) const;
161 void forEachRebase(Diagnostics& diag, void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, bool& stop)) const;
162 void forEachBind(Diagnostics& diag, void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, int libOrdinal,
163 uint64_t addend, const char* symbolName, bool weakImport, bool lazy, bool& stop)) const;
164 void forEachWeakDef(Diagnostics& diag, void (^callback)(bool strongDef, uint32_t dataSegIndex, uint64_t dataSegOffset,
165 uint64_t addend, const char* symbolName, bool& stop)) const;
166 void forEachIndirectPointer(Diagnostics& diag, void (^handler)(uint32_t dataSegIndex, uint64_t dataSegOffset, bool bind, int bindLibOrdinal,
167 const char* bindSymbolName, bool bindWeakImport, bool bindLazy, bool selfModifyingStub, bool& stop)) const;
168 void forEachInterposingTuple(Diagnostics& diag, void (^handler)(uint32_t segIndex, uint64_t replacementSegOffset, uint64_t replaceeSegOffset, uint64_t replacementContent, bool& stop)) const;
169 const void* content(uint64_t vmOffset);
170 #endif
171
172 static const uint8_t* trieWalk(Diagnostics& diag, const uint8_t* start, const uint8_t* end, const char* symbol);
173 static uint64_t read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
174 static int64_t read_sleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
175 static bool cdHashOfCodeSignature(const void* codeSigStart, size_t codeSignLen, uint8_t cdHash[20]);
176 static Platform currentPlatform();
177
178 private:
179 struct LayoutInfo {
180 #if DYLD_IN_PROCESS
181 uintptr_t slide;
182 uintptr_t textUnslidVMAddr;
183 uintptr_t linkeditUnslidVMAddr;
184 uint32_t linkeditFileOffset;
185 #else
186 uint32_t segmentCount;
187 uint32_t linkeditSegIndex;
188 struct {
189 uint64_t mappingOffset;
190 uint64_t fileOffset;
191 uint64_t fileSize;
192 uint64_t segUnslidAddress;
193 uint64_t writable : 1,
194 executable : 1,
195 textRelocsAllowed : 1, // segment supports text relocs (i386 only)
196 segSize : 61;
197 } segments[128];
198 #endif
199 };
200
201 struct LinkEditInfo
202 {
203 const dyld_info_command* dyldInfo;
204 const symtab_command* symTab;
205 const dysymtab_command* dynSymTab;
206 const linkedit_data_command* splitSegInfo;
207 const linkedit_data_command* functionStarts;
208 const linkedit_data_command* dataInCode;
209 const linkedit_data_command* codeSig;
210 LayoutInfo layout;
211 };
212
213 void getLinkEditPointers(Diagnostics& diag, LinkEditInfo&) const;
214 void getLinkEditLoadCommands(Diagnostics& diag, LinkEditInfo& result) const;
215 void getLayoutInfo(LayoutInfo&) const;
216 const uint8_t* getLinkEditContent(const LayoutInfo& info, uint32_t fileOffset) const;
217
218 #if !DYLD_IN_PROCESS
219 struct ArchInfo
220 {
221 const char* name;
222 uint32_t cputype;
223 uint32_t cpusubtype;
224 };
225 static const ArchInfo _s_archInfos[];
226
227 const uint8_t* getContentForVMAddr(const LayoutInfo& info, uint64_t vmAddr) const;
228 bool doLocalReloc(Diagnostics& diag, uint32_t r_address, bool& stop, void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, bool& stop)) const;
229 uint8_t relocPointerType() const;
230 int libOrdinalFromDesc(uint16_t n_desc) const;
231 bool doExternalReloc(Diagnostics& diag, uint32_t r_address, uint32_t r_symbolnum, LinkEditInfo& leInfo, bool& stop,
232 void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, int libOrdinal,
233 uint64_t addend, const char* symbolName, bool weakImport, bool lazy, bool& stop)) const;
234 bool validLoadCommands(Diagnostics& diag, size_t fileLen);
235 bool validEmbeddedPaths(Diagnostics& diag);
236 bool validSegments(Diagnostics& diag, size_t fileLen);
237 bool validLinkeditLayout(Diagnostics& diag);
238 bool invalidBindState(Diagnostics& diag, const char* opcodeName, const MachOParser::LinkEditInfo& leInfo, bool segIndexSet, bool libraryOrdinalSet,
239 uint32_t dylibCount, int libOrdinal, uint32_t pointerSize, uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, const char* symbolName) const;
240 bool invalidRebaseState(Diagnostics& diag, const char* opcodeName, const MachOParser::LinkEditInfo& leInfo, bool segIndexSet,
241 uint32_t pointerSize, uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type) const;
242 #endif
243 static const void* findCodeDirectoryBlob(const void* codeSigStart, size_t codeSignLen);
244 void forEachSection(void (^callback)(const char* segName, uint32_t segIndex, uint64_t segVMAddr, const char* sectionName, uint32_t sectFlags,
245 uint64_t sectAddr, uint64_t size, uint32_t alignP2, uint32_t reserved1, uint32_t reserved2, bool illegalSectionSize, bool& stop)) const;
246
247 void forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const;
248 bool isRaw() const;
249 bool inRawCache() const;
250
251 long _data; // if low bit true, then this is raw file (not loaded image)
252 };
253
254
255
256 class VIS_HIDDEN FatUtil
257 {
258 public:
259 static bool isFatFile(const void* fileStart);
260 static void forEachSlice(Diagnostics& diag, const void* fileContent, size_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, size_t sliceSize, bool& stop));
261 #if !DYLD_IN_PROCESS
262 static bool isFatFileWithSlice(Diagnostics& diag, const void* fileContent, size_t fileLen, const std::string& archName, size_t& sliceOffset, size_t& sliceLen, bool& missingSlice);
263 #endif
264 };
265
266
267 } // namespace dyld3
268
269 namespace std {
270 template <>
271 struct hash<dyld3::UUID> {
272 size_t operator()(const dyld3::UUID& x) const
273 {
274 return x.hash();
275 }
276 };
277 }
278
279 #endif // MachOParser_h