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