2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <uuid/uuid.h>
30 #include <mach/vm_page_size.h>
32 #include "ClosureWriter.h"
33 #include "MachOFile.h"
40 //////////////////////////// ContainerTypedBytesWriter ////////////////////////////////////////
43 void ContainerTypedBytesWriter::setContainerType(TypedBytes::Type containerType
)
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
);
57 void* ContainerTypedBytesWriter::append(TypedBytes::Type t
, const void* payload
, uint32_t payloadSize
)
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
;
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
;
88 const void* ContainerTypedBytesWriter::finalizeContainer()
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
);
97 _vmAllocationSize
= used
;
99 // mark vm region read-only
100 ::vm_protect(mach_task_self(), bufferStart
, used
, false, VM_PROT_READ
);
101 return (void*)_vmAllocationStart
;
104 const void* ContainerTypedBytesWriter::currentTypedBytes()
106 return (void*)_vmAllocationStart
;
109 void ContainerTypedBytesWriter::deallocate()
111 ::vm_deallocate(mach_task_self(), (long)_vmAllocationStart
, _vmAllocationSize
);
114 //////////////////////////// ImageWriter ////////////////////////////////////////
117 const Image
* ImageWriter::finalize()
119 return (Image
*)finalizeContainer();
122 const Image
* ImageWriter::currentImage()
124 return (Image
*)currentTypedBytes();
127 void ImageWriter::addPath(const char* path
)
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
);
135 Image::Flags
& ImageWriter::getFlags()
137 if ( _flagsOffset
== -1 ) {
138 setContainerType(TypedBytes::Type::image
);
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());
144 return *((Image::Flags
*)((uint8_t*)currentTypedBytes() + _flagsOffset
));
147 void ImageWriter::setImageNum(ImageNum num
)
149 getFlags().imageNum
= num
;
152 void ImageWriter::setHasObjC(bool value
)
154 getFlags().hasObjC
= value
;
157 void ImageWriter::setIs64(bool value
)
159 getFlags().is64
= value
;
162 void ImageWriter::setHasPlusLoads(bool value
)
164 getFlags().mayHavePlusLoads
= value
;
167 void ImageWriter::setIsBundle(bool value
)
169 getFlags().isBundle
= value
;
172 void ImageWriter::setIsDylib(bool value
)
174 getFlags().isDylib
= value
;
177 void ImageWriter::setIsExecutable(bool value
)
179 getFlags().isExecutable
= value
;
182 void ImageWriter::setHasWeakDefs(bool value
)
184 getFlags().hasWeakDefs
= value
;
187 void ImageWriter::setUses16KPages(bool value
)
189 getFlags().has16KBpages
= value
;
192 void ImageWriter::setOverridableDylib(bool value
)
194 getFlags().overridableDylib
= value
;
197 void ImageWriter::setInvalid()
199 getFlags().isInvalid
= true;
202 void ImageWriter::setInDyldCache(bool value
)
204 getFlags().inDyldCache
= value
;
207 void ImageWriter::setNeverUnload(bool value
)
209 getFlags().neverUnload
= value
;
212 void ImageWriter::setUUID(const uuid_t uuid
)
214 append(TypedBytes::Type::uuid
, uuid
, sizeof(uuid_t
));
217 void ImageWriter::setCDHash(const uint8_t cdHash
[20])
219 append(TypedBytes::Type::cdHash
, cdHash
, 20);
222 void ImageWriter::setDependents(const Array
<Image::LinkedImage
>& deps
)
224 append(TypedBytes::Type::dependents
, deps
.begin(), (uint32_t)deps
.count()*sizeof(Image::LinkedImage
));
227 void ImageWriter::setDofOffsets(const Array
<uint32_t>& dofSectionOffsets
)
229 append(TypedBytes::Type::dofOffsets
, &dofSectionOffsets
[0], (uint32_t)dofSectionOffsets
.count()*sizeof(uint32_t));
232 void ImageWriter::setInitOffsets(const uint32_t initOffsets
[], uint32_t count
)
234 append(TypedBytes::Type::initOffsets
, initOffsets
, count
*sizeof(uint32_t));
237 void ImageWriter::setDiskSegments(const Image::DiskSegment segs
[], uint32_t count
)
239 append(TypedBytes::Type::diskSegment
, segs
, count
*sizeof(Image::DiskSegment
));
242 void ImageWriter::setCachedSegments(const Image::DyldCacheSegment segs
[], uint32_t count
)
244 append(TypedBytes::Type::cacheSegment
, segs
, count
*sizeof(Image::DyldCacheSegment
));
247 void ImageWriter::setCodeSignatureLocation(uint32_t fileOffset
, uint32_t size
)
249 Image::CodeSignatureLocation loc
;
250 loc
.fileOffset
= fileOffset
;
252 append(TypedBytes::Type::codeSignLoc
, &loc
, sizeof(loc
));
255 void ImageWriter::setFairPlayEncryptionRange(uint32_t fileOffset
, uint32_t size
)
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
));
266 void ImageWriter::setMappingInfo(uint64_t sliceOffset
, uint64_t vmSize
)
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
));
275 void ImageWriter::setFileInfo(uint64_t inode
, uint64_t mTime
)
277 Image::FileInfo info
= { inode
, mTime
};
278 append(TypedBytes::Type::fileInodeAndTime
, &info
, sizeof(info
));
281 void ImageWriter::setRebaseInfo(const Array
<Image::RebasePattern
>& fixups
)
283 append(TypedBytes::Type::rebaseFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::RebasePattern
));
286 void ImageWriter::setTextRebaseInfo(const Array
<Image::TextFixupPattern
>& fixups
)
288 append(TypedBytes::Type::textFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::TextFixupPattern
));
291 void ImageWriter::setBindInfo(const Array
<Image::BindPattern
>& fixups
)
293 append(TypedBytes::Type::bindFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::BindPattern
));
296 void ImageWriter::setChainedFixups(const Array
<uint64_t>& starts
, const Array
<Image::ResolvedSymbolTarget
>& targets
)
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
));
302 void ImageWriter::addExportPatchInfo(uint32_t implCacheOff
, const char* name
, uint32_t locCount
, const Image::PatchableExport::PatchLocation
* locs
)
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
);
313 void ImageWriter::setAsOverrideOf(ImageNum imageNum
)
315 uint32_t temp
= imageNum
;
316 append(TypedBytes::Type::imageOverride
, &temp
, sizeof(temp
));
319 void ImageWriter::setInitsOrder(const ImageNum images
[], uint32_t count
)
321 append(TypedBytes::Type::initBefores
, images
, count
*sizeof(ImageNum
));
325 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
328 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum
, unsigned count
) : _index(0)
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
;
338 void ImageArrayWriter::appendImage(const Image
* image
)
340 ImageArray
* ia
= (ImageArray
*)_containerTypedBytes
;
341 ia
->offsets
[_index
++] = _containerTypedBytes
->payloadLength
;
342 append(TypedBytes::Type::image
, image
->payload(), image
->payloadLength
);
345 const ImageArray
* ImageArrayWriter::finalize()
347 return (ImageArray
*)finalizeContainer();
351 //////////////////////////// ClosureWriter ////////////////////////////////////////
353 void ClosureWriter::setTopImageNum(ImageNum imageNum
)
355 append(TypedBytes::Type::topImage
, &imageNum
, sizeof(ImageNum
));
358 void ClosureWriter::addCachePatches(const Array
<Closure::PatchEntry
>& patches
)
360 append(TypedBytes::Type::cacheOverrides
, patches
.begin(), (uint32_t)patches
.count()*sizeof(Closure::PatchEntry
));
364 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
366 LaunchClosureWriter::LaunchClosureWriter(const ImageArray
* images
)
368 setContainerType(TypedBytes::Type::launchClosure
);
369 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
372 const LaunchClosure
* LaunchClosureWriter::finalize()
374 return (LaunchClosure
*)finalizeContainer();
377 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum
)
379 append(TypedBytes::Type::libSystemNum
, &imageNum
, sizeof(ImageNum
));
382 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry
)
384 append(TypedBytes::Type::libDyldEntry
, &entry
, sizeof(entry
));
387 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main
)
389 append(TypedBytes::Type::mainEntry
, &main
, sizeof(main
));
392 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start
)
394 append(TypedBytes::Type::startEntry
, &start
, sizeof(start
));
397 void LaunchClosureWriter::setUsedFallbackPaths(bool value
)
399 getFlags().usedFallbackPaths
= value
;
402 void LaunchClosureWriter::setUsedAtPaths(bool value
)
404 getFlags().usedAtPaths
= value
;
407 void LaunchClosureWriter::setInitImageCount(uint32_t count
)
409 getFlags().initImageCount
= count
;
412 LaunchClosure::Flags
& LaunchClosureWriter::getFlags()
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());
420 return *((LaunchClosure::Flags
*)((uint8_t*)currentTypedBytes() + _flagsOffset
));
423 void LaunchClosureWriter::setMustBeMissingFiles(const Array
<const char*>& paths
)
425 uint32_t totalSize
= 0;
426 for (const char* s
: paths
)
427 totalSize
+= (strlen(s
) +1);
428 totalSize
= (totalSize
+ 3) & (-4); // align
430 char* buffer
= (char*)append(TypedBytes::Type::missingFiles
, nullptr, totalSize
);
432 for (const char* path
: paths
) {
433 for (const char* s
=path
; *s
!= '\0'; ++s
)
437 while (t
< &buffer
[totalSize
])
441 void LaunchClosureWriter::addEnvVar(const char* envVar
)
443 unsigned len
= (unsigned)strlen(envVar
);
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
);
452 void LaunchClosureWriter::addInterposingTuples(const Array
<InterposingTuple
>& tuples
)
454 append(TypedBytes::Type::interposeTuples
, tuples
.begin(), (uint32_t)tuples
.count()*sizeof(InterposingTuple
));
457 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid
)
459 append(TypedBytes::Type::dyldCacheUUID
, uuid
, sizeof(uuid_t
));
462 void LaunchClosureWriter::setBootUUID(const char* uuid
)
464 unsigned len
= (unsigned)strlen(uuid
);
467 unsigned paddedSize
= len
+1;
468 while ( (paddedSize
% 4) != 0 )
469 temp
[paddedSize
++] = '\0';
470 append(TypedBytes::Type::bootUUID
, temp
, paddedSize
);
473 void LaunchClosureWriter::applyInterposing()
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
;
486 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
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
;
498 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
500 DlopenClosureWriter::DlopenClosureWriter(const ImageArray
* images
)
502 setContainerType(TypedBytes::Type::dlopenClosure
);
503 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
506 const DlopenClosure
* DlopenClosureWriter::finalize()
508 return (DlopenClosure
*)finalizeContainer();
512 } // namespace closure