dyld-832.7.1.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::setFixupsNotEncoded()
316 {
317 getFlags().fixupsNotEncoded = true;
318 }
319
320 void ImageWriter::setRebasesNotEncoded()
321 {
322 getFlags().rebasesNotEncoded = true;
323 }
324
325 void ImageWriter::setChainedFixups(uint64_t runtimeStartsStructOffset, const Array<Image::ResolvedSymbolTarget>& targets)
326 {
327 getFlags().hasChainedFixups = true;
328 append(TypedBytes::Type::chainedStartsOffset, &runtimeStartsStructOffset, sizeof(uint64_t));
329 append(TypedBytes::Type::chainedFixupsTargets, targets.begin(), (uint32_t)targets.count()*sizeof(Image::ResolvedSymbolTarget));
330 }
331
332 void ImageWriter::setObjCFixupInfo(const Image::ResolvedSymbolTarget& objcProtocolClassTarget,
333 uint64_t objcImageInfoVMOffset,
334 const Array<Image::ProtocolISAFixup>& protocolISAFixups,
335 const Array<Image::SelectorReferenceFixup>& selRefFixups,
336 const Array<Image::ClassStableSwiftFixup>& classStableSwiftFixups,
337 const Array<Image::MethodListFixup>& methodListFixups)
338 {
339 // The layout here is:
340 // ResolvedSymbolTarget
341 // uint64_t vmOffset to objc_imageinfo
342 // uint32_t protocol count
343 // uint32_t selector reference count
344 // array of ProtocolISAFixup
345 // array of SelectorReferenceFixup
346 // optional uint32_t stable swift fixup count
347 // optional uint32_t method list fixup count
348 // optional array of ClassStableSwiftFixup
349 // optional array of MethodListFixup
350
351 uint64_t headerSize = sizeof(Image::ResolvedSymbolTarget) + sizeof(uint64_t) + (sizeof(uint32_t) * 4);
352 uint64_t protocolsSize = (sizeof(Image::ProtocolISAFixup) * protocolISAFixups.count());
353 uint64_t selRefsSize = (sizeof(Image::SelectorReferenceFixup) * selRefFixups.count());
354 uint64_t stableSwiftSize = (sizeof(Image::ClassStableSwiftFixup) * classStableSwiftFixups.count());
355 uint64_t methodListSize = (sizeof(Image::MethodListFixup) * methodListFixups.count());
356
357 uint64_t totalSize = headerSize + protocolsSize + selRefsSize + stableSwiftSize + methodListSize;
358 assert( (totalSize & 3) == 0);
359 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::objcFixups, nullptr, (uint32_t)totalSize);
360
361 // Set the statically sized data
362 uint32_t protocolFixupCount = (uint32_t)protocolISAFixups.count();
363 uint32_t selRefFixupCount = (uint32_t)selRefFixups.count();
364 memcpy(buffer, &objcProtocolClassTarget, sizeof(Image::ResolvedSymbolTarget));
365 buffer += sizeof(Image::ResolvedSymbolTarget);
366 memcpy(buffer, &objcImageInfoVMOffset, sizeof(uint64_t));
367 buffer += sizeof(uint64_t);
368 memcpy(buffer, &protocolFixupCount, sizeof(uint32_t));
369 buffer += sizeof(uint32_t);
370 memcpy(buffer, &selRefFixupCount, sizeof(uint32_t));
371 buffer += sizeof(uint32_t);
372
373 // Set the protocol fixups
374 if ( protocolFixupCount != 0 ) {
375 memcpy(buffer, protocolISAFixups.begin(), (size_t)protocolsSize);
376 buffer += protocolsSize;
377 }
378
379 // Set the selector reference fixups
380 if ( selRefFixupCount != 0 ) {
381 memcpy(buffer, selRefFixups.begin(), (size_t)selRefsSize);
382 buffer += selRefsSize;
383 }
384
385 // New closures get additional fixups. These are ignored by old dyld's
386 uint32_t stableSwiftFixupCount = (uint32_t)classStableSwiftFixups.count();
387 uint32_t methodListFixupCount = (uint32_t)methodListFixups.count();
388 memcpy(buffer, &stableSwiftFixupCount, sizeof(uint32_t));
389 buffer += sizeof(uint32_t);
390 memcpy(buffer, &methodListFixupCount, sizeof(uint32_t));
391 buffer += sizeof(uint32_t);
392
393 // Set the stable swift fixups
394 if ( stableSwiftFixupCount != 0 ) {
395 memcpy(buffer, classStableSwiftFixups.begin(), (size_t)stableSwiftSize);
396 buffer += stableSwiftSize;
397 }
398
399 // Set the method list fixups
400 if ( methodListFixupCount != 0 ) {
401 memcpy(buffer, methodListFixups.begin(), (size_t)methodListSize);
402 buffer += methodListSize;
403 }
404 }
405
406 void ImageWriter::setAsOverrideOf(ImageNum imageNum)
407 {
408 uint32_t temp = imageNum;
409 append(TypedBytes::Type::imageOverride, &temp, sizeof(temp));
410 getFlags().hasOverrideImageNum = true;
411 }
412
413 void ImageWriter::setInitsOrder(const ImageNum images[], uint32_t count)
414 {
415 append(TypedBytes::Type::initBefores, images, count*sizeof(ImageNum));
416 }
417
418
419 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
420
421
422 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum, unsigned count, bool hasRoots) : _index(0)
423 {
424 setContainerType(TypedBytes::Type::imageArray);
425 _end = (void*)((uint8_t*)_end + sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count);
426 _containerTypedBytes->payloadLength = sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count;
427 ImageArray* ia = (ImageArray*)_containerTypedBytes;
428 ia->firstImageNum = startImageNum;
429 ia->count = count;
430 ia->hasRoots = hasRoots;
431 }
432
433 void ImageArrayWriter::appendImage(const Image* image)
434 {
435 ImageArray* ia = (ImageArray*)_containerTypedBytes;
436 ia->offsets[_index++] = _containerTypedBytes->payloadLength;
437 append(TypedBytes::Type::image, image->payload(), image->payloadLength);
438 }
439
440 const ImageArray* ImageArrayWriter::finalize()
441 {
442 return (ImageArray*)finalizeContainer();
443 }
444
445
446 //////////////////////////// ClosureWriter ////////////////////////////////////////
447
448 void ClosureWriter::setTopImageNum(ImageNum imageNum)
449 {
450 append(TypedBytes::Type::topImage, &imageNum, sizeof(ImageNum));
451 }
452
453 void ClosureWriter::addCachePatches(const Array<Closure::PatchEntry>& patches)
454 {
455 append(TypedBytes::Type::cacheOverrides, patches.begin(), (uint32_t)patches.count()*sizeof(Closure::PatchEntry));
456 }
457
458 void ClosureWriter::applyInterposing(const LaunchClosure* launchClosure)
459 {
460 const Closure* currentClosure = (Closure*)currentTypedBytes();
461 const ImageArray* images = currentClosure->images();
462 launchClosure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool&) {
463 images->forEachImage(^(const dyld3::closure::Image* image, bool&) {
464 for (const Image::BindPattern& bindPat : image->bindFixups()) {
465 if ( (bindPat.target == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
466 Image::BindPattern* writePat = const_cast<Image::BindPattern*>(&bindPat);
467 writePat->target = tuple.newImplementation;
468 }
469 }
470
471 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
472 // the target list.
473 for (const Image::ResolvedSymbolTarget& symbolTarget : image->chainedTargets()) {
474 if ( (symbolTarget == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
475 Image::ResolvedSymbolTarget* writeTarget = const_cast<Image::ResolvedSymbolTarget*>(&symbolTarget);
476 *writeTarget = tuple.newImplementation;
477 }
478 }
479 });
480 });
481 }
482
483 void ClosureWriter::addWarning(Closure::Warning::Type warningType, const char* warning)
484 {
485 uint32_t roundedMessageLen = ((uint32_t)strlen(warning) + 1 + 3) & (-4);
486 Closure::Warning* ph = (Closure::Warning*)append(TypedBytes::Type::warning, nullptr, sizeof(Closure::Warning)+roundedMessageLen);
487 ph->type = warningType;
488 strcpy(ph->message, warning);
489 }
490
491
492 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
493
494 LaunchClosureWriter::LaunchClosureWriter(const ImageArray* images)
495 {
496 setContainerType(TypedBytes::Type::launchClosure);
497 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
498 }
499
500 const LaunchClosure* LaunchClosureWriter::finalize()
501 {
502 return (LaunchClosure*)finalizeContainer();
503 }
504
505 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum)
506 {
507 append(TypedBytes::Type::libSystemNum, &imageNum, sizeof(ImageNum));
508 }
509
510 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry)
511 {
512 append(TypedBytes::Type::libDyldEntry, &entry, sizeof(entry));
513 }
514
515 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main)
516 {
517 append(TypedBytes::Type::mainEntry, &main, sizeof(main));
518 }
519
520 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start)
521 {
522 append(TypedBytes::Type::startEntry, &start, sizeof(start));
523 }
524
525 void LaunchClosureWriter::setUsedFallbackPaths(bool value)
526 {
527 getFlags().usedFallbackPaths = value;
528 }
529
530 void LaunchClosureWriter::setUsedAtPaths(bool value)
531 {
532 getFlags().usedAtPaths = value;
533 }
534
535 void LaunchClosureWriter::setUsedInterposing(bool value)
536 {
537 getFlags().usedInterposing = value;
538 }
539
540 void LaunchClosureWriter::setHasInsertedLibraries(bool value)
541 {
542 getFlags().hasInsertedLibraries = value;
543 }
544
545 void LaunchClosureWriter::setInitImageCount(uint32_t count)
546 {
547 getFlags().initImageCount = count;
548 }
549
550 LaunchClosure::Flags& LaunchClosureWriter::getFlags()
551 {
552 if ( _flagsOffset == -1 ) {
553 LaunchClosure::Flags flags;
554 ::bzero(&flags, sizeof(flags));
555 uint8_t* p = (uint8_t*)append(TypedBytes::Type::closureFlags, &flags, sizeof(flags));
556 _flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
557 }
558 return *((LaunchClosure::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
559 }
560
561 void LaunchClosureWriter::setMustBeMissingFiles(const Array<const char*>& paths)
562 {
563 uint32_t totalSize = 0;
564 for (const char* s : paths)
565 totalSize += (strlen(s) +1);
566 totalSize = (totalSize + 3) & (-4); // align
567
568 char* buffer = (char*)append(TypedBytes::Type::missingFiles, nullptr, totalSize);
569 char* t = buffer;
570 for (const char* path : paths) {
571 for (const char* s=path; *s != '\0'; ++s)
572 *t++ = *s;
573 *t++ = '\0';
574 }
575 while (t < &buffer[totalSize])
576 *t++ = '\0';
577 }
578
579 void LaunchClosureWriter::setMustExistFiles(const Array<LaunchClosure::SkippedFile>& files)
580 {
581 // Start the structure with a count
582 uint32_t totalSize = sizeof(uint64_t);
583
584 // Then make space for the array of mod times and inode numbers
585 totalSize += files.count() * sizeof(uint64_t) * 2;
586
587 // Then the array of paths on the end
588 for (const LaunchClosure::SkippedFile& file : files)
589 totalSize += (strlen(file.path) + 1);
590 totalSize = (totalSize + 3) & (-4); // align
591
592 char* buffer = (char*)append(TypedBytes::Type::existingFiles, nullptr, totalSize);
593
594 // Set the size
595 uint64_t* bufferPtr = (uint64_t*)buffer;
596 *bufferPtr++ = (uint64_t)files.count();
597
598 // And the array of mod times and inode numbers
599 for (const LaunchClosure::SkippedFile& file : files) {
600 *bufferPtr++ = file.inode;
601 *bufferPtr++ = file.mtime;
602 }
603
604 char* t = (char*)bufferPtr;
605 for (const LaunchClosure::SkippedFile& file : files) {
606 for (const char* s=file.path; *s != '\0'; ++s)
607 *t++ = *s;
608 *t++ = '\0';
609 }
610 while (t < &buffer[totalSize])
611 *t++ = '\0';
612 }
613
614 void LaunchClosureWriter::addEnvVar(const char* envVar)
615 {
616 unsigned len = (unsigned)strlen(envVar);
617 char temp[len+8];
618 strcpy(temp, envVar);
619 unsigned paddedSize = len+1;
620 while ( (paddedSize % 4) != 0 )
621 temp[paddedSize++] = '\0';
622 append(TypedBytes::Type::envVar, temp, paddedSize);
623 }
624
625 void LaunchClosureWriter::addInterposingTuples(const Array<InterposingTuple>& tuples)
626 {
627 append(TypedBytes::Type::interposeTuples, tuples.begin(), (uint32_t)tuples.count()*sizeof(InterposingTuple));
628 }
629
630 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid)
631 {
632 append(TypedBytes::Type::dyldCacheUUID, uuid, sizeof(uuid_t));
633 }
634
635 void LaunchClosureWriter::setHasProgramVars(uint32_t offset)
636 {
637 getFlags().hasProgVars = true;
638 append(TypedBytes::Type::progVars, &offset, sizeof(uint32_t));
639 }
640
641 void LaunchClosureWriter::setObjCSelectorInfo(const Array<uint8_t>& hashTable, const Array<Image::ObjCSelectorImage>& hashTableImages) {
642 uint32_t count = (uint32_t)hashTableImages.count();
643 uint32_t totalSize = (uint32_t)(sizeof(count) + (sizeof(Image::ObjCSelectorImage) * count) + hashTable.count());
644 totalSize = (totalSize + 3) & (-4); // align
645 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::selectorTable, nullptr, totalSize);
646
647 // Write out out the image count
648 memcpy(buffer, &count, sizeof(count));
649 buffer += sizeof(count);
650
651 // Write out out the image nums
652 memcpy(buffer, hashTableImages.begin(), sizeof(Image::ObjCSelectorImage) * count);
653 buffer += sizeof(Image::ObjCSelectorImage) * count;
654
655 // Write out out the image count
656 memcpy(buffer, hashTable.begin(), hashTable.count());
657 }
658
659 void LaunchClosureWriter::setObjCClassAndProtocolInfo(const Array<uint8_t>& classHashTable, const Array<uint8_t>& protocolHashTable,
660 const Array<Image::ObjCClassImage>& hashTableImages) {
661 // The layout here is:
662 // uint32_t offset to class table (note this is 0 if there are no classes)
663 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
664 // uint32_t num images
665 // ObjCClassImage[num images]
666 // class hash table
667 // [ padding to 4-byte alignment if needed
668 // protocol hash table
669 // [ padding to 4-byte alignment if needed
670
671 uint32_t numImages = (uint32_t)hashTableImages.count();
672
673 uint32_t headerSize = sizeof(uint32_t) * 3;
674 uint32_t imagesSize = (sizeof(Image::ObjCClassImage) * numImages);
675 uint32_t classTableSize = ((uint32_t)classHashTable.count() + 3) & (-4); // pad to 4-byte multiple
676 uint32_t protocolTableSize = ((uint32_t)protocolHashTable.count() + 3) & (-4); // pad to 4-byte multiple
677 uint32_t offsetToClassTable = (classTableSize == 0) ? 0 : (headerSize + imagesSize);
678 uint32_t offsetToProtocolTable = (protocolTableSize == 0) ? 0 : (headerSize + imagesSize + classTableSize);
679
680 uint32_t totalSize = headerSize + imagesSize + classTableSize + protocolTableSize;
681 assert( (totalSize & 3) == 0);
682 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::classTable, nullptr, totalSize);
683
684 // Write out out the header
685 memcpy(buffer + 0, &offsetToClassTable, sizeof(uint32_t));
686 memcpy(buffer + 4, &offsetToProtocolTable, sizeof(uint32_t));
687 memcpy(buffer + 8, &numImages, sizeof(uint32_t));
688
689 // Write out out the image nums
690 memcpy(buffer + headerSize, hashTableImages.begin(), imagesSize);
691
692 // Write out out the class hash table
693 if ( offsetToClassTable != 0 )
694 memcpy(buffer + offsetToClassTable, classHashTable.begin(), classHashTable.count());
695
696 // Write out out the protocol hash table
697 if ( offsetToProtocolTable != 0 )
698 memcpy(buffer + offsetToProtocolTable, protocolHashTable.begin(), protocolHashTable.count());
699 }
700
701 void LaunchClosureWriter::setObjCDuplicateClassesInfo(const Array<uint8_t>& hashTable) {
702 uint32_t totalSize = (uint32_t)hashTable.count();
703 totalSize = (totalSize + 3) & (-4); // align
704 uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::duplicateClassesTable, nullptr, totalSize);
705
706 // Write out out the hash table
707 memcpy(buffer, hashTable.begin(), hashTable.count());
708 }
709
710 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
711
712 DlopenClosureWriter::DlopenClosureWriter(const ImageArray* images)
713 {
714 setContainerType(TypedBytes::Type::dlopenClosure);
715 append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
716 }
717
718 const DlopenClosure* DlopenClosureWriter::finalize()
719 {
720 return (DlopenClosure*)finalizeContainer();
721 }
722
723
724 } // namespace closure
725 } // namespace dyld3
726
727
728