]> git.saurik.com Git - apple/dyld.git/blob - src/dyldAPIs.cpp
31a5a8a1f7bb5958cb57bbfffb1c9658d836f206
[apple/dyld.git] / src / dyldAPIs.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 //
26 // This file implements that API's in <mach-o/dyld.h>
27 //
28 //
29
30 #define __STDC_LIMIT_MACROS
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <Availability.h>
37
38
39 #include <vector>
40 #include <map>
41 #include <algorithm>
42
43 #include <mach/mach.h>
44 #include <sys/time.h>
45 #include <sys/sysctl.h>
46 #include <mach/mach_traps.h> // for task_self_trap()
47
48
49 #include "mach-o/dyld_images.h"
50 #include "mach-o/dyld.h"
51 #include "mach-o/dyld_priv.h"
52
53 #include "ImageLoader.h"
54 #include "ImageLoaderMachO.h"
55 #include "dyld.h"
56 #include "dyldLibSystemInterface.h"
57
58 #undef _POSIX_C_SOURCE
59 #include "dlfcn.h"
60
61 // from dyldExceptions.c
62 extern "C" void __Unwind_SjLj_SetThreadKey(pthread_key_t key);
63
64 // from dyld_gdb.cpp
65 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
66 extern uint32_t allImagesCount();
67 extern const mach_header* allImagesIndexedMachHeader(uint32_t index);
68 extern const char* allImagesIndexedPath(uint32_t index);
69
70
71 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
72 #if __IPHONE_OS_VERSION_MIN_REQUIRED
73 #define DEPRECATED_APIS_SUPPORTED 0
74 #else
75 #define DEPRECATED_APIS_SUPPORTED 1
76 #endif
77
78 static bool sDynamicInterposing = false;
79
80 #if DEPRECATED_APIS_SUPPORTED
81 static char sLastErrorFilePath[1024];
82 static NSLinkEditErrors sLastErrorFileCode;
83 static int sLastErrorNo;
84 #endif
85
86 // In 10.3.x and earlier all the NSObjectFileImage API's were implemeneted in libSystem.dylib
87 // Beginning in 10.4 the NSObjectFileImage API's are implemented in dyld and libSystem just forwards
88 // This conditional keeps support for old libSystem's which needed some help implementing the API's
89 #define OLD_LIBSYSTEM_SUPPORT (__i386__)
90
91 // The following functions have no prototype in any header. They are special cases
92 // where _dyld_func_lookup() is used directly.
93 static void _dyld_make_delayed_module_initializer_calls();
94 static void registerThreadHelpers(const dyld::LibSystemHelpers*);
95 #if DEPRECATED_APIS_SUPPORTED
96 static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit);
97 #if OLD_LIBSYSTEM_SUPPORT
98 static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options);
99 #endif
100 static void _dyld_register_binding_handler(void * (*)(const char *, const char *, void *), ImageLoader::BindingOptions);
101 static bool NSMakePrivateModulePublic(NSModule module);
102 static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header);
103
104 // The following functions are dyld API's, but since dyld links with a static copy of libc.a
105 // the public name cannot be used.
106 static void client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module);
107 static bool client_NSIsSymbolNameDefined(const char* symbolName);
108 #endif // DEPRECATED_APIS_SUPPORTED
109 #if SUPPORT_ZERO_COST_EXCEPTIONS
110 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
111 #endif
112 #if DEPRECATED_APIS_SUPPORTED
113 #endif
114
115 static void unimplemented()
116 {
117 dyld::halt("unimplemented dyld function\n");
118 }
119
120 struct dyld_func {
121 const char* name;
122 void* implementation;
123 };
124
125 static struct dyld_func dyld_funcs[] = {
126 {"__dyld_register_func_for_add_image", (void*)_dyld_register_func_for_add_image },
127 {"__dyld_register_func_for_remove_image", (void*)_dyld_register_func_for_remove_image },
128 {"__dyld_dladdr", (void*)dladdr },
129 {"__dyld_dlclose", (void*)dlclose },
130 {"__dyld_dlerror", (void*)dlerror },
131 {"__dyld_dlopen", (void*)dlopen },
132 {"__dyld_dlsym", (void*)dlsym },
133 {"__dyld_dlopen_preflight", (void*)dlopen_preflight },
134 {"__dyld_image_count", (void*)_dyld_image_count },
135 {"__dyld_get_image_header", (void*)_dyld_get_image_header },
136 {"__dyld_get_image_vmaddr_slide", (void*)_dyld_get_image_vmaddr_slide },
137 {"__dyld_get_image_name", (void*)_dyld_get_image_name },
138 {"__dyld_get_image_slide", (void*)_dyld_get_image_slide },
139 {"__dyld__NSGetExecutablePath", (void*)_NSGetExecutablePath },
140
141 // SPIs
142 {"__dyld_register_thread_helpers", (void*)registerThreadHelpers },
143 {"__dyld_fork_child", (void*)_dyld_fork_child },
144 {"__dyld_make_delayed_module_initializer_calls", (void*)_dyld_make_delayed_module_initializer_calls },
145 {"__dyld_get_all_image_infos", (void*)_dyld_get_all_image_infos },
146 #if SUPPORT_ZERO_COST_EXCEPTIONS
147 {"__dyld_find_unwind_sections", (void*)client_dyld_find_unwind_sections },
148 #endif
149 #if __i386__ || __x86_64__ || __arm__ || __arm64__
150 {"__dyld_fast_stub_entry", (void*)dyld::fastBindLazySymbol },
151 #endif
152 {"__dyld_image_path_containing_address", (void*)dyld_image_path_containing_address },
153 {"__dyld_shared_cache_some_image_overridden", (void*)dyld_shared_cache_some_image_overridden },
154 {"__dyld_process_is_restricted", (void*)dyld::processIsRestricted },
155 {"__dyld_dynamic_interpose", (void*)dyld_dynamic_interpose },
156 #if DYLD_SHARED_CACHE_SUPPORT
157 {"__dyld_shared_cache_file_path", (void*)dyld::getStandardSharedCacheFilePath },
158 #endif
159 {"__dyld_get_image_header_containing_address", (void*)dyld_image_header_containing_address },
160 {"__dyld_is_memory_immutable", (void*)_dyld_is_memory_immutable },
161 {"__dyld_objc_notify_register", (void*)_dyld_objc_notify_register },
162 {"__dyld_get_shared_cache_uuid", (void*)_dyld_get_shared_cache_uuid },
163
164
165 // deprecated
166 #if DEPRECATED_APIS_SUPPORTED
167 {"__dyld_lookup_and_bind", (void*)client_dyld_lookup_and_bind },
168 {"__dyld_lookup_and_bind_with_hint", (void*)_dyld_lookup_and_bind_with_hint },
169 {"__dyld_lookup_and_bind_fully", (void*)_dyld_lookup_and_bind_fully },
170 {"__dyld_install_handlers", (void*)_dyld_install_handlers },
171 {"__dyld_link_edit_error", (void*)NSLinkEditError },
172 {"__dyld_unlink_module", (void*)NSUnLinkModule },
173 {"__dyld_bind_objc_module", (void*)_dyld_bind_objc_module },
174 {"__dyld_bind_fully_image_containing_address", (void*)_dyld_bind_fully_image_containing_address },
175 {"__dyld_image_containing_address", (void*)_dyld_image_containing_address },
176 {"__dyld_register_binding_handler", (void*)_dyld_register_binding_handler },
177 {"__dyld_NSNameOfSymbol", (void*)NSNameOfSymbol },
178 {"__dyld_NSAddressOfSymbol", (void*)NSAddressOfSymbol },
179 {"__dyld_NSModuleForSymbol", (void*)NSModuleForSymbol },
180 {"__dyld_NSLookupAndBindSymbol", (void*)NSLookupAndBindSymbol },
181 {"__dyld_NSLookupAndBindSymbolWithHint", (void*)NSLookupAndBindSymbolWithHint },
182 {"__dyld_NSLookupSymbolInModule", (void*)NSLookupSymbolInModule},
183 {"__dyld_NSLookupSymbolInImage", (void*)NSLookupSymbolInImage},
184 {"__dyld_NSMakePrivateModulePublic", (void*)NSMakePrivateModulePublic},
185 {"__dyld_NSIsSymbolNameDefined", (void*)client_NSIsSymbolNameDefined},
186 {"__dyld_NSIsSymbolNameDefinedWithHint", (void*)NSIsSymbolNameDefinedWithHint },
187 {"__dyld_NSIsSymbolNameDefinedInImage", (void*)NSIsSymbolNameDefinedInImage},
188 {"__dyld_NSNameOfModule", (void*)NSNameOfModule },
189 {"__dyld_NSLibraryNameForModule", (void*)NSLibraryNameForModule },
190 {"__dyld_NSAddLibrary", (void*)NSAddLibrary },
191 {"__dyld_NSAddLibraryWithSearching", (void*)NSAddLibraryWithSearching },
192 {"__dyld_NSAddImage", (void*)NSAddImage },
193 {"__dyld_launched_prebound", (void*)_dyld_launched_prebound },
194 {"__dyld_all_twolevel_modules_prebound", (void*)_dyld_all_twolevel_modules_prebound },
195 {"__dyld_call_module_initializers_for_dylib", (void*)_dyld_call_module_initializers_for_dylib },
196 {"__dyld_NSCreateObjectFileImageFromFile", (void*)NSCreateObjectFileImageFromFile },
197 {"__dyld_NSCreateObjectFileImageFromMemory", (void*)NSCreateObjectFileImageFromMemory },
198 {"__dyld_NSDestroyObjectFileImage", (void*)NSDestroyObjectFileImage },
199 {"__dyld_NSLinkModule", (void*)NSLinkModule },
200 {"__dyld_NSHasModInitObjectFileImage", (void*)NSHasModInitObjectFileImage },
201 {"__dyld_NSSymbolDefinitionCountInObjectFileImage", (void*)NSSymbolDefinitionCountInObjectFileImage },
202 {"__dyld_NSSymbolDefinitionNameInObjectFileImage", (void*)NSSymbolDefinitionNameInObjectFileImage },
203 {"__dyld_NSIsSymbolDefinedInObjectFileImage", (void*)NSIsSymbolDefinedInObjectFileImage },
204 {"__dyld_NSSymbolReferenceNameInObjectFileImage", (void*)NSSymbolReferenceNameInObjectFileImage },
205 {"__dyld_NSSymbolReferenceCountInObjectFileImage", (void*)NSSymbolReferenceCountInObjectFileImage },
206 {"__dyld_NSGetSectionDataInObjectFileImage", (void*)NSGetSectionDataInObjectFileImage },
207 #if OLD_LIBSYSTEM_SUPPORT
208 {"__dyld_link_module", (void*)_dyld_link_module },
209 #endif
210 #endif //DEPRECATED_APIS_SUPPORTED
211
212 {NULL, 0}
213 };
214
215
216
217 #if DEPRECATED_APIS_SUPPORTED
218
219 static void dyldAPIhalt(const char* apiName, const char* errorMsg)
220 {
221 dyld::log("dyld: %s() error\n", apiName);
222 dyld::halt(errorMsg);
223 }
224
225 // dyld's abstract type NSSymbol is implemented as const ImageLoader::Symbol*
226 inline NSSymbol SymbolToNSSymbol(const ImageLoader::Symbol* sym)
227 {
228 return (NSSymbol)sym;
229 }
230 inline const ImageLoader::Symbol* NSSymbolToSymbol(NSSymbol sym)
231 {
232 return (const ImageLoader::Symbol*)sym;
233 }
234
235 // dyld's abstract type NSModule is implemented as ImageLoader*
236 inline NSModule ImageLoaderToNSModule(const ImageLoader* image)
237 {
238 return (NSModule)image;
239 }
240 inline ImageLoader* NSModuleToImageLoader(NSModule module)
241 {
242 ImageLoader* image = (ImageLoader*)module;
243 if ( dyld::validImage(image) )
244 return image;
245 return NULL;
246 }
247
248 // actual definition for opaque type
249 struct __NSObjectFileImage
250 {
251 ImageLoader* image;
252 const void* imageBaseAddress; // not used with OFI created from files
253 size_t imageLength; // not used with OFI created from files
254 };
255
256
257 VECTOR_NEVER_DESTRUCTED(NSObjectFileImage);
258 static std::vector<NSObjectFileImage> sObjectFileImages;
259
260
261
262 //
263 // __NSObjectFileImage are deleted in NSDestroyObjectFileImage()
264 // The contained image is delete in one of two places:
265 // NSUnLinkModule deletes the image if there is no __NSObjectFileImage with a reference to it
266 // NSDestroyObjectFileImage deletes the image if image is not in list of valid images
267 //
268
269
270
271 static void setLastError(NSLinkEditErrors code, int errnum, const char* file, const char* message)
272 {
273 dyld::setErrorMessage(message);
274 strncpy(sLastErrorFilePath, file, 1024);
275 sLastErrorFilePath[1023] = '\0';
276 sLastErrorFileCode = code;
277 sLastErrorNo = errnum;
278 }
279
280 #endif // DEPRECATED_APIS_SUPPORTED
281
282 /*
283 *_dyld_NSGetExecutablePath is the dyld side of _NSGetExecutablePath which
284 * copies the path of the executable into the buffer and returns 0 if the path
285 * was successfully copied in the provided buffer. If the buffer is not large
286 * enough, -1 is returned and the expected buffer size is copied in *bufsize.
287 * Note that _NSGetExecutablePath will return "a path" to the executable not a
288 * "real path" to the executable. That is the path may be a symbolic link and
289 * not the real file. And with deep directories the total bufsize needed could
290 * be more than MAXPATHLEN.
291 */
292 int _NSGetExecutablePath(char* buf, uint32_t *bufsize)
293 {
294 if ( dyld::gLogAPIs )
295 dyld::log("%s(...)\n", __func__);
296 const char* exePath = dyld::getExecutablePath();
297 if(*bufsize < strlen(exePath) + 1){
298 *bufsize = (uint32_t)(strlen(exePath) + 1);
299 return -1;
300 }
301 strcpy(buf, exePath);
302 return 0;
303 }
304
305 uint32_t _dyld_image_count(void)
306 {
307 if ( dyld::gLogAPIs )
308 dyld::log("%s()\n", __func__);
309 return allImagesCount();
310 }
311
312 const struct mach_header* _dyld_get_image_header(uint32_t image_index)
313 {
314 if ( dyld::gLogAPIs )
315 dyld::log("%s(%u)\n", __func__, image_index);
316 return allImagesIndexedMachHeader(image_index);
317 }
318
319 intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index)
320 {
321 if ( dyld::gLogAPIs )
322 dyld::log("%s(%u)\n", __func__, image_index);
323 const struct mach_header* mh = allImagesIndexedMachHeader(image_index);
324 if ( mh != NULL )
325 return ImageLoaderMachO::computeSlide(mh);
326 else
327 return 0;
328 }
329
330 intptr_t _dyld_get_image_slide(const struct mach_header* mh)
331 {
332 if ( dyld::gLogAPIs )
333 dyld::log("%s(%p)\n", __func__, mh);
334 return ImageLoaderMachO::computeSlide(mh);
335 }
336
337
338 const char* _dyld_get_image_name(uint32_t image_index)
339 {
340 if ( dyld::gLogAPIs )
341 dyld::log("%s(%u)\n", __func__, image_index);
342 return allImagesIndexedPath(image_index);
343 }
344
345 const struct mach_header * dyld_image_header_containing_address(const void* address)
346 {
347 if ( dyld::gLogAPIs )
348 dyld::log("%s(%p)\n", __func__, address);
349 #if SUPPORT_ACCELERATE_TABLES
350 const mach_header* mh;
351 const char* path;
352 if ( dyld::addressInCache(address, &mh, &path) )
353 return mh;
354 #endif
355 ImageLoader* image = dyld::findImageContainingAddress(address);
356 if ( image != NULL )
357 return image->machHeader();
358 return NULL;
359 }
360
361
362 void _dyld_register_func_for_add_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
363 {
364 if ( dyld::gLogAPIs )
365 dyld::log("%s(%p)\n", __func__, (void *)func);
366 dyld::registerAddCallback(func);
367 }
368
369 void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
370 {
371 if ( dyld::gLogAPIs )
372 dyld::log("%s(%p)\n", __func__, (void *)func);
373 dyld::registerRemoveCallback(func);
374 }
375
376
377
378 // called by crt before main() by programs linked with 10.4 or earlier crt1.o
379 static void _dyld_make_delayed_module_initializer_calls()
380 {
381 if ( dyld::gLogAPIs )
382 dyld::log("%s()\n", __func__);
383
384 #if SUPPORT_OLD_CRT_INITIALIZATION
385 if ( dyld::gRunInitializersOldWay )
386 dyld::initializeMainExecutable();
387 #endif
388 }
389
390
391
392 #if DEPRECATED_APIS_SUPPORTED
393
394 //
395 // _dyld_call_module_initializers_for_dylib() is the dyld side of
396 // __initialize_Cplusplus() which is in dylib1.o.
397 // It is intended to only be called inside -init rouintes.
398 // -init routines are called before module initializers (what C++
399 // initializers use). Calling __initialize_Cplusplus() in a -init
400 // routine causes the module initializers for an image to be called
401 // which then allows C++ to be used inside a -init routine
402 //
403 static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header)
404 {
405 if ( dyld::gLogAPIs )
406 dyld::log("__initialize_Cplusplus()\n");
407
408 // for now, do nothing...
409 }
410
411
412 void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
413 {
414 if ( dyld::gLogAPIs )
415 dyld::log("%s(\"%s\", %p, %p)\n", __func__, symbolName, address, module);
416 ImageLoader* image;
417 const ImageLoader::Symbol* sym;
418 dyld::clearErrorMessage();
419 if ( dyld::flatFindExportedSymbol(symbolName, &sym, (const ImageLoader**)&image) ) {
420 try {
421 image->bindAllLazyPointers(dyld::gLinkContext, true);
422 if ( address != NULL)
423 *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
424 if ( module != NULL)
425 *module = ImageLoaderToNSModule(image);
426 }
427 catch (const char* msg) {
428 dyldAPIhalt(__func__, msg);
429 }
430 }
431 else {
432 // on failure to find symbol return NULLs
433 if ( address != NULL)
434 *address = NULL;
435 if ( module != NULL)
436 *module = NULL;
437 }
438 }
439
440 // Note: This cannot have public name because dyld is built with a static copy of libc.a
441 // which calls dyld_lookup_and_bind() and expects to find dyld's symbols not host process
442 static void client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module)
443 {
444 if ( dyld::gLogAPIs )
445 dyld::log("_dyld_lookup_and_bind(\"%s\", %p, %p)\n", symbolName, address, module);
446 const ImageLoader* image;
447 const ImageLoader::Symbol* sym;
448 if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
449 if ( address != NULL)
450 *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
451 if ( module != NULL)
452 *module = ImageLoaderToNSModule(image);
453 }
454 else {
455 // on failure to find symbol return NULLs
456 if ( address != NULL)
457 *address = NULL;
458 if ( module != NULL)
459 *module = NULL;
460 }
461 }
462
463 void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* library_name_hint, void** address, NSModule* module)
464 {
465 if ( dyld::gLogAPIs )
466 dyld::log("%s(\"%s\", \"%s\", %p, %p)\n", __func__, symbolName, library_name_hint, address, module);
467 const ImageLoader* image;
468 const ImageLoader::Symbol* sym;
469 // Look for library whose path contains the hint. If that fails search everywhere
470 if ( dyld::flatFindExportedSymbolWithHint(symbolName, library_name_hint, &sym, &image)
471 || dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
472 if ( address != NULL)
473 *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
474 if ( module != NULL)
475 *module = ImageLoaderToNSModule(image);
476 }
477 else {
478 // on failure to find symbol return NULLs
479 if ( address != NULL)
480 *address = NULL;
481 if ( module != NULL)
482 *module = NULL;
483 }
484 }
485
486
487 NSSymbol NSLookupAndBindSymbol(const char *symbolName)
488 {
489 if ( dyld::gLogAPIs )
490 dyld::log("%s(\"%s\")\n", __func__, symbolName);
491 const ImageLoader* image;
492 const ImageLoader::Symbol* sym;
493 if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
494 return SymbolToNSSymbol(sym);
495 }
496 // return NULL on failure
497 return NULL;
498 }
499
500 NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
501 {
502 if ( dyld::gLogAPIs )
503 dyld::log("%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
504 const ImageLoader* image;
505 const ImageLoader::Symbol* sym;
506 bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image);
507 if ( ! found ) {
508 // hint failed, do slow search of all images
509 found = dyld::flatFindExportedSymbol(symbolName, &sym, &image);
510 }
511 if ( found )
512 return SymbolToNSSymbol(sym);
513
514 // return NULL on failure and log
515 if ( dyld::gLogAPIs )
516 dyld::log("%s(\"%s\", \"%s\") => NULL \n", __func__, symbolName, libraryNameHint);
517 return NULL;
518 }
519
520
521
522
523 static __attribute__((noinline))
524 const struct mach_header* addImage(void* callerAddress, const char* path, bool search, bool dontLoad, bool matchInstallName, bool abortOnError)
525 {
526 ImageLoader* image = NULL;
527 std::vector<const char*> rpathsFromCallerImage;
528 try {
529 dyld::clearErrorMessage();
530 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
531 // like dlopen, use rpath from caller image and from main executable
532 if ( callerImage != NULL )
533 callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
534 ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
535 if ( callerImage != dyld::mainExecutable() ) {
536 dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
537 }
538 dyld::LoadContext context;
539 context.useSearchPaths = search;
540 context.useFallbackPaths = search;
541 context.useLdLibraryPath = false;
542 context.implicitRPath = false;
543 context.matchByInstallName = matchInstallName;
544 context.dontLoad = dontLoad;
545 context.mustBeBundle = false;
546 context.mustBeDylib = true;
547 context.canBePIE = false;
548 context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
549 context.rpath = &callersRPaths; // rpaths from caller and main executable
550
551 unsigned cacheIndex;
552 image = load(path, context, cacheIndex);
553 if ( image != NULL ) {
554 if ( context.matchByInstallName )
555 image->setMatchInstallPath(true);
556 dyld::link(image, false, false, callersRPaths, cacheIndex);
557 dyld::runInitializers(image);
558 // images added with NSAddImage() can never be unloaded
559 image->setNeverUnload();
560 }
561 }
562 catch (const char* msg) {
563 dyld::garbageCollectImages();
564 if ( abortOnError) {
565 char pathMsg[strlen(msg)+strlen(path)+4];
566 strcpy(pathMsg, msg);
567 strcat(pathMsg, " ");
568 strcat(pathMsg, path);
569 dyldAPIhalt("NSAddImage", pathMsg);
570 }
571 // not halting, so set error state for NSLinkEditError to find
572 setLastError(NSLinkEditOtherError, 0, path, msg);
573 free((void*)msg); // our free() will do nothing if msg is a string literal
574 image = NULL;
575 }
576 // free rpaths (getRPaths() malloc'ed each string)
577 for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
578 const char* str = *it;
579 free((void*)str);
580 }
581 if ( image == NULL )
582 return NULL;
583 else
584 return image->machHeader();
585 }
586
587
588 const struct mach_header* NSAddImage(const char* path, uint32_t options)
589 {
590 if ( dyld::gLogAPIs )
591 dyld::log("%s(\"%s\", 0x%08X)\n", __func__, path, options);
592 const bool dontLoad = ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 );
593 const bool search = ( (options & NSADDIMAGE_OPTION_WITH_SEARCHING) != 0 );
594 const bool matchInstallName = ( (options & NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME) != 0 );
595 const bool abortOnError = ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 );
596 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
597 return addImage(callerAddress, path, search, dontLoad, matchInstallName, abortOnError);
598 }
599
600 bool NSAddLibrary(const char* path)
601 {
602 if ( dyld::gLogAPIs )
603 dyld::log("%s(\"%s\")\n", __func__, path);
604 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
605 return (addImage(callerAddress, path, false, false, false, false) != NULL);
606 }
607
608 bool NSAddLibraryWithSearching(const char* path)
609 {
610 if ( dyld::gLogAPIs )
611 dyld::log("%s(\"%s\")\n", __func__, path);
612 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
613 return (addImage(callerAddress, path, true, false, false, false) != NULL);
614 }
615
616
617
618 //#define NSADDIMAGE_OPTION_NONE 0x0
619 //#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
620 //#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
621
622 bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
623 {
624 if ( dyld::gLogAPIs )
625 dyld::log("%s(%p, \"%s\")\n", __func__, (void *)mh, symbolName);
626 ImageLoader* image = dyld::findImageByMachHeader(mh);
627 if ( image != NULL ) {
628 if ( image->findExportedSymbol(symbolName, true, NULL) != NULL)
629 return true;
630 }
631 return false;
632 }
633
634
635 NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options)
636 {
637 if ( dyld::gLogAPIs )
638 dyld::log("%s(%p, \"%s\", 0x%08X)\n", __func__, mh, symbolName, options);
639 const ImageLoader::Symbol* symbol = NULL;
640 dyld::clearErrorMessage();
641 ImageLoader* image = dyld::findImageByMachHeader(mh);
642 if ( image != NULL ) {
643 try {
644 if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY ) {
645 image->bindAllLazyPointers(dyld::gLinkContext, true);
646 }
647 else if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW ) {
648 image->bindAllLazyPointers(dyld::gLinkContext, false);
649 }
650 }
651 catch (const char* msg) {
652 if ( (options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR) == 0 ) {
653 dyldAPIhalt(__func__, msg);
654 }
655 }
656 symbol = image->findExportedSymbol(symbolName, true, NULL);
657 }
658 if ( dyld::gLogAPIs && (symbol == NULL) )
659 dyld::log("%s(%p, \"%s\", 0x%08X) ==> NULL\n", __func__, mh, symbolName, options);
660 return SymbolToNSSymbol(symbol);
661 }
662
663
664 // Note: This cannot have public name because dyld is built with a static copy of libc.a
665 // which calls NSIsSymbolNameDefined() and expects to find dyld's symbols not host process
666 static bool client_NSIsSymbolNameDefined(const char* symbolName)
667 {
668 if ( dyld::gLogAPIs )
669 dyld::log("NSIsSymbolNameDefined(\"%s\")\n", symbolName);
670 const ImageLoader* image;
671 const ImageLoader::Symbol* sym;
672 return dyld::flatFindExportedSymbol(symbolName, &sym, &image);
673 }
674
675 bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
676 {
677 if ( dyld::gLogAPIs )
678 dyld::log("%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
679 const ImageLoader* image;
680 const ImageLoader::Symbol* sym;
681 bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image);
682 if ( ! found ) {
683 // hint failed, do slow search of all images
684 found = dyld::flatFindExportedSymbol(symbolName, &sym, &image);
685 }
686 if ( !found && dyld::gLogAPIs )
687 dyld::log("%s(\"%s\", \"%s\") => false \n", __func__, symbolName, libraryNameHint);
688 return found;
689 }
690
691 const char* NSNameOfSymbol(NSSymbol symbol)
692 {
693 if ( dyld::gLogAPIs )
694 dyld::log("%s(%p)\n", __func__, (void *)symbol);
695 const char* result = NULL;
696 ImageLoader* image = dyld::findImageContainingSymbol(symbol);
697 if ( image != NULL )
698 result = image->getExportedSymbolName(NSSymbolToSymbol(symbol));
699 return result;
700 }
701
702 void* NSAddressOfSymbol(NSSymbol symbol)
703 {
704 if ( dyld::gLogAPIs )
705 dyld::log("%s(%p)\n", __func__, (void *)symbol);
706 if ( symbol == NULL )
707 return NULL;
708 void* result = NULL;
709 ImageLoader* image = dyld::findImageContainingSymbol(symbol);
710 if ( image != NULL )
711 result = (void*)image->getExportedSymbolAddress(NSSymbolToSymbol(symbol), dyld::gLinkContext);
712 return result;
713 }
714
715 NSModule NSModuleForSymbol(NSSymbol symbol)
716 {
717 if ( dyld::gLogAPIs )
718 dyld::log("%s(%p)\n", __func__, (void *)symbol);
719 NSModule result = NULL;
720 ImageLoader* image = dyld::findImageContainingSymbol(symbol);
721 if ( image != NULL )
722 result = ImageLoaderToNSModule(image);
723 return result;
724 }
725
726
727
728
729 bool _dyld_all_twolevel_modules_prebound(void)
730 {
731 if ( dyld::gLogAPIs )
732 dyld::log("%s()\n", __func__);
733 return FALSE;
734 }
735
736 void _dyld_bind_objc_module(const void *objc_module)
737 {
738 if ( dyld::gLogAPIs )
739 dyld::log("%s(%p)\n", __func__, objc_module);
740 // do nothing, with new dyld everything already bound
741 }
742
743
744 bool _dyld_bind_fully_image_containing_address(const void* address)
745 {
746 if ( dyld::gLogAPIs )
747 dyld::log("%s(%p)\n", __func__, address);
748 dyld::clearErrorMessage();
749 ImageLoader* image = dyld::findImageContainingAddress(address);
750 if ( image != NULL ) {
751 try {
752 image->bindAllLazyPointers(dyld::gLinkContext, true);
753 return true;
754 }
755 catch (const char* msg) {
756 dyldAPIhalt(__func__, msg);
757 }
758 }
759 return false;
760 }
761
762 bool _dyld_image_containing_address(const void* address)
763 {
764 if ( dyld::gLogAPIs )
765 dyld::log("%s(%p)\n", __func__, address);
766 ImageLoader *imageLoader = dyld::findImageContainingAddress(address);
767 return (NULL != imageLoader);
768 }
769
770 static NSObjectFileImage createObjectImageFile(ImageLoader* image, const void* address = NULL, size_t len=0)
771 {
772 NSObjectFileImage result = new __NSObjectFileImage();
773 result->image = image;
774 result->imageBaseAddress = address;
775 result->imageLength = len;
776 sObjectFileImages.push_back(result);
777 return result;
778 }
779
780 NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage)
781 {
782 if ( dyld::gLogAPIs )
783 dyld::log("%s(\"%s\", ...)\n", __func__, pathName);
784 try {
785 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
786 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
787
788 dyld::LoadContext context;
789 context.useSearchPaths = false;
790 context.useFallbackPaths = false;
791 context.useLdLibraryPath = false;
792 context.implicitRPath = false;
793 context.matchByInstallName = false;
794 context.dontLoad = false;
795 context.mustBeBundle = true;
796 context.mustBeDylib = false;
797 context.canBePIE = false;
798 context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
799 context.rpath = NULL; // support not yet implemented
800
801 unsigned cacheIndex;
802 ImageLoader* image = dyld::load(pathName, context, cacheIndex);
803 // Note: We DO NOT link the image! NSLinkModule will do that
804 if ( image != NULL ) {
805 if ( !image->isBundle() ) {
806 // the image must have been already loaded (since context.mustBeBundle will prevent it from being loaded)
807 return NSObjectFileImageInappropriateFile;
808 }
809 *objectFileImage = createObjectImageFile(image);
810 return NSObjectFileImageSuccess;
811 }
812 }
813 catch (const char* msg) {
814 //dyld::log("dyld: NSCreateObjectFileImageFromFile() error: %s\n", msg);
815 dyld::garbageCollectImages();
816 free((void*)msg);
817 return NSObjectFileImageInappropriateFile;
818 }
819 return NSObjectFileImageFailure;
820 }
821
822
823 NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* address, size_t size, NSObjectFileImage *objectFileImage)
824 {
825 if ( dyld::gLogAPIs )
826 dyld::log("%s(%p, %lu, %p)\n", __func__, address, size, objectFileImage);
827
828 try {
829 ImageLoader* image = dyld::loadFromMemory((const uint8_t*)address, size, NULL);
830 if ( ! image->isBundle() ) {
831 // this API can only be used with bundles...
832 dyld::garbageCollectImages();
833 return NSObjectFileImageInappropriateFile;
834 }
835 // Note: We DO NOT link the image! NSLinkModule will do that
836 if ( image != NULL ) {
837 *objectFileImage = createObjectImageFile(image, address, size);
838 return NSObjectFileImageSuccess;
839 }
840 }
841 catch (const char* msg) {
842 free((void*)msg);
843 dyld::garbageCollectImages();
844 //dyld::log("dyld: NSCreateObjectFileImageFromMemory() error: %s\n", msg);
845 }
846 return NSObjectFileImageFailure;
847 }
848
849 static bool validOFI(NSObjectFileImage objectFileImage)
850 {
851 const int ofiCount = sObjectFileImages.size();
852 for (int i=0; i < ofiCount; ++i) {
853 if ( sObjectFileImages[i] == objectFileImage )
854 return true;
855 }
856 return false;
857 }
858
859 bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)
860 {
861 if ( dyld::gLogAPIs )
862 dyld::log("%s(%p)\n", __func__, objectFileImage);
863
864 if ( validOFI(objectFileImage) ) {
865 // a failure during NSLinkModule will delete the image
866 if ( objectFileImage->image != NULL ) {
867 // if the image has never been linked or has been unlinked, the image is not in the list of valid images
868 // and we should delete it
869 bool linkedImage = dyld::validImage(objectFileImage->image);
870 if ( ! linkedImage ) {
871 ImageLoader::deleteImage(objectFileImage->image);
872 objectFileImage->image = NULL;
873 }
874 }
875
876 // remove from list of ofi's
877 for (std::vector<NSObjectFileImage>::iterator it=sObjectFileImages.begin(); it != sObjectFileImages.end(); it++) {
878 if ( *it == objectFileImage ) {
879 sObjectFileImages.erase(it);
880 break;
881 }
882 }
883
884 // if object was created from a memory, release that memory
885 // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands over ownership of the memory to dyld
886 if ( objectFileImage->imageBaseAddress != NULL ) {
887 bool freed = false;
888 if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 6) ) {
889 size_t sz = (*dyld::gLibSystemHelpers->malloc_size)(objectFileImage->imageBaseAddress);
890 if ( sz != 0 ) {
891 (*dyld::gLibSystemHelpers->free)((void*)(objectFileImage->imageBaseAddress));
892 freed = true;
893 }
894 }
895 if ( ! freed )
896 vm_deallocate(mach_task_self(), (vm_address_t)objectFileImage->imageBaseAddress, objectFileImage->imageLength);
897 }
898
899 // free ofi object
900 delete objectFileImage;
901
902 return true;
903 }
904 return false;
905 }
906
907 bool NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage)
908 {
909 if ( dyld::gLogAPIs )
910 dyld::log("%s(%p)\n", __func__, objectFileImage);
911 return objectFileImage->image->needsInitialization();
912 }
913
914 uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
915 {
916 if ( dyld::gLogAPIs )
917 dyld::log("%s(%p)\n", __func__, objectFileImage);
918 return objectFileImage->image->getExportedSymbolCount();
919 }
920
921 const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
922 {
923 if ( dyld::gLogAPIs )
924 dyld::log("%s(%p,%d)\n", __func__, objectFileImage, ordinal);
925 const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedExportedSymbol(ordinal);
926 return objectFileImage->image->getExportedSymbolName(sym);
927 }
928
929 uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
930 {
931 if ( dyld::gLogAPIs )
932 dyld::log("%s(%p)\n", __func__, objectFileImage);
933 return objectFileImage->image->getImportedSymbolCount();
934 }
935
936 const char * NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal,
937 bool* tentative_definition)
938 {
939 if ( dyld::gLogAPIs )
940 dyld::log("%s(%p,%d)\n", __func__, objectFileImage, ordinal);
941 const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedImportedSymbol(ordinal);
942 if ( tentative_definition != NULL ) {
943 ImageLoader::ReferenceFlags flags = objectFileImage->image->getImportedSymbolInfo(sym);
944 if ( (flags & ImageLoader::kTentativeDefinition) != 0 )
945 *tentative_definition = true;
946 else
947 *tentative_definition = false;
948 }
949 return objectFileImage->image->getImportedSymbolName(sym);
950 }
951
952 void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage,
953 const char* segmentName, const char* sectionName, unsigned long* size)
954 {
955 if ( dyld::gLogAPIs )
956 dyld::log("%s(%p,%s, %s)\n", __func__, objectFileImage, segmentName, sectionName);
957
958 void* start;
959 size_t length;
960 if ( objectFileImage->image->getSectionContent(segmentName, sectionName, &start, &length) ) {
961 if ( size != NULL )
962 *size = length;
963 return start;
964 }
965 return NULL;
966 }
967
968
969
970 bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName)
971 {
972 if ( dyld::gLogAPIs )
973 dyld::log("%s(%p,%s)\n", __func__, objectFileImage, symbolName);
974 const ImageLoader::Symbol* sym = objectFileImage->image->findExportedSymbol(symbolName, true, NULL);
975 return ( sym != NULL );
976 }
977
978
979
980 NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options)
981 {
982 if ( dyld::gLogAPIs )
983 dyld::log("%s(%p, \"%s\", 0x%08X)\n", __func__, objectFileImage, moduleName, options);
984
985 dyld::clearErrorMessage();
986 try {
987 if ( (options & NSLINKMODULE_OPTION_CAN_UNLOAD) != 0 )
988 objectFileImage->image->setCanUnload();
989
990 // NSLinkModule allows a bundle to be link multpile times
991 // each link causes the bundle to be copied to a new address
992 if ( objectFileImage->image->isLinked() ) {
993 // already linked, so clone a new one and link it
994 objectFileImage->image = dyld::cloneImage(objectFileImage->image);
995 }
996
997 // for memory based images, set moduleName as the name anyone calling _dyld_get_image_name() will see
998 if ( objectFileImage->image->getPath() == NULL ) {
999 objectFileImage->image->setPath(moduleName);
1000 // <rdar://problem/8812589> dyld has NULL paths in image info array
1001 dyld_image_info info;
1002 info.imageLoadAddress = objectFileImage->image->machHeader();
1003 info.imageFilePath = moduleName;
1004 info.imageFileModDate = 0;
1005 addImagesToAllImages(1, &info);
1006 }
1007
1008 // support private bundles
1009 if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
1010 objectFileImage->image->setHideExports();
1011
1012 // set up linking options
1013 bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
1014
1015 // load libraries, rebase, bind, to make this image usable
1016 dyld::link(objectFileImage->image, forceLazysBound, false, ImageLoader::RPathChain(NULL,NULL), UINT32_MAX);
1017
1018 // bump reference count to keep this bundle from being garbage collected
1019 objectFileImage->image->incrementDlopenReferenceCount();
1020
1021 // run initializers unless magic flag says not to
1022 if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) == 0 )
1023 dyld::runInitializers(objectFileImage->image);
1024
1025 return ImageLoaderToNSModule(objectFileImage->image);
1026 }
1027 catch (const char* msg) {
1028 dyld::garbageCollectImages();
1029 if ( (options & NSLINKMODULE_OPTION_RETURN_ON_ERROR) == 0 )
1030 dyldAPIhalt(__func__, msg);
1031 // not halting, so set error state for NSLinkEditError to find
1032 setLastError(NSLinkEditOtherError, 0, moduleName, msg);
1033 // dyld::link() deleted the image so lose our reference
1034 objectFileImage->image = NULL;
1035 free((void*)msg);
1036 return NULL;
1037 }
1038 }
1039
1040
1041 #if OLD_LIBSYSTEM_SUPPORT
1042 // This is for compatibility with old libSystems (libdyld.a) which process ObjectFileImages outside dyld
1043 static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options)
1044 {
1045 if ( dyld::gLogAPIs )
1046 dyld::log("%s(%p, \"%s\", 0x%08X)\n", "NSLinkModule", object_addr, moduleName, options); // note name/args translation
1047 ImageLoader* image = NULL;
1048 dyld::clearErrorMessage();
1049 try {
1050 const char* imageName = moduleName;
1051 image = dyld::loadFromMemory((const uint8_t*)object_addr, object_size, imageName);
1052
1053 if ( image != NULL ) {
1054 // support private bundles
1055 if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
1056 image->setHideExports();
1057
1058 // set up linking options
1059 bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
1060
1061 // load libraries, rebase, bind, to make this image usable
1062 dyld::link(image, forceLazysBound, false, ImageLoader::RPathChain(NULL,NULL), UINT32_MAX);
1063
1064 // run initializers unless magic flag says not to
1065 if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) == 0 )
1066 dyld::runInitializers(image);
1067 }
1068 }
1069 catch (const char* msg) {
1070 if ( (options & NSLINKMODULE_OPTION_RETURN_ON_ERROR) == 0 )
1071 dyldAPIhalt("NSLinkModule", msg);
1072 // not halting, so set error state for NSLinkEditError to find
1073 setLastError(NSLinkEditOtherError, 0, moduleName, msg);
1074 // if image was created for this bundle, destroy it
1075 if ( image != NULL ) {
1076 dyld::removeImage(image);
1077 ImageLoader::deleteImage(image);
1078 }
1079 image = NULL;
1080 free((void*)msg);
1081 }
1082 return ImageLoaderToNSModule(image);
1083 }
1084 #endif
1085
1086 NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
1087 {
1088 if ( dyld::gLogAPIs )
1089 dyld::log("%s(%p, \"%s\")\n", __func__, (void *)module, symbolName);
1090 ImageLoader* image = NSModuleToImageLoader(module);
1091 if ( image == NULL )
1092 return NULL;
1093 return SymbolToNSSymbol(image->findExportedSymbol(symbolName, false, NULL));
1094 }
1095
1096 const char* NSNameOfModule(NSModule module)
1097 {
1098 if ( dyld::gLogAPIs )
1099 dyld::log("%s(%p)\n", __func__, module);
1100 ImageLoader* image = NSModuleToImageLoader(module);
1101 if ( image == NULL )
1102 return NULL;
1103 return image->getPath();
1104 }
1105
1106 const char* NSLibraryNameForModule(NSModule module)
1107 {
1108 if ( dyld::gLogAPIs )
1109 dyld::log("%s(%p)\n", __func__, module);
1110 ImageLoader* image = NSModuleToImageLoader(module);
1111 if ( image == NULL )
1112 return NULL;
1113 return image->getPath();
1114 }
1115
1116 bool NSUnLinkModule(NSModule module, uint32_t options)
1117 {
1118 if ( dyld::gLogAPIs )
1119 dyld::log("%s(%p, 0x%08X)\n", __func__, module, options);
1120 if ( module == NULL )
1121 return false;
1122 ImageLoader* image = NSModuleToImageLoader(module);
1123 if ( image == NULL )
1124 return false;
1125 dyld::runImageStaticTerminators(image);
1126 if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 13) ) {
1127 __cxa_range_t ranges[image->segmentCount()];
1128 int rangeCount = 0;
1129 for (unsigned int j=0; j < image->segmentCount(); ++j) {
1130 if ( !image->segExecutable(j) )
1131 continue;
1132 ranges[rangeCount].addr = (const void*)image->segActualLoadAddress(j);
1133 ranges[rangeCount].length = image->segSize(j);
1134 ++rangeCount;
1135 }
1136 (*dyld::gLibSystemHelpers->cxa_finalize_ranges)(ranges, rangeCount);
1137 }
1138 dyld::removeImage(image);
1139
1140 if ( (options & NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) != 0 )
1141 image->setLeaveMapped();
1142
1143 // TODO: NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
1144
1145 // Only delete image if there is no ofi referencing it
1146 // That means the ofi was destroyed after linking, so no one is left to delete this image
1147 const int ofiCount = sObjectFileImages.size();
1148 bool found = false;
1149 for (int i=0; i < ofiCount; ++i) {
1150 NSObjectFileImage ofi = sObjectFileImages[i];
1151 if ( ofi->image == image )
1152 found = true;
1153 }
1154 if ( !found )
1155 ImageLoader::deleteImage(image);
1156
1157 return true;
1158 }
1159
1160 // internal name and parameters do not match public name and parameters...
1161 static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit)
1162 {
1163 if ( dyld::gLogAPIs )
1164 dyld::log("NSLinkEditErrorHandlers()\n");
1165
1166 dyld::registerUndefinedHandler((dyld::UndefinedHandler)undefined);
1167 // no support for multiple or linkedit handlers
1168 }
1169
1170
1171
1172
1173 void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileName, const char** errorString)
1174 {
1175 // FIXME FIXME
1176 *c = sLastErrorFileCode;
1177 *errorNumber = sLastErrorNo;
1178 *fileName = sLastErrorFilePath;
1179 *errorString = dyld::getErrorMessage();
1180 }
1181
1182
1183
1184 static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *, const char *, void *), ImageLoader::BindingOptions bindingOptions)
1185 {
1186 if ( dyld::gLogAPIs )
1187 dyld::log("%s()\n", __func__);
1188 dyld::gLinkContext.bindingHandler = bindingHandler;
1189 dyld::gLinkContext.bindingOptions = bindingOptions;
1190 }
1191
1192 #endif //DEPRECATED_APIS_SUPPORTED
1193
1194
1195 // Call by fork() in libSystem after the kernel trap is done on the child side
1196 void _dyld_fork_child()
1197 {
1198 if ( dyld::gLogAPIs )
1199 dyld::log("%s()\n", __func__);
1200 // The implementation of fork() in libSystem knows to reset the variable mach_task_self_
1201 // in libSystem for the child of a fork. But dyld is built with a static copy
1202 // of libc.a and has its own copy of mach_task_self_ which we reset here.
1203 //
1204 // In mach_init.h mach_task_self() is #defined to mach_task_self_ and
1205 // in mach_init() mach_task_self_ is initialized to task_self_trap().
1206 //
1207 extern mach_port_t mach_task_self_;
1208 mach_task_self_ = task_self_trap();
1209
1210 // If dyld is sending load/unload notices to CoreSymbolication, the shared memory
1211 // page is not copied on fork. <rdar://problem/6797342>
1212 // NULL the CoreSymbolication shared memory pointer to prevent a crash.
1213 dyld::gProcessInfo->coreSymbolicationShmPage = NULL;
1214 // for safety, make sure child starts with clean systemOrderFlag
1215 dyld::gProcessInfo->systemOrderFlag = 0;
1216 }
1217
1218
1219 #if DEPRECATED_APIS_SUPPORTED
1220 // returns true if prebinding was used in main executable
1221 bool _dyld_launched_prebound()
1222 {
1223 if ( dyld::gLogAPIs )
1224 dyld::log("%s()\n", __func__);
1225
1226 // ¥¥¥Êif we deprecate prebinding, we may want to consider always returning true or false here
1227 return dyld::mainExecutablePrebound();
1228 }
1229
1230
1231 //
1232 // _dyld_NSMakePrivateModulePublic() is the dyld side of the hack
1233 // NSMakePrivateModulePublic() needed for the dlopen() to turn it's
1234 // RTLD_LOCAL handles into RTLD_GLOBAL. It just simply turns off the private
1235 // flag on the image for this module. If the module was found and it was
1236 // private then everything worked and TRUE is returned else FALSE is returned.
1237 //
1238 static bool NSMakePrivateModulePublic(NSModule module)
1239 {
1240 ImageLoader* image = NSModuleToImageLoader(module);
1241 if ( image != NULL ) {
1242 if ( image->hasHiddenExports() ) {
1243 image->setHideExports(false);
1244 return true;
1245 }
1246 }
1247 return false;
1248 }
1249
1250 #endif // DEPRECATED_APIS_SUPPORTED
1251
1252 int _dyld_func_lookup(const char* name, void** address)
1253 {
1254 for (const dyld_func* p = dyld_funcs; p->name != NULL; ++p) {
1255 if ( strcmp(p->name, name) == 0 ) {
1256 if( p->implementation == unimplemented )
1257 dyld::log("unimplemented dyld function: %s\n", p->name);
1258 *address = p->implementation;
1259 return true;
1260 }
1261 }
1262 *address = 0;
1263 return false;
1264 }
1265
1266
1267 static void registerThreadHelpers(const dyld::LibSystemHelpers* helpers)
1268 {
1269 dyld::gLibSystemHelpers = helpers;
1270
1271 #if !SUPPORT_ZERO_COST_EXCEPTIONS
1272 if ( helpers->version >= 5 ) {
1273 // create key use by dyld exception handling
1274 pthread_key_t key;
1275 int result = helpers->pthread_key_create(&key, NULL);
1276 if ( result == 0 )
1277 __Unwind_SjLj_SetThreadKey(key);
1278 }
1279 #endif
1280 }
1281
1282
1283 static void dlerrorClear()
1284 {
1285 if ( dyld::gLibSystemHelpers != NULL ) {
1286 // <rdar://problem/10595338> dlerror buffer leak
1287 // dlerrorClear() should not force allocation, but zero it if already allocated
1288 if ( dyld::gLibSystemHelpers->version >= 10 ) {
1289 if ( ! (*dyld::gLibSystemHelpers->hasPerThreadBufferFor_dlerror)() )
1290 return;
1291 }
1292
1293 // first char of buffer is flag whether string (starting at second char) is valid
1294 char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
1295 buffer[0] = '\0';
1296 buffer[1] = '\0';
1297 }
1298 }
1299
1300 static void dlerrorSet(const char* msg)
1301 {
1302 if ( dyld::gLibSystemHelpers != NULL ) {
1303 // first char of buffer is flag whether string (starting at second char) is valid
1304 char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(strlen(msg)+2);
1305 buffer[0] = '\1';
1306 strcpy(&buffer[1], msg);
1307 }
1308 }
1309
1310
1311 bool dlopen_preflight(const char* path)
1312 {
1313 if ( dyld::gLogAPIs )
1314 dyld::log("%s(%s)\n", __func__, path);
1315
1316 dlerrorClear();
1317
1318 CRSetCrashLogMessage("dyld: in dlopen_preflight()");
1319
1320 const bool leafName = (strchr(path, '/') == NULL);
1321 const bool absolutePath = (path[0] == '/');
1322 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1323 char canonicalPath[PATH_MAX];
1324 // <rdar://problem/7017050> dlopen() not opening frameworks from shared cache with // or ./ in path
1325 if ( !leafName ) {
1326 // make path canonical if it contains a // or ./
1327 if ( (strstr(path, "//") != NULL) || (strstr(path, "./") != NULL) ) {
1328 const char* lastSlash = strrchr(path, '/');
1329 char dirPath[PATH_MAX];
1330 if ( strlcpy(dirPath, path, sizeof(dirPath)) < sizeof(dirPath) ) {
1331 dirPath[lastSlash-path] = '\0';
1332 if ( realpath(dirPath, canonicalPath) ) {
1333 strlcat(canonicalPath, "/", sizeof(canonicalPath));
1334 if ( strlcat(canonicalPath, lastSlash+1, sizeof(canonicalPath)) < sizeof(canonicalPath) ) {
1335 // if all fit in buffer, use new canonical path
1336 path = canonicalPath;
1337 }
1338 }
1339 }
1340 }
1341 }
1342 #endif
1343 #if SUPPORT_ACCELERATE_TABLES
1344 if ( dyld::isPathInCache(path) )
1345 return true;
1346 #endif
1347
1348 #if DYLD_SHARED_CACHE_SUPPORT
1349 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
1350 // if requested path is to something in the dyld shared cache, always succeed
1351 if ( dyld::inSharedCache(path) )
1352 return true;
1353 #endif
1354
1355 bool result = false;
1356 std::vector<const char*> rpathsFromCallerImage;
1357 try {
1358 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1359 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
1360 // for dlopen, use rpath from caller image and from main executable
1361 if ( callerImage != NULL )
1362 callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
1363 ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
1364 if ( callerImage != dyld::mainExecutable() ) {
1365 dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
1366 }
1367
1368 ImageLoader* image = NULL;
1369 dyld::LoadContext context;
1370 context.useSearchPaths = true;
1371 context.useFallbackPaths= leafName; // a partial path implies don't use fallback paths
1372 context.useLdLibraryPath= leafName; // a leafname implies should search
1373 context.implicitRPath = !absolutePath; // a non-absolute path implies try rpath searching
1374 context.matchByInstallName = true;
1375 context.dontLoad = false;
1376 context.mustBeBundle = false;
1377 context.mustBeDylib = false;
1378 context.canBePIE = true;
1379 context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
1380 context.rpath = &callersRPaths; // rpaths from caller and main executable
1381
1382 unsigned cacheIndex;
1383 image = load(path, context, cacheIndex);
1384 if ( image != NULL ) {
1385 dyld::preflight(image, callersRPaths, cacheIndex); // image object deleted by dyld::preflight()
1386 result = true;
1387 }
1388 }
1389 catch (const char* msg) {
1390 const char* str = dyld::mkstringf("dlopen_preflight(%s): %s", path, msg);
1391 dlerrorSet(str);
1392 free((void*)str);
1393 free((void*)msg); // our free() will do nothing if msg is a string literal
1394 }
1395 // free rpaths (getRPaths() malloc'ed each string)
1396 for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
1397 const char* str = *it;
1398 free((void*)str);
1399 }
1400 CRSetCrashLogMessage(NULL);
1401 return result;
1402 }
1403
1404 #if SUPPORT_ACCELERATE_TABLES
1405 bool static callerIsNonOSApp(void* callerAddress, const char** shortName)
1406 {
1407 *shortName = NULL;
1408 const mach_header* unusedMh;
1409 const char* unusedPath;
1410 unsigned unusedIndex;
1411 // any address in shared cache is not from app
1412 if ( dyld::addressInCache(callerAddress, &unusedMh, &unusedPath, &unusedIndex) )
1413 return false;
1414
1415 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
1416 if ( callerImage == NULL )
1417 return false;
1418
1419 *shortName = callerImage->getShortName();
1420 return ( strncmp(callerImage->getPath(), "/var/containers/", 16) == 0 );
1421 }
1422 #endif
1423
1424 void* dlopen(const char* path, int mode)
1425 {
1426 if ( dyld::gLogAPIs )
1427 dyld::log("%s(%s, 0x%08X)\n", __func__, ((path==NULL) ? "NULL" : path), mode);
1428
1429 #if SUPPORT_ACCELERATE_TABLES
1430 if ( dyld::gLogAppAPIs ) {
1431 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1432 const char* shortName;
1433 if ( callerIsNonOSApp(callerAddress, &shortName) ) {
1434 dyld::log("%s: %s(%s, 0x%08X)\n", shortName, __func__, ((path==NULL) ? "NULL" : path), mode);
1435 }
1436 }
1437 #endif
1438
1439 dlerrorClear();
1440
1441 // passing NULL for path means return magic object
1442 if ( path == NULL ) {
1443 // RTLD_FIRST means any dlsym() calls on the handle should only search that handle and not subsequent images
1444 if ( (mode & RTLD_FIRST) != 0 )
1445 return RTLD_MAIN_ONLY;
1446 else
1447 return RTLD_DEFAULT;
1448 }
1449
1450 // acquire global dyld lock (dlopen is special - libSystem glue does not do locking)
1451 bool lockHeld = false;
1452 if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 4) ) {
1453 dyld::gLibSystemHelpers->acquireGlobalDyldLock();
1454 CRSetCrashLogMessage("dyld: in dlopen()");
1455 lockHeld = true;
1456 }
1457
1458 void* result = NULL;
1459 const bool leafName = (strchr(path, '/') == NULL);
1460 const bool absolutePath = (path[0] == '/');
1461 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1462 char canonicalPath[PATH_MAX];
1463 // <rdar://problem/7017050> dlopen() not opening frameworks from shared cache with // or ./ in path
1464 if ( !leafName ) {
1465 // make path canonical if it contains a // or ./
1466 if ( (strstr(path, "//") != NULL) || (strstr(path, "./") != NULL) ) {
1467 const char* lastSlash = strrchr(path, '/');
1468 char dirPath[PATH_MAX];
1469 if ( strlcpy(dirPath, path, sizeof(dirPath)) < sizeof(dirPath) ) {
1470 dirPath[lastSlash-path] = '\0';
1471 if ( realpath(dirPath, canonicalPath) ) {
1472 strlcat(canonicalPath, "/", sizeof(canonicalPath));
1473 if ( strlcat(canonicalPath, lastSlash+1, sizeof(canonicalPath)) < sizeof(canonicalPath) ) {
1474 // if all fit in buffer, use new canonical path
1475 path = canonicalPath;
1476 }
1477 }
1478 }
1479 }
1480 }
1481 #endif
1482 #if SUPPORT_ACCELERATE_TABLES
1483 if ( dyld::dlopenFromCache(path, mode, &result) ) {
1484 // Note: dlopenFromCache() releases the lock
1485 if ( dyld::gLogAPIs )
1486 dyld::log(" %s(%s) ==> %p\n", __func__, path, result);
1487 return result;
1488 }
1489 #endif
1490
1491 ImageLoader* image = NULL;
1492 std::vector<const char*> rpathsFromCallerImage;
1493 ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
1494 try {
1495 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1496 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
1497 if ( (mode & RTLD_NOLOAD) == 0 ) {
1498 // for dlopen, use rpath from caller image and from main executable
1499 if ( callerImage != NULL )
1500 callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
1501 if ( callerImage != dyld::mainExecutable() )
1502 dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
1503 }
1504
1505 dyld::LoadContext context;
1506 context.useSearchPaths = true;
1507 context.useFallbackPaths= leafName; // a partial path means no fallback paths
1508 context.useLdLibraryPath= leafName; // a leafname implies should search
1509 context.implicitRPath = !absolutePath; // a non-absolute path implies try rpath searching
1510 context.matchByInstallName = true;
1511 context.dontLoad = ( (mode & RTLD_NOLOAD) != 0 );
1512 context.mustBeBundle = false;
1513 context.mustBeDylib = false;
1514 context.canBePIE = true;
1515 context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
1516 context.rpath = &callersRPaths; // rpaths from caller and main executable
1517
1518 unsigned cacheIndex;
1519 image = load(path, context, cacheIndex);
1520 #if SUPPORT_ACCELERATE_TABLES
1521 if ( (image != NULL) && (cacheIndex != UINT32_MAX) ) {
1522 if ( dyld::makeCacheHandle(image, cacheIndex, mode, &result) ) {
1523 if ( dyld::gLogAPIs )
1524 dyld::log(" %s(%s) ==> %p\n", __func__, path, result);
1525 if ( lockHeld )
1526 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
1527 return result;
1528 }
1529 }
1530 #endif
1531 if ( image != NULL ) {
1532 // bump reference count. Do this before link() so that if an initializer calls dlopen and fails
1533 // this image is not garbage collected
1534 image->incrementDlopenReferenceCount();
1535 // link in all dependents
1536 if ( (mode & RTLD_NOLOAD) == 0 ) {
1537 bool alreadyLinked = image->isLinked();
1538 bool forceLazysBound = ( (mode & RTLD_NOW) != 0 );
1539 dyld::link(image, forceLazysBound, false, callersRPaths, cacheIndex);
1540 if ( ! alreadyLinked ) {
1541 // only hide exports if image is not already in use
1542 if ( (mode & RTLD_LOCAL) != 0 )
1543 image->setHideExports(true);
1544 }
1545 }
1546
1547 // RTLD_NODELETE means don't unmap image even after dlclosed. This is what dlcompat did on Mac OS X 10.3
1548 // On other *nix OS's, it means dlclose() should do nothing, but the handle should be invalidated.
1549 // The subtle differences are:
1550 // 1) if the image has any termination routines, whether they are run during dlclose or when the process terminates
1551 // 2) If someone does a supsequent dlopen() on the same image, whether the same address should be used.
1552 if ( (mode & RTLD_NODELETE) != 0 )
1553 image->setLeaveMapped();
1554
1555 // release global dyld lock early, this enables initializers to do threaded operations
1556 if ( lockHeld ) {
1557 CRSetCrashLogMessage(NULL);
1558 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
1559 lockHeld = false;
1560 }
1561
1562 // RTLD_NOLOAD means dlopen should fail unless path is already loaded.
1563 // don't run initializers when RTLD_NOLOAD is set. This only matters if dlopen() is
1564 // called from within an initializer because it can cause initializers to run
1565 // out of order. Most uses of RTLD_NOLOAD are "probes". If they want initialzers
1566 // to run, then don't use RTLD_NOLOAD.
1567 if ( (mode & RTLD_NOLOAD) == 0 ) {
1568 // run initializers
1569 dyld::runInitializers(image);
1570 }
1571
1572 // RTLD_FIRST means any dlsym() calls on the handle should only search that handle and not subsequent images
1573 // this is tracked by setting the low bit of the handle, which is usually zero by malloc alignment
1574 if ( (mode & RTLD_FIRST) != 0 )
1575 result = (void*)(((uintptr_t)image)|1);
1576 else
1577 result = image;
1578 }
1579 }
1580 catch (const char* msg) {
1581 if ( image != NULL ) {
1582 // load() succeeded but, link() failed
1583 // back down reference count and do GC
1584 image->decrementDlopenReferenceCount();
1585 if ( image->dlopenCount() == 0 )
1586 dyld::garbageCollectImages();
1587 }
1588 const char* str = dyld::mkstringf("dlopen(%s, %d): %s", path, mode, msg);
1589 if ( dyld::gLogAPIs )
1590 dyld::log(" %s() failed, error: '%s'\n", __func__, str);
1591 dlerrorSet(str);
1592 free((void*)str);
1593 free((void*)msg); // our free() will do nothing if msg is a string literal
1594 result = NULL;
1595 }
1596 // free rpaths (getRPaths() malloc'ed each string)
1597 for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
1598 const char* str = *it;
1599 free((void*)str);
1600 }
1601
1602 // when context.dontLoad is set, load() returns NULL instead of throwing an exception
1603 if ( (mode & RTLD_NOLOAD) && (result == NULL) ) {
1604 dlerrorSet("image not already loaded");
1605 }
1606
1607 if ( lockHeld ) {
1608 CRSetCrashLogMessage(NULL);
1609 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
1610 }
1611 if ( dyld::gLogAPIs && (result != NULL) )
1612 dyld::log(" %s(%s) ==> %p\n", __func__, path, result);
1613 return result;
1614 }
1615
1616
1617
1618 int dlclose(void* handle)
1619 {
1620 if ( dyld::gLogAPIs )
1621 dyld::log("%s(%p)\n", __func__, handle);
1622
1623 // silently accept magic handles for main executable
1624 if ( handle == RTLD_MAIN_ONLY )
1625 return 0;
1626 if ( handle == RTLD_DEFAULT )
1627 return 0;
1628
1629 ImageLoader* image = (ImageLoader*)(((uintptr_t)handle) & (-4)); // clear mode bits
1630 if ( dyld::validImage(image) ) {
1631 dlerrorClear();
1632 // decrement use count
1633 if ( image->decrementDlopenReferenceCount() ) {
1634 dlerrorSet("dlclose() called too many times");
1635 return -1;
1636 }
1637 // remove image if reference count went to zero
1638 if ( image->dlopenCount() == 0 )
1639 dyld::garbageCollectImages();
1640 return 0;
1641 }
1642 else {
1643 dlerrorSet("invalid handle passed to dlclose()");
1644 return -1;
1645 }
1646 }
1647
1648
1649
1650 int dladdr(const void* address, Dl_info* info)
1651 {
1652 if ( dyld::gLogAPIs )
1653 dyld::log("%s(%p, %p)\n", __func__, address, info);
1654
1655 CRSetCrashLogMessage("dyld: in dladdr()");
1656 #if SUPPORT_ACCELERATE_TABLES
1657 if ( dyld::dladdrFromCache(address, info) ) {
1658 CRSetCrashLogMessage(NULL);
1659 return 1; // success
1660 }
1661 #endif
1662
1663 ImageLoader* image = dyld::findImageContainingAddress(address);
1664 if ( image != NULL ) {
1665 info->dli_fname = image->getRealPath();
1666 info->dli_fbase = (void*)image->machHeader();
1667 if ( address == info->dli_fbase ) {
1668 // special case lookup of header
1669 info->dli_sname = "__dso_handle";
1670 info->dli_saddr = info->dli_fbase;
1671 CRSetCrashLogMessage(NULL);
1672 return 1; // success
1673 }
1674 // find closest symbol in the image
1675 info->dli_sname = image->findClosestSymbol(address, (const void**)&info->dli_saddr);
1676 // never return the mach_header symbol
1677 if ( info->dli_saddr == info->dli_fbase ) {
1678 info->dli_sname = NULL;
1679 info->dli_saddr = NULL;
1680 CRSetCrashLogMessage(NULL);
1681 return 1; // success
1682 }
1683 if ( info->dli_sname != NULL ) {
1684 if ( info->dli_sname[0] == '_' )
1685 info->dli_sname = info->dli_sname +1; // strip off leading underscore
1686 //dyld::log("dladdr(%p) => %p %s\n", address, info->dli_saddr, info->dli_sname);
1687 CRSetCrashLogMessage(NULL);
1688 return 1; // success
1689 }
1690 info->dli_sname = NULL;
1691 info->dli_saddr = NULL;
1692 CRSetCrashLogMessage(NULL);
1693 return 1; // success
1694 }
1695 CRSetCrashLogMessage(NULL);
1696 return 0; // failure
1697 }
1698
1699
1700 char* dlerror()
1701 {
1702 if ( dyld::gLogAPIs )
1703 dyld::log("%s()\n", __func__);
1704
1705 if ( dyld::gLibSystemHelpers != NULL ) {
1706 // if using newer libdyld.dylib and buffer if buffer not yet allocated, return NULL
1707 if ( dyld::gLibSystemHelpers->version >= 10 ) {
1708 if ( ! (*dyld::gLibSystemHelpers->hasPerThreadBufferFor_dlerror)() )
1709 return NULL;
1710 }
1711
1712 // first char of buffer is flag whether string (starting at second char) is valid
1713 char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
1714 if ( buffer[0] != '\0' ) { // if valid buffer
1715 buffer[0] = '\0'; // mark invalid, so next call to dlerror returns NULL
1716 return &buffer[1]; // return message
1717 }
1718 }
1719 return NULL;
1720 }
1721
1722 void* dlsym(void* handle, const char* symbolName)
1723 {
1724 if ( dyld::gLogAPIs )
1725 dyld::log("%s(%p, %s)\n", __func__, handle, symbolName);
1726
1727 #if SUPPORT_ACCELERATE_TABLES
1728 if ( dyld::gLogAppAPIs ) {
1729 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1730 const char* shortName;
1731 if ( callerIsNonOSApp(callerAddress, &shortName) ) {
1732 dyld::log("%s: %s(%p, %s)\n", shortName, __func__, handle, symbolName);
1733 }
1734 }
1735 #endif
1736
1737 CRSetCrashLogMessage("dyld: in dlsym()");
1738 dlerrorClear();
1739
1740 const ImageLoader* image;
1741 const ImageLoader::Symbol* sym;
1742 void* result;
1743
1744 // dlsym() assumes symbolName passed in is same as in C source code
1745 // dyld assumes all symbol names have an underscore prefix
1746 char underscoredName[strlen(symbolName)+2];
1747 underscoredName[0] = '_';
1748 strcpy(&underscoredName[1], symbolName);
1749
1750 // magic "search all" handle
1751 if ( handle == RTLD_DEFAULT ) {
1752 if ( dyld::flatFindExportedSymbol(underscoredName, &sym, &image) ) {
1753 CRSetCrashLogMessage(NULL);
1754 result = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext, NULL, false, underscoredName);
1755 if ( dyld::gLogAPIs )
1756 dyld::log(" %s(RTLD_DEFAULT, %s) ==> %p\n", __func__, symbolName, result);
1757 return result;
1758 }
1759 const char* str = dyld::mkstringf("dlsym(RTLD_DEFAULT, %s): symbol not found", symbolName);
1760 dlerrorSet(str);
1761 free((void*)str);
1762 CRSetCrashLogMessage(NULL);
1763 if ( dyld::gLogAPIs )
1764 dyld::log(" %s(RTLD_DEFAULT, %s) ==> NULL\n", __func__, symbolName);
1765 return NULL;
1766 }
1767
1768 // magic "search only main executable" handle
1769 else if ( handle == RTLD_MAIN_ONLY ) {
1770 image = dyld::mainExecutable();
1771 sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
1772 if ( sym != NULL ) {
1773 CRSetCrashLogMessage(NULL);
1774 result = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext, NULL, false, underscoredName);
1775 if ( dyld::gLogAPIs )
1776 dyld::log(" %s(RTLD_MAIN_ONLY, %s) ==> %p\n", __func__, symbolName, result);
1777 return result;
1778 }
1779 const char* str = dyld::mkstringf("dlsym(RTLD_MAIN_ONLY, %s): symbol not found", symbolName);
1780 dlerrorSet(str);
1781 free((void*)str);
1782 CRSetCrashLogMessage(NULL);
1783 if ( dyld::gLogAPIs )
1784 dyld::log(" %s(RTLD_MAIN_ONLY, %s) ==> NULL\n", __func__, symbolName);
1785 return NULL;
1786 }
1787
1788 // magic "search what I would see" handle
1789 else if ( handle == RTLD_NEXT ) {
1790 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1791 #if SUPPORT_ACCELERATE_TABLES
1792 const mach_header* mh;
1793 const char* path;
1794 unsigned index;
1795 if ( dyld::addressInCache(callerAddress, &mh, &path, &index) ) {
1796 // if dylib in cache is calling dlsym(RTLD_NEXT,xxx) handle search differently
1797 result = dyld::dlsymFromCache(RTLD_NEXT, underscoredName, index);
1798 if ( dyld::gLogAPIs )
1799 dyld::log(" %s(RTLD_NEXT, %s) ==> %p\n", __func__, symbolName, result);
1800 return result;
1801 }
1802 #endif
1803 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
1804 sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
1805 if ( sym != NULL ) {
1806 CRSetCrashLogMessage(NULL);
1807 result = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext , callerImage, false, underscoredName);
1808 if ( dyld::gLogAPIs )
1809 dyld::log(" %s(RTLD_NEXT, %s) ==> %p\n", __func__, symbolName, result);
1810 return result;
1811 }
1812 const char* str = dyld::mkstringf("dlsym(RTLD_NEXT, %s): symbol not found", symbolName);
1813 dlerrorSet(str);
1814 free((void*)str);
1815 CRSetCrashLogMessage(NULL);
1816 if ( dyld::gLogAPIs )
1817 dyld::log(" %s(RTLD_NEXT, %s) ==> NULL\n", __func__, symbolName);
1818 return NULL;
1819 }
1820 // magic "search me, then what I would see" handle
1821 else if ( handle == RTLD_SELF ) {
1822 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1823 #if SUPPORT_ACCELERATE_TABLES
1824 const mach_header* mh;
1825 const char* path;
1826 unsigned index;
1827 if ( dyld::addressInCache(callerAddress, &mh, &path, &index) ) {
1828 // if dylib in cache is calling dlsym(RTLD_SELF,xxx) handle search differently
1829 result = dyld::dlsymFromCache(RTLD_SELF, underscoredName, index);
1830 if ( dyld::gLogAPIs )
1831 dyld::log(" %s(RTLD_SELF, %s) ==> %p\n", __func__, symbolName, result);
1832 return result;
1833 }
1834 #endif
1835 ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
1836 sym = callerImage->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
1837 if ( sym != NULL ) {
1838 CRSetCrashLogMessage(NULL);
1839 result = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext, callerImage, false, underscoredName);
1840 if ( dyld::gLogAPIs )
1841 dyld::log(" %s(RTLD_SELF, %s) ==> %p\n", __func__, symbolName, result);
1842 return result;
1843 }
1844 const char* str = dyld::mkstringf("dlsym(RTLD_SELF, %s): symbol not found", symbolName);
1845 dlerrorSet(str);
1846 free((void*)str);
1847 CRSetCrashLogMessage(NULL);
1848 if ( dyld::gLogAPIs )
1849 dyld::log(" %s(RTLD_SELF, %s) ==> NULL\n", __func__, symbolName);
1850 return NULL;
1851 }
1852 #if SUPPORT_ACCELERATE_TABLES
1853 // check for mega dylib handle
1854 else if ( dyld::isCacheHandle(handle) ) {
1855 result = dyld::dlsymFromCache(handle, underscoredName, 0);
1856 if ( dyld::gLogAPIs )
1857 dyld::log(" %s(%p, %s) ==> %p\n", __func__, handle, symbolName, result);
1858 return result;
1859 }
1860 #endif
1861 // real handle
1862 image = (ImageLoader*)(((uintptr_t)handle) & (-4)); // clear mode bits
1863 if ( dyld::validImage(image) ) {
1864 if ( (((uintptr_t)handle) & 1) != 0 )
1865 sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
1866 else
1867 sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
1868
1869 if ( sym != NULL ) {
1870 CRSetCrashLogMessage(NULL);
1871 ImageLoader* callerImage = NULL;
1872 if ( sDynamicInterposing ) {
1873 // only take time to look up caller, if dynamic interposing in use
1874 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
1875 callerImage = dyld::findImageContainingAddress(callerAddress);
1876 }
1877 result = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext, callerImage, false, underscoredName);
1878 if ( dyld::gLogAPIs )
1879 dyld::log(" %s(%p, %s) ==> %p\n", __func__, handle, symbolName, result);
1880 return result;
1881 }
1882 const char* str = dyld::mkstringf("dlsym(%p, %s): symbol not found", handle, symbolName);
1883 dlerrorSet(str);
1884 free((void*)str);
1885 }
1886 else {
1887 dlerrorSet("invalid handle passed to dlsym()");
1888 }
1889 CRSetCrashLogMessage(NULL);
1890 if ( dyld::gLogAPIs )
1891 dyld::log(" %s(%p, %s) ==> NULL\n", __func__, handle, symbolName);
1892 return NULL;
1893 }
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904 const struct dyld_all_image_infos* _dyld_get_all_image_infos()
1905 {
1906 return dyld::gProcessInfo;
1907 }
1908
1909
1910 #if SUPPORT_ZERO_COST_EXCEPTIONS
1911 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
1912 {
1913 //if ( dyld::gLogAPIs )
1914 // dyld::log("%s(%p, %p)\n", __func__, addr, info);
1915
1916 #if SUPPORT_ACCELERATE_TABLES
1917 if ( dyld::findUnwindSections(addr, info) )
1918 return true;
1919 #endif
1920 ImageLoader* image = dyld::findImageContainingAddress(addr);
1921 if ( image != NULL ) {
1922 image->getUnwindInfo(info);
1923 return true;
1924 }
1925 return false;
1926 }
1927 #endif
1928
1929
1930 const char* dyld_image_path_containing_address(const void* address)
1931 {
1932 if ( dyld::gLogAPIs )
1933 dyld::log("%s(%p)\n", __func__, address);
1934
1935 #if SUPPORT_ACCELERATE_TABLES
1936 const mach_header* mh;
1937 const char* path;
1938 if ( dyld::addressInCache(address, &mh, &path) )
1939 return path;
1940 #endif
1941
1942 ImageLoader* image = dyld::findImageContainingAddress(address);
1943 if ( image != NULL )
1944 return image->getRealPath();
1945 return NULL;
1946 }
1947
1948
1949
1950 bool dyld_shared_cache_some_image_overridden()
1951 {
1952 #if DYLD_SHARED_CACHE_SUPPORT
1953 return dyld::gSharedCacheOverridden;
1954 #else
1955 return true;
1956 #endif
1957 }
1958
1959
1960 void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count)
1961 {
1962 if ( mh == NULL )
1963 return;
1964 if ( array == NULL )
1965 return;
1966 if ( count == 0 )
1967 return;
1968 ImageLoader* image = dyld::findImageByMachHeader(mh);
1969 if ( image == NULL )
1970 return;
1971
1972 // make pass at bound references in this image and update them
1973 dyld::gLinkContext.dynamicInterposeArray = array;
1974 dyld::gLinkContext.dynamicInterposeCount = count;
1975 image->dynamicInterpose(dyld::gLinkContext);
1976 dyld::gLinkContext.dynamicInterposeArray = NULL;
1977 dyld::gLinkContext.dynamicInterposeCount = 0;
1978
1979 // leave interposing info so any future (lazy) binding will get it too
1980 image->addDynamicInterposingTuples(array, count);
1981
1982 sDynamicInterposing = true;
1983 }
1984
1985
1986 bool _dyld_is_memory_immutable(const void* addr, size_t length)
1987 {
1988 if ( dyld::gLogAPIs )
1989 dyld::log("%s(%p, %ld)\n", __func__, addr, length);
1990
1991 uintptr_t checkStart = (uintptr_t)addr;
1992 uintptr_t checkEnd = checkStart + length;
1993
1994 #if DYLD_SHARED_CACHE_SUPPORT
1995 // quick check to see if in r/o region of shared cache. If so return true.
1996 if ( dyld_shared_cache_ranges.sharedRegionsCount > 2 ) {
1997 uintptr_t roStart = dyld_shared_cache_ranges.ranges[0].start;
1998 uintptr_t roEnd = roStart + dyld_shared_cache_ranges.ranges[0].length;
1999 if ( (roStart < checkStart) && (checkEnd < roEnd) )
2000 return true;
2001 }
2002 #endif
2003
2004 // Otherwise find if addr is in a dyld loaded image
2005 ImageLoader* image = dyld::findImageContainingAddress(addr);
2006 if ( image != NULL ) {
2007 // <rdar://problem/24091154> already checked for r/o portion of cache
2008 if ( image->inSharedCache() )
2009 return false;
2010 if ( !image->neverUnload() )
2011 return false;
2012 for (unsigned i=0, e=image->segmentCount(); i < e; ++i) {
2013 if ( (image->segActualLoadAddress(i) < checkStart) && (checkEnd < image->segActualEndAddress(i)) ) {
2014 return !image->segWriteable(i);
2015 }
2016 }
2017 }
2018 return false;
2019 }
2020
2021
2022
2023 void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
2024 _dyld_objc_notify_init init,
2025 _dyld_objc_notify_unmapped unmapped)
2026 {
2027 dyld::registerObjCNotifiers(mapped, init, unmapped);
2028 }
2029
2030
2031 bool _dyld_get_shared_cache_uuid(uuid_t uuid)
2032 {
2033 return dyld::sharedCacheUUID(uuid);
2034 }