]> git.saurik.com Git - apple/dyld.git/blob - dyld3/MachOAppCache.cpp
dyld-851.27.tar.gz
[apple/dyld.git] / dyld3 / MachOAppCache.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 "MachOAppCache.h"
25
26 #include <list>
27
28 #include <CoreFoundation/CFArray.h>
29 #include <CoreFoundation/CFPropertyList.h>
30 #include <CoreFoundation/CFString.h>
31
32 #ifndef LC_FILESET_ENTRY
33 #define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD) /* used with fileset_entry_command */
34 struct fileset_entry_command {
35 uint32_t cmd; /* LC_FILESET_ENTRY */
36 uint32_t cmdsize; /* includes id string */
37 uint64_t vmaddr; /* memory address of the dylib */
38 uint64_t fileoff; /* file offset of the dylib */
39 union lc_str entry_id; /* contained entry id */
40 uint32_t reserved; /* entry_id is 32-bits long, so this is the reserved padding */
41 };
42 #endif
43
44 namespace dyld3 {
45
46 void MachOAppCache::forEachDylib(Diagnostics& diag, void (^callback)(const MachOAnalyzer* ma, const char* name, bool& stop)) const {
47 const intptr_t slide = getSlide();
48 forEachLoadCommand(diag, ^(const load_command *cmd, bool &stop) {
49 if (cmd->cmd == LC_FILESET_ENTRY) {
50 const fileset_entry_command* app_cache_cmd = (const fileset_entry_command*)cmd;
51 const char* name = (char*)app_cache_cmd + app_cache_cmd->entry_id.offset;
52 callback((const MachOAnalyzer*)(app_cache_cmd->vmaddr + slide), name, stop);
53 return;
54 }
55 });
56 }
57
58 void MachOAppCache::forEachPrelinkInfoLibrary(Diagnostics& diags,
59 void (^callback)(const char* bundleName, const char* relativePath,
60 const std::vector<const char*>& deps)) const {
61
62 __block std::list<std::string> nonASCIIStrings;
63 auto getString = ^(Diagnostics& diags, CFStringRef symbolNameRef) {
64 const char* symbolName = CFStringGetCStringPtr(symbolNameRef, kCFStringEncodingUTF8);
65 if ( symbolName != nullptr )
66 return symbolName;
67
68 CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(symbolNameRef), kCFStringEncodingUTF8);
69 char buffer[len + 1];
70 if ( !CFStringGetCString(symbolNameRef, buffer, len, kCFStringEncodingUTF8) ) {
71 diags.error("Could not convert string to ASCII");
72 return (const char*)nullptr;
73 }
74 buffer[len] = '\0';
75 nonASCIIStrings.push_back(buffer);
76 return nonASCIIStrings.back().c_str();
77 };
78
79 const uint8_t* prelinkInfoBuffer = nullptr;
80 uint64_t prelinkInfoBufferSize = 0;
81 prelinkInfoBuffer = (const uint8_t*)findSectionContent("__PRELINK_INFO", "__info", prelinkInfoBufferSize);
82 if ( prelinkInfoBuffer == nullptr )
83 return;
84
85 CFReadStreamRef readStreamRef = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, prelinkInfoBuffer, prelinkInfoBufferSize, kCFAllocatorNull);
86 if ( !CFReadStreamOpen(readStreamRef) ) {
87 fprintf(stderr, "Could not open plist stream\n");
88 exit(1);
89 }
90 CFErrorRef errorRef = nullptr;
91 CFPropertyListRef plistRef = CFPropertyListCreateWithStream(kCFAllocatorDefault, readStreamRef, prelinkInfoBufferSize, kCFPropertyListImmutable, nullptr, &errorRef);
92 if ( errorRef != nullptr ) {
93 CFStringRef stringRef = CFErrorCopyFailureReason(errorRef);
94 fprintf(stderr, "Could not read plist because: %s\n", CFStringGetCStringPtr(stringRef, kCFStringEncodingASCII));
95 CFRelease(stringRef);
96 exit(1);
97 }
98 assert(CFGetTypeID(plistRef) == CFDictionaryGetTypeID());
99
100 // Get the "_PrelinkInfoDictionary" array
101 CFArrayRef prelinkInfoDictionaryArrayRef = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)plistRef, CFSTR("_PrelinkInfoDictionary"));
102 assert(CFGetTypeID(prelinkInfoDictionaryArrayRef) == CFArrayGetTypeID());
103
104 for (CFIndex i = 0; i != CFArrayGetCount(prelinkInfoDictionaryArrayRef); ++i) {
105 CFDictionaryRef kextInfoDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(prelinkInfoDictionaryArrayRef, i);
106 assert(CFGetTypeID(kextInfoDictionary) == CFDictionaryGetTypeID());
107
108 CFStringRef bundleIdentifierStringRef = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)kextInfoDictionary, CFSTR("CFBundleIdentifier"));
109 assert(CFGetTypeID(bundleIdentifierStringRef) == CFStringGetTypeID());
110
111 const char* bundleID = getString(diags, bundleIdentifierStringRef);
112 if ( bundleID == nullptr )
113 return;
114
115 const char* relativePath = nullptr;
116 CFStringRef relativePathStringRef = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)kextInfoDictionary, CFSTR("_PrelinkExecutableRelativePath"));
117 if ( relativePathStringRef != nullptr ) {
118 assert(CFGetTypeID(relativePathStringRef) == CFStringGetTypeID());
119 relativePath = getString(diags, relativePathStringRef);
120 if ( relativePath == nullptr )
121 return;
122 }
123
124 std::vector<const char*> dependencies;
125
126 CFDictionaryRef bundleLibrariesDictionaryRef = (CFDictionaryRef)CFDictionaryGetValue((CFDictionaryRef)kextInfoDictionary, CFSTR("OSBundleLibraries"));
127 if (bundleLibrariesDictionaryRef != nullptr) {
128 // Add the libraries to the dependencies
129 // If we didn't have bundle libraries then a placeholder was added
130 assert(CFGetTypeID(bundleLibrariesDictionaryRef) == CFDictionaryGetTypeID());
131
132 struct ApplyContext {
133 Diagnostics* diagnostics;
134 std::vector<const char*>* dependencies = nullptr;
135 const char* (^getString)(Diagnostics& diags, CFStringRef symbolNameRef) = nullptr;
136 };
137
138 CFDictionaryApplierFunction callback = [](const void *key, const void *value, void *context) {
139 CFStringRef keyStringRef = (CFStringRef)key;
140 assert(CFGetTypeID(keyStringRef) == CFStringGetTypeID());
141
142 ApplyContext* applyContext = (ApplyContext*)context;
143 const char* depString = applyContext->getString(*applyContext->diagnostics, keyStringRef);
144 if ( !depString )
145 return;
146
147 applyContext->dependencies->push_back(depString);
148 };
149
150 ApplyContext applyContext = { &diags, &dependencies, getString };
151 CFDictionaryApplyFunction(bundleLibrariesDictionaryRef, callback, &applyContext);
152
153 if ( diags.hasError() )
154 return;
155 }
156 callback(bundleID, relativePath, dependencies);
157 }
158
159 CFRelease(plistRef);
160 CFRelease(readStreamRef);
161 }
162
163 } // namespace dyld3