]> git.saurik.com Git - apple/dyld.git/blob - dyld3/APIs.cpp
dyld-732.8.tar.gz
[apple/dyld.git] / dyld3 / APIs.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <string.h>
26 #include <stdint.h>
27 #include <sys/errno.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #include <dirent.h>
31 #include <fcntl.h>
32 #include <libc_private.h>
33 #include <TargetConditionals.h>
34 #include <_simple.h>
35 #include <mach-o/dyld_priv.h>
36 #include <mach-o/dyld_images.h>
37 #include <crt_externs.h> // FIXME: Remove once we move off of _NSGetMainExecutable()
38 #include <os/once_private.h>
39
40 #include <array>
41 #include <algorithm>
42
43 #include "dlfcn.h"
44
45 #include "AllImages.h"
46 #include "Loading.h"
47 #include "Logging.h"
48 #include "Diagnostics.h"
49 #include "DyldSharedCache.h"
50 #include "PathOverrides.h"
51 #include "APIs.h"
52 #include "Closure.h"
53 #include "MachOLoaded.h"
54 #include "ClosureBuilder.h"
55 #include "ClosureFileSystemPhysical.h"
56
57 #if __has_feature(ptrauth_calls)
58 #include <ptrauth.h>
59 #endif
60
61
62 namespace dyld {
63 extern dyld_all_image_infos dyld_all_image_infos;
64 }
65
66
67 namespace dyld3 {
68
69
70 static const void *stripPointer(const void *ptr) {
71 #if __has_feature(ptrauth_calls)
72 return __builtin_ptrauth_strip(ptr, ptrauth_key_asia);
73 #else
74 return ptr;
75 #endif
76 }
77
78 pthread_mutex_t RecursiveAutoLock::_sMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
79
80 // forward declaration
81 static void dyld_get_image_versions_internal(const struct mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version));
82
83
84 uint32_t _dyld_image_count(void)
85 {
86 log_apis("_dyld_image_count()\n");
87
88 return gAllImages.count();
89 }
90
91 const mach_header* _dyld_get_image_header(uint32_t imageIndex)
92 {
93 log_apis("_dyld_get_image_header(%d)\n", imageIndex);
94 return gAllImages.imageLoadAddressByIndex(imageIndex);
95 }
96
97 intptr_t _dyld_get_image_slide(const mach_header* mh)
98 {
99 log_apis("_dyld_get_image_slide(%p)\n", mh);
100
101 const MachOLoaded* mf = (MachOLoaded*)mh;
102 if ( !mf->hasMachOMagic() )
103 return 0;
104
105 return mf->getSlide();
106 }
107
108 intptr_t _dyld_get_image_vmaddr_slide(uint32_t imageIndex)
109 {
110 log_apis("_dyld_get_image_vmaddr_slide(%d)\n", imageIndex);
111
112 const mach_header* mh = gAllImages.imageLoadAddressByIndex(imageIndex);
113 if ( mh != nullptr )
114 return dyld3::_dyld_get_image_slide(mh);
115 return 0;
116 }
117
118 const char* _dyld_get_image_name(uint32_t imageIndex)
119 {
120 log_apis("_dyld_get_image_name(%d)\n", imageIndex);
121 return gAllImages.imagePathByIndex(imageIndex);
122 }
123
124
125 static bool nameMatch(const char* installName, const char* libraryName)
126 {
127 const char* leafName = strrchr(installName, '/');
128 if ( leafName == NULL )
129 leafName = installName;
130 else
131 leafName++;
132
133 // -framework case is exact match of leaf name
134 if ( strcmp(leafName, libraryName) == 0 )
135 return true;
136
137 // -lxxx case: leafName must match "lib" <libraryName> ["." ?] ".dylib"
138 size_t leafNameLen = strlen(leafName);
139 size_t libraryNameLen = strlen(libraryName);
140 if ( leafNameLen < (libraryNameLen+9) )
141 return false;
142 if ( strncmp(leafName, "lib", 3) != 0 )
143 return false;
144 if ( strcmp(&leafName[leafNameLen-6], ".dylib") != 0 )
145 return false;
146 if ( strncmp(&leafName[3], libraryName, libraryNameLen) != 0 )
147 return false;
148 return (leafName[libraryNameLen+3] == '.');
149 }
150
151
152 //
153 // BETTER, USE: dyld_get_program_sdk_version()
154 //
155 // Scans the main executable and returns the version of the specified dylib the program was built against.
156 //
157 // The library to find is the leaf name that would have been passed to linker tool
158 // (e.g. -lfoo or -framework foo would use "foo").
159 //
160 // Returns -1 if the main executable did not link against the specified library, or is malformed.
161 //
162 int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)
163 {
164 log_apis("NSVersionOfLinkTimeLibrary(\"%s\")\n", libraryName);
165
166 __block int32_t result = -1;
167 gAllImages.mainExecutable()->forEachDependentDylib(^(const char* loadPath, bool, bool, bool, uint32_t compatVersion, uint32_t currentVersion, bool& stop) {
168 if ( nameMatch(loadPath, libraryName) )
169 result = currentVersion;
170 });
171 log_apis(" NSVersionOfLinkTimeLibrary() => 0x%08X\n", result);
172 return result;
173 }
174
175
176 //
177 // Searches loaded images for the requested dylib and returns its current version.
178 //
179 // The library to find is the leaf name that would have been passed to linker tool
180 // (e.g. -lfoo or -framework foo would use "foo").
181 //
182 // If the specified library is not loaded, -1 is returned.
183 //
184 int32_t NSVersionOfRunTimeLibrary(const char* libraryName)
185 {
186 log_apis("NSVersionOfRunTimeLibrary(\"%s\")\n", libraryName);
187 __block int32_t result = -1;
188 gAllImages.forEachImage(^(const dyld3::LoadedImage& loadedImage, bool &stop) {
189 const char* installName;
190 uint32_t currentVersion;
191 uint32_t compatVersion;
192 if ( loadedImage.loadedAddress()->getDylibInstallName(&installName, &compatVersion, &currentVersion) && nameMatch(installName, libraryName) ) {
193 result = currentVersion;
194 stop = true;
195 }
196 });
197 log_apis(" NSVersionOfRunTimeLibrary() => 0x%08X\n", result);
198 return result;
199 }
200
201
202 uint32_t dyld_get_program_sdk_watch_os_version()
203 {
204 log_apis("dyld_get_program_sdk_watch_os_version()\n");
205
206 __block uint32_t retval = 0;
207 __block bool versionFound = false;
208 dyld3::dyld_get_image_versions(gAllImages.mainExecutable(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
209 if (versionFound) return;
210
211 if (dyld_get_base_platform(platform) == PLATFORM_WATCHOS) {
212 versionFound = true;
213 retval = sdk_version;
214 }
215 });
216
217 return retval;
218 }
219
220 uint32_t dyld_get_program_min_watch_os_version()
221 {
222 log_apis("dyld_get_program_min_watch_os_version()\n");
223
224 __block uint32_t retval = 0;
225 __block bool versionFound = false;
226 dyld3::dyld_get_image_versions(gAllImages.mainExecutable(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
227 if (versionFound) return;
228
229 if (dyld_get_base_platform(platform) == PLATFORM_WATCHOS) {
230 versionFound = true;
231 retval = min_version;
232 }
233 });
234
235 return retval;
236 }
237
238 uint32_t dyld_get_program_sdk_bridge_os_version()
239 {
240 log_apis("dyld_get_program_sdk_bridge_os_version()\n");
241
242 __block uint32_t retval = 0;
243 __block bool versionFound = false;
244 dyld3::dyld_get_image_versions(gAllImages.mainExecutable(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
245 if (versionFound) return;
246
247 if (dyld_get_base_platform(platform) == PLATFORM_BRIDGEOS) {
248 versionFound = true;
249 retval = sdk_version;
250 }
251 });
252
253 return retval;
254 }
255
256 uint32_t dyld_get_program_min_bridge_os_version()
257 {
258 log_apis("dyld_get_program_min_bridge_os_version()\n");
259
260 __block uint32_t retval = 0;
261 __block bool versionFound = false;
262 dyld3::dyld_get_image_versions(gAllImages.mainExecutable(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
263 if (versionFound) return;
264
265 if (dyld_get_base_platform(platform) == PLATFORM_BRIDGEOS) {
266 versionFound = true;
267 retval = min_version;
268 }
269 });
270
271 return retval;
272 }
273
274 //
275 // Returns the sdk version (encode as nibble XXXX.YY.ZZ) that the
276 // specified binary was built against.
277 //
278 // First looks for LC_VERSION_MIN_* in binary and if sdk field is
279 // not zero, return that value.
280 // Otherwise, looks for the libSystem.B.dylib the binary linked
281 // against and uses a table to convert that to an sdk version.
282 //
283 uint32_t dyld_get_sdk_version(const mach_header* mh)
284 {
285 log_apis("dyld_get_sdk_version(%p)\n", mh);
286 __block bool versionFound = false;
287 __block uint32_t retval = 0;
288 dyld3::dyld_get_image_versions(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
289 if (versionFound) return;
290
291 if (platform == ::dyld_get_active_platform()) {
292 versionFound = true;
293 switch (dyld3::dyld_get_base_platform(platform)) {
294 case PLATFORM_BRIDGEOS: retval = sdk_version + 0x00090000; return;
295 case PLATFORM_WATCHOS: retval = sdk_version + 0x00070000; return;
296 default: retval = sdk_version; return;
297 }
298 }
299 });
300
301 return retval;
302 }
303
304 uint32_t dyld_get_program_sdk_version()
305 {
306 log_apis("dyld_get_program_sdk_version()\n");
307 return dyld3::dyld_get_sdk_version(gAllImages.mainExecutable());
308 }
309
310 uint32_t dyld_get_min_os_version(const mach_header* mh)
311 {
312 log_apis("dyld_get_min_os_version(%p)\n", mh);
313 __block bool versionFound = false;
314 __block uint32_t retval = 0;
315 dyld3::dyld_get_image_versions(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
316 if (versionFound) return;
317
318 if (platform == ::dyld_get_active_platform()) {
319 versionFound = true;
320 switch (dyld3::dyld_get_base_platform(platform)) {
321 case PLATFORM_BRIDGEOS: retval = min_version + 0x00090000; return;
322 case PLATFORM_WATCHOS: retval = min_version + 0x00070000; return;
323 default: retval = min_version; return;
324 }
325 }
326 });
327
328 return retval;
329 }
330
331 dyld_platform_t dyld_get_active_platform(void) {
332 return gAllImages.platform();
333 }
334
335 dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) {
336 switch (platform) {
337 case PLATFORM_IOSMAC: return PLATFORM_IOS;
338 case PLATFORM_IOSSIMULATOR: return PLATFORM_IOS;
339 case PLATFORM_WATCHOSSIMULATOR: return PLATFORM_WATCHOS;
340 case PLATFORM_TVOSSIMULATOR: return PLATFORM_TVOS;
341 default: return platform;
342 }
343 }
344
345 bool dyld_is_simulator_platform(dyld_platform_t platform) {
346 switch(platform) {
347 case PLATFORM_IOSSIMULATOR:
348 case PLATFORM_WATCHOSSIMULATOR:
349 case PLATFORM_TVOSSIMULATOR:
350 return true;
351 default:
352 return false;
353 }
354 }
355
356 bool dyld_sdk_at_least(const struct mach_header* mh, dyld_build_version_t version) {
357 __block bool retval = false;
358 dyld3::dyld_get_image_versions(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
359 if (dyld3::dyld_get_base_platform(platform) == version.platform && sdk_version >= version.version) {
360 retval = true;
361 }
362 });
363 return retval;
364 }
365
366 bool dyld_minos_at_least(const struct mach_header* mh, dyld_build_version_t version) {
367 __block bool retval = false;
368 dyld3::dyld_get_image_versions(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
369 if (dyld3::dyld_get_base_platform(platform) == version.platform && min_version >= version.version) {
370 retval = true;
371 }
372 });
373 return retval;
374 }
375
376 bool dyld_program_sdk_at_least(dyld_build_version_t version) {
377 return dyld3::dyld_sdk_at_least(gAllImages.mainExecutable(), version);
378 }
379
380 bool dyld_program_minos_at_least(dyld_build_version_t version) {
381 return dyld3::dyld_minos_at_least(gAllImages.mainExecutable(), version);
382 }
383
384 #if TARGET_OS_OSX || TARGET_OS_IOS
385 static
386 uint32_t linkedDylibVersion(const mach_header* mh, const char *installname) {
387 __block uint32_t retval = 0;
388 ((MachOLoaded*)mh)->forEachDependentDylib(^(const char* loadPath, bool, bool, bool, uint32_t compatVersion, uint32_t currentVersion, bool& stop) {
389 if (strcmp(loadPath, installname) == 0) {
390 retval = currentVersion;
391 stop = true;
392 }
393 });
394 return retval;
395 }
396 #endif
397
398
399 #define PACKED_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff))
400
401 static uint32_t deriveVersionFromDylibs(const struct mach_header* mh) {
402 // This is a binary without a version load command, we need to infer things
403 struct DylibToOSMapping {
404 uint32_t dylibVersion;
405 uint32_t osVersion;
406 };
407 uint32_t linkedVersion = 0;
408 #if TARGET_OS_OSX
409 linkedVersion = linkedDylibVersion(mh, "/usr/lib/libSystem.B.dylib");
410 static const DylibToOSMapping versionMapping[] = {
411 { PACKED_VERSION(88,1,3), 0x000A0400 },
412 { PACKED_VERSION(111,0,0), 0x000A0500 },
413 { PACKED_VERSION(123,0,0), 0x000A0600 },
414 { PACKED_VERSION(159,0,0), 0x000A0700 },
415 { PACKED_VERSION(169,3,0), 0x000A0800 },
416 { PACKED_VERSION(1197,0,0), 0x000A0900 },
417 { PACKED_VERSION(0,0,0), 0x000A0900 }
418 // We don't need to expand this table because all recent
419 // binaries have LC_VERSION_MIN_ load command.
420 };
421 #elif TARGET_OS_IOS
422 linkedVersion = linkedDylibVersion(mh, "/System/Library/Frameworks/Foundation.framework/Foundation");
423 static const DylibToOSMapping versionMapping[] = {
424 { PACKED_VERSION(678,24,0), 0x00020000 },
425 { PACKED_VERSION(678,26,0), 0x00020100 },
426 { PACKED_VERSION(678,29,0), 0x00020200 },
427 { PACKED_VERSION(678,47,0), 0x00030000 },
428 { PACKED_VERSION(678,51,0), 0x00030100 },
429 { PACKED_VERSION(678,60,0), 0x00030200 },
430 { PACKED_VERSION(751,32,0), 0x00040000 },
431 { PACKED_VERSION(751,37,0), 0x00040100 },
432 { PACKED_VERSION(751,49,0), 0x00040200 },
433 { PACKED_VERSION(751,58,0), 0x00040300 },
434 { PACKED_VERSION(881,0,0), 0x00050000 },
435 { PACKED_VERSION(890,1,0), 0x00050100 },
436 { PACKED_VERSION(992,0,0), 0x00060000 },
437 { PACKED_VERSION(993,0,0), 0x00060100 },
438 { PACKED_VERSION(1038,14,0),0x00070000 },
439 { PACKED_VERSION(0,0,0), 0x00070000 }
440 // We don't need to expand this table because all recent
441 // binaries have LC_VERSION_MIN_ load command.
442 };
443 #else
444 static const DylibToOSMapping versionMapping[] = {};
445 #endif
446 if ( linkedVersion != 0 ) {
447 uint32_t lastOsVersion = 0;
448 for (const DylibToOSMapping* p=versionMapping; ; ++p) {
449 if ( p->dylibVersion == 0 ) {
450 return p->osVersion;
451 }
452 if ( linkedVersion < p->dylibVersion ) {
453 return lastOsVersion;
454 }
455 lastOsVersion = p->osVersion;
456 }
457 }
458 return 0;
459 }
460
461 // assumes mh has already been validated
462 static void dyld_get_image_versions_internal(const struct mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version))
463 {
464 const MachOFile* mf = (MachOFile*)mh;
465 __block bool lcFound = false;
466 mf->forEachSupportedPlatform(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
467 lcFound = true;
468 // If SDK field is empty then derive the value from library linkages
469 if (sdk == 0) {
470 sdk = deriveVersionFromDylibs(mh);
471 }
472 if (platform == dyld3::Platform::iOSMac) {
473 sdk = 0x000A0F00;
474 }
475 callback((const dyld_platform_t)platform, sdk, minOS);
476 });
477
478 // No load command was found, so again, fallback to deriving it from library linkages
479 if (!lcFound) {
480 #if TARGET_OS_IOS
481 #if __x86_64__ || __x86__
482 dyld_platform_t platform = PLATFORM_IOSSIMULATOR;
483 #else
484 dyld_platform_t platform = PLATFORM_IOS;
485 #endif
486 #elif TARGET_OS_OSX
487 dyld_platform_t platform = PLATFORM_MACOS;
488 #else
489 dyld_platform_t platform = 0;
490 #endif
491 uint32_t derivedVersion = deriveVersionFromDylibs(mh);
492 if ( platform != 0 && derivedVersion != 0 ) {
493 callback(platform, derivedVersion, 0);
494 }
495 }
496 }
497
498 void dyld_get_image_versions(const struct mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version))
499 {
500 Diagnostics diag;
501 const MachOFile* mf = (MachOFile*)mh;
502 static dyld_platform_t mainExecutablePlatform = 0;
503 static uint32_t mainExecutableSDKVersion = 0;
504 static uint32_t mainExecutableMinOSVersion = 0;
505
506 // FIXME: Once dyld2 is gone gAllImages.mainExecutable() will be valid in all cases
507 // and we can stop calling _NSGetMachExecuteHeader()
508 if (mh == (const struct mach_header*)_NSGetMachExecuteHeader()) {
509 // Cache the main executable and short circuit parsing the
510 if (mainExecutablePlatform == 0) {
511 dyld_get_image_versions_internal(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
512 #if 0
513 //FIXME: Reenable this once Libc supports dynamic platforms.
514 if (platform == PLATFORM_MACOS && dyld_get_active_platform() == PLATFORM_IOSMAC) {
515 //FIXME: This version should be generated at link time
516 mainExecutablePlatform = PLATFORM_IOSMAC;
517 mainExecutableSDKVersion = 0x000D0000;
518 mainExecutableMinOSVersion = 0x000D0000;
519 } else {
520 mainExecutablePlatform = platform;
521 mainExecutableSDKVersion = sdk_version;
522 mainExecutableMinOSVersion = min_version;
523 }
524 #else
525 mainExecutablePlatform = platform;
526 mainExecutableSDKVersion = sdk_version;
527 mainExecutableMinOSVersion = min_version;
528 #endif
529 //FIXME: Assert if more than one command?
530 });
531 }
532 return callback(mainExecutablePlatform, mainExecutableSDKVersion, mainExecutableMinOSVersion);
533 }
534 #if TARGET_OS_EMBEDDED
535 // If we are on embedded AND in the shared cache then the versions should be the same as libdyld
536 if (mf->inDyldCache()) {
537 static dyld_platform_t libDyldPlatform = 0;
538 static uint32_t libDyldSDKVersion = 0;
539 static uint32_t libDyldMinOSVersion = 0;
540 if (libDyldPlatform == 0) {
541 dyld_get_image_versions_internal(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
542 libDyldPlatform = platform;
543 libDyldSDKVersion = sdk_version;
544 libDyldMinOSVersion = min_version;
545 //FIXME: Assert if more than one command?
546 });
547 }
548 return callback(libDyldPlatform, libDyldSDKVersion, libDyldMinOSVersion);
549 }
550 #endif
551 if ( mf->isMachO(diag, mh->sizeofcmds + sizeof(mach_header_64)) )
552 dyld_get_image_versions_internal(mh, callback);
553 }
554
555 uint32_t dyld_get_program_min_os_version()
556 {
557 log_apis("dyld_get_program_min_os_version()\n");
558 return dyld3::dyld_get_min_os_version(gAllImages.mainExecutable());
559 }
560
561 bool _dyld_get_image_uuid(const mach_header* mh, uuid_t uuid)
562 {
563 log_apis("_dyld_get_image_uuid(%p, %p)\n", mh, uuid);
564
565 const MachOFile* mf = (MachOFile*)mh;
566 if ( !mf->hasMachOMagic() )
567 return false;
568
569 return mf->getUuid(uuid);
570 }
571
572 //
573 // _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter
574 // should initially be the size of the buffer. The function returns 0 if the path was successfully copied,
575 // and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set
576 // to the size required.
577 //
578 int _NSGetExecutablePath(char* buf, uint32_t* bufsize)
579 {
580 log_apis("_NSGetExecutablePath(%p, %p)\n", buf, bufsize);
581
582 const closure::Image* mainImage = gAllImages.mainExecutableImage();
583 const char* path = gAllImages.imagePath(mainImage);
584 size_t pathSize = strlen(path) + 1;
585 if ( *bufsize >= pathSize ) {
586 strcpy(buf, path);
587 return 0;
588 }
589 *bufsize = (uint32_t)pathSize;
590 return -1;
591 }
592
593 void _dyld_register_func_for_add_image(void (*func)(const mach_header *mh, intptr_t vmaddr_slide))
594 {
595 log_apis("_dyld_register_func_for_add_image(%p)\n", func);
596
597 gAllImages.addLoadNotifier(func);
598 }
599
600 void _dyld_register_func_for_remove_image(void (*func)(const mach_header *mh, intptr_t vmaddr_slide))
601 {
602 log_apis("_dyld_register_func_for_remove_image(%p)\n", func);
603
604 gAllImages.addUnloadNotifier(func);
605 }
606
607 void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
608 _dyld_objc_notify_init init,
609 _dyld_objc_notify_unmapped unmapped)
610 {
611 log_apis("_dyld_objc_notify_register(%p, %p, %p)\n", mapped, init, unmapped);
612
613 gAllImages.setObjCNotifiers(mapped, init, unmapped);
614 }
615
616
617 const mach_header* dyld_image_header_containing_address(const void* addr)
618 {
619 log_apis("dyld_image_header_containing_address(%p)\n", addr);
620
621 addr = stripPointer(addr);
622
623 const MachOLoaded* ml;
624 if ( gAllImages.infoForImageMappedAt(addr, &ml, nullptr, nullptr) )
625 return ml;
626
627 return nullptr;
628 }
629
630
631 const char* dyld_image_path_containing_address(const void* addr)
632 {
633 log_apis("dyld_image_path_containing_address(%p)\n", addr);
634
635 addr = stripPointer(addr);
636 const char* result = gAllImages.pathForImageMappedAt(addr);
637
638 log_apis(" dyld_image_path_containing_address() => %s\n", result);
639 return result;
640 }
641
642
643
644 bool _dyld_is_memory_immutable(const void* addr, size_t length)
645 {
646 return gAllImages.immutableMemory(addr, length);
647 }
648
649 int dladdr(const void* addr, Dl_info* info)
650 {
651 log_apis("dladdr(%p, %p)\n", addr, info);
652
653 // <rdar://problem/42171466> calling dladdr(xx,NULL) crashes
654 if ( info == NULL )
655 return 0; // failure
656
657 addr = stripPointer(addr);
658
659 __block int result = 0;
660 const MachOLoaded* ml = nullptr;
661 const char* path = nullptr;
662 if ( gAllImages.infoForImageMappedAt(addr, &ml, nullptr, &path) ) {
663 info->dli_fname = path;
664 info->dli_fbase = (void*)ml;
665
666 uint64_t symbolAddr;
667 if ( addr == info->dli_fbase ) {
668 // special case lookup of header
669 info->dli_sname = "__dso_handle";
670 info->dli_saddr = info->dli_fbase;
671 }
672 else if ( ml->findClosestSymbol((long)addr, &(info->dli_sname), &symbolAddr) ) {
673 info->dli_saddr = (void*)(long)symbolAddr;
674 // never return the mach_header symbol
675 if ( info->dli_saddr == info->dli_fbase ) {
676 info->dli_sname = nullptr;
677 info->dli_saddr = nullptr;
678 }
679 // strip off leading underscore
680 else if ( (info->dli_sname != nullptr) && (info->dli_sname[0] == '_') ) {
681 info->dli_sname = info->dli_sname + 1;
682 }
683 }
684 else {
685 info->dli_sname = nullptr;
686 info->dli_saddr = nullptr;
687 }
688 result = 1;
689 }
690
691 if ( result == 0 )
692 log_apis(" dladdr() => 0\n");
693 else
694 log_apis(" dladdr() => 1, { \"%s\", %p, \"%s\", %p }\n", info->dli_fname, info->dli_fbase, info->dli_sname, info->dli_saddr);
695 return result;
696 }
697
698 #if !TARGET_OS_DRIVERKIT
699
700 struct PerThreadErrorMessage
701 {
702 size_t sizeAllocated;
703 bool valid;
704 char message[1];
705 };
706
707 static void dlerror_perThreadKey_once(void* ctx)
708 {
709 pthread_key_t* dlerrorPThreadKeyPtr = (pthread_key_t*)ctx;
710 pthread_key_create(dlerrorPThreadKeyPtr, &free);
711 }
712
713 static pthread_key_t dlerror_perThreadKey()
714 {
715 static os_once_t onceToken;
716 static pthread_key_t dlerrorPThreadKey;
717 os_once(&onceToken, &dlerrorPThreadKey, dlerror_perThreadKey_once);
718 return dlerrorPThreadKey;
719 }
720
721 static void clearErrorString()
722 {
723 PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)pthread_getspecific(dlerror_perThreadKey());
724 if ( errorBuffer != nullptr )
725 errorBuffer->valid = false;
726 }
727
728 __attribute__((format(printf, 1, 2)))
729 static void setErrorString(const char* format, ...)
730 {
731 _SIMPLE_STRING buf = _simple_salloc();
732 if ( buf != nullptr ) {
733 va_list list;
734 va_start(list, format);
735 _simple_vsprintf(buf, format, list);
736 va_end(list);
737 size_t strLen = strlen(_simple_string(buf)) + 1;
738 size_t sizeNeeded = sizeof(PerThreadErrorMessage) + strLen;
739 PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)pthread_getspecific(dlerror_perThreadKey());
740 if ( errorBuffer != nullptr ) {
741 if ( errorBuffer->sizeAllocated < sizeNeeded ) {
742 free(errorBuffer);
743 errorBuffer = nullptr;
744 }
745 }
746 if ( errorBuffer == nullptr ) {
747 size_t allocSize = std::max(sizeNeeded, (size_t)256);
748 PerThreadErrorMessage* p = (PerThreadErrorMessage*)malloc(allocSize);
749 p->sizeAllocated = allocSize;
750 p->valid = false;
751 pthread_setspecific(dlerror_perThreadKey(), p);
752 errorBuffer = p;
753 }
754 strcpy(errorBuffer->message, _simple_string(buf));
755 errorBuffer->valid = true;
756 _simple_sfree(buf);
757 }
758 }
759
760 char* dlerror()
761 {
762 log_apis("dlerror()\n");
763
764 PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)pthread_getspecific(dlerror_perThreadKey());
765 if ( errorBuffer != nullptr ) {
766 if ( errorBuffer->valid ) {
767 // you can only call dlerror() once, then the message is cleared
768 errorBuffer->valid = false;
769 return errorBuffer->message;
770 }
771 }
772 return nullptr;
773 }
774
775 #if __arm64__
776 #define CURRENT_CPU_TYPE CPU_TYPE_ARM64
777 #elif __arm__
778 #define CURRENT_CPU_TYPE CPU_TYPE_ARM
779 #endif
780
781
782 static void* makeDlHandle(const mach_header* mh, bool dontContinue)
783 {
784 uintptr_t flags = (dontContinue ? 1 : 0);
785 return (void*)((((uintptr_t)mh) >> 5) | flags);
786 }
787
788 VIS_HIDDEN
789 void parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue)
790 {
791 *dontContinue = (((uintptr_t)h) & 1);
792 *mh = (const MachOLoaded*)((((uintptr_t)h) & (-2)) << 5);
793 }
794
795 int dlclose(void* handle)
796 {
797 DYLD_LOAD_LOCK_THIS_BLOCK
798 log_apis("dlclose(%p)\n", handle);
799
800 // silently accept magic handles for main executable
801 if ( handle == RTLD_MAIN_ONLY )
802 return 0;
803 if ( handle == RTLD_DEFAULT )
804 return 0;
805
806 const MachOLoaded* mh;
807 bool dontContinue;
808 parseDlHandle(handle, &mh, &dontContinue);
809
810 __block bool unloadable = false;
811 __block bool validHandle = false;
812 gAllImages.infoForImageMappedAt(mh, ^(const LoadedImage& foundImage, uint8_t permissions) {
813 validHandle = true;
814 if ( !foundImage.image()->neverUnload() )
815 unloadable = true;
816 });
817 if ( unloadable ) {
818 gAllImages.decRefCount(mh); // removes image if reference count went to zero
819 }
820
821 if ( validHandle ) {
822 clearErrorString();
823 return 0;
824 }
825 else {
826 setErrorString("invalid handle passed to dlclose()");
827 return -1;
828 }
829 }
830
831
832 void* dlopen_internal(const char* path, int mode, void* callerAddress)
833 {
834 DYLD_LOAD_LOCK_THIS_BLOCK
835 log_apis("dlopen(\"%s\", 0x%08X)\n", ((path==NULL) ? "NULL" : path), mode);
836
837 clearErrorString();
838
839 // passing NULL for path means return magic object
840 if ( path == NULL ) {
841 // RTLD_FIRST means any dlsym() calls on the handle should only search that handle and not subsequent images
842 if ( (mode & RTLD_FIRST) != 0 )
843 return RTLD_MAIN_ONLY;
844 else
845 return RTLD_DEFAULT;
846 }
847
848 const char* leafName = strrchr(path, '/');
849 if ( leafName != nullptr )
850 ++leafName;
851 else
852 leafName = path;
853
854 #if __IPHONE_OS_VERSION_MIN_REQUIRED
855 // <rdar://problem/40235395> dyld3: dlopen() not working with non-canonical paths
856 char canonicalPath[PATH_MAX];
857 if ( leafName != path ) {
858 // make path canonical if it contains a // or ./
859 if ( (strstr(path, "//") != NULL) || (strstr(path, "./") != NULL) ) {
860 const char* lastSlash = strrchr(path, '/');
861 char dirPath[PATH_MAX];
862 if ( strlcpy(dirPath, path, sizeof(dirPath)) < sizeof(dirPath) ) {
863 dirPath[lastSlash-path] = '\0';
864 if ( realpath(dirPath, canonicalPath) ) {
865 strlcat(canonicalPath, "/", sizeof(canonicalPath));
866 if ( strlcat(canonicalPath, lastSlash+1, sizeof(canonicalPath)) < sizeof(canonicalPath) ) {
867 // if all fit in buffer, use new canonical path
868 path = canonicalPath;
869 }
870 }
871 }
872 }
873 }
874 #endif
875
876 // RTLD_FIRST means when dlsym() is called with handle, only search the image and not those loaded after it
877 const bool firstOnly = (mode & RTLD_FIRST);
878
879 // RTLD_LOCAL means when flat searches of all images (e.g. RTLD_DEFAULT) is done, this image should be skipped. But dlsym(handle, xx) can find symbols
880 const bool rtldLocal = (mode & RTLD_LOCAL);
881
882 // RTLD_NODELETE means don't unmap image during dlclose(). Leave the memory mapped, but orphan (leak) it.
883 // Note: this is a weird state and it slightly different semantics that other OSs
884 const bool rtldNoDelete = (mode & RTLD_NODELETE);
885
886 // RTLD_NOLOAD means do nothing if image not already loaded
887 const bool rtldNoLoad = (mode & RTLD_NOLOAD);
888
889 // RTLD_NOW means force lazy symbols bound and fail dlopen() if some cannot be bound
890 const bool rtldNow = (mode & RTLD_NOW);
891
892 // try to load image from specified path
893 Diagnostics diag;
894 const mach_header* topLoadAddress = gAllImages.dlopen(diag, path, rtldNoLoad, rtldLocal, rtldNoDelete, rtldNow, false, callerAddress);
895 if ( diag.hasError() ) {
896 setErrorString("dlopen(%s, 0x%04X): %s", path, mode, diag.errorMessage());
897 log_apis(" dlopen: closure creation error: %s\n", diag.errorMessage());
898 return nullptr;
899 }
900 if ( topLoadAddress == nullptr ) {
901 log_apis(" dlopen(%s) => NULL\n", leafName);
902 return nullptr;
903 }
904 void* result = makeDlHandle(topLoadAddress, firstOnly);
905 log_apis(" dlopen(%s) => %p\n", leafName, result);
906 return result;
907
908 }
909
910 bool dlopen_preflight_internal(const char* path)
911 {
912 DYLD_LOAD_LOCK_THIS_BLOCK
913 log_apis("dlopen_preflight(%s)\n", path);
914
915 // check if path is in dyld shared cache
916 if ( gAllImages.dyldCacheHasPath(path) )
917 return true;
918
919 // check if file is loadable
920 Diagnostics diag;
921 closure::FileSystemPhysical fileSystem;
922 char realerPath[MAXPATHLEN];
923 closure::LoadedFileInfo loadedFileInfo = MachOAnalyzer::load(diag, fileSystem, path, gAllImages.archs(), (Platform)gAllImages.platform(), realerPath);
924 if ( loadedFileInfo.fileContent != nullptr ) {
925 fileSystem.unloadFile(loadedFileInfo);
926 return true;
927 }
928
929 // FIXME: may be symlink to something in dyld cache
930
931 return false;
932 }
933
934 static void* dlsym_search(const char* symName, const LoadedImage& start, bool searchStartImage, MachOLoaded::DependentToMachOLoaded reExportHelper,
935 bool* resultPointsToInstructions)
936 {
937 MachOLoaded::DependentToMachOLoaded finder = ^(const MachOLoaded* mh, uint32_t depIndex) {
938 return gAllImages.findDependent(mh, depIndex);
939 };
940 //fprintf(stderr, "dlsym_search: %s, start=%s\n", symName, start.image()->path());
941
942 // walk all dependents of 'start' in order looking for symbol
943 __block void* result = nullptr;
944 gAllImages.visitDependentsTopDown(start, ^(const LoadedImage& aLoadedImage, bool& stop) {
945 //fprintf(stderr, " search: %s\n", aLoadedImage.image()->path());
946 if ( !searchStartImage && aLoadedImage.image() == start.image() )
947 return;
948 if ( aLoadedImage.loadedAddress()->hasExportedSymbol(symName, finder, &result, resultPointsToInstructions) ) {
949 result = gAllImages.interposeValue(result);
950 stop = true;
951 }
952 });
953
954 return result;
955 }
956
957
958 void* dlsym_internal(void* handle, const char* symbolName, void* callerAddress)
959 {
960 log_apis("dlsym(%p, \"%s\")\n", handle, symbolName);
961
962 clearErrorString();
963
964 MachOLoaded::DependentToMachOLoaded finder = ^(const MachOLoaded* mh, uint32_t depIndex) {
965 return gAllImages.findDependent(mh, depIndex);
966 };
967
968 // dlsym() assumes symbolName passed in is same as in C source code
969 // dyld assumes all symbol names have an underscore prefix
970 BLOCK_ACCCESSIBLE_ARRAY(char, underscoredName, strlen(symbolName)+2);
971 underscoredName[0] = '_';
972 strcpy(&underscoredName[1], symbolName);
973
974 __block void* result = nullptr;
975 __block bool resultPointsToInstructions = false;
976 if ( handle == RTLD_DEFAULT ) {
977 // magic "search all in load order" handle
978 gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) {
979 if ( loadedImage.hideFromFlatSearch() )
980 return;
981 if ( loadedImage.loadedAddress()->hasExportedSymbol(underscoredName, finder, &result, &resultPointsToInstructions) ) {
982 stop = true;
983 }
984 });
985 if ( result != nullptr ) {
986 result = gAllImages.interposeValue(result);
987 #if __has_feature(ptrauth_calls)
988 if (resultPointsToInstructions)
989 result = __builtin_ptrauth_sign_unauthenticated(result, ptrauth_key_asia, 0);
990 #endif
991 log_apis(" dlsym() => %p\n", result);
992 return result;
993 }
994 setErrorString("dlsym(RTLD_DEFAULT, %s): symbol not found", symbolName);
995 log_apis(" dlsym() => NULL\n");
996 return nullptr;
997 }
998 else if ( handle == RTLD_MAIN_ONLY ) {
999 // magic "search only main executable" handle
1000 if ( gAllImages.mainExecutable()->hasExportedSymbol(underscoredName, finder, &result, &resultPointsToInstructions) ) {
1001 result = gAllImages.interposeValue(result);
1002 log_apis(" dlsym() => %p\n", result);
1003 #if __has_feature(ptrauth_calls)
1004 if (resultPointsToInstructions)
1005 result = __builtin_ptrauth_sign_unauthenticated(result, ptrauth_key_asia, 0);
1006 #endif
1007 return result;
1008 }
1009 setErrorString("dlsym(RTLD_MAIN_ONLY, %s): symbol not found", symbolName);
1010 log_apis(" dlsym() => NULL\n");
1011 return nullptr;
1012 }
1013 // rest of cases search in dependency order
1014 if ( handle == RTLD_NEXT ) {
1015 // magic "search what I would see" handle
1016 __block bool foundCaller = false;
1017 gAllImages.infoForImageMappedAt(callerAddress, ^(const LoadedImage& foundImage, uint8_t permissions) {
1018 foundCaller = true;
1019 result = dlsym_search(underscoredName, foundImage, false, finder, &resultPointsToInstructions);
1020 });
1021 if ( !foundCaller ) {
1022 setErrorString("dlsym(RTLD_NEXT, %s): called by unknown image (caller=%p)", symbolName, callerAddress);
1023 return nullptr;
1024 }
1025 }
1026 else if ( handle == RTLD_SELF ) {
1027 // magic "search me, then what I would see" handle
1028 __block bool foundCaller = false;
1029 gAllImages.infoForImageMappedAt(callerAddress, ^(const LoadedImage& foundImage, uint8_t permissions) {
1030 foundCaller = true;
1031 result = dlsym_search(underscoredName, foundImage, true, finder, &resultPointsToInstructions);
1032 });
1033 if ( !foundCaller ) {
1034 setErrorString("dlsym(RTLD_SELF, %s): called by unknown image (caller=%p)", symbolName, callerAddress);
1035 return nullptr;
1036 }
1037 }
1038 else {
1039 // handle value was something returned by dlopen()
1040 const MachOLoaded* mh;
1041 bool dontContinue;
1042 parseDlHandle(handle, &mh, &dontContinue);
1043
1044 __block bool foundCaller = false;
1045 gAllImages.infoForImageWithLoadAddress(mh, ^(const LoadedImage& foundImage) {
1046 foundCaller = true;
1047 if ( dontContinue ) {
1048 // RTLD_FIRST only searches one place
1049 // we go through infoForImageWithLoadAddress() to validate the handle
1050 if (mh->hasExportedSymbol(underscoredName, finder, &result, &resultPointsToInstructions))
1051 result = gAllImages.interposeValue(result);
1052 }
1053 else {
1054 result = dlsym_search(underscoredName, foundImage, true, finder, &resultPointsToInstructions);
1055 }
1056 });
1057 if ( !foundCaller ) {
1058 setErrorString("dlsym(%p, %s): invalid handle", handle, symbolName);
1059 log_apis(" dlsym() => NULL\n");
1060 return nullptr;
1061 }
1062 }
1063
1064 if ( result != nullptr ) {
1065 #if __has_feature(ptrauth_calls)
1066 if (resultPointsToInstructions)
1067 result = __builtin_ptrauth_sign_unauthenticated(result, ptrauth_key_asia, 0);
1068 #endif
1069 log_apis(" dlsym() => %p\n", result);
1070 return result;
1071 }
1072
1073 setErrorString("dlsym(%p, %s): symbol not found", handle, symbolName);
1074 log_apis(" dlsym() => NULL\n");
1075 return nullptr;
1076 }
1077 #endif // !TARGET_OS_DRIVERKIT
1078
1079
1080 const struct dyld_all_image_infos* _dyld_get_all_image_infos()
1081 {
1082 return gAllImages.oldAllImageInfo();
1083 }
1084
1085 bool dyld_shared_cache_some_image_overridden()
1086 {
1087 log_apis("dyld_shared_cache_some_image_overridden()\n");
1088
1089 return gAllImages.hasCacheOverrides();
1090 }
1091
1092 bool _dyld_get_shared_cache_uuid(uuid_t uuid)
1093 {
1094 log_apis("_dyld_get_shared_cache_uuid()\n");
1095
1096 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1097 if ( sharedCache == nullptr )
1098 return false;
1099
1100 if ( gAllImages.oldAllImageInfo() != nullptr ) {
1101 memcpy(uuid, gAllImages.oldAllImageInfo()->sharedCacheUUID, sizeof(uuid_t));
1102 return true;
1103 }
1104 return false;
1105 }
1106
1107 const void* _dyld_get_shared_cache_range(size_t* mappedSize)
1108 {
1109 log_apis("_dyld_get_shared_cache_range()\n");
1110
1111 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1112 if ( sharedCache != nullptr ) {
1113 *mappedSize = (size_t)sharedCache->mappedSize();
1114 return sharedCache;
1115 }
1116 *mappedSize = 0;
1117 return NULL;
1118 }
1119
1120 bool _dyld_shared_cache_optimized()
1121 {
1122 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1123 if ( sharedCache != nullptr ) {
1124 return (sharedCache->header.cacheType == kDyldSharedCacheTypeProduction);
1125 }
1126 return false;
1127 }
1128
1129 bool _dyld_shared_cache_is_locally_built()
1130 {
1131 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1132 if ( sharedCache != nullptr ) {
1133 return (sharedCache->header.locallyBuiltCache == 1);
1134 }
1135 return false;
1136 }
1137
1138 void _dyld_images_for_addresses(unsigned count, const void* addresses[], dyld_image_uuid_offset infos[])
1139 {
1140 log_apis("_dyld_images_for_addresses(%u, %p, %p)\n", count, addresses, infos);
1141
1142 // in stack crawls, common for contiguous fames to be in same image, so cache
1143 // last lookup and check if next addresss in in there before doing full search
1144 const MachOLoaded* ml = nullptr;
1145 uint64_t textSize = 0;
1146 const void* end = (void*)ml;
1147 for (unsigned i=0; i < count; ++i) {
1148 const void* addr = stripPointer(addresses[i]);
1149 bzero(&infos[i], sizeof(dyld_image_uuid_offset));
1150 if ( (ml == nullptr) || (addr < (void*)ml) || (addr > end) ) {
1151 if ( gAllImages.infoForImageMappedAt(addr, &ml, &textSize, nullptr) ) {
1152 end = (void*)((uint8_t*)ml + textSize);
1153 }
1154 else {
1155 ml = nullptr;
1156 textSize = 0;
1157 }
1158 }
1159 if ( ml != nullptr ) {
1160 infos[i].image = ml;
1161 infos[i].offsetInImage = (uintptr_t)addr - (uintptr_t)ml;
1162 ml->getUuid(infos[i].uuid);
1163 }
1164 }
1165 }
1166
1167 void _dyld_register_for_image_loads(void (*func)(const mach_header* mh, const char* path, bool unloadable))
1168 {
1169 gAllImages.addLoadNotifier(func);
1170 }
1171
1172 void _dyld_register_for_bulk_image_loads(void (*func)(unsigned imageCount, const struct mach_header* mhs[], const char* paths[]))
1173 {
1174 gAllImages.addBulkLoadNotifier(func);
1175 }
1176
1177 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
1178 {
1179 log_apis("_dyld_find_unwind_sections(%p, %p)\n", addr, info);
1180 addr = (void*)stripPointer(addr);
1181
1182 const MachOLoaded* ml = nullptr;
1183 if ( gAllImages.infoForImageMappedAt(addr, &ml, nullptr, nullptr) ) {
1184 info->mh = ml;
1185 info->dwarf_section = nullptr;
1186 info->dwarf_section_length = 0;
1187 info->compact_unwind_section = nullptr;
1188 info->compact_unwind_section_length = 0;
1189
1190 uint64_t size;
1191 if ( const void* content = ml->findSectionContent("__TEXT", "__eh_frame", size) ) {
1192 info->dwarf_section = content;
1193 info->dwarf_section_length = (uintptr_t)size;
1194 }
1195 if ( const void* content = ml->findSectionContent("__TEXT", "__unwind_info", size) ) {
1196 info->compact_unwind_section = content;
1197 info->compact_unwind_section_length = (uintptr_t)size;
1198 }
1199 return true;
1200 }
1201
1202 return false;
1203 }
1204
1205
1206 bool dyld_process_is_restricted()
1207 {
1208 log_apis("dyld_process_is_restricted()\n");
1209 return gAllImages.isRestricted();
1210 }
1211
1212
1213 const char* dyld_shared_cache_file_path()
1214 {
1215 log_apis("dyld_shared_cache_file_path()\n");
1216
1217 return gAllImages.dyldCachePath();
1218 }
1219
1220
1221 bool dyld_has_inserted_or_interposing_libraries()
1222 {
1223 log_apis("dyld_has_inserted_or_interposing_libraries()\n");
1224
1225 return gAllImages.hasInsertedOrInterposingLibraries();
1226 }
1227
1228
1229 void dyld_dynamic_interpose(const mach_header* mh, const dyld_interpose_tuple array[], size_t count)
1230 {
1231 log_apis("dyld_dynamic_interpose(%p, %p, %lu)\n", mh, array, count);
1232 // FIXME
1233 }
1234
1235
1236 static void* mapStartOfCache(const char* path, size_t length)
1237 {
1238 struct stat statbuf;
1239 if ( ::stat(path, &statbuf) == -1 )
1240 return NULL;
1241
1242 if ( statbuf.st_size < length )
1243 return NULL;
1244
1245 int cache_fd = ::open(path, O_RDONLY);
1246 if ( cache_fd < 0 )
1247 return NULL;
1248
1249 void* result = ::mmap(NULL, length, PROT_READ, MAP_PRIVATE, cache_fd, 0);
1250 close(cache_fd);
1251
1252 if ( result == MAP_FAILED )
1253 return NULL;
1254
1255 return result;
1256 }
1257
1258 static const DyldSharedCache* findCacheInDirAndMap(const uuid_t cacheUuid, const char* dirPath, size_t& sizeMapped)
1259 {
1260 DIR* dirp = ::opendir(dirPath);
1261 if ( dirp != NULL) {
1262 dirent entry;
1263 dirent* entp = NULL;
1264 char cachePath[PATH_MAX];
1265 while ( ::readdir_r(dirp, &entry, &entp) == 0 ) {
1266 if ( entp == NULL )
1267 break;
1268 if ( entp->d_type != DT_REG )
1269 continue;
1270 if ( strlcpy(cachePath, dirPath, PATH_MAX) >= PATH_MAX )
1271 continue;
1272 if ( strlcat(cachePath, "/", PATH_MAX) >= PATH_MAX )
1273 continue;
1274 if ( strlcat(cachePath, entp->d_name, PATH_MAX) >= PATH_MAX )
1275 continue;
1276 if ( const DyldSharedCache* cache = (DyldSharedCache*)mapStartOfCache(cachePath, 0x00100000) ) {
1277 uuid_t foundUuid;
1278 cache->getUUID(foundUuid);
1279 if ( ::memcmp(foundUuid, cacheUuid, 16) != 0 ) {
1280 // wrong uuid, unmap and keep looking
1281 ::munmap((void*)cache, 0x00100000);
1282 }
1283 else {
1284 // found cache
1285 closedir(dirp);
1286 sizeMapped = 0x00100000;
1287 return cache;
1288 }
1289 }
1290 }
1291 closedir(dirp);
1292 }
1293 return nullptr;
1294 }
1295
1296 int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info))
1297 {
1298 log_apis("dyld_shared_cache_find_iterate_text()\n");
1299
1300 // see if requested cache is the active one in this process
1301 size_t sizeMapped = 0;
1302 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1303 if ( sharedCache != nullptr ) {
1304 uuid_t runningUuid;
1305 sharedCache->getUUID(runningUuid);
1306 if ( ::memcmp(runningUuid, cacheUuid, 16) != 0 )
1307 sharedCache = nullptr;
1308 }
1309 if ( sharedCache == nullptr ) {
1310 // if not, look in default location for cache files
1311 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1312 const char* defaultSearchDir = IPHONE_DYLD_SHARED_CACHE_DIR;
1313 #else
1314 const char* defaultSearchDir = MACOSX_DYLD_SHARED_CACHE_DIR;
1315 #endif
1316 sharedCache = findCacheInDirAndMap(cacheUuid, defaultSearchDir, sizeMapped);
1317 // if not there, look in extra search locations
1318 if ( sharedCache == nullptr ) {
1319 for (const char** p = extraSearchDirs; *p != nullptr; ++p) {
1320 sharedCache = findCacheInDirAndMap(cacheUuid, *p, sizeMapped);
1321 if ( sharedCache != nullptr )
1322 break;
1323 }
1324 }
1325 }
1326 if ( sharedCache == nullptr )
1327 return -1;
1328
1329 // get base address of cache
1330 __block uint64_t cacheUnslidBaseAddress = 0;
1331 sharedCache->forEachRegion(^(const void *content, uint64_t vmAddr, uint64_t size, uint32_t permissions) {
1332 if ( cacheUnslidBaseAddress == 0 )
1333 cacheUnslidBaseAddress = vmAddr;
1334 });
1335
1336 // iterate all images
1337 sharedCache->forEachImageTextSegment(^(uint64_t loadAddressUnslid, uint64_t textSegmentSize, const uuid_t dylibUUID, const char* installName, bool& stop) {
1338 dyld_shared_cache_dylib_text_info dylibTextInfo;
1339 dylibTextInfo.version = 2;
1340 dylibTextInfo.loadAddressUnslid = loadAddressUnslid;
1341 dylibTextInfo.textSegmentSize = textSegmentSize;
1342 dylibTextInfo.path = installName;
1343 ::memcpy(dylibTextInfo.dylibUuid, dylibUUID, 16);
1344 dylibTextInfo.textSegmentOffset = loadAddressUnslid - cacheUnslidBaseAddress;
1345 callback(&dylibTextInfo);
1346 });
1347
1348 if ( sizeMapped != 0 )
1349 ::munmap((void*)sharedCache, sizeMapped);
1350
1351 return 0;
1352 }
1353
1354 int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info))
1355 {
1356 log_apis("dyld_shared_cache_iterate_text()\n");
1357
1358 const char* extraSearchDirs[] = { NULL };
1359 return dyld3::dyld_shared_cache_find_iterate_text(cacheUuid, extraSearchDirs, callback);
1360 }
1361
1362 bool dyld_need_closure(const char* execPath, const char* tempDir)
1363 {
1364 log_apis("dyld_need_closure()\n");
1365
1366 // We don't need to build a closure if the shared cache has it already
1367 const DyldSharedCache* sharedCache = (DyldSharedCache*)gAllImages.cacheLoadAddress();
1368 if ( sharedCache != nullptr ) {
1369 if ( sharedCache->findClosure(execPath) != nullptr )
1370 return false;
1371 }
1372
1373
1374 char closurePath[PATH_MAX];
1375 if ( dyld3::closure::LaunchClosure::buildClosureCachePath(execPath, closurePath, tempDir, false) ) {
1376 struct stat statbuf;
1377 return (::stat(closurePath, &statbuf) != 0);
1378 }
1379
1380 // Not containerized so no point in building a closure.
1381 return false;
1382 }
1383
1384 void _dyld_missing_symbol_abort()
1385 {
1386 // We don't know the name of the lazy symbol that is missing.
1387 // dyld3 binds all such missing symbols to this one handler.
1388 // We need the crash log to contain the backtrace so someone can
1389 // figure out the symbol.
1390 abort_report_np("missing lazy symbol called");
1391 }
1392
1393 const char* _dyld_get_objc_selector(const char* selName)
1394 {
1395 log_apis("dyld_get_objc_selector()\n");
1396 return gAllImages.getObjCSelector(selName);
1397 }
1398
1399 void _dyld_for_each_objc_class(const char* className,
1400 void (^callback)(void* classPtr, bool isLoaded, bool* stop)) {
1401 log_apis("_dyld_for_each_objc_class()\n");
1402 gAllImages.forEachObjCClass(className, callback);
1403 }
1404
1405 void _dyld_for_each_objc_protocol(const char* protocolName,
1406 void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) {
1407 log_apis("_dyld_for_each_objc_protocol()\n");
1408 gAllImages.forEachObjCProtocol(protocolName, callback);
1409 }
1410
1411 #if !TARGET_OS_DRIVERKIT
1412 struct dyld_func {
1413 const char* name;
1414 void* implementation;
1415 };
1416
1417 static const struct dyld_func dyld_funcs[] = {
1418 {"__dyld_dlsym", (void*)dlsym }, // needs to go through generic function to get caller address
1419 {"__dyld_dlopen", (void*)dlopen },// needs to go through generic function to get caller address
1420 {"__dyld_dladdr", (void*)dyld3::dladdr },
1421 {"__dyld_image_count", (void*)dyld3::_dyld_image_count },
1422 {"__dyld_get_image_name", (void*)dyld3::_dyld_get_image_name },
1423 {"__dyld_get_image_header", (void*)dyld3::_dyld_get_image_header },
1424 {"__dyld_get_image_vmaddr_slide", (void*)dyld3::_dyld_get_image_vmaddr_slide },
1425 };
1426 #endif
1427
1428 int compatFuncLookup(const char* name, void** address)
1429 {
1430 #if !TARGET_OS_DRIVERKIT
1431 for (const dyld_func* p = dyld_funcs; p->name != NULL; ++p) {
1432 if ( strcmp(p->name, name) == 0 ) {
1433 *address = p->implementation;
1434 return true;
1435 }
1436 }
1437 *address = 0;
1438 #endif
1439 return false;
1440 }
1441
1442
1443
1444 } // namespace dyld3
1445