2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
29 #include "CFBundle_Internal.h"
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>
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 */
47 #if defined(BINARY_SUPPORT_DLFCN)
49 #endif /* BINARY_SUPPORT_DLFCN */
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 */
65 CF_PRIVATE SInt32
_CFBundleCurrentArchitecture(void) {
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
;
82 #if defined(BINARY_SUPPORT_DYLD)
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();
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
;
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
, '/');
108 CFStringRef str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, lastComponent
+ 1);
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
);
113 CFArrayAppendValue(result
, curStr
);
124 static char *_cleanedPathForPath(const char *curName
) {
125 char *thePath
= strdup(curName
);
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
];
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);
135 thePath
[dstIndex
] = 0;
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;
146 if (numImages
!= _cachedDYLDImageCount
) {
148 char *cleanedCurName
= NULL
;
150 const char *processPath
= _CFProcessPath();
151 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
153 result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
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
);
161 CFArrayAppendValue(result
, curStr
);
165 if (cleanedCurName
) {
166 free(cleanedCurName
);
167 cleanedCurName
= NULL
;
170 _cachedDYLDImageCount
= numImages
;
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 */
182 uint32_t i
, j
, n
= _dyld_image_count();
183 Boolean foundit
= false;
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
190 #define MACH_HEADER_TYPE struct mach_header
191 #define MACH_SEGMENT_CMD_TYPE struct segment_command
192 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
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
);
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
) {
202 name
= _dyld_get_image_name(i
);
203 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
208 #undef MACH_HEADER_TYPE
209 #undef MACH_SEGMENT_CMD_TYPE
210 #undef MACH_SEGMENT_FLAVOR
212 #endif /* USE_DYLD_PRIV */
214 printf("dyld image path for pointer %p is %p\n", p
, result
);
215 #endif /* LOG_BUNDLE_LOAD */
219 #if !defined(BINARY_SUPPORT_DLFCN)
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
;
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
);
234 for (i
= 0; i
< numImages
; i
++) {
235 curName
= _dyld_get_image_name(i
);
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;
243 header
= _dyld_get_image_header(i
);
249 return (numMatches
== 1) ? header
: NULL
;
252 CF_PRIVATE Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
253 if (!bundle
->_isLoaded
) {
254 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
255 char buff
[CFMaxPathSize
];
257 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
258 const void *header
= __CFBundleDYLDFindImage(buff
);
260 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
261 if (!bundle
->_imageCookie
) {
262 bundle
->_imageCookie
= header
;
264 printf("dyld check load bundle %p, find %s getting image %p\n", bundle
, buff
, bundle
->_imageCookie
);
265 #endif /* LOG_BUNDLE_LOAD */
267 bundle
->_isLoaded
= true;
270 printf("dyld check load bundle %p, find %s no image\n", bundle
, buff
);
271 #endif /* LOG_BUNDLE_LOAD */
274 if (executableURL
) CFRelease(executableURL
);
276 return bundle
->_isLoaded
;
279 CF_PRIVATE Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
280 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
281 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
283 const char *fileName
= NULL
;
284 const char *errorString
= NULL
;
286 if (!bundle
->_isLoaded
) {
287 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
288 char buff
[CFMaxPathSize
];
290 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
291 NSObjectFileImage image
;
292 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
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
);
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 */
303 bundle
->_imageCookie
= image
;
304 bundle
->_moduleCookie
= module;
305 bundle
->_isLoaded
= true;
307 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
309 #if defined(BINARY_SUPPORT_DLFCN)
310 _CFBundleDlfcnPreflight(bundle
, subError
);
311 #endif /* BINARY_SUPPORT_DLFCN */
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
);
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
);
324 (void)NSDestroyObjectFileImage(image
);
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;
336 if (hasRuntimeMismatch
) {
337 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
);
339 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
342 #if defined(BINARY_SUPPORT_DLFCN)
343 _CFBundleDlfcnPreflight(bundle
, subError
);
344 #endif /* BINARY_SUPPORT_DLFCN */
346 CFStringRef debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("dyld returns %d"), retCode
);
347 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
348 CFRelease(debugString
);
352 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
357 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
359 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
362 if (executableURL
) CFRelease(executableURL
);
364 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
365 return bundle
->_isLoaded
;
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
;
373 const char *fileName
= NULL
;
374 const char *errorString
= NULL
;
376 if (!bundle
->_isLoaded
) {
377 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
378 char buff
[CFMaxPathSize
];
380 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
381 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
383 printf("dyld load framework %p, add image of %s returns image %p\n", bundle
, buff
, image
);
384 #endif /* LOG_BUNDLE_LOAD */
386 bundle
->_imageCookie
= image
;
387 bundle
->_isLoaded
= true;
389 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
391 #if defined(BINARY_SUPPORT_DLFCN)
392 _CFBundleDlfcnPreflight(bundle
, subError
);
393 #endif /* BINARY_SUPPORT_DLFCN */
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
);
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
);
409 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
411 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
414 if (executableURL
) CFRelease(executableURL
);
416 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
417 return bundle
->_isLoaded
;
420 CF_PRIVATE
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
421 if (bundle
->_isLoaded
) {
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
);
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;
436 CF_PRIVATE
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
437 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);
440 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
443 NSSymbol symbol
= NULL
;
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
);
452 if (!symbol
&& !bundle
->_moduleCookie
&& (!bundle
->_imageCookie
|| globalSearch
)) {
454 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
456 if (executableName
) {
457 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
458 CFRelease(executableName
);
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
);
466 if (symbol
) result
= NSAddressOfSymbol(symbol
);
468 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %@ in %@"), symbolName
, bundle
);
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 */
477 #endif /* !BINARY_SUPPORT_DLFCN */
478 #endif /* BINARY_SUPPORT_DYLD */
480 #if defined(BINARY_SUPPORT_DLFCN)
482 CF_PRIVATE Boolean
_CFBundleDlfcnCheckLoaded(CFBundleRef bundle
) {
483 if (!bundle
->_isLoaded
) {
484 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
485 char buff
[CFMaxPathSize
];
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
);
491 if (!bundle
->_handleCookie
) {
492 bundle
->_handleCookie
= handle
;
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 */
497 bundle
->_isLoaded
= true;
500 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle
, buff
, mode
);
501 #endif /* LOG_BUNDLE_LOAD */
504 if (executableURL
) CFRelease(executableURL
);
506 return bundle
->_isLoaded
;
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
];
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
);
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;
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;
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
);
547 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
551 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
553 if (debugString
) CFRelease(debugString
);
556 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
558 if (executableURL
) CFRelease(executableURL
);
560 if (!retval
&& error
) *error
= localError
;
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
);
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
578 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle
, cookie
);
579 #endif /* LOG_BUNDLE_LOAD */
580 dlclose(bundle
->_handleCookie
);
582 bundle
->_handleCookie
= cookie
;
583 if (bundle
->_handleCookie
) {
584 bundle
->_isLoaded
= true;
586 const char *dyldError
= dlerror();
587 CFStringRef errorString
= dyldError
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, dyldError
) : NULL
;
589 _CFBundleDlfcnPreflight(bundle
, subError
);
590 if (!localError
) localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, errorString
);
592 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
593 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, errorString
? errorString
: CFSTR("(no additional info)"));
594 if (executableString
) CFRelease(executableString
);
596 if (errorString
) CFRelease(errorString
);
600 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
602 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
605 if (executableURL
) CFRelease(executableURL
);
607 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
608 return bundle
->_isLoaded
;
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
);
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
625 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle
, cookie
);
626 #endif /* LOG_BUNDLE_LOAD */
627 dlclose(bundle
->_handleCookie
);
629 bundle
->_handleCookie
= cookie
;
630 if (bundle
->_handleCookie
) {
631 bundle
->_isLoaded
= true;
633 const char *dyldError
= dlerror();
634 CFStringRef errorString
= dyldError
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, dyldError
) : NULL
;
636 _CFBundleDlfcnPreflight(bundle
, subError
);
637 if (!localError
) localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, errorString
);
639 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
640 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, errorString
? errorString
: CFSTR("(no additional info)"));
642 if (errorString
) CFRelease(errorString
);
646 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
648 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
651 if (executableURL
) CFRelease(executableURL
);
653 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
654 return bundle
->_isLoaded
;
657 CF_PRIVATE
void _CFBundleDlfcnUnload(CFBundleRef bundle
) {
658 if (bundle
->_isLoaded
) {
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
);
665 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
666 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
667 bundle
->_isLoaded
= false;
672 CF_PRIVATE
void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
673 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, symbolName
, false);
676 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
680 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingUTF8
)) {
681 result
= dlsym(bundle
->_handleCookie
, buff
);
682 if (!result
&& globalSearch
) result
= dlsym(RTLD_DEFAULT
, buff
);
684 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName
, bundle
);
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 */
693 #if !defined(BINARY_SUPPORT_DYLD)
695 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
) {
696 CFStringRef result
= NULL
;
698 if (0 != dladdr(p
, &info
) && info
.dli_fname
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, info
.dli_fname
);
700 printf("dlfcn image path for pointer %p is %p\n", p
, result
);
701 #endif /* LOG_BUNDLE_LOAD */
705 #endif /* !BINARY_SUPPORT_DYLD */
706 #endif /* BINARY_SUPPORT_DLFCN */
708 #if defined(BINARY_SUPPORT_DLL)
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
];
716 if (executableURL
&& _CFURLGetWideFileSystemRepresentation(executableURL
, true, (wchar_t *)buff
, CFMaxPathSize
)) {
717 bundle
->_hModule
= LoadLibraryW(buff
);
718 if (bundle
->_hModule
) {
719 bundle
->_isLoaded
= true;
722 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
);
724 CFLog(__kCFLogBundle
, CFSTR("Failed to load bundle %@"), bundle
);
729 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
731 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
734 if (executableURL
) CFRelease(executableURL
);
736 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
737 return bundle
->_isLoaded
;
740 CF_PRIVATE
void _CFBundleDLLUnload(CFBundleRef bundle
) {
741 if (bundle
->_isLoaded
) {
742 FreeLibrary(bundle
->_hModule
);
743 bundle
->_hModule
= NULL
;
744 bundle
->_isLoaded
= false;
748 CF_PRIVATE
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
751 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) result
= GetProcAddress(bundle
->_hModule
, buff
);
755 #endif /* BINARY_SUPPORT_DLL */
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 */
767 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
770 if (!bundle
->_isLoaded
) {
771 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
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 */
785 #endif /* BINARY_SUPPORT_DYLD */
786 #if defined(BINARY_SUPPORT_DLL)
787 case __CFBundleDLLBinary
:
788 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
790 #endif /* BINARY_SUPPORT_DLL */
792 #if defined(BINARY_SUPPORT_DLFCN)
793 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
794 #endif /* BINARY_SUPPORT_DLFCN */
800 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
803 if (!bundle
->_isLoaded
) {
804 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
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 */
818 #endif /* BINARY_SUPPORT_DYLD */
820 #if defined(BINARY_SUPPORT_DLFCN)
821 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
822 #endif /* BINARY_SUPPORT_DLFCN */
825 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
829 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
834 c
= CFArrayGetCount(functionNames
);
835 for (i
= 0; i
< c
; i
++) ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
838 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
843 c
= CFArrayGetCount(functionNames
);
844 for (i
= 0; i
< c
; i
++) ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
847 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
850 if (!bundle
->_isLoaded
&& !CFBundleLoadExecutable(bundle
)) return NULL
;
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 */
863 #endif /* BINARY_SUPPORT_DYLD */
864 #if defined(BINARY_SUPPORT_DLL)
865 case __CFBundleDLLBinary
:
866 /* MF:!!! Handle this someday */
868 #endif /* BINARY_SUPPORT_DLL */
870 #if defined(BINARY_SUPPORT_DLFCN)
871 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
872 #endif /* BINARY_SUPPORT_DLFCN */
878 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
883 c
= CFArrayGetCount(symbolNames
);
884 for (i
= 0; i
< c
; i
++) stbl
[i
] = CFBundleGetDataPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(symbolNames
, i
));