]> git.saurik.com Git - apple/dyld.git/blob - dyld3/ClosurePrinter.cpp
dyld-750.5.tar.gz
[apple/dyld.git] / dyld3 / ClosurePrinter.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 #include <string.h>
25
26 #include <string>
27 #include <map>
28 #include <vector>
29
30 #include "ClosurePrinter.h"
31 #include "JSONWriter.h"
32
33 #include "objc-shared-cache.h"
34
35 using namespace dyld3::json;
36
37 namespace dyld3 {
38 namespace closure {
39
40 static std::string printTarget(const Array<const ImageArray*>& imagesArrays, Image::ResolvedSymbolTarget target)
41 {
42 const Image* targetImage;
43 uint64_t value;
44 switch ( target.image.kind ) {
45 case Image::ResolvedSymbolTarget::kindImage:
46 targetImage = ImageArray::findImage(imagesArrays, target.image.imageNum);
47 if ( target.image.offset & 0x8000000000ULL ) {
48 uint64_t signExtend = target.image.offset | 0xFFFFFF0000000000ULL;
49 return std::string("bind to ") + targetImage->leafName() + " - " + hex8(-signExtend);
50 }
51 else
52 return std::string("bind to ") + targetImage->leafName() + " + " + hex8(target.image.offset);
53 break;
54 case Image::ResolvedSymbolTarget::kindSharedCache:
55 return std::string("bind to dyld cache + ") + hex8(target.sharedCache.offset);
56 break;
57 case Image::ResolvedSymbolTarget::kindAbsolute:
58 value = target.absolute.value;
59 if ( value & 0x2000000000000000LL )
60 value |= 0xC000000000000000LL;
61 return std::string("bind to absolute ") + hex(value);
62 break;
63 }
64 return "???";
65 }
66
67 static const char* nameForType(TypedBytes::Type type) {
68 switch (type) {
69 // containers
70 case TypedBytes::Type::launchClosure:
71 return "launchClosure";
72 case TypedBytes::Type::imageArray:
73 return "imageArray";
74 case TypedBytes::Type::image:
75 return "image";
76 case TypedBytes::Type::dlopenClosure:
77 return "dlopenClosure";
78 // attributes for Images
79 case TypedBytes::Type::imageFlags:
80 return "imageFlags";
81 case TypedBytes::Type::pathWithHash:
82 return "pathWithHash";
83 case TypedBytes::Type::fileInodeAndTime:
84 return "fileInodeAndTime";
85 case TypedBytes::Type::cdHash:
86 return "cdHash";
87 case TypedBytes::Type::uuid:
88 return "uuid";
89 case TypedBytes::Type::mappingInfo:
90 return "mappingInfo";
91 case TypedBytes::Type::diskSegment:
92 return "diskSegment";
93 case TypedBytes::Type::cacheSegment:
94 return "cacheSegment";
95 case TypedBytes::Type::dependents:
96 return "dependents";
97 case TypedBytes::Type::initOffsets:
98 return "initOffsets";
99 case TypedBytes::Type::dofOffsets:
100 return "dofOffsets";
101 case TypedBytes::Type::codeSignLoc:
102 return "codeSignLoc";
103 case TypedBytes::Type::fairPlayLoc:
104 return "fairPlayLoc";
105 case TypedBytes::Type::rebaseFixups:
106 return "rebaseFixups";
107 case TypedBytes::Type::bindFixups:
108 return "bindFixups";
109 case TypedBytes::Type::cachePatchInfo:
110 return "cachePatchInfo";
111 case TypedBytes::Type::textFixups:
112 return "textFixups";
113 case TypedBytes::Type::imageOverride:
114 return "imageOverride";
115 case TypedBytes::Type::initBefores:
116 return "initBefores";
117 case TypedBytes::Type::initsSection:
118 return "initSection";
119 case TypedBytes::Type::chainedFixupsTargets:
120 return "chainedFixupsTargets";
121 case TypedBytes::Type::termOffsets:
122 return "termOffsets";
123 case TypedBytes::Type::chainedStartsOffset:
124 return "chainedStartsOffset";
125 case TypedBytes::Type::objcFixups:
126 return "objcFixups";
127 // attributes for Closures (launch or dlopen)
128 case TypedBytes::Type::closureFlags:
129 return "closureFlags";
130 case TypedBytes::Type::dyldCacheUUID:
131 return "dyldCacheUUID";
132 case TypedBytes::Type::missingFiles:
133 return "missingFiles";
134 case TypedBytes::Type::envVar:
135 return "envVar";
136 case TypedBytes::Type::topImage:
137 return "topImage";
138 case TypedBytes::Type::libDyldEntry:
139 return "libDyldEntry";
140 case TypedBytes::Type::libSystemNum:
141 return "libSystemNum";
142 case TypedBytes::Type::bootUUID:
143 return "bootUUID";
144 case TypedBytes::Type::mainEntry:
145 return "mainEntry";
146 case TypedBytes::Type::startEntry:
147 return "startEntry";
148 case TypedBytes::Type::cacheOverrides:
149 return "cacheOverrides";
150 case TypedBytes::Type::interposeTuples:
151 return "interposeTuples";
152 case TypedBytes::Type::existingFiles:
153 return "existingFiles";
154 case TypedBytes::Type::selectorTable:
155 return "selectorTable";
156 case TypedBytes::Type::classTable:
157 return "classTable";
158 case TypedBytes::Type::warning:
159 return "warning";
160 case TypedBytes::Type::duplicateClassesTable:
161 return "duplicateClassesTable";
162 case TypedBytes::Type::progVars:
163 return "programVars";
164 }
165 }
166
167 static Node buildImageNode(const Image* image, const Array<const ImageArray*>& imagesArrays, bool printFixups,
168 bool printDependentsDetails, bool printRaw,
169 const DyldSharedCache* dyldCache, const closure::ObjCSelectorOpt* selOpt,
170 const Array<closure::Image::ObjCSelectorImage>& selImages)
171 {
172 __block Node imageNode;
173
174 if ( image->isInvalid() )
175 return imageNode;
176
177 imageNode.map["image-num"].value = hex4(image->imageNum());
178 imageNode.map["path"].value = image->path();
179
180 if (printRaw) {
181 __block Node attributes;
182 image->forEachAttribute(^(const TypedBytes *typedBytes, bool &stop) {
183 Node anAttribute;
184 anAttribute.map["type"].value = decimal((uint32_t)typedBytes->type);
185 anAttribute.map["type-name"].value = nameForType((TypedBytes::Type)typedBytes->type);
186 anAttribute.map["length"].value = decimal(typedBytes->payloadLength);
187 attributes.array.push_back(anAttribute);
188 });
189 imageNode.map["attributes"] = attributes;
190 return imageNode;
191 }
192
193 __block Node imageAliases;
194 image->forEachAlias(^(const char* aliasPath, bool& stop) {
195 Node anAlias;
196 anAlias.value = aliasPath;
197 imageAliases.array.push_back(anAlias);
198 });
199 if ( !imageAliases.array.empty() )
200 imageNode.map["aliases"] = imageAliases;
201 uuid_t uuid;
202 if ( image->getUuid(uuid) ) {
203 uuid_string_t uuidStr;
204 uuid_unparse(uuid, uuidStr);
205 imageNode.map["uuid"].value = uuidStr;
206 }
207 imageNode.map["has-objc"].value = (image->hasObjC() ? "true" : "false");
208 imageNode.map["has-weak-defs"].value = (image->hasWeakDefs() ? "true" : "false");
209 imageNode.map["has-plus-loads"].value = (image->mayHavePlusLoads() ? "true" : "false");
210 imageNode.map["never-unload"].value = (image->neverUnload() ? "true" : "false");
211 imageNode.map["has-precomputed-objc"].value = (image->hasPrecomputedObjC() ? "true" : "false");
212 // imageNode.map["platform-binary"].value = (image->isPlatformBinary() ? "true" : "false");
213 // if ( image->cwdMustBeThisDir() )
214 // imageNode.map["cwd-must-be-this-dir"].value = "true";
215 if ( !image->inDyldCache() ) {
216 uint32_t csFileOffset;
217 uint32_t csSize;
218 if ( image->hasCodeSignature(csFileOffset, csSize) ) {
219 imageNode.map["code-sign-location"].map["offset"].value = hex(csFileOffset);
220 imageNode.map["code-sign-location"].map["size"].value = hex(csSize);
221 }
222 // uint32_t fpTextOffset;
223 // uint32_t fpSize;
224 // if ( image->isFairPlayEncrypted(fpTextOffset, fpSize) ) {
225 // imageNode.map["fairplay-encryption-location"].map["offset"].value = hex(fpTextOffset);
226 // imageNode.map["fairplay-encryption-location"].map["size"].value = hex(fpSize);
227 // }
228 uint64_t inode;
229 uint64_t mTime;
230 if ( image->hasFileModTimeAndInode(inode, mTime) ) {
231 imageNode.map["file-mod-time"].value = hex(inode);
232 imageNode.map["file-inode"].value = hex(mTime);
233 }
234 image->forEachCDHash(^(const uint8_t *cdHash, bool& stop) {
235 std::string cdHashStr;
236 cdHashStr.reserve(24);
237 for (int i=0; i < 20; ++i) {
238 uint8_t byte = cdHash[i];
239 uint8_t nibbleL = byte & 0x0F;
240 uint8_t nibbleH = byte >> 4;
241 if ( nibbleH < 10 )
242 cdHashStr += '0' + nibbleH;
243 else
244 cdHashStr += 'a' + (nibbleH-10);
245 if ( nibbleL < 10 )
246 cdHashStr += '0' + nibbleL;
247 else
248 cdHashStr += 'a' + (nibbleL-10);
249 }
250 if ( cdHashStr != "0000000000000000000000000000000000000000" ) {
251 Node hashNode;
252 hashNode.value = cdHashStr;
253 imageNode.map["cd-hashes"].array.push_back(hashNode);
254 }
255 });
256 imageNode.map["total-vm-size"].value = hex(image->vmSizeToMap());
257 uint64_t sliceOffset = image->sliceOffsetInFile();
258 if ( sliceOffset != 0 )
259 imageNode.map["file-offset-of-slice"].value = hex(sliceOffset);
260 //if ( image->hasTextRelocs() )
261 // imageNode.map["has-text-relocs"].value = "true";
262 image->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
263 Node segInfoNode;
264 segInfoNode.map["file-offset"].value = hex(fileOffset);
265 segInfoNode.map["file-size"].value = hex(fileSize);
266 segInfoNode.map["vm-size"].value = hex(vmSize);
267 imageNode.map["mappings"].array.push_back(segInfoNode);
268 switch ( permissions ) {
269 case 0:
270 segInfoNode.map["permissions"].value = "--";
271 break;
272 case 1:
273 segInfoNode.map["permissions"].value = "r";
274 break;
275 case 2:
276 segInfoNode.map["permissions"].value = "ro"; // r/w then r/o
277 break;
278 case 3:
279 segInfoNode.map["permissions"].value = "rw";
280 break;
281 case 4:
282 segInfoNode.map["permissions"].value = "rx";
283 break;
284 default:
285 segInfoNode.map["permissions"].value = "??";
286 }
287 });
288
289
290 if ( printFixups ) {
291 image->forEachFixup(^(uint64_t imageOffsetToRebase, bool &stop) {
292 // rebase
293 imageNode.map["fixups"].map[hex8(imageOffsetToRebase)].value = "rebase";
294 }, ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
295 // bind
296 imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = printTarget(imagesArrays, target);
297 }, ^(uint64_t startsStructImageOffset, const Array<Image::ResolvedSymbolTarget>& targets, bool& stop) {
298 // chain
299 imageNode.map["fixups-chain-starts-offset"].value = hex8(startsStructImageOffset);
300 for (const Image::ResolvedSymbolTarget& target: targets) {
301 Node targetNode;
302 targetNode.value = printTarget(imagesArrays, target);
303 imageNode.map["fixups-targets"].array.push_back(targetNode);
304 }
305
306 }, ^(uint64_t imageOffsetToFixup) {
307 // fixupObjCImageInfo
308 imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc image info pre-optimized by dyld flag";
309 }, ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
310 // fixupObjCProtocol
311 imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = printTarget(imagesArrays, target);
312 }, ^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &stop) {
313 // fixupObjCSelRefs
314 Image::ResolvedSymbolTarget target;
315 if ( inSharedCache ) {
316 const char* selectorString = dyldCache->objcOpt()->selopt()->getEntryForIndex(selectorIndex);
317 target.sharedCache.kind = Image::ResolvedSymbolTarget::kindSharedCache;
318 target.sharedCache.offset = (uint64_t)selectorString - (uint64_t)dyldCache;
319 } else {
320 ImageNum imageNum;
321 uint64_t vmOffset;
322 bool gotLocation = selOpt->getStringLocation(selectorIndex, selImages, imageNum, vmOffset);
323 assert(gotLocation);
324 target.image.kind = Image::ResolvedSymbolTarget::kindImage;
325 target.image.imageNum = imageNum;
326 target.image.offset = vmOffset;
327 }
328 imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = printTarget(imagesArrays, target);
329 }, ^(uint64_t imageOffsetToFixup, bool &stop) {
330 // fixupObjCStableSwift
331 imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc set stable Swift";
332 }, ^(uint64_t imageOffsetToFixup, bool &stop) {
333 // fixupObjCMethodList
334 imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc set fixed up method list";
335 });
336 image->forEachTextReloc(^(uint32_t imageOffsetToRebase, bool &stop) {
337 // rebase
338 imageNode.map["fixups"].map[hex8(imageOffsetToRebase)].value = "text rebase";
339 }, ^(uint32_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
340 imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = "text " + printTarget(imagesArrays, target);
341 });
342 }
343 }
344 else {
345 if ( printFixups ) {
346 if ( dyldCache != nullptr ) {
347 uint32_t imageIndex = image->imageNum() - (uint32_t)dyldCache->cachedDylibsImageArray()->startImageNum();
348 dyldCache->forEachPatchableExport(imageIndex, ^(uint32_t cacheOffsetOfImpl, const char* name) {
349 __block Node implNode;
350 implNode.map["name"].value = name;
351 implNode.map["impl-cache-offset"].value = hex8(cacheOffsetOfImpl);
352 dyldCache->forEachPatchableUseOfExport(imageIndex, cacheOffsetOfImpl, ^(dyld_cache_patchable_location patchLocation) {
353 Node siteNode;
354 siteNode.map["cache-offset"].value = hex8(patchLocation.cacheOffset);
355 if ( patchLocation.addend != 0 )
356 siteNode.map["addend"].value = hex(patchLocation.addend);
357 if ( patchLocation.authenticated != 0 ) {
358 siteNode.map["key"].value = DyldSharedCache::keyName(patchLocation);
359 siteNode.map["address-diversity"].value = patchLocation.usesAddressDiversity ? "true" : "false";
360 siteNode.map["discriminator"].value = hex4(patchLocation.discriminator);
361 }
362 implNode.map["usage-sites"].array.push_back(siteNode);
363 });
364 imageNode.map["patches"].array.push_back(implNode);
365 });
366 }
367 }
368 }
369
370 // add dependents
371 image->forEachDependentImage(^(uint32_t depIndex, Image::LinkKind kind, ImageNum imageNum, bool& stop) {
372 Node depMapNode;
373 const Image* depImage = ImageArray::findImage(imagesArrays, imageNum);
374 depMapNode.map["image-num"].value = hex4(imageNum);
375 if ( depImage != nullptr )
376 depMapNode.map["path"].value = depImage->path();
377 switch ( kind ) {
378 case Image::LinkKind::regular:
379 depMapNode.map["link"].value = "regular";
380 break;
381 case Image::LinkKind::reExport:
382 depMapNode.map["link"].value = "re-export";
383 break;
384 case Image::LinkKind::upward:
385 depMapNode.map["link"].value = "upward";
386 break;
387 case Image::LinkKind::weak:
388 depMapNode.map["link"].value = "weak";
389 break;
390 }
391 imageNode.map["dependents"].array.push_back(depMapNode);
392 });
393
394 // add initializers
395 bool usesInitsSection = image->forEachInitializerSection(^(uint32_t sectionOffset, uint32_t sectionSize) {
396 Node initSectNode;
397 initSectNode.map["offset"].value = hex(sectionOffset);
398 initSectNode.map["size"].value = hex(sectionSize);
399 imageNode.map["initializers-section"].array.push_back(initSectNode);
400 });
401 if ( !usesInitsSection ) {
402 image->forEachInitializer(nullptr, ^(const void* initializer) {
403 Node initNode;
404 initNode.value = hex((long)initializer);
405 imageNode.map["initializer-offsets"].array.push_back(initNode);
406 });
407 }
408 __block Node initBeforeNode;
409 image->forEachImageToInitBefore(^(ImageNum imageToInit, bool& stop) {
410 Node beforeNode;
411 const Image* initImage = ImageArray::findImage(imagesArrays, imageToInit);
412 assert(initImage != nullptr);
413 beforeNode.value = initImage->path();
414 imageNode.map["initializer-order"].array.push_back(beforeNode);
415 });
416
417 // add static terminators
418 image->forEachTerminator(nullptr, ^(const void* terminator) {
419 Node termNode;
420 termNode.value = hex8((long)terminator);
421 imageNode.map["terminator-offsets"].array.push_back(termNode);
422 });
423
424 ImageNum cacheImageNum;
425 if ( image->isOverrideOfDyldCacheImage(cacheImageNum) ) {
426 imageNode.map["override-of-dyld-cache-image"].value = ImageArray::findImage(imagesArrays, cacheImageNum)->path();
427 }
428
429
430 #if 0
431 // add things to init before this image
432 __block Node initBeforeNode;
433 image->forEachInitBefore(groupList, ^(Image beforeImage) {
434 Node beforeNode;
435 beforeNode.value = beforeimage->path();
436 imageNode.map["initializer-order"].array.push_back(beforeNode);
437 });
438
439 // add override info if relevant
440 group.forEachImageRefOverride(groupList, ^(Image standardDylib, Image overrideDylib, bool& stop) {
441 if ( overrideDylib.binaryData() == image->binaryData() ) {
442 imageNode.map["override-of-cached-dylib"].value = standardDylib.path();
443 }
444 });
445 // add dtrace info
446 image->forEachDOF(nullptr, ^(const void* section) {
447 Node initNode;
448 initNode.value = hex((long)section);
449 imageNode.map["dof-offsets"].array.push_back(initNode);
450 });
451 #endif
452
453 return imageNode;
454 }
455
456
457 static Node buildImageArrayNode(const ImageArray* imageArray, const Array<const ImageArray*>& imagesArrays,
458 bool printFixups, bool printDependentsDetails, bool printRaw,
459 const DyldSharedCache* dyldCache, const closure::ObjCSelectorOpt* selOpt,
460 const Array<closure::Image::ObjCSelectorImage>& selImages)
461 {
462 __block Node images;
463 imageArray->forEachImage(^(const Image* image, bool& stop) {
464 images.array.push_back(buildImageNode(image, imagesArrays, printFixups, printDependentsDetails, printRaw, dyldCache, selOpt, selImages));
465 });
466 return images;
467 }
468
469
470 static Node buildClosureNode(const DlopenClosure* closure, const Array<const ImageArray*>& imagesArrays,
471 bool printFixups, bool printRaw, bool printDependentsDetails)
472 {
473 __block Node root;
474 root.map["images"] = buildImageArrayNode(closure->images(), imagesArrays,
475 printFixups, printDependentsDetails, printRaw,
476 nullptr, nullptr, {});
477
478 closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
479 Node patchNode;
480 patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
481 patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
482 patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
483 root.map["dyld-cache-fixups"].array.push_back(patchNode);
484 });
485
486 return root;
487 }
488
489 static Node buildClosureNode(const LaunchClosure* closure, const Array<const ImageArray*>& imagesArrays,
490 bool printFixups, bool printDependentsDetails, bool printRaw,
491 const DyldSharedCache* dyldCache)
492 {
493 __block Node root;
494
495 Array<Image::ObjCSelectorImage> selectorImages;
496 const closure::ObjCSelectorOpt* selectorHashTable = nullptr;
497 bool hasPreoptimizedObjCSelectors = closure->selectorHashTable(selectorImages, selectorHashTable);
498
499 root.map["images"] = buildImageArrayNode(closure->images(), imagesArrays, printFixups,
500 printDependentsDetails, printRaw,
501 dyldCache, selectorHashTable, selectorImages);
502
503 if ( printRaw ) {
504 __block Node attributes;
505 closure->forEachAttribute(^(const TypedBytes *typedBytes, bool &stop) {
506 Node anAttribute;
507 anAttribute.map["type"].value = decimal((uint32_t)typedBytes->type);
508 anAttribute.map["type-name"].value = nameForType((TypedBytes::Type)typedBytes->type);
509 anAttribute.map["length"].value = decimal(typedBytes->payloadLength);
510 attributes.array.push_back(anAttribute);
511 });
512 root.map["attributes"] = attributes;
513 return root;
514 }
515
516 closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
517 Node patchNode;
518 patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
519 patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
520 patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
521 root.map["dyld-cache-fixups"].array.push_back(patchNode);
522 });
523
524 Image::ResolvedSymbolTarget entry;
525 if ( closure->mainEntry(entry) )
526 root.map["main"].value = printTarget(imagesArrays, entry);
527 else if ( closure->startEntry(entry) )
528 root.map["start"].value = printTarget(imagesArrays, entry);
529
530 Image::ResolvedSymbolTarget libdyldEntry;
531 closure->libDyldEntry(libdyldEntry);
532 root.map["libdyld-entry"].value = printTarget(imagesArrays, libdyldEntry);
533
534 root.map["uses-@paths"].value = (closure->usedAtPaths() ? "true" : "false");
535 root.map["uses-fallback-paths"].value = (closure->usedFallbackPaths() ? "true" : "false");
536
537 // add missing files array if they exist
538 closure->forEachMustBeMissingFile(^(const char* path, bool& stop) {
539 Node fileNode;
540 fileNode.value = path;
541 root.map["must-be-missing-files"].array.push_back(fileNode);
542 });
543
544 // add skipped files array if they exist
545 closure->forEachSkipIfExistsFile(^(const LaunchClosure::SkippedFile &file, bool &stop) {
546 Node fileNode;
547 fileNode.map["path"].value = file.path;
548 fileNode.map["file-mod-time"].value = hex(file.mtime);
549 fileNode.map["file-inode"].value = hex(file.inode);
550 root.map["skipped-existing-files"].array.push_back(fileNode);
551 });
552
553 // add interposing info, if any
554 closure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool& stop) {
555 Node tupleNode;
556 tupleNode.map["stock"].value = printTarget(imagesArrays, tuple.stockImplementation);
557 tupleNode.map["replace"].value = printTarget(imagesArrays, tuple.newImplementation);
558 root.map["interposing-tuples"].array.push_back(tupleNode);
559 });
560
561 closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
562 Node patchNode;
563 patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
564 patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
565 patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
566 root.map["dyld-cache-fixups"].array.push_back(patchNode);
567 });
568
569 root.map["initial-image-count"].value = decimal(closure->initialLoadCount());
570
571 // add env-vars if they exist
572 closure->forEachEnvVar(^(const char* keyEqualValue, bool& stop) {
573 const char* equ = strchr(keyEqualValue, '=');
574 if ( equ != nullptr ) {
575 char key[512];
576 strncpy(key, keyEqualValue, equ-keyEqualValue);
577 key[equ-keyEqualValue] = '\0';
578 root.map["env-vars"].map[key].value = equ+1;
579 }
580 });
581
582 if (hasPreoptimizedObjCSelectors) {
583 __block Node selectorsNode;
584 selectorHashTable->forEachString(selectorImages,
585 ^(uint64_t selVMOffset, ImageNum imageNum) {
586 // Convert to a target we can get a real name for
587 dyld3::closure::Image::ResolvedSymbolTarget target;
588 target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
589 target.image.imageNum = imageNum;
590 target.image.offset = selVMOffset;
591
592 Node targetNode;
593 targetNode.value = printTarget(imagesArrays, target);
594 selectorsNode.array.push_back(targetNode);
595 });
596
597 root.map["objc-selectors"] = selectorsNode;
598 }
599
600 Array<Image::ObjCClassImage> classImages;
601 const ObjCClassOpt* classHashTable = nullptr;
602 const ObjCClassOpt* protocolHashTable = nullptr;
603 if (closure->classAndProtocolHashTables(classImages, classHashTable, protocolHashTable)) {
604 if ( classHashTable != nullptr ) {
605 __block Node classesNode;
606
607 classHashTable->forEachClass(classImages,
608 ^(uint64_t classNameVMOffset, ImageNum imageNum) {
609 // Convert to a target we can get a real name for
610 dyld3::closure::Image::ResolvedSymbolTarget target;
611 target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
612 target.image.imageNum = imageNum;
613 target.image.offset = classNameVMOffset;
614
615 Node targetNode;
616 targetNode.value = printTarget(imagesArrays, target);
617
618 Node classNode;
619 classNode.map["name"] = targetNode;
620 classesNode.array.push_back(classNode);
621 },
622 ^(uint64_t classVMOffset, ImageNum imageNum) {
623 dyld3::closure::Image::ResolvedSymbolTarget implTarget;
624 implTarget.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
625 implTarget.image.imageNum = imageNum;
626 implTarget.image.offset = classVMOffset;
627
628 Node implNode;
629 implNode.value = printTarget(imagesArrays, implTarget);
630 classesNode.array.back().map["implementations"].array.push_back(implNode);
631 });
632
633 root.map["objc-classes"] = classesNode;
634 }
635
636 if ( protocolHashTable != nullptr ) {
637 __block Node protocolsNode;
638
639 protocolHashTable->forEachClass(classImages,
640 ^(uint64_t protocolNameVMOffset, ImageNum imageNum) {
641 // Convert to a target we can get a real name for
642 dyld3::closure::Image::ResolvedSymbolTarget target;
643 target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
644 target.image.imageNum = imageNum;
645 target.image.offset = protocolNameVMOffset;
646
647 Node targetNode;
648 targetNode.value = printTarget(imagesArrays, target);
649
650 Node protocolNode;
651 protocolNode.map["name"] = targetNode;
652 protocolsNode.array.push_back(protocolNode);
653 },
654 ^(uint64_t protocolVMOffset, ImageNum imageNum) {
655 dyld3::closure::Image::ResolvedSymbolTarget implTarget;
656 implTarget.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
657 implTarget.image.imageNum = imageNum;
658 implTarget.image.offset = protocolVMOffset;
659
660 Node implNode;
661 implNode.value = printTarget(imagesArrays, implTarget);
662 protocolsNode.array.back().map["implementations"].array.push_back(implNode);
663 });
664
665 root.map["objc-protocols"] = protocolsNode;
666 }
667 }
668
669 const ObjCClassDuplicatesOpt* duplicateClassesHashTable = nullptr;
670 closure->duplicateClassesHashTable(duplicateClassesHashTable);
671 if ( duplicateClassesHashTable != nullptr ) {
672 __block Node duplicateClassesNode;
673 duplicateClassesHashTable->forEachClass(^(Image::ObjCDuplicateClass duplicateClass) {
674 objc_opt::objc_clsopt_t* clsOpt = dyldCache->objcOpt()->clsopt();
675 const char* className = clsOpt->getClassNameForIndex(duplicateClass.sharedCacheClassOptIndex);
676 const void* classImpl = clsOpt->getClassForIndex(duplicateClass.sharedCacheClassOptIndex, duplicateClass.sharedCacheClassDuplicateIndex);
677
678 // Convert to a target we can get a real name for
679 dyld3::closure::Image::ResolvedSymbolTarget target;
680 target.sharedCache.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindSharedCache;
681 target.sharedCache.offset = (uint64_t)classImpl - (uint64_t)dyldCache;
682
683 Node targetNode;
684 targetNode.value = printTarget(imagesArrays, target);
685
686 Node duplicateClassNode;
687 duplicateClassNode.map["name"].value = className;
688 duplicateClassNode.map["implementation"] = targetNode;
689 duplicateClassNode.array.push_back(targetNode);
690
691 duplicateClassesNode.array.push_back(duplicateClassNode);
692 });
693
694 root.map["objc-duplicate-classes"] = duplicateClassesNode;
695 }
696
697 // add warnings for objc if they exist
698 closure->forEachWarning(Closure::Warning::duplicateObjCClass, ^(const char *warning, bool &stop) {
699 Node warningNode;
700 warningNode.value = warning;
701 root.map["objc-duplicate-class-warnings"].array.push_back(warningNode);
702 });
703
704 // add program vars info for old macOS binaries
705 uint32_t progVarsOffset;
706 if ( closure->hasProgramVars(progVarsOffset) )
707 root.map["program-vars-offset"].value = hex8(progVarsOffset);
708
709 #if 0
710
711
712 // add uuid of dyld cache this closure requires
713 closure.dyldCacheUUID();
714 uuid_string_t cacheUuidStr;
715 uuid_unparse(*closure.dyldCacheUUID(), cacheUuidStr);
716 root.map["dyld-cache-uuid"].value = cacheUuidStr;
717
718 // add top level images
719 Node& rootImages = root.map["root-images"];
720 uint32_t initImageCount = closure.mainExecutableImageIndex();
721 rootImages.array.resize(initImageCount+1);
722 for (uint32_t i=0; i <= initImageCount; ++i) {
723 const Image image = closure.group().image(i);
724 uuid_string_t uuidStr;
725 uuid_unparse(image->uuid(), uuidStr);
726 rootImages.array[i].value = uuidStr;
727 }
728 root.map["initial-image-count"].value = decimal(closure.initialImageCount());
729
730 // add images
731 root.map["group-num"].value = decimal(closure.group().groupNum());
732
733
734 __block Node cacheOverrides;
735 closure.group().forEachDyldCacheSymbolOverride(^(uint32_t patchTableIndex, uint32_t imageIndexInClosure, uint32_t imageOffset, bool& stop) {
736 Node patch;
737 patch.map["patch-index"].value = decimal(patchTableIndex);
738 patch.map["replacement"].value = "{closure[" + decimal(imageIndexInClosure) + "]+" + hex(imageOffset) + "}";
739 cacheOverrides.array.push_back(patch);
740 });
741 if ( !cacheOverrides.array.empty() )
742 root.map["dyld-cache-overrides"].array = cacheOverrides.array;
743 #endif
744 return root;
745 }
746
747 void printImageAsJSON(const Image* image, const Array<const ImageArray*>& imagesArrays,
748 bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
749 {
750 Node root = buildImageNode(image, imagesArrays, printFixups, false, printRaw, dyldCache, nullptr, {});
751 printJSON(root, 0, out);
752 }
753
754 void printDyldCacheImagesAsJSON(const DyldSharedCache* dyldCache, bool printFixups, bool printRaw, std::ostream& out)
755 {
756 const dyld3::closure::ImageArray* dylibs = dyldCache->cachedDylibsImageArray();
757 STACK_ALLOC_ARRAY(const ImageArray*, imagesArrays, 2);
758 imagesArrays.push_back(dylibs);
759
760 Node root = buildImageArrayNode(dylibs, imagesArrays, printFixups, false, printRaw, dyldCache, nullptr, {});
761 printJSON(root, 0, out);
762 }
763
764 void printClosureAsJSON(const LaunchClosure* cls, const Array<const ImageArray*>& imagesArrays,
765 bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
766 {
767 Node root = buildClosureNode(cls, imagesArrays, printFixups, false, printRaw, dyldCache);
768 printJSON(root, 0, out);
769 }
770
771 void printClosureAsJSON(const DlopenClosure* cls, const Array<const ImageArray*>& imagesArrays,
772 bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
773 {
774 Node root = buildClosureNode(cls, imagesArrays, printFixups, printRaw, false);
775 printJSON(root, 0, out);
776 }
777
778
779 } // namespace closure
780 } // namespace dyld3