]> git.saurik.com Git - apple/dyld.git/blob - interlinked-dylibs/mega-dylib-utils.h
dyld-421.2.tar.gz
[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 <vector>
43 #include <string>
44 #include <algorithm>
45 #include <unordered_set>
46 #include <unordered_map>
47
48 #include "CacheFileAbstraction.hpp"
49
50 #include "MachOFileAbstraction.hpp"
51
52 #include "Manifest.h"
53 #include "MachOProxy.h"
54
55 struct SharedCache;
56
57 struct FileCache {
58 FileCache(void);
59 std::tuple<uint8_t *, struct stat, bool> cacheLoad(const std::string path);
60 void preflightCache(const std::string& path);
61 void preflightCache(const std::unordered_set<std::string> &paths);
62 private:
63 void fill(const std::string& path);
64
65 std::unordered_map<std::string, std::tuple<uint8_t *, struct stat, bool>> entries;
66 dispatch_queue_t cache_queue;
67 };
68
69 extern FileCache fileCache;
70
71 typedef std::pair<Manifest*,std::set<std::pair<std::string, std::string>>> WarningTargets;
72
73 inline uint64_t align(uint64_t addr, uint8_t p2)
74 {
75 uint64_t mask = (1 << p2);
76 return (addr + mask - 1) & (-mask);
77 }
78
79
80 uint64_t sharedRegionRegionSize(ArchPair arch);
81 uint8_t sharedRegionRegionAlignment(ArchPair arch);
82 ArchPair archForString(const std::string& archStr);
83 std::string stringForArch(ArchPair arch, bool allowUnknown = false);
84 std::string fallbackArchStringForArchString( const std::string& archStr );
85
86 struct SharedCache {
87 struct SegmentInfo {
88 SegmentInfo(const MachOProxy::Segment* seg)
89 : base(seg), address(0), cacheFileOffset(0), cacheSegSize(0) { }
90
91 const MachOProxy::Segment* base;
92 uint64_t address;
93 uint64_t cacheFileOffset;
94 uint64_t cacheSegSize;
95 };
96
97 struct Region {
98 uint64_t address;
99 uint64_t size;
100 uint64_t fileOffset;
101 uint32_t prot;
102 };
103
104 SharedCache(Manifest& manifest,
105 const std::string& configuration, const std::string& architecture);
106
107 // We do not need an explicit destructor despite our move/copy constructor because the resource the are dealing with is a
108 // std::unique<void> which has a registered destructor
109
110 //FIXME reminants of merging the two classes, unifyu these
111 uint64_t vmSize() const { return _vmSize; }
112 uint64_t fileSize() const { return _fileSize; }
113 const uint8_t* cdHash() { return _cdHash; }
114 std::string cdHashString();
115
116 //FIXME: This should be private, but we can't do that until we move write out into the class after the next refactor
117 std::shared_ptr<void> buffer() const;
118
119 void buildForDevelopment(const std::string& cachePath);
120 void buildForProduction(const std::string& cachePath);
121 bool writeCacheMapFile(const std::string& mapPath);
122
123 typedef std::function<void(const void* machHeader, const char* installName, time_t lastModTime, ino_t inode,
124 const std::vector<MachOProxy::Segment>& segments)> DylibHandler;
125 // Calls lambda once per image in the cache
126 void forEachImage(DylibHandler handler);
127
128 typedef std::function<void(void* content, uint64_t vmAddr, uint64_t size, uint32_t permissions)> RegionHandler;
129 // Calls lambda once per region in the cache
130 void forEachRegion(RegionHandler handler);
131
132 void setLinkeditsMappingEndFileOffset(uint64_t newFileSize);
133 void setAcceleratorInfoRange(uint64_t accelInfoAddr, uint32_t accelInfoSize);
134 void setUnmappedLocalsRange(uint64_t localSymbolsOffset, uint32_t unmappedSize);
135 void recomputeCacheUUID(void);
136
137 private:
138 void loadDirtyDataOrderFile(const std::string& dirtyDataOrderFile);
139 void sortDylibs(const std::string& dylibOrderFile);
140 void assignSegmentAddresses();
141 void bypassStubs(const std::vector<uint64_t>& branchPoolStartAddrs);
142 void optimizeLinkedit(bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets);
143
144 // Once all a dylib's segments are copied into a cache, this function will adjust the contents of
145 // the TEXT, DATA, and LINKEDIT segments in the cache to be correct for their new addresses.
146 void bindAllImagesInCache(const std::unordered_map<std::string, void*>& dylibPathToMachHeader, std::vector<void*>& pointersForASLR);
147
148 // After adjustImageForNewSegmentLocations() is called to rebase all segments, this function can be called to
149 // bind all symbols to their new addresses
150 void adjustImageForNewSegmentLocations(const std::vector<uint64_t>& segNewStartAddresses,
151 const std::vector<uint64_t>& segCacheFileOffsets,
152 const std::vector<uint64_t>& segCacheSizes, std::vector<void*>& pointersForASLR);
153
154 uint64_t pathHash(const char* path);
155 void writeCacheHeader(void);
156 void writeCacheSegments(void);
157 void rebaseAll(void);
158 void rebase(MachOProxy* dylib);
159 void bindAll(void);
160 void optimizeObjC(bool forProduction);
161 void writeSlideInfoV2(void);
162
163 void buildUnoptimizedCache();
164 void appendCodeSignature(const std::string& suffix);
165 template <typename P> void buildForDevelopment(const std::string& cachePath);
166 template <typename P> void buildForProduction(const std::string& cachePath);
167 template <typename P> void forEachImage(DylibHandler handler);
168 template <typename P> void forEachRegion(RegionHandler handler);
169 template <typename P> void setLinkeditsMappingEndFileOffset(uint64_t newFileSize);
170 template <typename P> void setAcceleratorInfoRange(uint64_t accelInfoAddr, uint32_t accelInfoSize);
171 template <typename P> void setUnmappedLocalsRange(uint64_t localSymbolsOffset, uint32_t unmappedSize);
172 template <typename P> void recomputeCacheUUID(void);
173 template <typename P> void bypassStubs(const std::vector<uint64_t>& branchPoolStartAddrs);
174 template <typename P> void optimizeLinkedit(bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets);
175 template <typename P> void writeCacheHeader(void);
176 template <typename E> void writeSlideInfo(void);
177 template <typename P> void writeSlideInfoV2(uint64_t deltaMask, uint64_t valueAdd);
178
179 template <typename P> void findImplicitAliases(std::shared_ptr<MachOProxy> dylib);
180 template <typename P> void addPageStarts(uint8_t* pageContent, const bool bitmap[], const dyldCacheSlideInfo2<typename P::E>* info,
181 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
182 template <typename P> bool makeRebaseChain(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const dyldCacheSlideInfo2<typename P::E>* info);
183 void findDylibAndSegment(const void* contentPtr, std::string& dylibName, std::string& segName);
184
185 ArchPair _arch;
186 std::vector<MachOProxy *> _dylibs;
187 std::shared_ptr<void> _buffer;
188 std::unordered_map<const MachOProxy *, std::vector<SegmentInfo>> _segmentMap;
189
190 std::string archName();
191
192 Manifest& _manifest;
193 const Manifest::Architecture& _archManifest;
194 uint32_t _aliasCount;
195 Region _textRegion;
196 Region _dataRegion;
197 Region _readOnlyRegion;
198 uint64_t _slideInfoFileOffset;
199 uint64_t _slideInfoBufferSize;
200 uint64_t _fileSize;
201 uint64_t _vmSize;
202 std::unordered_map<std::string, uint32_t> _dataDirtySegsOrder;
203 std::vector<void*> _pointersForASLR;
204 std::vector<uint64_t> _branchPoolStarts;
205 uint64_t _branchPoolsLinkEditStartAddr;
206 uint8_t _cdHash[20];
207 };
208
209 std::string normalize_absolute_file_path(const std::string &path);
210 std::string baspath(const std::string& path);
211 std::string dirpath(const std::string& path);
212
213 std::string toolDir();
214 bool isProtectedBySIP(const std::string& path, int fd=-1);
215
216
217 template <class Set1, class Set2>
218 inline bool is_disjoint(const Set1& set1, const Set2& set2)
219 {
220 if (set1.empty() || set2.empty())
221 return true;
222
223 typename Set1::const_iterator it1 = set1.begin(), it1End = set1.end();
224 typename Set2::const_iterator it2 = set2.begin(), it2End = set2.end();
225
226 if (*it1 > *set2.rbegin() || *it2 > *set1.rbegin())
227 return true;
228
229 while (it1 != it1End && it2 != it2End) {
230 if (*it1 == *it2)
231 return false;
232 if (*it1 < *it2) {
233 it1++;
234 } else {
235 it2++;
236 }
237 }
238
239 return true;
240 }
241
242 inline bool has_prefix(const std::string& str, const std::string& prefix)
243 {
244 return std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end();
245 }
246
247
248 #define NEW_CACHE_FILE_FORMAT 0
249
250 #endif // __MEGA_DYLIB_UTILS_H__
251
252
253
254
255