]> git.saurik.com Git - apple/dyld.git/blob - dyld3/DyldCacheParser.cpp
dyld-519.2.2.tar.gz
[apple/dyld.git] / dyld3 / DyldCacheParser.cpp
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 #include <stdint.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <uuid/uuid.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <sys/uio.h>
33 #include <sys/param.h>
34 #include <sys/sysctl.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/mman.h>
39
40
41 #include "DyldCacheParser.h"
42 #include "Trie.hpp"
43
44
45 namespace dyld3 {
46
47 DyldCacheParser::DyldCacheParser(const DyldSharedCache* cacheHeader, bool rawFile)
48 {
49 _data = (long)cacheHeader;
50 if ( rawFile )
51 _data |= 1;
52 }
53
54 const dyld_cache_header* DyldCacheParser::header() const
55 {
56 return (dyld_cache_header*)(_data & -2);
57 }
58
59 const DyldSharedCache* DyldCacheParser::cacheHeader() const
60 {
61 return (DyldSharedCache*)header();
62 }
63
64 bool DyldCacheParser::cacheIsMappedRaw() const
65 {
66 return (_data & 1);
67 }
68
69
70 uint64_t DyldCacheParser::dataRegionRuntimeVmOffset() const
71 {
72 const dyld_cache_header* cacheHeader = header();
73 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
74 return (mappings[1].address - mappings[0].address);
75 }
76
77 const dyld3::launch_cache::binary_format::ImageGroup* DyldCacheParser::cachedDylibsGroup() const
78 {
79 const dyld_cache_header* cacheHeader = header();
80 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
81
82 if ( cacheIsMappedRaw() ) {
83 // Whole file is mapped read-only. Use mapping file-offsets to find ImageGroup
84 uint64_t offsetInLinkEditRegion = (cacheHeader->dylibsImageGroupAddr - mappings[2].address);
85 return (dyld3::launch_cache::binary_format::ImageGroup*)((uint8_t*)cacheHeader + mappings[2].fileOffset + offsetInLinkEditRegion);
86 }
87 else {
88 // Cache file is mapped in three non-contiguous ranges. Use mapping addresses to find ImageGroup
89 return (dyld3::launch_cache::binary_format::ImageGroup*)((uint8_t*)cacheHeader + (cacheHeader->dylibsImageGroupAddr - mappings[0].address));
90 }
91 }
92
93
94 const dyld3::launch_cache::binary_format::ImageGroup* DyldCacheParser::otherDylibsGroup() const
95 {
96 const dyld_cache_header* cacheHeader = header();
97 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
98
99 if ( cacheIsMappedRaw() ) {
100 // Whole file is mapped read-only. Use mapping file-offsets to find ImageGroup
101 uint64_t offsetInLinkEditRegion = (cacheHeader->otherImageGroupAddr - mappings[2].address);
102 return (dyld3::launch_cache::binary_format::ImageGroup*)((uint8_t*)cacheHeader + mappings[2].fileOffset + offsetInLinkEditRegion);
103 }
104 else {
105 // Cache file is mapped in three non-contiguous ranges. Use mapping addresses to find ImageGroup
106 return (dyld3::launch_cache::binary_format::ImageGroup*)((uint8_t*)cacheHeader + (cacheHeader->otherImageGroupAddr - mappings[0].address));
107 }
108 }
109
110 const dyld3::launch_cache::binary_format::Closure* DyldCacheParser::findClosure(const char* path) const
111 {
112 const dyld_cache_header* cacheHeader = header();
113 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
114
115 const uint8_t* executableTrieStart = nullptr;
116 const uint8_t* executableTrieEnd = nullptr;
117 const uint8_t* closuresStart = nullptr;
118
119 if ( cacheIsMappedRaw() ) {
120 // Whole file is mapped read-only. Use mapping file-offsets to find trie and closures
121 executableTrieStart = (uint8_t*)cacheHeader + cacheHeader->progClosuresTrieAddr - mappings[2].address + mappings[2].fileOffset;
122 executableTrieEnd = executableTrieStart + cacheHeader->progClosuresTrieSize;
123 closuresStart = (uint8_t*)cacheHeader + cacheHeader->progClosuresAddr - mappings[2].address + mappings[2].fileOffset;
124 }
125 else {
126 // Cache file is mapped in three non-contiguous ranges. Use mapping addresses to find trie and closures
127 uintptr_t slide = (uintptr_t)cacheHeader - (uintptr_t)(mappings[0].address);
128 executableTrieStart = (uint8_t*)(cacheHeader->progClosuresTrieAddr + slide);
129 executableTrieEnd = executableTrieStart + cacheHeader->progClosuresTrieSize;
130 closuresStart = (uint8_t*)(cacheHeader->progClosuresAddr + slide);
131 }
132 Diagnostics diag;
133 const uint8_t* imageNode = dyld3::MachOParser::trieWalk(diag, executableTrieStart, executableTrieEnd, path);
134 if ( imageNode != NULL ) {
135 uint32_t closureOffset = (uint32_t)dyld3::MachOParser::read_uleb128(diag, imageNode, executableTrieEnd);
136 return (const dyld3::launch_cache::BinaryClosureData*)((uint8_t*)closuresStart + closureOffset);
137 }
138 return nullptr;
139 }
140
141
142 #if !DYLD_IN_PROCESS
143 void DyldCacheParser::forEachClosure(void (^handler)(const char* runtimePath, const dyld3::launch_cache::binary_format::Closure* cls)) const
144 {
145 const dyld_cache_header* cacheHeader = header();
146 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
147
148 const uint8_t* executableTrieStart = nullptr;
149 const uint8_t* executableTrieEnd = nullptr;
150 const uint8_t* closuresStart = nullptr;
151
152 if ( cacheIsMappedRaw() ) {
153 // Whole file is mapped read-only. Use mapping file-offsets to find trie and closures
154 executableTrieStart = (uint8_t*)cacheHeader + cacheHeader->progClosuresTrieAddr - mappings[2].address + mappings[2].fileOffset;
155 executableTrieEnd = executableTrieStart + cacheHeader->progClosuresTrieSize;
156 closuresStart = (uint8_t*)cacheHeader + cacheHeader->progClosuresAddr - mappings[2].address + mappings[2].fileOffset;
157 }
158 else {
159 // Cache file is mapped in three non-contiguous ranges. Use mapping addresses to find trie and closures
160 uintptr_t slide = (uintptr_t)cacheHeader - (uintptr_t)(mappings[0].address);
161 executableTrieStart = (uint8_t*)(cacheHeader->progClosuresTrieAddr + slide);
162 executableTrieEnd = executableTrieStart + cacheHeader->progClosuresTrieSize;
163 closuresStart = (uint8_t*)(cacheHeader->progClosuresAddr + slide);
164 }
165
166 std::vector<DylibIndexTrie::Entry> closureEntries;
167 if ( Trie<DylibIndex>::parseTrie(executableTrieStart, executableTrieEnd, closureEntries) ) {
168 for (DylibIndexTrie::Entry& entry : closureEntries ) {
169 uint32_t offset = entry.info.index;
170 if ( offset < cacheHeader->progClosuresSize )
171 handler(entry.name.c_str(), (const dyld3::launch_cache::binary_format::Closure*)(closuresStart+offset));
172 }
173 }
174 }
175 #endif
176
177
178
179
180 } // namespace dyld3
181