]> git.saurik.com Git - apple/cf.git/blob - CFBundle_Binary.c
CF-1152.14.tar.gz
[apple/cf.git] / CFBundle_Binary.c
1 /*
2 * Copyright (c) 2015 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 /* CFBundle_Binary.c
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
27 */
28
29 #include "CFBundle_Internal.h"
30
31 #if defined(BINARY_SUPPORT_DYLD)
32 // Import the mach-o headers that define the macho magic numbers
33 #include <mach-o/loader.h>
34 #include <mach-o/fat.h>
35 #include <mach-o/arch.h>
36 #include <mach-o/dyld.h>
37 #include <mach-o/getsect.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/mman.h>
41 #include <crt_externs.h>
42 #if defined(USE_DYLD_PRIV)
43 #include <mach-o/dyld_priv.h>
44 #endif /* USE_DYLD_PRIV */
45 #endif /* BINARY_SUPPORT_DYLD */
46
47 #if defined(BINARY_SUPPORT_DLFCN)
48 #include <dlfcn.h>
49 #endif /* BINARY_SUPPORT_DLFCN */
50
51 #if defined(BINARY_SUPPORT_DYLD)
52 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p);
53 #if !defined(BINARY_SUPPORT_DLFCN)
54 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
55 #endif /* !BINARY_SUPPORT_DLFCN */
56 #endif /* BINARY_SUPPORT_DYLD */
57 #if defined(BINARY_SUPPORT_DLFCN)
58 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
59 #if !defined(BINARY_SUPPORT_DYLD)
60 static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p);
61 #endif /* !BINARY_SUPPORT_DYLD */
62 #endif /* BINARY_SUPPORT_DLFCN */
63
64
65 CF_PRIVATE SInt32 _CFBundleCurrentArchitecture(void) {
66 SInt32 arch = 0;
67 #if defined(__ppc__)
68 arch = kCFBundleExecutableArchitecturePPC;
69 #elif defined(__ppc64__)
70 arch = kCFBundleExecutableArchitecturePPC64;
71 #elif defined(__i386__)
72 arch = kCFBundleExecutableArchitectureI386;
73 #elif defined(__x86_64__)
74 arch = kCFBundleExecutableArchitectureX86_64;
75 #elif defined(BINARY_SUPPORT_DYLD)
76 const NXArchInfo *archInfo = NXGetLocalArchInfo();
77 if (archInfo) arch = archInfo->cputype;
78 #endif
79 return arch;
80 }
81
82 #if defined(BINARY_SUPPORT_DYLD)
83
84 CF_PRIVATE CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) {
85 uint32_t i, numImages = _dyld_image_count();
86 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
87 CFRange range = CFRangeMake(0, CFStringGetLength(hint)), altRange = CFRangeMake(0, 0), testRange = CFRangeMake(0, 0);
88 const char *processPath = _CFProcessPath();
89 const void *mhp = (const void *)_NSGetMachExecuteHeader();
90
91 if (range.length > 14) {
92 // handle some common variations on framework bundle identifiers
93 if (CFStringFindWithOptions(hint, CFSTR(".framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
94 // identifier has .framework appended
95 altRange.length = testRange.location;
96 } else if (CFStringFindWithOptions(hint, CFSTR("framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
97 // identifier has Framework appended
98 altRange.length = testRange.location;
99 } else if (CFStringFindWithOptions(hint, CFSTR("fw"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
100 // identifier has FW appended
101 altRange.length = testRange.location;
102 }
103 }
104 for (i = 0; i < numImages; i++) {
105 const char *curName = _dyld_get_image_name(i), *lastComponent = NULL;
106 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) lastComponent = strrchr(curName, '/');
107 if (lastComponent) {
108 CFStringRef str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, lastComponent + 1);
109 if (str) {
110 if (CFStringFindWithOptions(hint, str, range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL) || (altRange.length > 0 && CFStringFindWithOptions(hint, str, altRange, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL))) {
111 CFStringRef curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName);
112 if (curStr) {
113 CFArrayAppendValue(result, curStr);
114 CFRelease(curStr);
115 }
116 }
117 CFRelease(str);
118 }
119 }
120 }
121 return result;
122 }
123
124 static char *_cleanedPathForPath(const char *curName) {
125 char *thePath = strdup(curName);
126 if (thePath) {
127 // We are going to process the buffer replacing all "/./" and "//" with "/"
128 CFIndex srcIndex = 0, dstIndex = 0;
129 CFIndex len = strlen(thePath);
130 for (srcIndex=0; srcIndex<len; srcIndex++) {
131 thePath[dstIndex] = thePath[srcIndex];
132 dstIndex++;
133 while (srcIndex < len-1 && thePath[srcIndex] == '/' && (thePath[srcIndex+1] == '/' || (thePath[srcIndex+1] == '.' && srcIndex < len-2 && thePath[srcIndex+2] == '/'))) srcIndex += (thePath[srcIndex+1] == '/' ? 1 : 2);
134 }
135 thePath[dstIndex] = 0;
136 }
137 return thePath;
138 }
139
140 CF_PRIVATE CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
141 // This returns an array of the paths of all the dyld images in the process. These paths may not be absolute, they may point at things that are not bundles, they may be staticly linked bundles or dynamically loaded bundles, they may be NULL.
142 uint32_t i, numImages = _dyld_image_count();
143 CFMutableArrayRef result = NULL;
144 static uint32_t _cachedDYLDImageCount = -1;
145
146 if (numImages != _cachedDYLDImageCount) {
147 const char *curName;
148 char *cleanedCurName = NULL;
149 CFStringRef curStr;
150 const char *processPath = _CFProcessPath();
151 const void *mhp = (const void *)_NSGetMachExecuteHeader();
152
153 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
154
155 for (i = 0; i < numImages; i++) {
156 curName = _dyld_get_image_name(i);
157 if (curName && i == 0) cleanedCurName = _cleanedPathForPath(curName);
158 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && (!processPath || !cleanedCurName || 0 != strcmp(cleanedCurName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) {
159 curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName);
160 if (curStr) {
161 CFArrayAppendValue(result, curStr);
162 CFRelease(curStr);
163 }
164 }
165 if (cleanedCurName) {
166 free(cleanedCurName);
167 cleanedCurName = NULL;
168 }
169 }
170 _cachedDYLDImageCount = numImages;
171 }
172 return result;
173 }
174
175 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) {
176 CFStringRef result = NULL;
177 #if defined(USE_DYLD_PRIV)
178 const char *name = dyld_image_path_containing_address(p);
179 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name);
180 #else /* USE_DYLD_PRIV */
181 if (!result) {
182 uint32_t i, j, n = _dyld_image_count();
183 Boolean foundit = false;
184 const char *name;
185 #if __LP64__
186 #define MACH_HEADER_TYPE struct mach_header_64
187 #define MACH_SEGMENT_CMD_TYPE struct segment_command_64
188 #define MACH_SEGMENT_FLAVOR LC_SEGMENT_64
189 #else
190 #define MACH_HEADER_TYPE struct mach_header
191 #define MACH_SEGMENT_CMD_TYPE struct segment_command
192 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
193 #endif
194 for (i = 0; !foundit && i < n; i++) {
195 const MACH_HEADER_TYPE *mh = (const MACH_HEADER_TYPE *)_dyld_get_image_header(i);
196 uintptr_t addr = (uintptr_t)p - _dyld_get_image_vmaddr_slide(i);
197 if (mh) {
198 struct load_command *lc = (struct load_command *)((char *)mh + sizeof(MACH_HEADER_TYPE));
199 for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) {
200 if (MACH_SEGMENT_FLAVOR == lc->cmd && ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr <= addr && addr < ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr + ((MACH_SEGMENT_CMD_TYPE *)lc)->vmsize) {
201 foundit = true;
202 name = _dyld_get_image_name(i);
203 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name);
204 }
205 }
206 }
207 }
208 #undef MACH_HEADER_TYPE
209 #undef MACH_SEGMENT_CMD_TYPE
210 #undef MACH_SEGMENT_FLAVOR
211 }
212 #endif /* USE_DYLD_PRIV */
213 #if LOG_BUNDLE_LOAD
214 printf("dyld image path for pointer %p is %p\n", p, result);
215 #endif /* LOG_BUNDLE_LOAD */
216 return result;
217 }
218
219 #if !defined(BINARY_SUPPORT_DLFCN)
220
221 static const void *__CFBundleDYLDFindImage(char *buff) {
222 const void *header = NULL;
223 uint32_t i, numImages = _dyld_image_count(), numMatches = 0;
224 const char *curName, *p, *q;
225
226 for (i = 0; !header && i < numImages; i++) {
227 curName = _dyld_get_image_name(i);
228 if (curName && 0 == strncmp(curName, buff, CFMaxPathSize)) {
229 header = _dyld_get_image_header(i);
230 numMatches = 1;
231 }
232 }
233 if (!header) {
234 for (i = 0; i < numImages; i++) {
235 curName = _dyld_get_image_name(i);
236 if (curName) {
237 for (p = buff, q = curName; *p && *q && (q - curName < CFMaxPathSize); p++, q++) {
238 if (*p != *q && (q - curName > 11) && 0 == strncmp(q - 11, ".framework/Versions/", 20) && *(q + 9) && '/' == *(q + 10)) q += 11;
239 else if (*p != *q && (q - curName > 12) && 0 == strncmp(q - 12, ".framework/Versions/", 20) && *(q + 8) && '/' == *(q + 9)) q += 10;
240 if (*p != *q) break;
241 }
242 if (*p == *q) {
243 header = _dyld_get_image_header(i);
244 numMatches++;
245 }
246 }
247 }
248 }
249 return (numMatches == 1) ? header : NULL;
250 }
251
252 CF_PRIVATE Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) {
253 if (!bundle->_isLoaded) {
254 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
255 char buff[CFMaxPathSize];
256
257 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
258 const void *header = __CFBundleDYLDFindImage(buff);
259 if (header) {
260 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
261 if (!bundle->_imageCookie) {
262 bundle->_imageCookie = header;
263 #if LOG_BUNDLE_LOAD
264 printf("dyld check load bundle %p, find %s getting image %p\n", bundle, buff, bundle->_imageCookie);
265 #endif /* LOG_BUNDLE_LOAD */
266 }
267 bundle->_isLoaded = true;
268 } else {
269 #if LOG_BUNDLE_LOAD
270 printf("dyld check load bundle %p, find %s no image\n", bundle, buff);
271 #endif /* LOG_BUNDLE_LOAD */
272 }
273 }
274 if (executableURL) CFRelease(executableURL);
275 }
276 return bundle->_isLoaded;
277 }
278
279 CF_PRIVATE Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
280 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
281 NSLinkEditErrors c = NSLinkEditUndefinedError;
282 int errorNumber = 0;
283 const char *fileName = NULL;
284 const char *errorString = NULL;
285
286 if (!bundle->_isLoaded) {
287 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
288 char buff[CFMaxPathSize];
289
290 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
291 NSObjectFileImage image;
292 NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image);
293 #if LOG_BUNDLE_LOAD
294 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle, buff, image, retCode);
295 #endif /* LOG_BUNDLE_LOAD */
296 if (retCode == NSObjectFileImageSuccess) {
297 uint32_t options = forceGlobal ? NSLINKMODULE_OPTION_RETURN_ON_ERROR : (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
298 NSModule module = NSLinkModule(image, buff, options);
299 #if LOG_BUNDLE_LOAD
300 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle, buff, options, module, image);
301 #endif /* LOG_BUNDLE_LOAD */
302 if (module) {
303 bundle->_imageCookie = image;
304 bundle->_moduleCookie = module;
305 bundle->_isLoaded = true;
306 } else {
307 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
308 if (error) {
309 #if defined(BINARY_SUPPORT_DLFCN)
310 _CFBundleDlfcnPreflight(bundle, subError);
311 #endif /* BINARY_SUPPORT_DLFCN */
312 if (!localError) {
313 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString);
314 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
315 if (tempString) CFRelease(tempString);
316 if (debugString) CFRelease(debugString);
317 }
318 } else {
319 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName);
320 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString);
321 if (tempString) CFRelease(tempString);
322 if (executableString) CFRelease(executableString);
323 }
324 (void)NSDestroyObjectFileImage(image);
325 }
326 } else {
327 if (error) {
328 if (retCode == NSObjectFileImageArch) {
329 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError);
330 } else if (retCode == NSObjectFileImageInappropriateFile) {
331 Boolean hasRuntimeMismatch = false;
332 uint32_t mainFlags = 0, bundleFlags = 0;
333 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) {
334 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true;
335 }
336 if (hasRuntimeMismatch) {
337 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError);
338 } else {
339 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
340 }
341 } else {
342 #if defined(BINARY_SUPPORT_DLFCN)
343 _CFBundleDlfcnPreflight(bundle, subError);
344 #endif /* BINARY_SUPPORT_DLFCN */
345 if (!localError) {
346 CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("dyld returns %d"), retCode);
347 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
348 CFRelease(debugString);
349 }
350 }
351 } else {
352 CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL);
353 }
354 }
355 } else {
356 if (error) {
357 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
358 } else {
359 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
360 }
361 }
362 if (executableURL) CFRelease(executableURL);
363 }
364 if (!bundle->_isLoaded && error) *error = localError;
365 return bundle->_isLoaded;
366 }
367
368 CF_PRIVATE Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle, CFErrorRef *error) {
369 // !!! Framework loading should be better. Can't unload frameworks.
370 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
371 NSLinkEditErrors c = NSLinkEditUndefinedError;
372 int errorNumber = 0;
373 const char *fileName = NULL;
374 const char *errorString = NULL;
375
376 if (!bundle->_isLoaded) {
377 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
378 char buff[CFMaxPathSize];
379
380 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
381 void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
382 #if LOG_BUNDLE_LOAD
383 printf("dyld load framework %p, add image of %s returns image %p\n", bundle, buff, image);
384 #endif /* LOG_BUNDLE_LOAD */
385 if (image) {
386 bundle->_imageCookie = image;
387 bundle->_isLoaded = true;
388 } else {
389 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
390 if (error) {
391 #if defined(BINARY_SUPPORT_DLFCN)
392 _CFBundleDlfcnPreflight(bundle, subError);
393 #endif /* BINARY_SUPPORT_DLFCN */
394 if (!localError) {
395 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString);
396 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
397 if (tempString) CFRelease(tempString);
398 if (debugString) CFRelease(debugString);
399 }
400 } else {
401 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName);
402 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString);
403 if (tempString) CFRelease(tempString);
404 if (executableString) CFRelease(executableString);
405 }
406 }
407 } else {
408 if (error) {
409 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
410 } else {
411 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
412 }
413 }
414 if (executableURL) CFRelease(executableURL);
415 }
416 if (!bundle->_isLoaded && error) *error = localError;
417 return bundle->_isLoaded;
418 }
419
420 CF_PRIVATE void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) {
421 if (bundle->_isLoaded) {
422 #if LOG_BUNDLE_LOAD
423 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie);
424 #endif /* LOG_BUNDLE_LOAD */
425 if (bundle->_moduleCookie && !NSUnLinkModule((NSModule)(bundle->_moduleCookie), NSUNLINKMODULE_OPTION_NONE)) {
426 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
427 } else {
428 if (bundle->_moduleCookie && bundle->_imageCookie) (void)NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie));
429 bundle->_connectionCookie = bundle->_handleCookie = NULL;
430 bundle->_imageCookie = bundle->_moduleCookie = NULL;
431 bundle->_isLoaded = false;
432 }
433 }
434 }
435
436 CF_PRIVATE void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
437 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle, symbolName, false);
438 }
439
440 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
441 void *result = NULL;
442 char buff[1026];
443 NSSymbol symbol = NULL;
444
445 buff[0] = '_';
446 if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingUTF8)) {
447 if (bundle->_moduleCookie) {
448 symbol = NSLookupSymbolInModule((NSModule)(bundle->_moduleCookie), buff);
449 } else if (bundle->_imageCookie) {
450 symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
451 }
452 if (!symbol && !bundle->_moduleCookie && (!bundle->_imageCookie || globalSearch)) {
453 char hintBuff[1026];
454 CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL);
455 hintBuff[0] = '\0';
456 if (executableName) {
457 if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0';
458 CFRelease(executableName);
459 }
460 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint()
461 // are identical, except the first just returns a bool, so checking with the
462 // Is function first just causes a redundant lookup.
463 // This returns NULL on failure.
464 symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff);
465 }
466 if (symbol) result = NSAddressOfSymbol(symbol);
467 #if defined(DEBUG)
468 if (!result) CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %@ in %@"), symbolName, bundle);
469 #endif /* DEBUG */
470 #if LOG_BUNDLE_LOAD
471 printf("bundle %p handle %p module %p image %p dyld returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff + 1);
472 #endif /* LOG_BUNDLE_LOAD */
473 }
474 return result;
475 }
476
477 #endif /* !BINARY_SUPPORT_DLFCN */
478 #endif /* BINARY_SUPPORT_DYLD */
479
480 #if defined(BINARY_SUPPORT_DLFCN)
481
482 CF_PRIVATE Boolean _CFBundleDlfcnCheckLoaded(CFBundleRef bundle) {
483 if (!bundle->_isLoaded) {
484 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
485 char buff[CFMaxPathSize];
486
487 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
488 int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST;
489 void *handle = dlopen(buff, mode);
490 if (handle) {
491 if (!bundle->_handleCookie) {
492 bundle->_handleCookie = handle;
493 #if LOG_BUNDLE_LOAD
494 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle, buff, mode, bundle->_handleCookie);
495 #endif /* LOG_BUNDLE_LOAD */
496 }
497 bundle->_isLoaded = true;
498 } else {
499 #if LOG_BUNDLE_LOAD
500 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle, buff, mode);
501 #endif /* LOG_BUNDLE_LOAD */
502 }
503 }
504 if (executableURL) CFRelease(executableURL);
505 }
506 return bundle->_isLoaded;
507 }
508
509 CF_EXPORT Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error) {
510 Boolean retval = true;
511 CFErrorRef localError = NULL;
512 if (!bundle->_isLoaded) {
513 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
514 char buff[CFMaxPathSize];
515
516 retval = false;
517 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
518 retval = dlopen_preflight(buff);
519 if (!retval && error) {
520 CFArrayRef archs = CFBundleCopyExecutableArchitectures(bundle);
521 CFStringRef debugString = NULL;
522 const char *errorString = dlerror();
523 if (errorString && strlen(errorString) > 0) debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString);
524 if (archs) {
525 Boolean hasSuitableArch = false, hasRuntimeMismatch = false;
526 CFIndex i, count = CFArrayGetCount(archs);
527 SInt32 arch, curArch = _CFBundleCurrentArchitecture();
528 for (i = 0; !hasSuitableArch && i < count; i++) {
529 if (CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(archs, i), kCFNumberSInt32Type, (void *)&arch) && arch == curArch) hasSuitableArch = true;
530 }
531 #if defined(BINARY_SUPPORT_DYLD)
532 if (hasSuitableArch) {
533 uint32_t mainFlags = 0;
534 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) {
535 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
536 uint32_t bundleFlags = 0;
537 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true;
538 #endif
539 }
540 }
541 #endif /* BINARY_SUPPORT_DYLD */
542 if (hasRuntimeMismatch) {
543 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError, debugString);
544 } else if (!hasSuitableArch) {
545 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError, debugString);
546 } else {
547 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString);
548 }
549 CFRelease(archs);
550 } else {
551 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString);
552 }
553 if (debugString) CFRelease(debugString);
554 }
555 } else {
556 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
557 }
558 if (executableURL) CFRelease(executableURL);
559 }
560 if (!retval && error) *error = localError;
561 return retval;
562 }
563
564 CF_PRIVATE Boolean _CFBundleDlfcnLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
565 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
566 if (!bundle->_isLoaded) {
567 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
568 char buff[CFMaxPathSize];
569 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
570 int mode = forceGlobal ? (RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST) : (RTLD_NOW | RTLD_LOCAL | RTLD_FIRST);
571 void *cookie = dlopen(buff, mode);
572 #if LOG_BUNDLE_LOAD
573 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie);
574 #endif /* LOG_BUNDLE_LOAD */
575 if (cookie && cookie == bundle->_handleCookie) {
576 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
577 #if LOG_BUNDLE_LOAD
578 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle, cookie);
579 #endif /* LOG_BUNDLE_LOAD */
580 dlclose(bundle->_handleCookie);
581 }
582 bundle->_handleCookie = cookie;
583 if (bundle->_handleCookie) {
584 bundle->_isLoaded = true;
585 } else {
586 const char *dyldError = dlerror();
587 CFStringRef errorString = dyldError ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, dyldError) : NULL;
588 if (error) {
589 _CFBundleDlfcnPreflight(bundle, subError);
590 if (!localError) localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, errorString);
591 } else {
592 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
593 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, errorString ? errorString : CFSTR("(no additional info)"));
594 if (executableString) CFRelease(executableString);
595 }
596 if (errorString) CFRelease(errorString);
597 }
598 } else {
599 if (error) {
600 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
601 } else {
602 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
603 }
604 }
605 if (executableURL) CFRelease(executableURL);
606 }
607 if (!bundle->_isLoaded && error) *error = localError;
608 return bundle->_isLoaded;
609 }
610
611 CF_PRIVATE Boolean _CFBundleDlfcnLoadFramework(CFBundleRef bundle, CFErrorRef *error) {
612 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
613 if (!bundle->_isLoaded) {
614 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
615 char buff[CFMaxPathSize];
616 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
617 int mode = RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST;
618 void *cookie = dlopen(buff, mode);
619 #if LOG_BUNDLE_LOAD
620 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie);
621 #endif /* LOG_BUNDLE_LOAD */
622 if (cookie && cookie == bundle->_handleCookie) {
623 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
624 #if LOG_BUNDLE_LOAD
625 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle, cookie);
626 #endif /* LOG_BUNDLE_LOAD */
627 dlclose(bundle->_handleCookie);
628 }
629 bundle->_handleCookie = cookie;
630 if (bundle->_handleCookie) {
631 bundle->_isLoaded = true;
632 } else {
633 const char *dyldError = dlerror();
634 CFStringRef errorString = dyldError ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, dyldError) : NULL;
635 if (error) {
636 _CFBundleDlfcnPreflight(bundle, subError);
637 if (!localError) localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, errorString);
638 } else {
639 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
640 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, errorString ? errorString : CFSTR("(no additional info)"));
641 }
642 if (errorString) CFRelease(errorString);
643 }
644 } else {
645 if (error) {
646 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
647 } else {
648 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
649 }
650 }
651 if (executableURL) CFRelease(executableURL);
652 }
653 if (!bundle->_isLoaded && error) *error = localError;
654 return bundle->_isLoaded;
655 }
656
657 CF_PRIVATE void _CFBundleDlfcnUnload(CFBundleRef bundle) {
658 if (bundle->_isLoaded) {
659 #if LOG_BUNDLE_LOAD
660 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie);
661 #endif /* LOG_BUNDLE_LOAD */
662 if (0 != dlclose(bundle->_handleCookie)) {
663 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
664 } else {
665 bundle->_connectionCookie = bundle->_handleCookie = NULL;
666 bundle->_imageCookie = bundle->_moduleCookie = NULL;
667 bundle->_isLoaded = false;
668 }
669 }
670 }
671
672 CF_PRIVATE void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
673 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, symbolName, false);
674 }
675
676 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
677 void *result = NULL;
678 char buff[1026];
679
680 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingUTF8)) {
681 result = dlsym(bundle->_handleCookie, buff);
682 if (!result && globalSearch) result = dlsym(RTLD_DEFAULT, buff);
683 #if defined(DEBUG)
684 if (!result) CFLog(__kCFLogBundle, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName, bundle);
685 #endif /* DEBUG */
686 #if LOG_BUNDLE_LOAD
687 printf("bundle %p handle %p module %p image %p dlsym returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff);
688 #endif /* LOG_BUNDLE_LOAD */
689 }
690 return result;
691 }
692
693 #if !defined(BINARY_SUPPORT_DYLD)
694
695 static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p) {
696 CFStringRef result = NULL;
697 Dl_info info;
698 if (0 != dladdr(p, &info) && info.dli_fname) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, info.dli_fname);
699 #if LOG_BUNDLE_LOAD
700 printf("dlfcn image path for pointer %p is %p\n", p, result);
701 #endif /* LOG_BUNDLE_LOAD */
702 return result;
703 }
704
705 #endif /* !BINARY_SUPPORT_DYLD */
706 #endif /* BINARY_SUPPORT_DLFCN */
707
708 #if defined(BINARY_SUPPORT_DLL)
709
710 CF_PRIVATE Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error) {
711 CFErrorRef localError = NULL;
712 if (!bundle->_isLoaded) {
713 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
714 wchar_t buff[CFMaxPathSize];
715
716 if (executableURL && _CFURLGetWideFileSystemRepresentation(executableURL, true, (wchar_t *)buff, CFMaxPathSize)) {
717 bundle->_hModule = LoadLibraryW(buff);
718 if (bundle->_hModule) {
719 bundle->_isLoaded = true;
720 } else {
721 if (error) {
722 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError);
723 } else {
724 CFLog(__kCFLogBundle, CFSTR("Failed to load bundle %@"), bundle);
725 }
726 }
727 } else {
728 if (error) {
729 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
730 } else {
731 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
732 }
733 }
734 if (executableURL) CFRelease(executableURL);
735 }
736 if (!bundle->_isLoaded && error) *error = localError;
737 return bundle->_isLoaded;
738 }
739
740 CF_PRIVATE void _CFBundleDLLUnload(CFBundleRef bundle) {
741 if (bundle->_isLoaded) {
742 FreeLibrary(bundle->_hModule);
743 bundle->_hModule = NULL;
744 bundle->_isLoaded = false;
745 }
746 }
747
748 CF_PRIVATE void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
749 void *result = NULL;
750 char buff[1024];
751 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) result = GetProcAddress(bundle->_hModule, buff);
752 return result;
753 }
754
755 #endif /* BINARY_SUPPORT_DLL */
756
757 CF_PRIVATE CFStringRef _CFBundleCopyLoadedImagePathForPointer(void *p) {
758 CFStringRef imagePath = NULL;
759 #if defined(BINARY_SUPPORT_DYLD)
760 if (!imagePath) imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p);
761 #elif defined(BINARY_SUPPORT_DLFCN)
762 if (!imagePath) imagePath = _CFBundleDlfcnCopyLoadedImagePathForPointer(p);
763 #endif /* BINARY_SUPPORT_DYLD */
764 return imagePath;
765 }
766
767 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
768 void *tvp = NULL;
769 // Load if necessary
770 if (!bundle->_isLoaded) {
771 if (!CFBundleLoadExecutable(bundle)) return NULL;
772 }
773
774 switch (bundle->_binaryType) {
775 #if defined(BINARY_SUPPORT_DYLD)
776 case __CFBundleDYLDBundleBinary:
777 case __CFBundleDYLDFrameworkBinary:
778 case __CFBundleDYLDExecutableBinary:
779 #if defined(BINARY_SUPPORT_DLFCN)
780 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName);
781 #else /* BINARY_SUPPORT_DLFCN */
782 return _CFBundleDYLDGetSymbolByName(bundle, funcName);
783 #endif /* BINARY_SUPPORT_DLFCN */
784 break;
785 #endif /* BINARY_SUPPORT_DYLD */
786 #if defined(BINARY_SUPPORT_DLL)
787 case __CFBundleDLLBinary:
788 tvp = _CFBundleDLLGetSymbolByName(bundle, funcName);
789 break;
790 #endif /* BINARY_SUPPORT_DLL */
791 default:
792 #if defined(BINARY_SUPPORT_DLFCN)
793 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName);
794 #endif /* BINARY_SUPPORT_DLFCN */
795 break;
796 }
797 return tvp;
798 }
799
800 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
801 void *fp = NULL;
802 // Load if necessary
803 if (!bundle->_isLoaded) {
804 if (!CFBundleLoadExecutable(bundle)) return NULL;
805 }
806 #if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN)
807 switch (bundle->_binaryType) {
808 #if defined(BINARY_SUPPORT_DYLD)
809 case __CFBundleDYLDBundleBinary:
810 case __CFBundleDYLDFrameworkBinary:
811 case __CFBundleDYLDExecutableBinary:
812 #if defined(BINARY_SUPPORT_DLFCN)
813 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true);
814 #else /* BINARY_SUPPORT_DLFCN */
815 fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true);
816 #endif /* BINARY_SUPPORT_DLFCN */
817 break;
818 #endif /* BINARY_SUPPORT_DYLD */
819 default:
820 #if defined(BINARY_SUPPORT_DLFCN)
821 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true);
822 #endif /* BINARY_SUPPORT_DLFCN */
823 break;
824 }
825 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
826 return fp;
827 }
828
829 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
830 SInt32 i, c;
831
832 if (!ftbl) return;
833
834 c = CFArrayGetCount(functionNames);
835 for (i = 0; i < c; i++) ftbl[i] = CFBundleGetFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i));
836 }
837
838 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
839 SInt32 i, c;
840
841 if (!ftbl) return;
842
843 c = CFArrayGetCount(functionNames);
844 for (i = 0; i < c; i++) ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i));
845 }
846
847 void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) {
848 void *dp = NULL;
849 // Load if necessary
850 if (!bundle->_isLoaded && !CFBundleLoadExecutable(bundle)) return NULL;
851
852 switch (bundle->_binaryType) {
853 #if defined(BINARY_SUPPORT_DYLD)
854 case __CFBundleDYLDBundleBinary:
855 case __CFBundleDYLDFrameworkBinary:
856 case __CFBundleDYLDExecutableBinary:
857 #if defined(BINARY_SUPPORT_DLFCN)
858 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName);
859 #else /* BINARY_SUPPORT_DLFCN */
860 dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName);
861 #endif /* BINARY_SUPPORT_DLFCN */
862 break;
863 #endif /* BINARY_SUPPORT_DYLD */
864 #if defined(BINARY_SUPPORT_DLL)
865 case __CFBundleDLLBinary:
866 /* MF:!!! Handle this someday */
867 break;
868 #endif /* BINARY_SUPPORT_DLL */
869 default:
870 #if defined(BINARY_SUPPORT_DLFCN)
871 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName);
872 #endif /* BINARY_SUPPORT_DLFCN */
873 break;
874 }
875 return dp;
876 }
877
878 void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, void *stbl[]) {
879 SInt32 i, c;
880
881 if (!stbl) return;
882
883 c = CFArrayGetCount(symbolNames);
884 for (i = 0; i < c; i++) stbl[i] = CFBundleGetDataPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(symbolNames, i));
885 }
886