dyld-640.2.tar.gz
[apple/dyld.git] / dyld3 / ClosureWriter.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 <assert.h>
27 #include <uuid/uuid.h>
28 #include <unistd.h>
29 #include <limits.h>
30 #include <mach/vm_page_size.h>
31
32 #include "ClosureWriter.h"
33 #include "MachOFile.h"
34
35
36 namespace dyld3 {
37 namespace closure {
38
39
40 //////////////////////////// ContainerTypedBytesWriter ////////////////////////////////////////
41
42
43 void ContainerTypedBytesWriter::setContainerType(TypedBytes::Type containerType)
44 {
45 assert(_vmAllocationStart == 0);
46 _vmAllocationSize = 1024 * 1024;
47 vm_address_t allocationAddr;
48 ::vm_allocate(mach_task_self(), &allocationAddr, _vmAllocationSize, VM_FLAGS_ANYWHERE);
49 assert(allocationAddr != 0);
50 _vmAllocationStart = (void*)allocationAddr;
51 _containerTypedBytes = (TypedBytes*)_vmAllocationStart;
52 _containerTypedBytes->type = (uint32_t)containerType;
53 _containerTypedBytes->payloadLength = 0;
54 _end = (uint8_t*)_vmAllocationStart + sizeof(TypedBytes);
55 }
56
57 void* ContainerTypedBytesWriter::append(TypedBytes::Type t, const void* payload, uint32_t payloadSize)
58 {
59 assert((payloadSize & 0x3) == 0);
60 if ( (uint8_t*)_end + payloadSize >= (uint8_t*)_vmAllocationStart + _vmAllocationSize ) {
61 // if current buffer too small, grow it
62 size_t growth = _vmAllocationSize;
63 if ( growth < payloadSize )
64 growth = _vmAllocationSize*((payloadSize/_vmAllocationSize)+1);
65 vm_address_t newAllocationAddr;
66 size_t newAllocationSize = _vmAllocationSize+growth;
67 ::vm_allocate(mach_task_self(), &newAllocationAddr, newAllocationSize, VM_FLAGS_ANYWHERE);
68 assert(newAllocationAddr != 0);
69 size_t currentInUse = (char*)_end - (char*)_vmAllocationStart;
70 memcpy((void*)newAllocationAddr, _vmAllocationStart, currentInUse);
71 ::vm_deallocate(mach_task_self(), (vm_address_t)_vmAllocationStart, _vmAllocationSize);
72 _end = (void*)(newAllocationAddr + currentInUse);
73 _vmAllocationStart = (void*)newAllocationAddr;
74 _containerTypedBytes = (TypedBytes*)_vmAllocationStart;
75 _vmAllocationSize = newAllocationSize;
76 }
77 assert( (uint8_t*)_end + payloadSize < (uint8_t*)_vmAllocationStart + _vmAllocationSize);
78 TypedBytes* tb = (TypedBytes*)_end;
79 tb->type = (uint32_t)t;
80 tb->payloadLength = payloadSize;
81 if ( payload != nullptr )
82 ::memcpy(tb->payload(), payload, payloadSize);
83 _end = (uint8_t*)_end + sizeof(TypedBytes) + payloadSize;
84 _containerTypedBytes->payloadLength += sizeof(TypedBytes) + payloadSize;
85 return tb->payload();
86 }
87
88 const void* ContainerTypedBytesWriter::finalizeContainer()
89 {
90 // trim vm allocation down to just what is needed
91 uintptr_t bufferStart = (uintptr_t)_vmAllocationStart;
92 uintptr_t used = round_page((uintptr_t)_end - bufferStart);
93 if ( used < _vmAllocationSize ) {
94 uintptr_t deallocStart = bufferStart + used;
95 ::vm_deallocate(mach_task_self(), deallocStart, _vmAllocationSize - used);
96 _end = nullptr;
97 _vmAllocationSize = used;
98 }
99 // mark vm region read-only
100 ::vm_protect(mach_task_self(), bufferStart, used, false, VM_PROT_READ);
101 return (void*)_vmAllocationStart;
102 }
103
104 const void* ContainerTypedBytesWriter::currentTypedBytes()
105 {
106 return (void*)_vmAllocationStart;
107 }
108
109 void ContainerTypedBytesWriter::deallocate()
110 {
111 ::vm_deallocate(mach_task_self(), (long)_vmAllocationStart, _vmAllocationSize);
112 }
113
114 //////////////////////////// ImageWriter ////////////////////////////////////////
115
116
117 const Image* ImageWriter::finalize()
118 {
119 return (Image*)finalizeContainer();
120 }
121
122 const Image* ImageWriter::currentImage()
123 {
124 return (Image*)currentTypedBytes();
125 }
126
127 void ImageWriter::addPath(const char* path)
128 {
129 uint32_t roundedPathLen = ((uint32_t)strlen(path) + 1 + 3) & (-4);
130 Image::PathAndHash* ph = (Image::PathAndHash*)append(TypedBytes::Type::pathWithHash, nullptr, sizeof(Image::PathAndHash)+roundedPathLen);
131 ph->hash = Image::hashFunction(path);
132 strcpy(ph->path, path);
133 }
134
135 Image::Flags& ImageWriter::getFlags()
136 {
137 if ( _flagsOffset == -1 ) {
138 setContainerType(TypedBytes::Type::image);
139 Image::Flags flags;
140 ::bzero(&flags, sizeof(flags));
141 uint8_t* p = (uint8_t*)append(TypedBytes::Type::imageFlags, &flags, sizeof(flags));
142 _flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
143 }
144 return *((Image::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
145 }
146
147 void ImageWriter::setImageNum(ImageNum num)
148 {
149 getFlags().imageNum = num;
150 }
151
152 void ImageWriter::setHasObjC(bool value)
153 {
154 getFlags().hasObjC = value;
155 }
156
157 void ImageWriter::setIs64(bool value)
158 {
159 getFlags().is64 = value;
160 }
161
162 void ImageWriter::setHasPlusLoads(bool value)
163 {
164 getFlags().mayHavePlusLoads = value;
165 }
166
167 void ImageWriter::setIsBundle(bool value)
168 {
169 getFlags().isBundle = value;
170 }
171
172 void ImageWriter::setIsDylib(bool value)
173 {
174 getFlags().isDylib = value;
175 }
176
177 void ImageWriter::setIsExecutable(bool value)
178 {
179 getFlags().isExecutable = value;
180 }
181
182 void ImageWriter::setHasWeakDefs(bool value)
183 {
184 getFlags().hasWeakDefs = value;
185 }
186
187 void ImageWriter::setUses16KPages(bool value)
188 {
189 getFlags().has16KBpages = value;
190 }
191
192 void ImageWriter::setOverridableDylib(bool value)
193 {
194 getFlags().overridableDylib = value;
195 }
196
197 void ImageWriter::setInvalid()
198 {
199 getFlags().isInvalid = true;
200 }
201
202 void ImageWriter::setInDyldCache(bool value)
203 {
204 getFlags().inDyldCache = value;
205 }
206
207 void ImageWriter::setNeverUnload(bool value)
208 {
209 getFlags().neverUnload = value;
210 }
211
212 void ImageWriter::setUUID(const uuid_t uuid)
213 {
214 append(TypedBytes::Type::uuid, uuid, sizeof(uuid_t));
215 }
216
217 void ImageWriter::setCDHash(const uint8_t cdHash[20])
218 {
219 append(TypedBytes::Type::cdHash, cdHash, 20);
220 }
221
222 void ImageWriter::setDependents(const Array<Image::LinkedImage>& deps)
223 {
224 append(TypedBytes::Type::dependents, deps.begin(), (uint32_t)deps.count()*sizeof(Image::LinkedImage));
225 }
226
227 void ImageWriter::setDofOffsets(const Array<uint32_t>& dofSectionOffsets)
228 {
229 append(TypedBytes::Type::dofOffsets, &dofSectionOffsets[0], (uint32_t)dofSectionOffsets.count()*sizeof(uint32_t));
230 }
231
232 void ImageWriter::setInitOffsets(const uint32_t initOffsets[], uint32_t count)
233 {
234 append(TypedBytes::Type::initOffsets, initOffsets, count*sizeof(uint32_t));
235 }
236
237 void ImageWriter::setDiskSegments(const Image::DiskSegment segs[], uint32_t count)
238 {
239 append(TypedBytes::Type::diskSegment, segs, count*sizeof(Image::DiskSegment));
240 }
241
242 void ImageWriter::setCachedSegments(const Image::DyldCacheSegment segs[], uint32_t count)
243 {
244 append(TypedBytes::Type::cacheSegment, segs, count*sizeof(Image::DyldCacheSegment));
245 }
246
247 void ImageWriter::setCodeSignatureLocation(uint32_t fileOffset, uint32_t size)
248 {
249 Image::CodeSignatureLocation loc;
250 loc.fileOffset = fileOffset;
251 loc.fileSize = size;
252 append(TypedBytes::Type::codeSignLoc, &loc, sizeof(loc));
253 }
254
255 void ImageWriter::setFairPlayEncryptionRange(uint32_t fileOffset, uint32_t size)
256 {
257 const uint32_t pageSize = getFlags().has16KBpages ? 0x4000 : 0x1000;
258 assert((fileOffset % pageSize) == 0);
259 assert((size % pageSize) == 0);
260 Image::FairPlayRange loc;
261 loc.textStartPage = fileOffset/pageSize;
262 loc.textPageCount = size/pageSize;
263 append(TypedBytes::Type::fairPlayLoc, &loc, sizeof(loc));
264 }
265
266 void ImageWriter::setMappingInfo(uint64_t sliceOffset, uint64_t vmSize)
267 {
268 const uint32_t pageSize = getFlags().has16KBpages ? 0x4000 : 0x1000;
269 Image::MappingInfo info;
270 info.sliceOffsetIn4K = (uint32_t)(sliceOffset / 0x1000);
271 info.totalVmPages = (uint32_t)(vmSize / pageSize);
272 append(TypedBytes::Type::mappingInfo, &info, sizeof(info));
273 }
274
275 void ImageWriter::setFileInfo(uint64_t inode, uint64_t mTime)
276 {
277 Image::FileInfo info = { inode, mTime };
278 append(TypedBytes::Type::fileInodeAndTime, &info, sizeof(info));
279 }
280
281 void ImageWriter::setRebaseInfo(const Array<Image::RebasePattern>& fixups)
282 {
283 append(TypedBytes::Type::rebaseFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::RebasePattern));
284 }
285
286 void ImageWriter::setTextRebaseInfo(const Array<Image::TextFixupPattern>& fixups)
287 {
288 append(TypedBytes::Type::textFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::TextFixupPattern));
289 }
290
291 void ImageWriter::setBindInfo(const Array<Image::BindPattern>& fixups)
292 {
293 append(TypedBytes::Type::bindFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::BindPattern));
294 }
295
296 void ImageWriter::setChainedFixups(const Array<uint64_t>& starts, const Array<Image::ResolvedSymbolTarget>& targets)
297 {
298 append(TypedBytes::Type::chainedFixupsStarts, starts.begin(), (uint32_t)starts.count()*sizeof(uint64_t));
299 append(TypedBytes::Type::chainedFixupsTargets, targets.begin(), (uint32_t)targets.count()*sizeof(Image::ResolvedSymbolTarget));
300 }
301
302 void ImageWriter::addExportPatchInfo(uint32_t implCacheOff, const char* name, uint32_t locCount, const Image::PatchableExport::PatchLocation* locs)
303 {
304 uint32_t roundedNameLen = ((uint32_t)strlen(name) + 1 + 3) & (-4);
305 uint32_t payloadSize = sizeof(Image::PatchableExport) + locCount*sizeof(Image::PatchableExport::PatchLocation) + roundedNameLen;
306 Image::PatchableExport* buffer = (Image::PatchableExport*)append(TypedBytes::Type::cachePatchInfo, nullptr, payloadSize);
307 buffer->cacheOffsetOfImpl = implCacheOff;
308 buffer->patchLocationsCount = locCount;
309 memcpy(&buffer->patchLocations[0], locs, locCount*sizeof(Image::PatchableExport::PatchLocation));
310 strcpy((char*)(&buffer->patchLocations[locCount]), name);
311 }
312
313 void ImageWriter::setAsOverrideOf(ImageNum imageNum)
314 {
315 uint32_t temp = imageNum;
316 append(TypedBytes::Type::imageOverride, &temp, sizeof(temp));
317 }
318
319 void ImageWriter::setInitsOrder(const ImageNum images[], uint32_t count)
320 {
321 append(TypedBytes::Type::initBefores, images, count*sizeof(ImageNum));
322 }
323
324
325 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
326
327
328 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum, unsigned count) : _index(0)
329 {
330 setContainerType(TypedBytes::Type::imageArray);
331 _end = (void*)((uint8_t*)_end + sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count);
332 _containerTypedBytes->payloadLength = sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count;
333 ImageArray* ia = (ImageArray*)_containerTypedBytes;
334 ia->firstImageNum = startImageNum;
335 ia->count = count;
336 }
337
338 void ImageArrayWriter::appendImage(const Image* image)
339 {
340 ImageArray* ia = (ImageArray*)_containerTypedBytes;
341 ia->offsets[_index++] = _containerTypedBytes->payloadLength;
342 append(TypedBytes::Type::image, image->payload(), image->payloadLength);
343 }
344
345 const ImageArray* ImageArrayWriter::finalize()
346 {
347 return (ImageArray*)finalizeContainer();
348 }
349
350
351 //////////////////////////// ClosureWriter ////////////////////////////////////////
352
353 void ClosureWriter::setTopImageNum(ImageNum imageNum)
354 {
355 append(TypedBytes::Type::topImage, &imageNum, sizeof(ImageNum));
356 }
357
358 void ClosureWriter::addCachePatches(const Array<Closure::PatchEntry>& patches)
359 {
360 append(TypedBytes::Type::cacheOverrides, patches.begin(), (uint32_t)patches.count()*sizeof(Closure::PatchEntry));
361 }
362
363
364 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
365
366 LaunchClosureWriter::LaunchClosureWriter(const ImageArray* images)
367 {
368 setContainerType(TypedBytes::Type::launchClosure);
369 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
370 }
371
372 const LaunchClosure* LaunchClosureWriter::finalize()
373 {
374 return (LaunchClosure*)finalizeContainer();
375 }
376
377 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum)
378 {
379 append(TypedBytes::Type::libSystemNum, &imageNum, sizeof(ImageNum));
380 }
381
382 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry)
383 {
384 append(TypedBytes::Type::libDyldEntry, &entry, sizeof(entry));
385 }
386
387 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main)
388 {
389 append(TypedBytes::Type::mainEntry, &main, sizeof(main));
390 }
391
392 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start)
393 {
394 append(TypedBytes::Type::startEntry, &start, sizeof(start));
395 }
396
397 void LaunchClosureWriter::setUsedFallbackPaths(bool value)
398 {
399 getFlags().usedFallbackPaths = value;
400 }
401
402 void LaunchClosureWriter::setUsedAtPaths(bool value)
403 {
404 getFlags().usedAtPaths = value;
405 }
406
407 void LaunchClosureWriter::setInitImageCount(uint32_t count)
408 {
409 getFlags().initImageCount = count;
410 }
411
412 LaunchClosure::Flags& LaunchClosureWriter::getFlags()
413 {
414 if ( _flagsOffset == -1 ) {
415 LaunchClosure::Flags flags;
416 ::bzero(&flags, sizeof(flags));
417 uint8_t* p = (uint8_t*)append(TypedBytes::Type::closureFlags, &flags, sizeof(flags));
418 _flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
419 }
420 return *((LaunchClosure::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
421 }
422
423 void LaunchClosureWriter::setMustBeMissingFiles(const Array<const char*>& paths)
424 {
425 uint32_t totalSize = 0;
426 for (const char* s : paths)
427 totalSize += (strlen(s) +1);
428 totalSize = (totalSize + 3) & (-4); // align
429
430 char* buffer = (char*)append(TypedBytes::Type::missingFiles, nullptr, totalSize);
431 char* t = buffer;
432 for (const char* path : paths) {
433 for (const char* s=path; *s != '\0'; ++s)
434 *t++ = *s;
435 *t++ = '\0';
436 }
437 while (t < &buffer[totalSize])
438 *t++ = '\0';
439 }
440
441 void LaunchClosureWriter::addEnvVar(const char* envVar)
442 {
443 unsigned len = (unsigned)strlen(envVar);
444 char temp[len+8];
445 strcpy(temp, envVar);
446 unsigned paddedSize = len+1;
447 while ( (paddedSize % 4) != 0 )
448 temp[paddedSize++] = '\0';
449 append(TypedBytes::Type::envVar, temp, paddedSize);
450 }
451
452 void LaunchClosureWriter::addInterposingTuples(const Array<InterposingTuple>& tuples)
453 {
454 append(TypedBytes::Type::interposeTuples, tuples.begin(), (uint32_t)tuples.count()*sizeof(InterposingTuple));
455 }
456
457 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid)
458 {
459 append(TypedBytes::Type::dyldCacheUUID, uuid, sizeof(uuid_t));
460 }
461
462 void LaunchClosureWriter::setBootUUID(const char* uuid)
463 {
464 unsigned len = (unsigned)strlen(uuid);
465 char temp[len+8];
466 strcpy(temp, uuid);
467 unsigned paddedSize = len+1;
468 while ( (paddedSize % 4) != 0 )
469 temp[paddedSize++] = '\0';
470 append(TypedBytes::Type::bootUUID, temp, paddedSize);
471 }
472
473 void LaunchClosureWriter::applyInterposing()
474 {
475 const LaunchClosure* currentClosure = (LaunchClosure*)currentTypedBytes();
476 const ImageArray* images = currentClosure->images();
477 currentClosure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool&) {
478 images->forEachImage(^(const dyld3::closure::Image* image, bool&) {
479 for (const Image::BindPattern& bindPat : image->bindFixups()) {
480 if ( (bindPat.target == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
481 Image::BindPattern* writePat = const_cast<Image::BindPattern*>(&bindPat);
482 writePat->target = tuple.newImplementation;
483 }
484 }
485
486 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
487 // the target list.
488 for (const Image::ResolvedSymbolTarget& symbolTarget : image->chainedTargets()) {
489 if ( (symbolTarget == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
490 Image::ResolvedSymbolTarget* writeTarget = const_cast<Image::ResolvedSymbolTarget*>(&symbolTarget);
491 *writeTarget = tuple.newImplementation;
492 }
493 }
494 });
495 });
496 }
497
498 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
499
500 DlopenClosureWriter::DlopenClosureWriter(const ImageArray* images)
501 {
502 setContainerType(TypedBytes::Type::dlopenClosure);
503 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
504 }
505
506 const DlopenClosure* DlopenClosureWriter::finalize()
507 {
508 return (DlopenClosure*)finalizeContainer();
509 }
510
511
512 } // namespace closure
513 } // namespace dyld3
514
515
516