1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2014 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __MEGA_DYLIB_UTILS_H__
26 #define __MEGA_DYLIB_UTILS_H__
28 #include <sys/types.h>
37 #include <dispatch/dispatch.h>
46 #include <unordered_set>
47 #include <unordered_map>
50 #include <uuid/uuid.h>
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
); }
62 for (auto i
= 0; i
< 16/sizeof(size_t); ++i
) {
63 retval
^= ((size_t *)(&_bytes
[0]))[i
];
67 const unsigned char* get() const { return &_bytes
[0]; };
69 std::array
<unsigned char, 16> _bytes
;
72 struct 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
); }
87 size_t operator()(const UUID
& x
) const
94 struct hash
<ImageIdentifier
> {
95 size_t operator()(const ImageIdentifier
& x
) const
104 #include "CacheFileAbstraction.hpp"
106 #include "MachOFileAbstraction.hpp"
108 #include "Manifest.h"
111 struct MachOProxySegment
;
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
);
120 std::tuple
<uint8_t *, struct stat
, bool> fill(const std::string
& path
);
122 std::unordered_map
<std::string
, std::tuple
<uint8_t *, struct stat
, bool>> entries
;
123 dispatch_queue_t cache_queue
;
126 extern FileCache fileCache
;
128 typedef std::pair
<Manifest
*,std::set
<std::pair
<std::string
, std::string
>>> WarningTargets
;
130 inline uint64_t align(uint64_t addr
, uint8_t p2
)
132 uint64_t mask
= (1 << p2
);
133 return (addr
+ mask
- 1) & (-mask
);
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
);
145 SegmentInfo(const MachOProxySegment
* seg
)
153 const MachOProxySegment
* base
;
155 uint64_t cacheFileOffset
;
156 uint64_t cacheSegSize
;
166 SharedCache(Manifest
& manifest
,
167 const std::string
& configuration
, const std::string
& architecture
);
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
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();
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;
181 void buildForDevelopment(const std::string
& cachePath
);
182 void buildForProduction(const std::string
& cachePath
);
183 bool writeCacheMapFile(const std::string
& mapPath
);
185 typedef std::function
<void(const void* machHeader
, const char* installName
, time_t lastModTime
, ino_t inode
,
186 const std::vector
<MachOProxySegment
>& segments
)>
188 // Calls lambda once per image in the cache
189 void forEachImage(DylibHandler handler
);
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
);
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);
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
);
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
);
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
);
217 uint64_t pathHash(const char* path
);
218 void writeCacheHeader(void);
219 void writeCacheSegments(void);
220 void rebaseAll(void);
221 void rebase(MachOProxy
* dylib
);
223 void optimizeObjC(bool forProduction
);
224 void writeSlideInfoV2(void);
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
);
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
);
249 std::vector
<MachOProxy
*> _dylibs
;
250 std::shared_ptr
<void> _buffer
;
251 std::map
<const MachOProxy
*, std::vector
<SegmentInfo
>> _segmentMap
;
253 std::string
archName();
256 const Manifest::Architecture
& _archManifest
;
257 uint32_t _aliasCount
;
260 Region _readOnlyRegion
;
261 uint64_t _slideInfoFileOffset
;
262 uint64_t _slideInfoBufferSize
;
265 std::unordered_map
<std::string
, uint32_t> _dataDirtySegsOrder
;
266 std::vector
<void*> _pointersForASLR
;
267 std::vector
<uint64_t> _branchPoolStarts
;
268 uint64_t _branchPoolsLinkEditStartAddr
;
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
);
276 std::string
toolDir();
277 bool isProtectedBySIP(const std::string
& path
, int fd
=-1);
279 template <class Set1
, class Set2
>
280 inline bool is_disjoint(const Set1
& set1
, const Set2
& set2
)
282 if (set1
.empty() || set2
.empty())
285 typename
Set1::const_iterator it1
= set1
.begin(), it1End
= set1
.end();
286 typename
Set2::const_iterator it2
= set2
.begin(), it2End
= set2
.end();
288 if (*it1
> *set2
.rbegin() || *it2
> *set1
.rbegin())
291 while (it1
!= it1End
&& it2
!= it2End
) {
304 inline bool has_prefix(const std::string
& str
, const std::string
& prefix
)
306 return std::mismatch(prefix
.begin(), prefix
.end(), str
.begin()).first
== prefix
.end();
309 #define NEW_CACHE_FILE_FORMAT 0
311 #endif // __MEGA_DYLIB_UTILS_H__