dyld-733.8.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 = 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 = t;
80 tb->payloadLength = payloadSize;
81 if ( payload != nullptr )
82 ::memcpy(tb->payload(), payload, payloadSize);
83 _end = (uint8_t*)_end + sizeof(TypedBytes) + payloadSize;
84 assert((_containerTypedBytes->payloadLength + sizeof(TypedBytes) + payloadSize) < (16 * 1024 * 1024));
85 _containerTypedBytes->payloadLength += sizeof(TypedBytes) + payloadSize;
86 return tb->payload();
87 }
88
89 const void* ContainerTypedBytesWriter::finalizeContainer()
90 {
91 // trim vm allocation down to just what is needed
92 uintptr_t bufferStart = (uintptr_t)_vmAllocationStart;
93 uintptr_t used = round_page((uintptr_t)_end - bufferStart);
94 if ( used < _vmAllocationSize ) {
95 uintptr_t deallocStart = bufferStart + used;
96 ::vm_deallocate(mach_task_self(), deallocStart, _vmAllocationSize - used);
97 _end = nullptr;
98 _vmAllocationSize = used;
99 }
100 // mark vm region read-only
101 ::vm_protect(mach_task_self(), bufferStart, used, false, VM_PROT_READ);
102 return (void*)_vmAllocationStart;
103 }
104
105 const void* ContainerTypedBytesWriter::currentTypedBytes()
106 {
107 return (void*)_vmAllocationStart;
108 }
109
110 void ContainerTypedBytesWriter::deallocate()
111 {
112 ::vm_deallocate(mach_task_self(), (long)_vmAllocationStart, _vmAllocationSize);
113 }
114
115 //////////////////////////// ImageWriter ////////////////////////////////////////
116
117
118 const Image* ImageWriter::finalize()
119 {
120 return (Image*)finalizeContainer();
121 }
122
123 const Image* ImageWriter::currentImage()
124 {
125 return (Image*)currentTypedBytes();
126 }
127
128 void ImageWriter::addPath(const char* path)
129 {
130 uint32_t roundedPathLen = ((uint32_t)strlen(path) + 1 + 3) & (-4);
131 Image::PathAndHash* ph = (Image::PathAndHash*)append(TypedBytes::Type::pathWithHash, nullptr, sizeof(Image::PathAndHash)+roundedPathLen);
132 ph->hash = Image::hashFunction(path);
133 strcpy(ph->path, path);
134 }
135
136 Image::Flags& ImageWriter::getFlags()
137 {
138 if ( _flagsOffset == -1 ) {
139 setContainerType(TypedBytes::Type::image);
140 Image::Flags flags;
141 ::bzero(&flags, sizeof(flags));
142 uint8_t* p = (uint8_t*)append(TypedBytes::Type::imageFlags, &flags, sizeof(flags));
143 _flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
144 }
145 return *((Image::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
146 }
147
148 void ImageWriter::setImageNum(ImageNum num)
149 {
150 getFlags().imageNum = num;
151 }
152
153 void ImageWriter::setHasObjC(bool value)
154 {
155 getFlags().hasObjC = value;
156 }
157
158 void ImageWriter::setIs64(bool value)
159 {
160 getFlags().is64 = value;
161 }
162
163 void ImageWriter::setHasPlusLoads(bool value)
164 {
165 getFlags().mayHavePlusLoads = value;
166 }
167
168 void ImageWriter::setIsBundle(bool value)
169 {
170 getFlags().isBundle = value;
171 }
172
173 void ImageWriter::setIsDylib(bool value)
174 {
175 getFlags().isDylib = value;
176 }
177
178 void ImageWriter::setIsExecutable(bool value)
179 {
180 getFlags().isExecutable = value;
181 }
182
183 void ImageWriter::setHasWeakDefs(bool value)
184 {
185 getFlags().hasWeakDefs = value;
186 }
187
188 void ImageWriter::setUses16KPages(bool value)
189 {
190 getFlags().has16KBpages = value;
191 }
192
193 void ImageWriter::setOverridableDylib(bool value)
194 {
195 getFlags().overridableDylib = value;
196 }
197
198 void ImageWriter::setInvalid()
199 {
200 getFlags().isInvalid = true;
201 }
202
203 void ImageWriter::setInDyldCache(bool value)
204 {
205 getFlags().inDyldCache = value;
206 }
207
208 void ImageWriter::setHasPrecomputedObjC(bool value)
209 {
210 getFlags().hasPrecomputedObjC = value;
211 }
212
213 void ImageWriter::setNeverUnload(bool value)
214 {
215 getFlags().neverUnload = value;
216 }
217
218 void ImageWriter::setUUID(const uuid_t uuid)
219 {
220 append(TypedBytes::Type::uuid, uuid, sizeof(uuid_t));
221 }
222
223 void ImageWriter::addCDHash(const uint8_t cdHash[20])
224 {
225 append(TypedBytes::Type::cdHash, cdHash, 20);
226 }
227
228 void ImageWriter::setDependents(const Array<Image::LinkedImage>& deps)
229 {
230 append(TypedBytes::Type::dependents, deps.begin(), (uint32_t)deps.count()*sizeof(Image::LinkedImage));
231 }
232
233 void ImageWriter::setDofOffsets(const Array<uint32_t>& dofSectionOffsets)
234 {
235 append(TypedBytes::Type::dofOffsets, &dofSectionOffsets[0], (uint32_t)dofSectionOffsets.count()*sizeof(uint32_t));
236 }
237
238 void ImageWriter::setInitOffsets(const uint32_t initOffsets[], uint32_t count)
239 {
240 append(TypedBytes::Type::initOffsets, initOffsets, count*sizeof(uint32_t));
241 }
242
243 void ImageWriter::setTermOffsets(const uint32_t termOffsets[], uint32_t count)
244 {
245 getFlags().hasTerminators = true;
246 append(TypedBytes::Type::termOffsets, termOffsets, count*sizeof(uint32_t));
247 }
248
249 void ImageWriter::setInitSectRange(uint32_t sectionOffset, uint32_t sectionSize)
250 {
251 Image::InitializerSectionRange range = { sectionOffset, sectionSize };
252 append(TypedBytes::Type::initsSection, &range, sizeof(Image::InitializerSectionRange));
253 }
254
255 void ImageWriter::setDiskSegments(const Image::DiskSegment segs[], uint32_t count)
256 {
257 append(TypedBytes::Type::diskSegment, segs, count*sizeof(Image::DiskSegment));
258 for (uint32_t i=0; i < count; ++i) {
259 if ( segs[i].permissions == Image::DiskSegment::kReadOnlyDataPermissions )
260 getFlags().hasReadOnlyData = true;
261 }
262 }
263
264 void ImageWriter::setCachedSegments(const Image::DyldCacheSegment segs[], uint32_t count)
265 {
266 append(TypedBytes::Type::cacheSegment, segs, count*sizeof(Image::DyldCacheSegment));
267 }
268
269 void ImageWriter::setCodeSignatureLocation(uint32_t fileOffset, uint32_t size)
270 {
271 Image::CodeSignatureLocation loc;
272 loc.fileOffset = fileOffset;
273 loc.fileSize = size;
274 append(TypedBytes::Type::codeSignLoc, &loc, sizeof(loc));
275 }
276
277 void ImageWriter::setFairPlayEncryptionRange(uint32_t fileOffset, uint32_t size)
278 {
279 Image::FairPlayRange loc;
280 loc.rangeStart = fileOffset;
281 loc.rangeLength = size;
282 append(TypedBytes::Type::fairPlayLoc, &loc, sizeof(loc));
283 }
284
285 void ImageWriter::setMappingInfo(uint64_t sliceOffset, uint64_t vmSize)
286 {
287 const uint32_t pageSize = getFlags().has16KBpages ? 0x4000 : 0x1000;
288 Image::MappingInfo info;
289 info.sliceOffsetIn4K = (uint32_t)(sliceOffset / 0x1000);
290 info.totalVmPages = (uint32_t)(vmSize / pageSize);
291 append(TypedBytes::Type::mappingInfo, &info, sizeof(info));
292 }
293
294 void ImageWriter::setFileInfo(uint64_t inode, uint64_t mTime)
295 {
296 Image::FileInfo info = { inode, mTime };
297 append(TypedBytes::Type::fileInodeAndTime, &info, sizeof(info));
298 }
299
300 void ImageWriter::setRebaseInfo(const Array<Image::RebasePattern>& fixups)
301 {
302 append(TypedBytes::Type::rebaseFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::RebasePattern));
303 }
304
305 void ImageWriter::setTextRebaseInfo(const Array<Image::TextFixupPattern>& fixups)
306 {
307 append(TypedBytes::Type::textFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::TextFixupPattern));
308 }
309
310 void ImageWriter::setBindInfo(const Array<Image::BindPattern>& fixups)
311 {
312 append(TypedBytes::Type::bindFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::BindPattern));
313 }
314
315 void ImageWriter::setChainedFixups(uint64_t runtimeStartsStructOffset, const Array<Image::ResolvedSymbolTarget>& targets)
316 {
317 getFlags().hasChainedFixups = true;
318 append(TypedBytes::Type::chainedStartsOffset, &runtimeStartsStructOffset, sizeof(uint64_t));
319 append(TypedBytes::Type::chainedFixupsTargets, targets.begin(), (uint32_t)targets.count()*sizeof(Image::ResolvedSymbolTarget));
320 }
321
322 void ImageWriter::setObjCFixupInfo(const Image::ResolvedSymbolTarget& objcProtocolClassTarget,
323 uint64_t objcImageInfoVMOffset,
324 const Array<Image::ProtocolISAFixup>& protocolISAFixups,
325 const Array<Image::SelectorReferenceFixup>& selRefFixups,
326 const Array<Image::ClassStableSwiftFixup>& classStableSwiftFixups,
327 const Array<Image::MethodListFixup>& methodListFixups)
328 {
329 // The layout here is:
330 // ResolvedSymbolTarget
331 // uint64_t vmOffset to objc_imageinfo
332 // uint32_t protocol count
333 // uint32_t selector reference count
334 // array of ProtocolISAFixup
335 // array of SelectorReferenceFixup
336 // optional uint32_t stable swift fixup count
337 // optional uint32_t method list fixup count
338 // optional array of ClassStableSwiftFixup
339 // optional array of MethodListFixup
340
341 uint64_t headerSize = sizeof(Image::ResolvedSymbolTarget) + sizeof(uint64_t) + (sizeof(uint32_t) * 4);
342 uint64_t protocolsSize = (sizeof(Image::ProtocolISAFixup) * protocolISAFixups.count());
343 uint64_t selRefsSize = (sizeof(Image::SelectorReferenceFixup) * selRefFixups.count());
344 uint64_t stableSwiftSize = (sizeof(Image::ClassStableSwiftFixup) * classStableSwiftFixups.count());
345 uint64_t methodListSize = (sizeof(Image::MethodListFixup) * methodListFixups.count());
346
347 uint64_t totalSize = headerSize + protocolsSize + selRefsSize + stableSwiftSize + methodListSize;
348 assert( (totalSize & 3) == 0);
349 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::objcFixups, nullptr, (uint32_t)totalSize);
350
351 // Set the statically sized data
352 uint32_t protocolFixupCount = (uint32_t)protocolISAFixups.count();
353 uint32_t selRefFixupCount = (uint32_t)selRefFixups.count();
354 memcpy(buffer, &objcProtocolClassTarget, sizeof(Image::ResolvedSymbolTarget));
355 buffer += sizeof(Image::ResolvedSymbolTarget);
356 memcpy(buffer, &objcImageInfoVMOffset, sizeof(uint64_t));
357 buffer += sizeof(uint64_t);
358 memcpy(buffer, &protocolFixupCount, sizeof(uint32_t));
359 buffer += sizeof(uint32_t);
360 memcpy(buffer, &selRefFixupCount, sizeof(uint32_t));
361 buffer += sizeof(uint32_t);
362
363 // Set the protocol fixups
364 if ( protocolFixupCount != 0 ) {
365 memcpy(buffer, protocolISAFixups.begin(), (size_t)protocolsSize);
366 buffer += protocolsSize;
367 }
368
369 // Set the selector reference fixups
370 if ( selRefFixupCount != 0 ) {
371 memcpy(buffer, selRefFixups.begin(), (size_t)selRefsSize);
372 buffer += selRefsSize;
373 }
374
375 // New closures get additional fixups. These are ignored by old dyld's
376 uint32_t stableSwiftFixupCount = (uint32_t)classStableSwiftFixups.count();
377 uint32_t methodListFixupCount = (uint32_t)methodListFixups.count();
378 memcpy(buffer, &stableSwiftFixupCount, sizeof(uint32_t));
379 buffer += sizeof(uint32_t);
380 memcpy(buffer, &methodListFixupCount, sizeof(uint32_t));
381 buffer += sizeof(uint32_t);
382
383 // Set the stable swift fixups
384 if ( stableSwiftFixupCount != 0 ) {
385 memcpy(buffer, classStableSwiftFixups.begin(), (size_t)stableSwiftSize);
386 buffer += stableSwiftSize;
387 }
388
389 // Set the method list fixups
390 if ( methodListFixupCount != 0 ) {
391 memcpy(buffer, methodListFixups.begin(), (size_t)methodListSize);
392 buffer += methodListSize;
393 }
394 }
395
396 void ImageWriter::setAsOverrideOf(ImageNum imageNum)
397 {
398 uint32_t temp = imageNum;
399 append(TypedBytes::Type::imageOverride, &temp, sizeof(temp));
400 }
401
402 void ImageWriter::setInitsOrder(const ImageNum images[], uint32_t count)
403 {
404 append(TypedBytes::Type::initBefores, images, count*sizeof(ImageNum));
405 }
406
407
408 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
409
410
411 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum, unsigned count, bool hasRoots) : _index(0)
412 {
413 setContainerType(TypedBytes::Type::imageArray);
414 _end = (void*)((uint8_t*)_end + sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count);
415 _containerTypedBytes->payloadLength = sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count;
416 ImageArray* ia = (ImageArray*)_containerTypedBytes;
417 ia->firstImageNum = startImageNum;
418 ia->count = count;
419 ia->hasRoots = hasRoots;
420 }
421
422 void ImageArrayWriter::appendImage(const Image* image)
423 {
424 ImageArray* ia = (ImageArray*)_containerTypedBytes;
425 ia->offsets[_index++] = _containerTypedBytes->payloadLength;
426 append(TypedBytes::Type::image, image->payload(), image->payloadLength);
427 }
428
429 const ImageArray* ImageArrayWriter::finalize()
430 {
431 return (ImageArray*)finalizeContainer();
432 }
433
434
435 //////////////////////////// ClosureWriter ////////////////////////////////////////
436
437 void ClosureWriter::setTopImageNum(ImageNum imageNum)
438 {
439 append(TypedBytes::Type::topImage, &imageNum, sizeof(ImageNum));
440 }
441
442 void ClosureWriter::addCachePatches(const Array<Closure::PatchEntry>& patches)
443 {
444 append(TypedBytes::Type::cacheOverrides, patches.begin(), (uint32_t)patches.count()*sizeof(Closure::PatchEntry));
445 }
446
447 void ClosureWriter::applyInterposing(const LaunchClosure* launchClosure)
448 {
449 const Closure* currentClosure = (Closure*)currentTypedBytes();
450 const ImageArray* images = currentClosure->images();
451 launchClosure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool&) {
452 images->forEachImage(^(const dyld3::closure::Image* image, bool&) {
453 for (const Image::BindPattern& bindPat : image->bindFixups()) {
454 if ( (bindPat.target == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
455 Image::BindPattern* writePat = const_cast<Image::BindPattern*>(&bindPat);
456 writePat->target = tuple.newImplementation;
457 }
458 }
459
460 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
461 // the target list.
462 for (const Image::ResolvedSymbolTarget& symbolTarget : image->chainedTargets()) {
463 if ( (symbolTarget == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
464 Image::ResolvedSymbolTarget* writeTarget = const_cast<Image::ResolvedSymbolTarget*>(&symbolTarget);
465 *writeTarget = tuple.newImplementation;
466 }
467 }
468 });
469 });
470 }
471
472 void ClosureWriter::addWarning(Closure::Warning::Type warningType, const char* warning)
473 {
474 uint32_t roundedMessageLen = ((uint32_t)strlen(warning) + 1 + 3) & (-4);
475 Closure::Warning* ph = (Closure::Warning*)append(TypedBytes::Type::warning, nullptr, sizeof(Closure::Warning)+roundedMessageLen);
476 ph->type = warningType;
477 strcpy(ph->message, warning);
478 }
479
480
481 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
482
483 LaunchClosureWriter::LaunchClosureWriter(const ImageArray* images)
484 {
485 setContainerType(TypedBytes::Type::launchClosure);
486 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
487 }
488
489 const LaunchClosure* LaunchClosureWriter::finalize()
490 {
491 return (LaunchClosure*)finalizeContainer();
492 }
493
494 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum)
495 {
496 append(TypedBytes::Type::libSystemNum, &imageNum, sizeof(ImageNum));
497 }
498
499 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry)
500 {
501 append(TypedBytes::Type::libDyldEntry, &entry, sizeof(entry));
502 }
503
504 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main)
505 {
506 append(TypedBytes::Type::mainEntry, &main, sizeof(main));
507 }
508
509 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start)
510 {
511 append(TypedBytes::Type::startEntry, &start, sizeof(start));
512 }
513
514 void LaunchClosureWriter::setUsedFallbackPaths(bool value)
515 {
516 getFlags().usedFallbackPaths = value;
517 }
518
519 void LaunchClosureWriter::setUsedAtPaths(bool value)
520 {
521 getFlags().usedAtPaths = value;
522 }
523
524 void LaunchClosureWriter::setUsedInterposing(bool value)
525 {
526 getFlags().usedInterposing = value;
527 }
528
529 void LaunchClosureWriter::setHasInsertedLibraries(bool value)
530 {
531 getFlags().hasInsertedLibraries = value;
532 }
533
534 void LaunchClosureWriter::setInitImageCount(uint32_t count)
535 {
536 getFlags().initImageCount = count;
537 }
538
539 LaunchClosure::Flags& LaunchClosureWriter::getFlags()
540 {
541 if ( _flagsOffset == -1 ) {
542 LaunchClosure::Flags flags;
543 ::bzero(&flags, sizeof(flags));
544 uint8_t* p = (uint8_t*)append(TypedBytes::Type::closureFlags, &flags, sizeof(flags));
545 _flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
546 }
547 return *((LaunchClosure::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
548 }
549
550 void LaunchClosureWriter::setMustBeMissingFiles(const Array<const char*>& paths)
551 {
552 uint32_t totalSize = 0;
553 for (const char* s : paths)
554 totalSize += (strlen(s) +1);
555 totalSize = (totalSize + 3) & (-4); // align
556
557 char* buffer = (char*)append(TypedBytes::Type::missingFiles, nullptr, totalSize);
558 char* t = buffer;
559 for (const char* path : paths) {
560 for (const char* s=path; *s != '\0'; ++s)
561 *t++ = *s;
562 *t++ = '\0';
563 }
564 while (t < &buffer[totalSize])
565 *t++ = '\0';
566 }
567
568 void LaunchClosureWriter::setMustExistFiles(const Array<LaunchClosure::SkippedFile>& files)
569 {
570 // Start the structure with a count
571 uint32_t totalSize = sizeof(uint64_t);
572
573 // Then make space for the array of mod times and inode numbers
574 totalSize += files.count() * sizeof(uint64_t) * 2;
575
576 // Then the array of paths on the end
577 for (const LaunchClosure::SkippedFile& file : files)
578 totalSize += (strlen(file.path) + 1);
579 totalSize = (totalSize + 3) & (-4); // align
580
581 char* buffer = (char*)append(TypedBytes::Type::existingFiles, nullptr, totalSize);
582
583 // Set the size
584 uint64_t* bufferPtr = (uint64_t*)buffer;
585 *bufferPtr++ = (uint64_t)files.count();
586
587 // And the array of mod times and inode numbers
588 for (const LaunchClosure::SkippedFile& file : files) {
589 *bufferPtr++ = file.inode;
590 *bufferPtr++ = file.mtime;
591 }
592
593 char* t = (char*)bufferPtr;
594 for (const LaunchClosure::SkippedFile& file : files) {
595 for (const char* s=file.path; *s != '\0'; ++s)
596 *t++ = *s;
597 *t++ = '\0';
598 }
599 while (t < &buffer[totalSize])
600 *t++ = '\0';
601 }
602
603 void LaunchClosureWriter::addEnvVar(const char* envVar)
604 {
605 unsigned len = (unsigned)strlen(envVar);
606 char temp[len+8];
607 strcpy(temp, envVar);
608 unsigned paddedSize = len+1;
609 while ( (paddedSize % 4) != 0 )
610 temp[paddedSize++] = '\0';
611 append(TypedBytes::Type::envVar, temp, paddedSize);
612 }
613
614 void LaunchClosureWriter::addInterposingTuples(const Array<InterposingTuple>& tuples)
615 {
616 append(TypedBytes::Type::interposeTuples, tuples.begin(), (uint32_t)tuples.count()*sizeof(InterposingTuple));
617 }
618
619 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid)
620 {
621 append(TypedBytes::Type::dyldCacheUUID, uuid, sizeof(uuid_t));
622 }
623
624 void LaunchClosureWriter::setBootUUID(const char* uuid)
625 {
626 unsigned len = (unsigned)strlen(uuid);
627 char temp[len+8];
628 strcpy(temp, uuid);
629 unsigned paddedSize = len+1;
630 while ( (paddedSize % 4) != 0 )
631 temp[paddedSize++] = '\0';
632 append(TypedBytes::Type::bootUUID, temp, paddedSize);
633 }
634
635 void LaunchClosureWriter::setObjCSelectorInfo(const Array<uint8_t>& hashTable, const Array<Image::ObjCSelectorImage>& hashTableImages) {
636 uint32_t count = (uint32_t)hashTableImages.count();
637 uint32_t totalSize = (uint32_t)(sizeof(count) + (sizeof(Image::ObjCSelectorImage) * count) + hashTable.count());
638 totalSize = (totalSize + 3) & (-4); // align
639 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::selectorTable, nullptr, totalSize);
640
641 // Write out out the image count
642 memcpy(buffer, &count, sizeof(count));
643 buffer += sizeof(count);
644
645 // Write out out the image nums
646 memcpy(buffer, hashTableImages.begin(), sizeof(Image::ObjCSelectorImage) * count);
647 buffer += sizeof(Image::ObjCSelectorImage) * count;
648
649 // Write out out the image count
650 memcpy(buffer, hashTable.begin(), hashTable.count());
651 }
652
653 void LaunchClosureWriter::setObjCClassAndProtocolInfo(const Array<uint8_t>& classHashTable, const Array<uint8_t>& protocolHashTable,
654 const Array<Image::ObjCClassImage>& hashTableImages) {
655 // The layout here is:
656 // uint32_t offset to class table (note this is 0 if there are no classes)
657 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
658 // uint32_t num images
659 // ObjCClassImage[num images]
660 // class hash table
661 // [ padding to 4-byte alignment if needed
662 // protocol hash table
663 // [ padding to 4-byte alignment if needed
664
665 uint32_t numImages = (uint32_t)hashTableImages.count();
666
667 uint32_t headerSize = sizeof(uint32_t) * 3;
668 uint32_t imagesSize = (sizeof(Image::ObjCClassImage) * numImages);
669 uint32_t classTableSize = ((uint32_t)classHashTable.count() + 3) & (-4); // pad to 4-byte multiple
670 uint32_t protocolTableSize = ((uint32_t)protocolHashTable.count() + 3) & (-4); // pad to 4-byte multiple
671 uint32_t offsetToClassTable = (classTableSize == 0) ? 0 : (headerSize + imagesSize);
672 uint32_t offsetToProtocolTable = (protocolTableSize == 0) ? 0 : (headerSize + imagesSize + classTableSize);
673
674 uint32_t totalSize = headerSize + imagesSize + classTableSize + protocolTableSize;
675 assert( (totalSize & 3) == 0);
676 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::classTable, nullptr, totalSize);
677
678 // Write out out the header
679 memcpy(buffer + 0, &offsetToClassTable, sizeof(uint32_t));
680 memcpy(buffer + 4, &offsetToProtocolTable, sizeof(uint32_t));
681 memcpy(buffer + 8, &numImages, sizeof(uint32_t));
682
683 // Write out out the image nums
684 memcpy(buffer + headerSize, hashTableImages.begin(), imagesSize);
685
686 // Write out out the class hash table
687 if ( offsetToClassTable != 0 )
688 memcpy(buffer + offsetToClassTable, classHashTable.begin(), classHashTable.count());
689
690 // Write out out the protocol hash table
691 if ( offsetToProtocolTable != 0 )
692 memcpy(buffer + offsetToProtocolTable, protocolHashTable.begin(), protocolHashTable.count());
693 }
694
695 void LaunchClosureWriter::setObjCDuplicateClassesInfo(const Array<uint8_t>& hashTable) {
696 uint32_t totalSize = (uint32_t)hashTable.count();
697 totalSize = (totalSize + 3) & (-4); // align
698 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::duplicateClassesTable, nullptr, totalSize);
699
700 // Write out out the hash table
701 memcpy(buffer, hashTable.begin(), hashTable.count());
702 }
703
704 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
705
706 DlopenClosureWriter::DlopenClosureWriter(const ImageArray* images)
707 {
708 setContainerType(TypedBytes::Type::dlopenClosure);
709 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
710 }
711
712 const DlopenClosure* DlopenClosureWriter::finalize()
713 {
714 return (DlopenClosure*)finalizeContainer();
715 }
716
717
718 } // namespace closure
719 } // namespace dyld3
720
721
722