]> git.saurik.com Git - apple/dyld.git/blob - interlinked-dylibs/mega-dylib-utils.h
16fc4ab2ff5d9a97948bb3435fa4101b536dd406
[apple/dyld.git] / interlinked-dylibs / mega-dylib-utils.h
1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 *
3 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef __MEGA_DYLIB_UTILS_H__
26 #define __MEGA_DYLIB_UTILS_H__
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <limits.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36
37 #include <dispatch/dispatch.h>
38
39 #include <memory>
40 #include <map>
41 #include <set>
42 #include <array>
43 #include <vector>
44 #include <string>
45 #include <algorithm>
46 #include <unordered_set>
47 #include <unordered_map>
48
49 #ifndef UUID
50 #include <uuid/uuid.h>
51
52 struct UUID {
53 UUID() {}
54 UUID(const UUID& other) { uuid_copy(&_bytes[0], &other._bytes[0]); }
55 UUID(const uuid_t other_uuid) { uuid_copy(&_bytes[0], other_uuid); }
56 bool operator<(const UUID& other) const { return uuid_compare(&_bytes[0], &other._bytes[0]) < 0; }
57 bool operator==(const UUID& other) const { return uuid_compare(&_bytes[0], &other._bytes[0]) == 0; }
58 bool operator!=(const UUID& other) const { return !(*this == other); }
59
60 size_t hash() const {
61 size_t retval = 0;
62 for (auto i = 0; i < 16/sizeof(size_t); ++i) {
63 retval ^= ((size_t *)(&_bytes[0]))[i];
64 }
65 return retval;
66 }
67 const unsigned char* get() const { return &_bytes[0]; };
68 private:
69 std::array<unsigned char, 16> _bytes;
70 };
71
72 struct ImageIdentifier {
73 ImageIdentifier() {}
74 ImageIdentifier(const UUID &U) : _uuid(U) {}
75 size_t hash() const { return _uuid.hash(); }
76 bool operator<(const ImageIdentifier& other) const { return _uuid < other._uuid; }
77 bool operator==(const ImageIdentifier& other) const { return _uuid == other._uuid; }
78 bool operator!=(const ImageIdentifier& other) const { return !(*this == other); }
79
80 private:
81 UUID _uuid;
82 };
83
84 namespace std {
85 template <>
86 struct hash<UUID> {
87 size_t operator()(const UUID& x) const
88 {
89 return x.hash();
90 }
91 };
92
93 template <>
94 struct hash<ImageIdentifier> {
95 size_t operator()(const ImageIdentifier& x) const
96 {
97 return x.hash();
98 }
99 };
100 }
101
102 #endif
103
104 #include "CacheFileAbstraction.hpp"
105
106 #include "MachOFileAbstraction.hpp"
107
108 #include "Manifest.h"
109
110 struct MachOProxy;
111 struct MachOProxySegment;
112 struct SharedCache;
113
114 struct FileCache {
115 FileCache(void);
116 std::tuple<uint8_t *, struct stat, bool> cacheLoad(const std::string path);
117 void preflightCache(const std::string& path);
118 void preflightCache(const std::unordered_set<std::string> &paths);
119 private:
120 std::tuple<uint8_t *, struct stat, bool> fill(const std::string& path);
121
122 std::unordered_map<std::string, std::tuple<uint8_t *, struct stat, bool>> entries;
123 dispatch_queue_t cache_queue;
124 };
125
126 extern FileCache fileCache;
127
128 typedef std::pair<Manifest*,std::set<std::pair<std::string, std::string>>> WarningTargets;
129
130 inline uint64_t align(uint64_t addr, uint8_t p2)
131 {
132 uint64_t mask = (1 << p2);
133 return (addr + mask - 1) & (-mask);
134 }
135
136
137 uint64_t sharedRegionRegionSize(ArchPair arch);
138 uint8_t sharedRegionRegionAlignment(ArchPair arch);
139 ArchPair archForString(const std::string& archStr);
140 std::string stringForArch(ArchPair arch, bool allowUnknown = false);
141 std::string fallbackArchStringForArchString( const std::string& archStr );
142
143 struct SharedCache {
144 struct SegmentInfo {
145 SegmentInfo(const MachOProxySegment* seg)
146 : base(seg)
147 , address(0)
148 , cacheFileOffset(0)
149 , cacheSegSize(0)
150 {
151 }
152
153 const MachOProxySegment* base;
154 uint64_t address;
155 uint64_t cacheFileOffset;
156 uint64_t cacheSegSize;
157 };
158
159 struct Region {
160 uint64_t address;
161 uint64_t size;
162 uint64_t fileOffset;
163 uint32_t prot;
164 };
165
166 SharedCache(Manifest& manifest,
167 const std::string& configuration, const std::string& architecture);
168
169 // We do not need an explicit destructor despite our move/copy constructor because the resource the are dealing with is a
170 // std::unique<void> which has a registered destructor
171
172 //FIXME reminants of merging the two classes, unifyu these
173 uint64_t vmSize() const { return _vmSize; }
174 uint64_t fileSize() const { return _fileSize; }
175 const uint8_t* cdHash() { return _cdHash; }
176 std::string cdHashString();
177
178 //FIXME: This should be private, but we can't do that until we move write out into the class after the next refactor
179 std::shared_ptr<void> buffer() const;
180
181 void buildForDevelopment(const std::string& cachePath);
182 void buildForProduction(const std::string& cachePath);
183 bool writeCacheMapFile(const std::string& mapPath);
184
185 typedef std::function<void(const void* machHeader, const char* installName, time_t lastModTime, ino_t inode,
186 const std::vector<MachOProxySegment>& segments)>
187 DylibHandler;
188 // Calls lambda once per image in the cache
189 void forEachImage(DylibHandler handler);
190
191 typedef std::function<void(void* content, uint64_t vmAddr, uint64_t size, uint32_t permissions)> RegionHandler;
192 // Calls lambda once per region in the cache
193 void forEachRegion(RegionHandler handler);
194
195 void setLinkeditsMappingEndFileOffset(uint64_t newFileSize);
196 void setAcceleratorInfoRange(uint64_t accelInfoAddr, uint32_t accelInfoSize);
197 void setUnmappedLocalsRange(uint64_t localSymbolsOffset, uint32_t unmappedSize);
198 void recomputeCacheUUID(void);
199
200 private:
201 void loadDirtyDataOrderFile(const std::string& dirtyDataOrderFile);
202 void sortDylibs(const std::string& dylibOrderFile);
203 void assignSegmentAddresses();
204 void bypassStubs(const std::vector<uint64_t>& branchPoolStartAddrs);
205 void optimizeLinkedit(bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets);
206
207 // Once all a dylib's segments are copied into a cache, this function will adjust the contents of
208 // the TEXT, DATA, and LINKEDIT segments in the cache to be correct for their new addresses.
209 void bindAllImagesInCache(const std::vector<MachOProxy*> dylibs, const std::map<const MachOProxy*, std::vector<SegmentInfo>>& segmentMap, std::vector<void*>& pointersForASLR);
210
211 // After adjustImageForNewSegmentLocations() is called to rebase all segments, this function can be called to
212 // bind all symbols to their new addresses
213 void adjustImageForNewSegmentLocations(const std::vector<uint64_t>& segNewStartAddresses,
214 const std::vector<uint64_t>& segCacheFileOffsets,
215 const std::vector<uint64_t>& segCacheSizes, std::vector<void*>& pointersForASLR);
216
217 uint64_t pathHash(const char* path);
218 void writeCacheHeader(void);
219 void writeCacheSegments(void);
220 void rebaseAll(void);
221 void rebase(MachOProxy* dylib);
222 void bindAll(void);
223 void optimizeObjC(bool forProduction);
224 void writeSlideInfoV2(void);
225
226 void buildUnoptimizedCache(void);
227 void appendCodeSignature(const std::string& suffix);
228 template <typename P> void buildForDevelopment(const std::string& cachePath);
229 template <typename P> void buildForProduction(const std::string& cachePath);
230 template <typename P> void forEachImage(DylibHandler handler);
231 template <typename P> void forEachRegion(RegionHandler handler);
232 template <typename P> void setLinkeditsMappingEndFileOffset(uint64_t newFileSize);
233 template <typename P> void setAcceleratorInfoRange(uint64_t accelInfoAddr, uint32_t accelInfoSize);
234 template <typename P> void setUnmappedLocalsRange(uint64_t localSymbolsOffset, uint32_t unmappedSize);
235 template <typename P> void recomputeCacheUUID(void);
236 template <typename P> void bypassStubs(const std::vector<uint64_t>& branchPoolStartAddrs);
237 template <typename P> void optimizeLinkedit(bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets);
238 template <typename P> void writeCacheHeader(void);
239 template <typename E> void writeSlideInfo(void);
240 template <typename P> void writeSlideInfoV2(uint64_t deltaMask, uint64_t valueAdd);
241
242 template <typename P> void findImplicitAliases(std::shared_ptr<MachOProxy> dylib);
243 template <typename P> void addPageStarts(uint8_t* pageContent, const bool bitmap[], const dyldCacheSlideInfo2<typename P::E>* info,
244 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
245 template <typename P> bool makeRebaseChain(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const dyldCacheSlideInfo2<typename P::E>* info);
246 void findDylibAndSegment(const void* contentPtr, std::string& dylibName, std::string& segName);
247
248 ArchPair _arch;
249 std::vector<MachOProxy *> _dylibs;
250 std::shared_ptr<void> _buffer;
251 std::map<const MachOProxy*, std::vector<SegmentInfo>> _segmentMap;
252
253 std::string archName();
254
255 Manifest& _manifest;
256 const Manifest::Architecture& _archManifest;
257 uint32_t _aliasCount;
258 Region _textRegion;
259 Region _dataRegion;
260 Region _readOnlyRegion;
261 uint64_t _slideInfoFileOffset;
262 uint64_t _slideInfoBufferSize;
263 uint64_t _fileSize;
264 uint64_t _vmSize;
265 std::unordered_map<std::string, uint32_t> _dataDirtySegsOrder;
266 std::vector<void*> _pointersForASLR;
267 std::vector<uint64_t> _branchPoolStarts;
268 uint64_t _branchPoolsLinkEditStartAddr;
269 uint8_t _cdHash[20];
270 };
271
272 std::string normalize_absolute_file_path(const std::string &path);
273 std::string baspath(const std::string& path);
274 std::string dirpath(const std::string& path);
275
276 std::string toolDir();
277 bool isProtectedBySIP(const std::string& path, int fd=-1);
278
279 template <class Set1, class Set2>
280 inline bool is_disjoint(const Set1& set1, const Set2& set2)
281 {
282 if (set1.empty() || set2.empty())
283 return true;
284
285 typename Set1::const_iterator it1 = set1.begin(), it1End = set1.end();
286 typename Set2::const_iterator it2 = set2.begin(), it2End = set2.end();
287
288 if (*it1 > *set2.rbegin() || *it2 > *set1.rbegin())
289 return true;
290
291 while (it1 != it1End && it2 != it2End) {
292 if (*it1 == *it2)
293 return false;
294 if (*it1 < *it2) {
295 it1++;
296 } else {
297 it2++;
298 }
299 }
300
301 return true;
302 }
303
304 inline bool has_prefix(const std::string& str, const std::string& prefix)
305 {
306 return std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end();
307 }
308
309 #define NEW_CACHE_FILE_FORMAT 0
310
311 #endif // __MEGA_DYLIB_UTILS_H__
312
313
314
315
316