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