]> git.saurik.com Git - apple/dyld.git/blob - dyld3/LaunchCacheReader.cpp
dyld-519.2.2.tar.gz
[apple/dyld.git] / dyld3 / LaunchCacheReader.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
31 #include "LaunchCacheFormat.h"
32 #include "LaunchCache.h"
33 #include "MachOParser.h"
34 #include "DyldCacheParser.h"
35
36 namespace dyld {
37 extern void log(const char* format, ...) __attribute__((format(printf, 1, 2)));
38 }
39
40 namespace dyld3 {
41 namespace launch_cache {
42
43 static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
44 {
45 uint64_t result = 0;
46 int bit = 0;
47 do {
48 if (p == end) {
49 assert("malformed uleb128");
50 break;
51 }
52 uint64_t slice = *p & 0x7f;
53
54 if (bit > 63) {
55 assert("uleb128 too big for uint64");
56 break;
57 }
58 else {
59 result |= (slice << bit);
60 bit += 7;
61 }
62 } while (*p++ & 0x80);
63 return (uintptr_t)result;
64 }
65
66
67 bool MemoryRange::contains(const MemoryRange& other) const
68 {
69 if ( this->address > other.address )
70 return false;
71 const uint8_t* thisEnd = (uint8_t*)address + size;
72 const uint8_t* otherEnd = (uint8_t*)other.address + other.size;
73 return (thisEnd >= otherEnd);
74 }
75
76 bool MemoryRange::intersects(const MemoryRange& other) const
77 {
78 const uint8_t* thisEnd = (uint8_t*)address + size;
79 const uint8_t* otherEnd = (uint8_t*)other.address + other.size;
80 if ( otherEnd < this->address )
81 return false;
82 return ( other.address < thisEnd );
83 }
84
85
86 //////////////////////////// SlowLoadSet ////////////////////////////////////////
87
88 bool SlowLoadSet::contains(const BinaryImageData* image)
89 {
90 for (const BinaryImageData** p=_start; p < _current; ++p) {
91 if ( *p == image )
92 return true;
93 }
94 return false;
95 }
96
97 bool SlowLoadSet::add(const BinaryImageData* image)
98 {
99 if ( _current < _end ) {
100 *_current++ = image;
101 return true;
102 }
103 return false;
104 }
105
106 void SlowLoadSet::forEach(void (^handler)(const BinaryImageData*))
107 {
108 for (const BinaryImageData** p=_start; p < _current; ++p) {
109 handler(*p);
110 }
111 }
112
113 void SlowLoadSet::forEach(void (^handler)(const BinaryImageData*, bool& stop))
114 {
115 bool stop = false;
116 for (const BinaryImageData** p=_start; p < _current; ++p) {
117 handler(*p, stop);
118 if ( stop )
119 break;
120 }
121 }
122
123
124 long SlowLoadSet::count() const
125 {
126 return (_current - _start);
127 }
128
129
130 //////////////////////////// TargetSymbolValue ////////////////////////////////////////
131
132
133 #if DYLD_IN_PROCESS
134
135 uintptr_t TargetSymbolValue::resolveTarget(Diagnostics& diag, const ImageGroup& inGroup, LoadedImages& images) const
136 {
137 // this block is only used if findExportedSymbol() needs to trace re-exported dylibs to find a symbol
138 MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
139 *foundMH = nullptr;
140 images.forEachImage(^(uint32_t idx, const BinaryImageData* binImage, const mach_header* mh, bool& stop) {
141 Image anImage(binImage);
142 if ( strcmp(depLoadPath, anImage.path()) == 0 ) {
143 *foundMH = mh;
144 stop = true;
145 }
146 });
147 return (*foundMH != nullptr);
148 };
149
150 uintptr_t offset;
151 switch ( _data.sharedCache.kind ) {
152
153 case TargetSymbolValue::kindSharedCache:
154 assert(_data.sharedCache.offsetIntoCache != 0);
155 return (uintptr_t)(images.dyldCacheLoadAddressForImage() + _data.sharedCache.offsetIntoCache);
156
157 case TargetSymbolValue::kindAbsolute:
158 offset = (uintptr_t)_data.absolute.value;
159 // sign extend 42 bit value
160 if ( offset & 0x2000000000000000ULL )
161 offset |= 0xC000000000000000ULL;
162 return offset;
163
164 case TargetSymbolValue::kindGroup: {
165 uint32_t groupNum = _data.group.isIndirectGroup ? inGroup.indirectGroupNum(_data.group.groupNum) : _data.group.groupNum;
166 uintptr_t targetImageLoadAddress = (uintptr_t)(images.loadAddressFromGroupAndIndex(groupNum, _data.group.indexInGroup));
167 if ( targetImageLoadAddress == 0 )
168 diag.error("image for groupNum=%d, indexInGroup=%d not found", groupNum, _data.group.indexInGroup);
169 offset = (uintptr_t)_data.group.offsetInImage;
170 // sign extend 42 bit offset
171 if ( offset & 0x0000020000000000ULL )
172 offset |= 0xFFFFFC0000000000ULL;
173 return targetImageLoadAddress + offset;
174 }
175
176 case TargetSymbolValue::kindDynamicGroup: {
177 const char* imagePath = inGroup.stringFromPool(_data.dynamicGroup.imagePathOffset);
178 const char* symbolName = inGroup.stringFromPool(_data.dynamicGroup.symbolNameOffset);
179 __block uintptr_t result = 0;
180 __block bool found = false;
181 if ( strcmp(imagePath, "@flat") == 0 ) {
182 // search all images in load order
183 images.forEachImage(^(uint32_t idx, const BinaryImageData* binImage, const mach_header* mh, bool& stop) {
184 Diagnostics findSymbolDiag;
185 dyld3::MachOParser parser(mh);
186 dyld3::MachOParser::FoundSymbol foundInfo;
187 if ( parser.findExportedSymbol(findSymbolDiag, symbolName, nullptr, foundInfo, ^(uint32_t, const char* depLoadPath, void*, const mach_header** foundMH, void**) {
188 // <rdar://problem/31921090> need to follow re-exported symbols to support libc renamed and reexported symbols
189 *foundMH = nullptr;
190 images.forEachImage(^(uint32_t innerIndex, const BinaryImageData* innerBinImage, const mach_header* innerMH, bool& innerStop) {
191 Image innerImage(innerBinImage);
192 if ( strcmp(depLoadPath, innerImage.path()) == 0 ) {
193 *foundMH = innerMH;
194 innerStop = true;
195 }
196 });
197 return (*foundMH != nullptr);
198 }) ) {
199 result = ((uintptr_t)(foundInfo.foundInDylib) + (uintptr_t)foundInfo.value);
200 images.setAsNeverUnload(idx);
201 found = true;
202 stop = true;
203 }
204 });
205 // <rdar://problem/31944092> bind unfound flat symbols to NULL to support lazy binding semantics
206 if ( !found ) {
207 result = 0;
208 found = true;
209 }
210 }
211 else if ( strcmp(imagePath, "@main") == 0 ) {
212 // search only main executable
213 images.forEachImage(^(uint32_t idx, const BinaryImageData* binImage, const mach_header* mh, bool& stop) {
214 if ( mh->filetype == MH_EXECUTE ) {
215 Diagnostics findSymbolDiag;
216 dyld3::MachOParser parser(mh);
217 dyld3::MachOParser::FoundSymbol foundInfo;
218 if ( parser.findExportedSymbol(findSymbolDiag, symbolName, nullptr, foundInfo, nullptr) ) {
219 result = ((uintptr_t)(foundInfo.foundInDylib) + (uintptr_t)foundInfo.value);
220 found = true;
221 stop = true;
222 }
223 }
224 });
225 }
226 else if ( strcmp(imagePath, "@weak_def") == 0 ) {
227 // search images with weak definitions in load order
228 images.forEachImage(^(uint32_t idx, const BinaryImageData* binImage, const mach_header* mh, bool& stop) {
229 Image anImage(binImage);
230 if ( anImage.hasWeakDefs() ) {
231 Diagnostics findSymbolDiag;
232 dyld3::MachOParser parser(mh);
233 dyld3::MachOParser::FoundSymbol foundInfo;
234 if ( parser.findExportedSymbol(findSymbolDiag, symbolName, nullptr, foundInfo, nullptr) ) {
235 result = ((uintptr_t)(foundInfo.foundInDylib) + (uintptr_t)foundInfo.value);
236 found = true;
237 images.setAsNeverUnload(idx);
238 stop = true;
239 }
240 }
241 });
242 }
243 else {
244 // search only image the matches supplied path
245 images.forEachImage(^(uint32_t idx, const BinaryImageData* binImage, const mach_header* mh, bool& stop) {
246 Image anImage(binImage);
247 if ( strcmp(anImage.path(), imagePath) == 0 ) {
248 Diagnostics findSymbolDiag;
249 dyld3::MachOParser parser(mh);
250 dyld3::MachOParser::FoundSymbol foundInfo;
251 if ( parser.findExportedSymbol(findSymbolDiag, symbolName, nullptr, foundInfo, reExportFollower) ) {
252 result = ((uintptr_t)(foundInfo.foundInDylib) + (uintptr_t)foundInfo.value);
253 found = true;
254 stop = true;
255 }
256 }
257 });
258 }
259 if ( found )
260 return result;
261 if ( _data.dynamicGroup.weakImport )
262 return 0;
263 diag.error("dynamic symbol '%s' not found for %s", symbolName, imagePath);
264 return 0;
265 }
266 }
267 assert(0 && "resolveTarget() not reachable");
268 }
269
270 #else
271
272 TargetSymbolValue::TargetSymbolValue()
273 {
274 _data.raw = 0;
275 }
276
277 TargetSymbolValue TargetSymbolValue::makeInvalid()
278 {
279 return TargetSymbolValue();
280 }
281
282 TargetSymbolValue TargetSymbolValue::makeSharedCacheOffset(uint32_t offset)
283 {
284 TargetSymbolValue t;
285 t._data.sharedCache.kind = kindSharedCache;
286 t._data.sharedCache.offsetIntoCache = offset;
287 return t;
288 }
289
290 TargetSymbolValue TargetSymbolValue::makeAbsolute(uint64_t value)
291 {
292 TargetSymbolValue t;
293 t._data.absolute.kind = kindAbsolute;
294 t._data.absolute.value = value;
295 return t;
296 }
297
298 TargetSymbolValue TargetSymbolValue::makeGroupValue(uint32_t groupIndex, uint32_t imageIndexInGroup, uint64_t offsetInImage, bool isIndirectGroupNum)
299 {
300 assert(groupIndex != 0 || isIndirectGroupNum);
301 assert(groupIndex < 128);
302 assert(imageIndexInGroup < 4096);
303 TargetSymbolValue t;
304 t._data.group.kind = kindGroup;
305 t._data.group.isIndirectGroup = isIndirectGroupNum;
306 t._data.group.groupNum = groupIndex;
307 t._data.group.indexInGroup = imageIndexInGroup;
308 t._data.group.offsetInImage = offsetInImage;
309 return t;
310 }
311
312 TargetSymbolValue TargetSymbolValue::makeDynamicGroupValue(uint32_t imagePathPoolOffset, uint32_t imageSymbolPoolOffset, bool weakImport)
313 {
314 TargetSymbolValue t;
315 t._data.dynamicGroup.kind = kindDynamicGroup;
316 t._data.dynamicGroup.weakImport = weakImport;
317 t._data.dynamicGroup.imagePathOffset = imagePathPoolOffset;
318 t._data.dynamicGroup.symbolNameOffset = imageSymbolPoolOffset;
319 return t;
320 }
321
322 bool TargetSymbolValue::isSharedCacheTarget(uint64_t& offsetInCache) const
323 {
324 if ( _data.sharedCache.kind != kindSharedCache )
325 return false;
326 offsetInCache = _data.sharedCache.offsetIntoCache;
327 return true;
328 }
329
330 bool TargetSymbolValue::isGroupImageTarget(uint32_t& groupNum, uint32_t& indexInGroup, uint64_t& offsetInImage) const
331 {
332 if ( _data.sharedCache.kind != kindGroup )
333 return false;
334 // This is only used for interposing, so refuse to allow indirect for group 2
335 assert(!_data.group.isIndirectGroup);
336 groupNum = _data.group.groupNum;
337 indexInGroup = _data.group.indexInGroup;
338 offsetInImage = _data.group.offsetInImage;
339 return true;
340 }
341
342 bool TargetSymbolValue::isInvalid() const
343 {
344 return (_data.raw == 0);
345 }
346
347 static std::string hex8(uint64_t value) {
348 char buff[64];
349 sprintf(buff, "0x%08llX", value);
350 return buff;
351 }
352
353 static std::string decimal(uint64_t value) {
354 char buff[64];
355 sprintf(buff, "%llu", value);
356 return buff;
357 }
358
359 std::string TargetSymbolValue::asString(ImageGroup group) const
360 {
361 int64_t offset;
362 switch ( _data.sharedCache.kind ) {
363 case kindSharedCache:
364 if ( _data.sharedCache.offsetIntoCache == 0 )
365 return "{invalid target}";
366 else
367 return "{cache+" + hex8(_data.sharedCache.offsetIntoCache) + "}";
368 case kindAbsolute:
369 offset = (uintptr_t)_data.absolute.value;
370 // sign extend 42 bit value
371 if ( offset & 0x2000000000000000ULL )
372 offset |= 0xC000000000000000ULL;
373 return "{absolute:" + hex8(offset) + "}";
374 case kindGroup:
375 offset = _data.group.offsetInImage;
376 // sign extend 42 bit offset
377 if ( offset & 0x0000020000000000ULL )
378 offset |= 0xFFFFFC0000000000ULL;
379 if ( _data.group.groupNum == 1 )
380 return "{otherDylib[" + decimal(_data.group.indexInGroup) +"]+" + hex8(offset) + "}";
381 if ( _data.group.groupNum == 2 )
382 return "{closure[" + decimal(_data.group.indexInGroup) +"]+" + hex8(offset) + "}";
383 else {
384 uint32_t groupNum = _data.group.isIndirectGroup ? group.indirectGroupNum(_data.group.groupNum) : _data.group.groupNum;
385 return "{dlopen-group-" + decimal(groupNum-2) + "[" + decimal(_data.group.indexInGroup) +"]+" + hex8(offset) + "}";
386 }
387 case kindDynamicGroup:
388 return "{dynamic image='" + std::string(group.stringFromPool(_data.dynamicGroup.imagePathOffset))
389 + "' symbol='" + std::string(group.stringFromPool(_data.dynamicGroup.symbolNameOffset)) + "'}";
390 }
391 assert(0 && "unreachable");
392 return "xx";
393 }
394
395 #endif
396
397 //////////////////////////// ImageRef ////////////////////////////////////////
398
399 binary_format::ImageRef binary_format::ImageRef::weakImportMissing()
400 {
401 ImageRef missing(0xFFFFFFFF);
402 return missing;
403 }
404
405
406
407 //////////////////////////// Closure ////////////////////////////////////////
408
409 Closure::Closure(const binary_format::Closure* closure)
410 : _binaryData(closure)
411 {
412 assert(closure->magic == binary_format::Closure::magicV1);
413 }
414
415 size_t Closure::size() const
416 {
417 return _binaryData->stringPoolOffset + _binaryData->stringPoolSize;
418 }
419
420 const ImageGroup Closure::group() const
421 {
422 return ImageGroup(&_binaryData->group);
423 }
424
425 void Closure::forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const
426 {
427 const uint32_t* envVarStringOffsets = (uint32_t*)((uint8_t*)_binaryData + _binaryData->dyldEnvVarsOffset);
428 const char* stringPool = (char*)_binaryData + _binaryData->stringPoolOffset;
429 bool stop = false;
430 for (uint32_t i=0; i < _binaryData->dyldEnvVarsCount; ++i) {
431 handler(&stringPool[envVarStringOffsets[i]], stop);
432 if ( stop )
433 break;
434 }
435 }
436
437 void Closure::forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const
438 {
439 const uint16_t* offsets = (uint16_t*)((uint8_t*)_binaryData + _binaryData->missingFileComponentsOffset);
440 if ( *offsets == 0 )
441 return;
442 const char* stringPool = (char*)_binaryData + _binaryData->stringPoolOffset;
443 bool stop = false;
444 while ( !stop ) {
445 char path[PATH_MAX];
446 path[0] = '\0';
447 while ( *offsets != 0 ) {
448 const char* component = &stringPool[*offsets++];
449 strlcat(path, "/", PATH_MAX);
450 strlcat(path, component, PATH_MAX);
451 }
452 handler(path, stop);
453 ++offsets; // move to next path
454 if ( *offsets == 0 ) // if no next path, then end of list of strings
455 stop = true;
456 }
457 }
458
459 const uuid_t* Closure::dyldCacheUUID() const
460 {
461 return &(_binaryData->dyldCacheUUID);
462 }
463
464
465 const uint8_t* Closure::cdHash() const
466 {
467 return _binaryData->mainExecutableCdHash;
468 }
469
470
471 uint32_t Closure::initialImageCount() const
472 {
473 return _binaryData->initialImageCount;
474 }
475
476
477 uint32_t Closure::mainExecutableImageIndex() const
478 {
479 return _binaryData->mainExecutableIndexInGroup;
480 }
481
482
483 uint32_t Closure::mainExecutableEntryOffset() const
484 {
485 return _binaryData->mainExecutableEntryOffset;
486 }
487
488 bool Closure::mainExecutableUsesCRT() const
489 {
490 return _binaryData->usesCRT;
491 }
492
493 bool Closure::isRestricted() const
494 {
495 return _binaryData->isRestricted;
496 }
497
498 bool Closure::usesLibraryValidation() const
499 {
500 return _binaryData->usesLibraryValidation;
501 }
502
503 uint32_t Closure::libdyldVectorOffset() const
504 {
505 return _binaryData->libdyldVectorOffset;
506 }
507
508 const BinaryImageData* Closure::libSystem(const ImageGroupList& groups)
509 {
510 return Image::resolveImageRef(groups, _binaryData->libSystemRef).binaryData();
511 }
512
513 const BinaryImageData* Closure::libDyld(const ImageGroupList& groups)
514 {
515 return Image::resolveImageRef(groups, _binaryData->libDyldRef).binaryData();
516 }
517
518
519 //////////////////////////// ImageGroup ////////////////////////////////////////
520
521 size_t ImageGroup::size() const
522 {
523 return (_binaryData->stringsPoolOffset + _binaryData->stringsPoolSize + 3) & (-4);
524 }
525
526 uint32_t ImageGroup::groupNum() const
527 {
528 return _binaryData->groupNum;
529 }
530
531 bool ImageGroup::dylibsExpectedOnDisk() const
532 {
533 return _binaryData->dylibsExpectedOnDisk;
534 }
535
536 uint32_t ImageGroup::imageCount() const
537 {
538 return _binaryData->imagesPoolCount;
539 }
540
541 const binary_format::Image* ImageGroup::imageBinary(uint32_t index) const
542 {
543 assert(index <_binaryData->imagesPoolCount);
544 return (binary_format::Image*)((char*)_binaryData + _binaryData->imagesPoolOffset + (index * _binaryData->imagesEntrySize));
545 }
546
547
548 const Image ImageGroup::image(uint32_t index) const
549 {
550 return Image(imageBinary(index));
551 }
552
553 uint32_t ImageGroup::indexInGroup(const binary_format::Image* img) const
554 {
555 long delta = (char*)img - ((char*)_binaryData + _binaryData->imagesPoolOffset);
556 uint32_t index = (uint32_t)(delta /_binaryData->imagesEntrySize);
557 assert(image(index)._binaryData == img);
558 return index;
559 }
560
561 const binary_format::Image* ImageGroup::findImageByPath(const char* path, uint32_t& foundIndex) const
562 {
563 // check path of each image in group
564 uint32_t targetHash = hashFunction(path);
565 const uint8_t* p = (uint8_t*)_binaryData + _binaryData->imagesPoolOffset;
566 for (uint32_t i=0; i < _binaryData->imagesPoolCount; ++i) {
567 const binary_format::Image* binImage = (binary_format::Image*)p;
568 if ( binImage->pathHash == targetHash ) {
569 Image img(binImage);
570 if ( !img.isInvalid() && (strcmp(img.path(), path) == 0) ) {
571 foundIndex = i;
572 return binImage;
573 }
574 }
575 p += _binaryData->imagesEntrySize;
576 }
577 // check each alias
578 const binary_format::AliasEntry* aliasEntries = (binary_format::AliasEntry*)((uint8_t*)_binaryData + _binaryData->imageAliasOffset);
579 for (uint32_t i=0; i < _binaryData->imageAliasCount; ++i) {
580 const char* aliasPath = stringFromPool(aliasEntries[i].aliasOffsetInStringPool);
581 if ( aliasEntries[i].aliasHash == targetHash ) {
582 if ( strcmp(aliasPath, path) == 0 ) {
583 Image img = image(aliasEntries[i].imageIndexInGroup);
584 if ( !img.isInvalid() ) {
585 foundIndex = aliasEntries[i].imageIndexInGroup;
586 return img.binaryData();
587 }
588 }
589 }
590 }
591 return nullptr;
592 }
593
594 const binary_format::Image* ImageGroup::findImageByCacheOffset(size_t cacheVmOffset, uint32_t& mhCacheOffset, uint8_t& foundPermissions) const
595 {
596 assert(groupNum() == 0);
597
598 const binary_format::DyldCacheSegment* cacheSegs = (binary_format::DyldCacheSegment*)segmentPool(0);
599 const binary_format::Image* image = (binary_format::Image*)((char*)_binaryData + _binaryData->imagesPoolOffset);
600 // most address lookups are in TEXT, so just search first segment in first pass
601 for (uint32_t imageIndex=0; imageIndex < _binaryData->imagesPoolCount; ++imageIndex) {
602 const binary_format::DyldCacheSegment* segInfo = &cacheSegs[image->segmentsArrayStartIndex];
603 if ( (cacheVmOffset >= segInfo->cacheOffset) && (cacheVmOffset < (segInfo->cacheOffset + segInfo->size)) ) {
604 mhCacheOffset = segInfo->cacheOffset;
605 foundPermissions = segInfo->permissions;
606 return image;
607 }
608 image = (binary_format::Image*)((char*)image + _binaryData->imagesEntrySize);
609 }
610 // second pass, skip TEXT segment
611 image = (binary_format::Image*)((char*)_binaryData + _binaryData->imagesPoolOffset);
612 for (uint32_t imageIndex=0; imageIndex < _binaryData->imagesPoolCount; ++imageIndex) {
613 for (uint32_t segIndex=1; segIndex < image->segmentsArrayCount; ++segIndex) {
614 const binary_format::DyldCacheSegment* segInfo = &cacheSegs[image->segmentsArrayStartIndex+segIndex];
615 if ( (cacheVmOffset >= segInfo->cacheOffset) && (cacheVmOffset < (segInfo->cacheOffset + segInfo->size)) ) {
616 mhCacheOffset = cacheSegs[image->segmentsArrayStartIndex].cacheOffset;
617 foundPermissions = segInfo->permissions;
618 return image;
619 }
620 }
621 image = (binary_format::Image*)((char*)image + _binaryData->imagesEntrySize);
622 }
623 return nullptr;
624 }
625
626 void ImageGroup::forEachAliasOf(uint32_t imageIndex, void (^handler)(const char* aliasPath, uint32_t aliasPathHash, bool& stop)) const
627 {
628 bool stop = false;
629 const binary_format::AliasEntry* aliasEntries = (binary_format::AliasEntry*)((uint8_t*)_binaryData + _binaryData->imageAliasOffset);
630 for (uint32_t i=0; i < _binaryData->imageAliasCount; ++i) {
631 if ( aliasEntries[i].imageIndexInGroup == imageIndex ) {
632 const char* aliasPath = stringFromPool(aliasEntries[i].aliasOffsetInStringPool);
633 handler(aliasPath, aliasEntries[i].aliasHash, stop);
634 if ( stop )
635 break;
636 }
637 }
638 }
639
640 const char* ImageGroup::stringPool() const
641 {
642 return (char*)_binaryData + _binaryData->stringsPoolOffset;
643 }
644
645 const char* ImageGroup::stringFromPool(uint32_t offset) const
646 {
647 assert(offset < _binaryData->stringsPoolSize);
648 return (char*)_binaryData + _binaryData->stringsPoolOffset + offset;
649 }
650
651 uint32_t ImageGroup::stringPoolSize() const
652 {
653 return _binaryData->stringsPoolSize;;
654 }
655
656 binary_format::ImageRef ImageGroup::dependentPool(uint32_t index) const
657 {
658 assert(index < _binaryData->dependentsPoolCount);
659 const binary_format::ImageRef* depArray = (binary_format::ImageRef*)((char*)_binaryData + _binaryData->dependentsPoolOffset);
660 return depArray[index];
661 }
662
663 const uint64_t* ImageGroup::segmentPool(uint32_t index) const
664 {
665 assert(index < _binaryData->segmentsPoolCount);
666 const uint64_t* segArray = (uint64_t*)((char*)_binaryData + _binaryData->segmentsPoolOffset);
667 return &segArray[index];
668 }
669
670
671 const uint32_t* ImageGroup::initializerOffsetsPool() const
672 {
673 return (uint32_t*)((char*)_binaryData + _binaryData->intializerOffsetPoolOffset);
674 }
675
676 const uint32_t ImageGroup::initializerOffsetsCount() const
677 {
678 return _binaryData->intializerOffsetPoolCount;
679 }
680
681 const binary_format::ImageRef* ImageGroup::intializerListPool() const
682 {
683 return (binary_format::ImageRef*)((char*)_binaryData + _binaryData->intializerListPoolOffset);
684 }
685
686 const uint32_t ImageGroup::intializerListPoolCount() const
687 {
688 return _binaryData->intializerListPoolCount;
689 }
690
691 const binary_format::AllFixupsBySegment* ImageGroup::fixUps(uint32_t offset) const
692 {
693 return (binary_format::AllFixupsBySegment*)((char*)_binaryData + _binaryData->fixupsOffset + offset);
694 }
695
696 const TargetSymbolValue* ImageGroup::targetValuesArray() const
697 {
698 return (TargetSymbolValue*)((char*)_binaryData + _binaryData->targetsOffset);
699 }
700
701 uint32_t ImageGroup::targetValuesCount() const
702 {
703 return _binaryData->targetsPoolCount;
704 }
705
706
707 const uint32_t* ImageGroup::dofOffsetsPool() const
708 {
709 return (uint32_t*)((char*)_binaryData + _binaryData->dofOffsetPoolOffset);
710 }
711
712 const uint32_t ImageGroup::dofOffsetsCount() const
713 {
714 return _binaryData->dofOffsetPoolCount;
715 }
716
717
718 const uint32_t* ImageGroup::indirectGroupNumsPool() const
719 {
720 return (uint32_t*)((char*)_binaryData + _binaryData->indirectGroupNumPoolOffset);
721 }
722
723 const uint32_t ImageGroup::indirectGroupNumsCount() const
724 {
725 return _binaryData->indirectGroupNumPoolCount;
726 }
727
728 uint32_t ImageGroup::indirectGroupNum(uint32_t offset) const
729 {
730 assert(offset < _binaryData->indirectGroupNumPoolCount);
731 return indirectGroupNumsPool()[offset];
732 }
733
734 uint32_t ImageGroup::hashFunction(const char* str)
735 {
736 uint32_t h = 0;
737 for (const char* s=str; *s != '\0'; ++s)
738 h = h*5 + *s;
739 return h;
740 }
741
742
743 void ImageGroup::forEachDyldCachePatch(uint32_t patchTargetIndex, uint32_t cacheDataVmOffset, void (^handler)(uint32_t targetCacheOffset, uint32_t usePointersCacheOffset, bool hasAddend, bool& stop)) const
744 {
745 assert(_binaryData->imagesEntrySize == sizeof(binary_format::CachedImage) && "only callable on group-0 in shared cache");
746 assert(patchTargetIndex < _binaryData->cachePatchTableCount);
747 const binary_format::PatchTable* patches = (binary_format::PatchTable*)((char*)_binaryData + _binaryData->cachePatchTableOffset);
748 uint32_t offsetsIndex = patches[patchTargetIndex].offsetsStartIndex;
749 uint32_t targetCacheOffset = patches[patchTargetIndex].targetCacheOffset;
750 const binary_format::PatchOffset* patchLocationOffsets = (binary_format::PatchOffset*)((char*)_binaryData + _binaryData->cachePatchOffsetsOffset);
751 bool stop = false;
752 while ( !stop ) {
753 assert(offsetsIndex < _binaryData->cachePatchOffsetsCount);
754 binary_format::PatchOffset entry = patchLocationOffsets[offsetsIndex];
755 ++offsetsIndex;
756 handler(targetCacheOffset, cacheDataVmOffset+entry.dataRegionOffset, entry.hasAddend, stop);
757 if ( entry.last )
758 stop = true;
759 }
760 }
761
762 void ImageGroup::forEachImageRefOverride(void (^handler)(binary_format::ImageRef standardDylibRef, binary_format::ImageRef overrideDylibRef, bool& stop)) const
763 {
764 bool stop = false;
765 const binary_format::ImageRefOverride* entries = (binary_format::ImageRefOverride*)((char*)_binaryData + _binaryData->imageOverrideTableOffset);
766 for (uint32_t i=0; (i < _binaryData->imageOverrideTableCount) && !stop; ++i) {
767 handler(entries[i].standardDylib, entries[i].overrideDylib, stop);
768 }
769 }
770
771 void ImageGroup::forEachImageRefOverride(const ImageGroupList& groupList, void (^handler)(Image standardDylib, Image overrideDylib, bool& stop)) const
772 {
773 forEachImageRefOverride(^(binary_format::ImageRef standardDylibRef, binary_format::ImageRef overrideDylibRef, bool& stop) {
774 Image standardDylib = Image::resolveImageRef(groupList, standardDylibRef, false);
775 Image overrideDylib = Image::resolveImageRef(groupList, overrideDylibRef, false);
776 handler(standardDylib, overrideDylib, stop);
777 });
778 }
779
780
781 #if DYLD_IN_PROCESS
782
783 void ImageGroup::forEachDyldCachePatchLocation(const void* dyldCacheLoadAddress, uint32_t patchTargetIndex, void (^handler)(uintptr_t* locationToPatch, uintptr_t addend, bool&)) const
784 {
785 DyldCacheParser cacheParser((DyldSharedCache*)dyldCacheLoadAddress, false);
786 uint32_t cacheDataVmOffset = (uint32_t)cacheParser.dataRegionRuntimeVmOffset();
787 forEachDyldCachePatch(patchTargetIndex, cacheDataVmOffset, ^(uint32_t targetCacheOffset, uint32_t usePointersCacheOffset, bool hasAddend, bool& stop) {
788 uintptr_t addend = 0;
789 uintptr_t* fixupLoc = (uintptr_t*)((char*)dyldCacheLoadAddress + usePointersCacheOffset);
790 if ( hasAddend ) {
791 uintptr_t currentValue = *fixupLoc;
792 uintptr_t expectedValue = (uintptr_t)dyldCacheLoadAddress + targetCacheOffset;
793 uintptr_t delta = currentValue - expectedValue;
794 assert(delta < 32);
795 addend = delta;
796 }
797 handler(fixupLoc, addend, stop);
798 });
799 }
800
801 void ImageGroup::forEachDyldCacheSymbolOverride(void (^handler)(uint32_t patchTableIndex, const BinaryImageData* image, uint32_t imageOffset, bool& stop)) const
802 {
803 bool stop = false;
804 const binary_format::DyldCacheOverride* entries = (binary_format::DyldCacheOverride*)((char*)_binaryData + _binaryData->symbolOverrideTableOffset);
805 for (uint32_t i=0; (i < _binaryData->symbolOverrideTableCount) && !stop; ++i) {
806 handler(entries[i].patchTableIndex, imageBinary(entries[i].imageIndex), entries[i].imageOffset, stop);
807 }
808 }
809
810 #else
811
812 void ImageGroup::forEachDyldCacheSymbolOverride(void (^handler)(uint32_t patchTableIndex, uint32_t imageIndexInClosure, uint32_t imageOffset, bool& stop)) const
813 {
814 bool stop = false;
815 const binary_format::DyldCacheOverride* entries = (binary_format::DyldCacheOverride*)((char*)_binaryData + _binaryData->symbolOverrideTableOffset);
816 for (uint32_t i=0; (i < _binaryData->symbolOverrideTableCount) && !stop; ++i) {
817 handler(entries[i].patchTableIndex, entries[i].imageIndex, entries[i].imageOffset, stop);
818 }
819 }
820
821 void ImageGroup::forEachDyldCachePatchLocation(const DyldCacheParser& cacheParser, void (^handler)(uint32_t targetCacheOffset, const std::vector<uint32_t>& usesPointersCacheOffsets, bool& stop)) const
822 {
823 uint32_t cacheDataVmOffset = (uint32_t)cacheParser.dataRegionRuntimeVmOffset();
824 __block std::vector<uint32_t> pointerCacheOffsets;
825 bool stop = false;
826 for (uint32_t patchIndex=0; patchIndex < _binaryData->cachePatchTableCount; ++patchIndex) {
827 pointerCacheOffsets.clear();
828 __block uint32_t targetCacheOffset = 0;
829 forEachDyldCachePatch(patchIndex, cacheDataVmOffset, ^(uint32_t targetCacheOff, uint32_t usePointersCacheOffset, bool hasAddend, bool&) {
830 targetCacheOffset = targetCacheOff;
831 pointerCacheOffsets.push_back(usePointersCacheOffset);
832 });
833 std::sort(pointerCacheOffsets.begin(), pointerCacheOffsets.end(), [&](uint32_t a, uint32_t b) { return a < b; });
834 handler(targetCacheOffset, pointerCacheOffsets, stop);
835 if ( stop )
836 break;
837 }
838 }
839
840 bool ImageGroup::hasPatchTableIndex(uint32_t targetCacheOffset, uint32_t& foundIndex) const
841 {
842 const binary_format::PatchTable* patches = (binary_format::PatchTable*)((char*)_binaryData + _binaryData->cachePatchTableOffset);
843 for (uint32_t i=0; i < _binaryData->cachePatchTableCount; ++i) {
844 if ( patches[i].targetCacheOffset == targetCacheOffset ) {
845 foundIndex = i;
846 return true;
847 }
848 }
849 return false;
850 }
851
852 #endif
853
854
855 //////////////////////////// Image ////////////////////////////////////////
856
857
858
859 const ImageGroup Image::group() const
860 {
861 return ImageGroup((binary_format::ImageGroup*)(((char*)_binaryData) + (_binaryData->groupOffset)));
862 }
863
864 uint32_t Image::maxLoadCount() const
865 {
866 return _binaryData->maxLoadCount;
867 }
868
869 const char* Image::path() const
870 {
871 return group().stringFromPool(_binaryData->pathPoolOffset);
872 }
873
874 uint32_t Image::pathHash() const
875 {
876 return _binaryData->pathHash;
877 }
878
879 const char* Image::leafName() const
880 {
881 const char* path = group().stringFromPool(_binaryData->pathPoolOffset);
882 const char* lastSlash = strrchr(path, '/');
883 if ( lastSlash != nullptr )
884 return lastSlash+1;
885 else
886 return path;
887 }
888
889 const uuid_t* Image::uuid() const
890 {
891 return &(_binaryData->uuid);
892 }
893
894 bool Image::isInvalid() const
895 {
896 return (_binaryData == nullptr) || _binaryData->isInvalid;
897 }
898
899 bool Image::hasObjC() const
900 {
901 return _binaryData->hasObjC;
902 }
903
904 bool Image::isBundle() const
905 {
906 return _binaryData->isBundle;
907 }
908
909 bool Image::hasWeakDefs() const
910 {
911 return _binaryData->hasWeakDefs;
912 }
913
914 bool Image::mayHavePlusLoads() const
915 {
916 return _binaryData->mayHavePlusLoads;
917 }
918
919 bool Image::hasTextRelocs() const
920 {
921 return _binaryData->hasTextRelocs;
922 }
923
924 bool Image::neverUnload() const
925 {
926 return _binaryData->neverUnload;
927 }
928
929 bool Image::cwdMustBeThisDir() const
930 {
931 return _binaryData->cwdSameAsThis;
932 }
933
934 bool Image::isPlatformBinary() const
935 {
936 return _binaryData->isPlatformBinary;
937 }
938
939 bool Image::overridableDylib() const
940 {
941 return _binaryData->overridableDylib;
942 }
943
944 void Image::forEachDependentImage(const ImageGroupList& groups, void (^handler)(uint32_t depIndex, Image depImage, LinkKind kind, bool& stop)) const
945 {
946 assert(!_binaryData->isInvalid);
947 binary_format::ImageRef missingRef = binary_format::ImageRef::weakImportMissing();
948 __block bool stop = false;
949 for (uint32_t depIndex=0; (depIndex < _binaryData->dependentsArrayCount) && !stop; ++depIndex) {
950 binary_format::ImageRef ref = group().dependentPool(_binaryData->dependentsArrayStartIndex + depIndex);
951 if ( ref != missingRef ) {
952 Image depImage(resolveImageRef(groups, ref));
953 handler(depIndex, depImage, (LinkKind)ref.kind(), stop);
954 }
955 }
956 }
957
958
959 #if !DYLD_IN_PROCESS
960 bool Image::recurseAllDependentImages(const ImageGroupList& groups, std::unordered_set<const BinaryImageData*>& allDependents) const
961 {
962 if ( isInvalid() )
963 return false;
964 __block bool result = true;
965 forEachDependentImage(groups, ^(uint32_t depIndex, Image depImage, LinkKind kind, bool& stop) {
966 if ( allDependents.count(depImage.binaryData()) == 0 ) {
967 allDependents.insert(depImage.binaryData());
968 if ( !depImage.recurseAllDependentImages(groups, allDependents) ) {
969 result = false;
970 stop = true;
971 }
972 }
973 });
974 return result;
975 }
976 #endif
977
978 bool Image::recurseAllDependentImages(const ImageGroupList& groups, SlowLoadSet& allDependents, bool& stopped,
979 void (^handler)(const dyld3::launch_cache::binary_format::Image* aBinImage, bool& stop)) const
980 {
981 __block bool result = true;
982 // breadth first, add all directly dependent images
983 const dyld3::launch_cache::binary_format::Image* needToProcessArray[_binaryData->dependentsArrayCount];
984 memset((void*)needToProcessArray, 0, _binaryData->dependentsArrayCount * sizeof(*needToProcessArray));
985 const dyld3::launch_cache::binary_format::Image** const needToProcess = needToProcessArray;
986 forEachDependentImage(groups, ^(uint32_t depIndex, Image depImage, LinkKind kind, bool& stop) {
987 const dyld3::launch_cache::binary_format::Image* depImageData = depImage.binaryData();
988 if ( allDependents.contains(depImageData) ) {
989 needToProcess[depIndex] = nullptr;
990 }
991 else {
992 needToProcess[depIndex] = depImageData;
993 if ( !allDependents.add(depImageData) ) {
994 result = false;
995 stop = true;
996 return;
997 }
998 if (handler) {
999 handler(depImageData, stop);
1000 if ( stop )
1001 stopped = true;
1002 }
1003 }
1004 });
1005
1006 // recurse on each dependent image
1007 for (int i=0; !stopped && (i < _binaryData->dependentsArrayCount); ++i) {
1008 if ( const dyld3::launch_cache::binary_format::Image* depImageData = needToProcess[i] ) {
1009 Image depImage(depImageData);
1010 if ( !depImage.recurseAllDependentImages(groups, allDependents, stopped, handler) ) {
1011 return false;
1012 }
1013 }
1014 }
1015
1016 return result;
1017 }
1018
1019 bool Image::recurseAllDependentImages(const ImageGroupList& groups, SlowLoadSet& allDependents,
1020 void (^handler)(const dyld3::launch_cache::binary_format::Image* aBinImage, bool& stop)) const
1021 {
1022 bool stopped = false;
1023 return recurseAllDependentImages(groups, allDependents, stopped, handler);
1024 }
1025
1026 void Image::forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const
1027 {
1028 assert(isDiskImage());
1029 const uint32_t pageSize = (_binaryData->has16KBpages ? 0x4000 : 0x1000);
1030 const uint64_t* rawSegs = group().segmentPool(_binaryData->segmentsArrayStartIndex);
1031 const binary_format::DiskSegment* diskSegs = (binary_format::DiskSegment*)rawSegs;
1032 uint32_t segIndex = 0;
1033 uint32_t fileOffset = 0;
1034 int64_t vmOffset = 0;
1035 // decrement vmOffset by all segments before TEXT (e.g. PAGEZERO)
1036 for (uint32_t i=0; i < _binaryData->segmentsArrayCount; ++i) {
1037 const binary_format::DiskSegment* seg = &diskSegs[i];
1038 if ( seg->filePageCount != 0 ) {
1039 break;
1040 }
1041 vmOffset -= (uint64_t)seg->vmPageCount * pageSize;
1042 }
1043 // walk each segment and call handler
1044 for (uint32_t i=0; i < _binaryData->segmentsArrayCount; ++i) {
1045 const binary_format::DiskSegment* seg = &diskSegs[i];
1046 uint64_t vmSize = (uint64_t)seg->vmPageCount * pageSize;
1047 uint32_t fileSize = seg->filePageCount * pageSize;
1048 if ( !seg->paddingNotSeg ) {
1049 bool stop = false;
1050 handler(segIndex, ( fileSize == 0) ? 0 : fileOffset, fileSize, vmOffset, vmSize, seg->permissions, stop);
1051 ++segIndex;
1052 if ( stop )
1053 break;
1054 }
1055 vmOffset += vmSize;
1056 fileOffset += fileSize;
1057 }
1058 }
1059
1060 void Image::forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const
1061 {
1062 assert(!isDiskImage());
1063 const uint64_t* rawSegs = group().segmentPool(_binaryData->segmentsArrayStartIndex);
1064 const binary_format::DyldCacheSegment* cacheSegs = (binary_format::DyldCacheSegment*)rawSegs;
1065 bool stop = false;
1066 for (uint32_t i=0; i < _binaryData->segmentsArrayCount; ++i) {
1067 uint64_t vmOffset = cacheSegs[i].cacheOffset - cacheSegs[0].cacheOffset;
1068 uint64_t vmSize = cacheSegs[i].size;
1069 uint8_t permissions = cacheSegs[i].permissions;
1070 handler(i, vmOffset, vmSize, permissions, stop);
1071 if ( stop )
1072 break;
1073 }
1074 }
1075
1076 bool Image::segmentHasFixups(uint32_t segIndex) const
1077 {
1078 return (segmentFixups(segIndex) != nullptr);
1079 }
1080
1081 bool Image::containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions) const
1082 {
1083 if ( addr < imageLoadAddress )
1084 return false;
1085
1086 __block bool found = false;
1087 uint64_t offsetInImage = (char*)addr - (char*)imageLoadAddress;
1088 if ( _binaryData->isDiskImage ) {
1089 forEachDiskSegment(^(uint32_t segIterIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t segPerms, bool& stop) {
1090 if ( (offsetInImage >= vmOffset) && (offsetInImage < vmOffset+vmSize) ) {
1091 if ( permissions != nullptr )
1092 *permissions = segPerms;
1093 found = true;
1094 stop = true;
1095 }
1096 });
1097 }
1098 else {
1099 forEachCacheSegment(^(uint32_t segIterIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t segPerms, bool& stop) {
1100 if ( (offsetInImage >= vmOffset) && (offsetInImage < vmOffset+vmSize) ) {
1101 if ( permissions != nullptr )
1102 *permissions = segPerms;
1103 found = true;
1104 stop = true;
1105 }
1106 });
1107 }
1108 return found;
1109 }
1110
1111 void Image::forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const
1112 {
1113 const uint32_t initCount = _binaryData->initOffsetsArrayCount;
1114 const uint32_t startIndex = _binaryData->initOffsetsArrayStartIndex;
1115 const uint32_t* initOffsets = group().initializerOffsetsPool();
1116 assert(startIndex + initCount <= group().initializerOffsetsCount());
1117 for (uint32_t i=0; i < initCount; ++i) {
1118 uint32_t anOffset = initOffsets[startIndex+i];
1119 const void* func = (char*)imageLoadAddress + anOffset;
1120 handler(func);
1121 }
1122 }
1123
1124 void Image::forEachInitBefore(void (^handler)(binary_format::ImageRef imageToInit)) const
1125 {
1126 const uint32_t initCount = _binaryData->initBeforeArrayCount;
1127 const uint32_t startIndex = _binaryData->initBeforeArrayStartIndex;
1128 const uint32_t endIndex = group().intializerListPoolCount();
1129 const binary_format::ImageRef* initRefs = group().intializerListPool();
1130 assert(startIndex + initCount <= endIndex);
1131 for (uint32_t i=0; i < initCount; ++i) {
1132 binary_format::ImageRef ref = initRefs[startIndex+i];
1133 handler(ref);
1134 }
1135 }
1136
1137 void Image::forEachDOF(const void* imageLoadAddress, void (^handler)(const void* section)) const
1138 {
1139 const uint32_t dofCount = _binaryData->dofOffsetsArrayCount;
1140 const uint32_t startIndex = _binaryData->dofOffsetsArrayStartIndex;
1141 const uint32_t* dofOffsets = group().dofOffsetsPool();
1142 assert(startIndex + dofCount <= group().dofOffsetsCount());
1143 for (uint32_t i=0; i < dofCount; ++i) {
1144 uint32_t anOffset = dofOffsets[startIndex+i];
1145 const void* section = (char*)imageLoadAddress + anOffset;
1146 handler(section);
1147 }
1148 }
1149
1150 Image Image::resolveImageRef(const ImageGroupList& groups, binary_format::ImageRef ref, bool applyOverrides)
1151 {
1152 // first look if ref image is overridden in closure
1153 __block binary_format::ImageRef targetRef = ref;
1154 if ( applyOverrides ) {
1155 binary_format::ImageRef refToMatch = ref;
1156 refToMatch.clearKind();
1157 for (int i=0; i < groups.count(); ++i) {
1158 ImageGroup aGroup(groups[i]);
1159 if ( aGroup.groupNum() >= 2 ) {
1160 aGroup.forEachImageRefOverride(^(binary_format::ImageRef standardDylibRef, binary_format::ImageRef overrideDylibRef, bool &stop) {
1161 if ( refToMatch == standardDylibRef ) {
1162 targetRef = overrideDylibRef;
1163 stop = true;
1164 }
1165 });
1166 }
1167 }
1168 }
1169 // create Image object from targetRef
1170 for (int i=0; i < groups.count(); ++i) {
1171 ImageGroup aGroup(groups[i]);
1172 if ( aGroup.groupNum() == targetRef.groupNum() ) {
1173 return aGroup.image(targetRef.indexInGroup());
1174 }
1175 }
1176 //assert(0 && "invalid ImageRef");
1177 return Image(nullptr);
1178 }
1179
1180 void Image::forEachInitBefore(const ImageGroupList& groups, void (^handler)(Image imageToInit)) const
1181 {
1182 forEachInitBefore(^(binary_format::ImageRef ref) {
1183 handler(resolveImageRef(groups, ref));
1184 });
1185 }
1186
1187 bool Image::validateUsingModTimeAndInode() const
1188 {
1189 return !group().binaryData()->imageFileInfoIsCdHash;
1190 }
1191
1192 bool Image::validateUsingCdHash() const
1193 {
1194 // don't have cdHash info if union has modtime info in it
1195 if ( !group().binaryData()->imageFileInfoIsCdHash )
1196 return false;
1197
1198 // don't have codesign blob in dyld cache
1199 if ( !_binaryData->isDiskImage )
1200 return false;
1201
1202 // return true if image is code signed and cdHash16 is non-zero
1203 const binary_format::DiskImage* diskImage = asDiskImage();
1204 if ( diskImage->codeSignFileOffset == 0 )
1205 return false;
1206
1207 uint8_t zeros[16];
1208 bzero(zeros, 16);
1209 return (memcmp(cdHash16(), zeros, 16) != 0);
1210 }
1211
1212 const uint8_t* Image::cdHash16() const
1213 {
1214 return _binaryData->fileInfo.cdHash16.bytes;
1215 }
1216
1217 uint64_t Image::fileModTime() const
1218 {
1219 return _binaryData->fileInfo.statInfo.mtime;
1220 }
1221
1222 uint64_t Image::fileINode() const
1223 {
1224 return _binaryData->fileInfo.statInfo.inode;
1225 }
1226
1227
1228 bool Image::isDiskImage() const
1229 {
1230 return _binaryData->isDiskImage;
1231 }
1232
1233 const binary_format::DiskImage* Image::asDiskImage() const
1234 {
1235 assert(_binaryData->isDiskImage);
1236 return (binary_format::DiskImage*)_binaryData;
1237 }
1238
1239 const binary_format::CachedImage* Image::asCachedImage() const
1240 {
1241 assert(!_binaryData->isDiskImage);
1242 return (binary_format::CachedImage*)_binaryData;
1243 }
1244
1245 uint32_t Image::pageSize() const
1246 {
1247 return (_binaryData->has16KBpages ? 0x4000 : 0x1000);
1248 }
1249
1250 uint32_t Image::cacheOffset() const
1251 {
1252 assert(!_binaryData->isDiskImage);
1253 const uint64_t* rawSegs = group().segmentPool(_binaryData->segmentsArrayStartIndex);
1254 const binary_format::DyldCacheSegment* cacheSegs = (binary_format::DyldCacheSegment*)rawSegs;
1255 return cacheSegs[0].cacheOffset;
1256 }
1257
1258 uint32_t Image::patchStartIndex() const
1259 {
1260 return asCachedImage()->patchStartIndex;
1261 }
1262
1263 uint32_t Image::patchCount() const
1264 {
1265 return asCachedImage()->patchCount;
1266 }
1267
1268 uint64_t Image::sliceOffsetInFile() const
1269 {
1270 return asDiskImage()->sliceOffsetIn4K * 4096;
1271 }
1272
1273 bool Image::hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const
1274 {
1275 const binary_format::DiskImage* diskImage = asDiskImage();
1276 if ( diskImage->codeSignFileOffset != 0 ) {
1277 fileOffset = diskImage->codeSignFileOffset;
1278 size = diskImage->codeSignFileSize;
1279 return true;
1280 }
1281 return false;
1282 }
1283
1284 bool Image::isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const
1285 {
1286 const binary_format::DiskImage* diskImage = asDiskImage();
1287 if ( diskImage->fairPlayTextPageCount != 0 ) {
1288 textOffset = diskImage->fairPlayTextStartPage * pageSize();
1289 size = diskImage->fairPlayTextPageCount * pageSize();
1290 return true;
1291 }
1292 return false;
1293 }
1294
1295 uint64_t Image::vmSizeToMap() const
1296 {
1297 return asDiskImage()->totalVmPages * pageSize();
1298 }
1299
1300 void Image::forEachFixup(const uint8_t* pageFixups, const void* segContent, uint32_t& offset, uint32_t& ordinal,
1301 void (^handler)(uint32_t pageOffset, FixupKind kind, uint32_t ordinal, bool& stop))
1302 {
1303 bool stop = false;
1304 for (const uint8_t* p = pageFixups; (*p != 0) && !stop;) {
1305 binary_format::FixUpOpcode fullOp = (binary_format::FixUpOpcode)(*p);
1306 binary_format::FixUpOpcode majorOp = (binary_format::FixUpOpcode)(*p & 0xF0);
1307 uint8_t low4 = (*p & 0x0F);
1308 switch ( majorOp ) {
1309 case binary_format::FixUpOpcode::done:
1310 return;
1311 case binary_format::FixUpOpcode::rebase32: // apply
1312 switch ( fullOp ) {
1313 case binary_format::FixUpOpcode::bind64:
1314 handler(offset, FixupKind::bind64, ordinal, stop);
1315 offset += 8;
1316 ++p;
1317 break;
1318 case binary_format::FixUpOpcode::bind32:
1319 handler(offset, FixupKind::bind32, ordinal, stop);
1320 offset += 4;
1321 ++p;
1322 break;
1323 case binary_format::FixUpOpcode::rebase64:
1324 handler(offset, FixupKind::rebase64, 0, stop);
1325 offset += 8;
1326 ++p;
1327 break;
1328 case binary_format::FixUpOpcode::rebase32:
1329 handler(offset, FixupKind::rebase32, 0, stop);
1330 offset += 4;
1331 ++p;
1332 break;
1333 case binary_format::FixUpOpcode::rebaseText32:
1334 handler(offset, FixupKind::rebaseText32, 0, stop);
1335 offset += 4;
1336 ++p;
1337 break;
1338 case binary_format::FixUpOpcode::bindText32:
1339 handler(offset, FixupKind::bindText32, ordinal, stop);
1340 offset += 4;
1341 ++p;
1342 break;
1343 case binary_format::FixUpOpcode::bindTextRel32:
1344 handler(offset, FixupKind::bindTextRel32, ordinal, stop);
1345 offset += 4;
1346 ++p;
1347 break;
1348 case binary_format::FixUpOpcode::bindImportJmp32:
1349 handler(offset, FixupKind::bindImportJmp32, ordinal, stop);
1350 offset += 5;
1351 ++p;
1352 break;
1353 //case binary_format::FixUpOpcode::fixupChain64:
1354 // assert(0 && "rebase/bind chain support not implemented yet");
1355 // break;
1356 default:
1357 assert(0 && "bad opcode");
1358 break;
1359 }
1360 break;
1361 case binary_format::FixUpOpcode::incPageOffset:
1362 if ( low4 == 0 ) {
1363 ++p;
1364 offset += read_uleb128(p, p+8)*4;
1365 }
1366 else {
1367 offset += (low4*4);
1368 ++p;
1369 }
1370 break;
1371 case binary_format::FixUpOpcode::setPageOffset:
1372 if ( low4 == 0 ) {
1373 ++p;
1374 offset = (uint32_t)read_uleb128(p, p+8);
1375 }
1376 else {
1377 offset = low4;
1378 ++p;
1379 }
1380 break;
1381 case binary_format::FixUpOpcode::incOrdinal:
1382 if ( low4 == 0 ) {
1383 ++p;
1384 ordinal += read_uleb128(p, p+8);
1385 }
1386 else {
1387 ordinal += low4;
1388 ++p;
1389 }
1390 break;
1391 case binary_format::FixUpOpcode::setOrdinal:
1392 if ( low4 == 0 ) {
1393 ++p;
1394 ordinal = (uint32_t)read_uleb128(p, p+8);
1395 }
1396 else {
1397 ordinal = low4;
1398 ++p;
1399 }
1400 break;
1401 case binary_format::FixUpOpcode::repeat: {
1402 ++p;
1403 uint32_t count = (uint32_t)read_uleb128(p, p+8);
1404 uint8_t pattern[32];
1405 for (int j=0; j < low4; ++j) {
1406 pattern[j] = *p++;
1407 }
1408 pattern[low4] = (uint8_t)binary_format::FixUpOpcode::done;
1409 for (int j=0; j < count; ++j) {
1410 forEachFixup(&pattern[0], segContent, offset, ordinal, handler);
1411 if ( stop )
1412 break;
1413 }
1414 }
1415 break;
1416 default:
1417 assert(0 && "bad opcode");
1418 break;
1419 }
1420 }
1421 }
1422
1423 const binary_format::SegmentFixupsByPage* Image::segmentFixups(uint32_t segIndex) const
1424 {
1425 const binary_format::DiskImage* diskImage = asDiskImage();
1426 //const BinaryImageGroupData* g = group().binaryData();
1427 uint32_t segCountWithFixups = diskImage->fixupsPoolSegCount;
1428 //fprintf(stderr,"segmentFixups(binImage=%p, segIndex=%d), group=%p, segCountWithFixup=%d\n", _binaryData, segIndex, g, segCountWithFixups);
1429 const binary_format::AllFixupsBySegment* allFixups = group().fixUps(diskImage->fixupsPoolOffset);
1430 for (uint32_t i=0; i < segCountWithFixups; ++i) {
1431 if ( allFixups[i].segIndex == segIndex ) {
1432 //fprintf(stderr,"segmentFixups(binImage=%p, segIndex=%d) allFixups=%p, allFixups[%d].segIndex=%d, allFixups[%d].offset=%d\n", _binaryData, segIndex, allFixups, i, allFixups[i].segIndex, i, allFixups[i].offset);
1433 return (binary_format::SegmentFixupsByPage*)((char*)allFixups + allFixups[i].offset);
1434 }
1435 }
1436 //fprintf(stderr,"segmentFixups(binImage=%p, segIndex=%d) => nullptr\n", _binaryData, segIndex);
1437 return nullptr;
1438 }
1439
1440 void Image::forEachFixup(uint32_t segIndex, MemoryRange segContent, void (^handler)(uint64_t segOffset, FixupKind, TargetSymbolValue, bool& stop)) const
1441 {
1442 const binary_format::SegmentFixupsByPage* segFixups = segmentFixups(segIndex);
1443 if ( segFixups == nullptr )
1444 return;
1445
1446 assert(segFixups->pageCount*segFixups->pageSize <= segContent.size);
1447
1448 const uint32_t ordinalsIndexInGroupPool = asDiskImage()->targetsArrayStartIndex;
1449 const uint32_t maxOrdinal = asDiskImage()->targetsArrayCount;
1450 const TargetSymbolValue* groupArray = group().targetValuesArray();
1451 assert(ordinalsIndexInGroupPool < group().targetValuesCount());
1452 const TargetSymbolValue* targetOrdinalArray = &groupArray[ordinalsIndexInGroupPool];
1453
1454 for (uint32_t pageIndex=0; pageIndex < segFixups->pageCount; ++pageIndex) {
1455 const uint8_t* opcodes = (uint8_t*)(segFixups) + segFixups->pageInfoOffsets[pageIndex];
1456 uint64_t pageStartOffet = pageIndex * segFixups->pageSize;
1457 uint32_t curOffset = 0;
1458 uint32_t curOrdinal = 0;
1459 forEachFixup(opcodes, segContent.address, curOffset, curOrdinal, ^(uint32_t pageOffset, FixupKind kind, uint32_t targetOrdinal, bool& stop) {
1460 assert(targetOrdinal < maxOrdinal);
1461 handler(pageStartOffet + pageOffset, kind, targetOrdinalArray[targetOrdinal], stop);
1462 });
1463 }
1464 }
1465
1466
1467 } // namespace launch_cache
1468 } // namespace dyld3
1469
1470
1471