]>
Commit | Line | Data |
---|---|---|
0959b6d4 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
2fd3f4e8 | 3 | * Copyright (c) 2004-2012 Apple Inc. All rights reserved. |
0959b6d4 A |
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 | #include <stddef.h> | |
26 | #include <string.h> | |
39a8cd10 | 27 | #include <malloc/malloc.h> |
2fd3f4e8 | 28 | #include <sys/mman.h> |
39a8cd10 | 29 | |
0959b6d4 | 30 | #include <crt_externs.h> |
39a8cd10 | 31 | #include <Availability.h> |
2fd3f4e8 | 32 | #include <vproc_priv.h> |
0959b6d4 | 33 | |
9f83892a A |
34 | #include <dirent.h> |
35 | #include <sys/stat.h> | |
36 | ||
37 | #include "mach-o/dyld_images.h" | |
0959b6d4 A |
38 | #include "mach-o/dyld.h" |
39 | #include "mach-o/dyld_priv.h" | |
9f83892a | 40 | #include "dyld_cache_format.h" |
0959b6d4 | 41 | |
19894a12 | 42 | #include "ImageLoader.h" |
0959b6d4 | 43 | #include "dyldLock.h" |
2fd3f4e8 | 44 | #include "start_glue.h" |
0959b6d4 | 45 | |
412ebb8e A |
46 | extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso); |
47 | extern "C" void __cxa_finalize(const void *dso); | |
19894a12 | 48 | extern "C" void __cxa_finalize_ranges(const struct __cxa_range_t ranges[], int count); |
bac542e6 | 49 | |
832b6fce A |
50 | |
51 | #ifndef LC_VERSION_MIN_MACOSX | |
52 | #define LC_VERSION_MIN_MACOSX 0x24 | |
53 | struct version_min_command { | |
54 | uint32_t cmd; /* LC_VERSION_MIN_MACOSX or | |
55 | LC_VERSION_MIN_IPHONEOS */ | |
56 | uint32_t cmdsize; /* sizeof(struct min_version_command) */ | |
57 | uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ | |
58 | uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ | |
59 | }; | |
60 | #endif | |
61 | ||
62 | #ifndef LC_VERSION_MIN_IPHONEOS | |
63 | #define LC_VERSION_MIN_IPHONEOS 0x25 | |
64 | #endif | |
65 | ||
df9d6cf7 A |
66 | #ifndef LC_VERSION_MIN_TVOS |
67 | #define LC_VERSION_MIN_TVOS 0x2F | |
68 | #endif | |
69 | ||
70 | #ifndef LC_VERSION_MIN_WATCHOS | |
71 | #define LC_VERSION_MIN_WATCHOS 0x30 | |
72 | #endif | |
73 | ||
832b6fce | 74 | |
412ebb8e A |
75 | #ifndef LC_LOAD_UPWARD_DYLIB |
76 | #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */ | |
77 | #endif | |
78 | ||
39a8cd10 A |
79 | |
80 | // deprecated APIs are still availble on Mac OS X, but not on iPhone OS | |
81 | #if __IPHONE_OS_VERSION_MIN_REQUIRED | |
82 | #define DEPRECATED_APIS_SUPPORTED 0 | |
83 | #else | |
84 | #define DEPRECATED_APIS_SUPPORTED 1 | |
85 | #endif | |
bac542e6 | 86 | |
0959b6d4 A |
87 | /* |
88 | * names_match() takes an install_name from an LC_LOAD_DYLIB command and a | |
89 | * libraryName (which is -lx or -framework Foo argument passed to the static | |
90 | * link editor for the same library) and determines if they match. This depends | |
91 | * on conventional use of names including major versioning. | |
92 | */ | |
93 | static | |
94 | bool | |
95 | names_match( | |
19894a12 | 96 | const char *install_name, |
0959b6d4 A |
97 | const char* libraryName) |
98 | { | |
19894a12 | 99 | const char *basename; |
0959b6d4 A |
100 | unsigned long n; |
101 | ||
102 | /* | |
103 | * Conventional install names have these forms: | |
104 | * /System/Library/Frameworks/AppKit.framework/Versions/A/Appkit | |
105 | * /Local/Library/Frameworks/AppKit.framework/Appkit | |
106 | * /lib/libsys_s.A.dylib | |
107 | * /usr/lib/libsys_s.dylib | |
108 | */ | |
109 | basename = strrchr(install_name, '/'); | |
110 | if(basename == NULL) | |
111 | basename = install_name; | |
112 | else | |
113 | basename++; | |
114 | ||
115 | /* | |
116 | * By checking the base name matching the library name we take care | |
117 | * of the -framework cases. | |
118 | */ | |
119 | if(strcmp(basename, libraryName) == 0) | |
19894a12 | 120 | return true; |
0959b6d4 A |
121 | |
122 | /* | |
123 | * Now check the base name for "lib" if so proceed to check for the | |
124 | * -lx case dealing with a possible .X.dylib and a .dylib extension. | |
125 | */ | |
126 | if(strncmp(basename, "lib", 3) ==0){ | |
127 | n = strlen(libraryName); | |
128 | if(strncmp(basename+3, libraryName, n) == 0){ | |
129 | if(strncmp(basename+3+n, ".dylib", 6) == 0) | |
19894a12 | 130 | return true; |
0959b6d4 A |
131 | if(basename[3+n] == '.' && |
132 | basename[3+n+1] != '\0' && | |
133 | strncmp(basename+3+n+2, ".dylib", 6) == 0) | |
19894a12 | 134 | return true; |
0959b6d4 A |
135 | } |
136 | } | |
19894a12 | 137 | return false; |
0959b6d4 A |
138 | } |
139 | ||
39a8cd10 A |
140 | #if DEPRECATED_APIS_SUPPORTED |
141 | ||
0959b6d4 A |
142 | void NSInstallLinkEditErrorHandlers( |
143 | const NSLinkEditErrorHandlers* handlers) | |
144 | { | |
bac542e6 | 145 | DYLD_LOCK_THIS_BLOCK; |
412ebb8e A |
146 | typedef void (*ucallback_t)(const char* symbol_name); |
147 | typedef NSModule (*mcallback_t)(NSSymbol s, NSModule old, NSModule newhandler); | |
148 | typedef void (*lcallback_t)(NSLinkEditErrors c, int errorNumber, | |
149 | const char* fileName, const char* errorString); | |
150 | static void (*p)(ucallback_t undefined, mcallback_t multiple, lcallback_t linkEdit) = NULL; | |
0959b6d4 A |
151 | |
152 | if(p == NULL) | |
153 | _dyld_func_lookup("__dyld_install_handlers", (void**)&p); | |
412ebb8e A |
154 | mcallback_t m = handlers->multiple; |
155 | p(handlers->undefined, m, handlers->linkEdit); | |
0959b6d4 A |
156 | } |
157 | ||
158 | const char* | |
159 | NSNameOfModule( | |
160 | NSModule module) | |
161 | { | |
bac542e6 | 162 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
163 | static const char* (*p)(NSModule module) = NULL; |
164 | ||
165 | if(p == NULL) | |
166 | _dyld_func_lookup("__dyld_NSNameOfModule", (void**)&p); | |
167 | return(p(module)); | |
168 | } | |
169 | ||
170 | const char* | |
171 | NSLibraryNameForModule( | |
172 | NSModule module) | |
173 | { | |
bac542e6 | 174 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
175 | static const char* (*p)(NSModule module) = NULL; |
176 | ||
177 | if(p == NULL) | |
178 | _dyld_func_lookup("__dyld_NSLibraryNameForModule", (void**)&p); | |
179 | return(p(module)); | |
180 | } | |
181 | ||
182 | bool | |
183 | NSIsSymbolNameDefined( | |
184 | const char* symbolName) | |
185 | { | |
bac542e6 | 186 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
187 | static bool (*p)(const char* symbolName) = NULL; |
188 | ||
189 | if(p == NULL) | |
190 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefined", (void**)&p); | |
191 | return(p(symbolName)); | |
192 | } | |
193 | ||
194 | bool | |
195 | NSIsSymbolNameDefinedWithHint( | |
196 | const char* symbolName, | |
197 | const char* libraryNameHint) | |
198 | { | |
bac542e6 | 199 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
200 | static bool (*p)(const char* symbolName, |
201 | const char* libraryNameHint) = NULL; | |
202 | ||
203 | if(p == NULL) | |
204 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedWithHint", (void**)&p); | |
205 | return(p(symbolName, libraryNameHint)); | |
206 | } | |
207 | ||
208 | bool | |
209 | NSIsSymbolNameDefinedInImage( | |
210 | const struct mach_header *image, | |
211 | const char* symbolName) | |
212 | { | |
bac542e6 | 213 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
214 | static bool (*p)(const struct mach_header *image, |
215 | const char* symbolName) = NULL; | |
216 | ||
217 | if(p == NULL) | |
218 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", (void**)&p); | |
219 | return(p(image, symbolName)); | |
220 | } | |
221 | ||
222 | NSSymbol | |
223 | NSLookupAndBindSymbol( | |
224 | const char* symbolName) | |
225 | { | |
bac542e6 | 226 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
227 | static NSSymbol (*p)(const char* symbolName) = NULL; |
228 | ||
229 | if(p == NULL) | |
230 | _dyld_func_lookup("__dyld_NSLookupAndBindSymbol", (void**)&p); | |
231 | return(p(symbolName)); | |
232 | } | |
233 | ||
234 | NSSymbol | |
235 | NSLookupAndBindSymbolWithHint( | |
236 | const char* symbolName, | |
237 | const char* libraryNameHint) | |
238 | { | |
bac542e6 | 239 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
240 | static NSSymbol (*p)(const char* symbolName, |
241 | const char* libraryNameHint) = NULL; | |
242 | ||
243 | if(p == NULL) | |
244 | _dyld_func_lookup("__dyld_NSLookupAndBindSymbolWithHint", (void**)&p); | |
245 | return(p(symbolName, libraryNameHint)); | |
246 | } | |
247 | ||
248 | NSSymbol | |
249 | NSLookupSymbolInModule( | |
250 | NSModule module, | |
251 | const char* symbolName) | |
252 | { | |
bac542e6 | 253 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
254 | static NSSymbol (*p)(NSModule module, const char* symbolName) = NULL; |
255 | ||
256 | if(p == NULL) | |
257 | _dyld_func_lookup("__dyld_NSLookupSymbolInModule", (void**)&p); | |
258 | return(p(module, symbolName)); | |
259 | } | |
260 | ||
261 | NSSymbol | |
262 | NSLookupSymbolInImage( | |
263 | const struct mach_header *image, | |
264 | const char* symbolName, | |
265 | uint32_t options) | |
266 | { | |
bac542e6 | 267 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
268 | static NSSymbol (*p)(const struct mach_header *image, |
269 | const char* symbolName, | |
270 | uint32_t options) = NULL; | |
271 | ||
272 | if(p == NULL) | |
273 | _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void**)&p); | |
274 | return(p(image, symbolName, options)); | |
275 | } | |
276 | ||
277 | const char* | |
278 | NSNameOfSymbol( | |
279 | NSSymbol symbol) | |
280 | { | |
bac542e6 | 281 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
282 | static char * (*p)(NSSymbol symbol) = NULL; |
283 | ||
284 | if(p == NULL) | |
285 | _dyld_func_lookup("__dyld_NSNameOfSymbol",(void**)&p); | |
286 | return(p(symbol)); | |
287 | } | |
288 | ||
289 | void * | |
290 | NSAddressOfSymbol( | |
291 | NSSymbol symbol) | |
292 | { | |
bac542e6 | 293 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
294 | static void * (*p)(NSSymbol symbol) = NULL; |
295 | ||
296 | if(p == NULL) | |
297 | _dyld_func_lookup("__dyld_NSAddressOfSymbol", (void**)&p); | |
298 | return(p(symbol)); | |
299 | } | |
300 | ||
301 | NSModule | |
302 | NSModuleForSymbol( | |
303 | NSSymbol symbol) | |
304 | { | |
bac542e6 | 305 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
306 | static NSModule (*p)(NSSymbol symbol) = NULL; |
307 | ||
308 | if(p == NULL) | |
309 | _dyld_func_lookup("__dyld_NSModuleForSymbol", (void**)&p); | |
310 | return(p(symbol)); | |
311 | } | |
312 | ||
313 | bool | |
314 | NSAddLibrary( | |
315 | const char* pathName) | |
316 | { | |
bac542e6 | 317 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
318 | static bool (*p)(const char* pathName) = NULL; |
319 | ||
320 | if(p == NULL) | |
321 | _dyld_func_lookup("__dyld_NSAddLibrary", (void**)&p); | |
322 | return(p(pathName)); | |
323 | } | |
324 | ||
325 | bool | |
326 | NSAddLibraryWithSearching( | |
327 | const char* pathName) | |
328 | { | |
bac542e6 | 329 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
330 | static bool (*p)(const char* pathName) = NULL; |
331 | ||
332 | if(p == NULL) | |
333 | _dyld_func_lookup("__dyld_NSAddLibraryWithSearching", (void**)&p); | |
334 | return(p(pathName)); | |
335 | } | |
336 | ||
337 | const struct mach_header * | |
338 | NSAddImage( | |
339 | const char* image_name, | |
340 | uint32_t options) | |
341 | { | |
bac542e6 | 342 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
343 | static const struct mach_header * (*p)(const char* image_name, |
344 | uint32_t options) = NULL; | |
345 | ||
346 | if(p == NULL) | |
347 | _dyld_func_lookup("__dyld_NSAddImage", (void**)&p); | |
348 | return(p(image_name, options)); | |
349 | } | |
39a8cd10 | 350 | #endif // DEPRECATED_APIS_SUPPORTED |
0959b6d4 A |
351 | |
352 | /* | |
353 | * This routine returns the current version of the named shared library the | |
354 | * executable it was built with. The libraryName parameter is the same as the | |
355 | * -lx or -framework Foo argument passed to the static link editor when building | |
356 | * the executable (with -lx it would be "x" and with -framework Foo it would be | |
357 | * "Foo"). If this the executable was not built against the specified library | |
358 | * it returns -1. It should be noted that if this only returns the value the | |
359 | * current version of the named shared library the executable was built with | |
360 | * and not a list of current versions that dependent libraries and bundles the | |
361 | * program is using were built with. | |
362 | */ | |
19894a12 | 363 | int32_t NSVersionOfLinkTimeLibrary(const char* libraryName) |
0959b6d4 | 364 | { |
19894a12 | 365 | // Lazily call _NSGetMachExecuteHeader() and cache result |
bac542e6 | 366 | #if __LP64__ |
19894a12 | 367 | static mach_header_64* mh = NULL; |
bac542e6 | 368 | #else |
19894a12 | 369 | static mach_header* mh = NULL; |
bac542e6 | 370 | #endif |
19894a12 | 371 | if ( mh == NULL ) |
0959b6d4 | 372 | mh = _NSGetMachExecuteHeader(); |
bac542e6 | 373 | #if __LP64__ |
19894a12 | 374 | const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64)); |
0959b6d4 | 375 | #else |
19894a12 | 376 | const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header)); |
0959b6d4 | 377 | #endif |
19894a12 | 378 | for(uint32_t i = 0; i < mh->ncmds; i++){ |
bac542e6 A |
379 | switch ( lc->cmd ) { |
380 | case LC_LOAD_DYLIB: | |
381 | case LC_LOAD_WEAK_DYLIB: | |
412ebb8e | 382 | case LC_LOAD_UPWARD_DYLIB: |
19894a12 A |
383 | const dylib_command* dl = (dylib_command *)lc; |
384 | const char* install_name = (char*)dl + dl->dylib.name.offset; | |
385 | if ( names_match(install_name, libraryName) ) | |
386 | return dl->dylib.current_version; | |
bac542e6 A |
387 | break; |
388 | } | |
19894a12 | 389 | lc = (load_command*)((char*)lc + lc->cmdsize); |
0959b6d4 | 390 | } |
19894a12 | 391 | return (-1); |
0959b6d4 A |
392 | } |
393 | ||
394 | /* | |
395 | * This routine returns the current version of the named shared library the | |
396 | * program it is running against. The libraryName parameter is the same as | |
397 | * would be static link editor using the -lx or -framework Foo flags (with -lx | |
398 | * it would be "x" and with -framework Foo it would be "Foo"). If the program | |
399 | * is not using the specified library it returns -1. | |
400 | */ | |
19894a12 A |
401 | int32_t NSVersionOfRunTimeLibrary(const char* libraryName) |
402 | { | |
403 | uint32_t n = _dyld_image_count(); | |
404 | for(uint32_t i = 0; i < n; i++){ | |
405 | const mach_header* mh = _dyld_get_image_header(i); | |
406 | if ( mh == NULL ) | |
407 | continue; | |
408 | if ( mh->filetype != MH_DYLIB ) | |
409 | continue; | |
bac542e6 | 410 | #if __LP64__ |
19894a12 | 411 | const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64)); |
bac542e6 | 412 | #else |
19894a12 | 413 | const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header)); |
bac542e6 | 414 | #endif |
19894a12 A |
415 | for(uint32_t j = 0; j < mh->ncmds; j++){ |
416 | if ( lc->cmd == LC_ID_DYLIB ) { | |
417 | const dylib_command* dl = (dylib_command*)lc; | |
418 | const char* install_name = (char *)dl + dl->dylib.name.offset; | |
419 | if ( names_match(install_name, libraryName) ) | |
420 | return dl->dylib.current_version; | |
421 | } | |
422 | lc = (load_command*)((char*)lc + lc->cmdsize); | |
0959b6d4 A |
423 | } |
424 | } | |
19894a12 | 425 | return (-1); |
0959b6d4 A |
426 | } |
427 | ||
df9d6cf7 | 428 | |
2fd3f4e8 A |
429 | #define PACKED_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff)) |
430 | ||
832b6fce | 431 | |
df9d6cf7 A |
432 | static bool getVersionLoadCommandInfo(const mach_header* mh, uint32_t* loadCommand, uint32_t* minOS, uint32_t* sdk) |
433 | { | |
434 | const load_command* startCmds = NULL; | |
435 | if ( mh->magic == MH_MAGIC_64 ) | |
436 | startCmds = (load_command*)((char *)mh + sizeof(mach_header_64)); | |
437 | else if ( mh->magic == MH_MAGIC ) | |
438 | startCmds = (load_command*)((char *)mh + sizeof(mach_header)); | |
439 | else | |
440 | return false; // not a mach-o file, or wrong endianness | |
441 | ||
442 | const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds); | |
443 | const load_command* cmd = startCmds; | |
444 | for(uint32_t i = 0; i < mh->ncmds; ++i) { | |
445 | const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize); | |
446 | if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) { | |
447 | return 0; | |
448 | } | |
449 | const version_min_command* versCmd; | |
450 | switch ( cmd->cmd ) { | |
451 | case LC_VERSION_MIN_IPHONEOS: | |
452 | case LC_VERSION_MIN_MACOSX: | |
453 | case LC_VERSION_MIN_TVOS: | |
454 | case LC_VERSION_MIN_WATCHOS: | |
455 | versCmd = (version_min_command*)cmd; | |
456 | *loadCommand = versCmd->cmd; | |
457 | *minOS = versCmd->version; | |
458 | *sdk = versCmd->sdk; | |
459 | return true; | |
460 | } | |
461 | cmd = nextCmd; | |
462 | } | |
463 | return false; | |
464 | } | |
465 | ||
466 | #if !__WATCH_OS_VERSION_MIN_REQUIRED && !__TV_OS_VERSION_MIN_REQUIRED | |
467 | static uint32_t deriveSDKVersFromDylibs(const mach_header* mh) | |
832b6fce | 468 | { |
48479956 | 469 | const load_command* startCmds = NULL; |
2fd3f4e8 | 470 | if ( mh->magic == MH_MAGIC_64 ) |
48479956 | 471 | startCmds = (load_command*)((char *)mh + sizeof(mach_header_64)); |
2fd3f4e8 | 472 | else if ( mh->magic == MH_MAGIC ) |
48479956 | 473 | startCmds = (load_command*)((char *)mh + sizeof(mach_header)); |
2fd3f4e8 A |
474 | else |
475 | return 0; // not a mach-o file, or wrong endianness | |
476 | ||
48479956 | 477 | const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds); |
832b6fce | 478 | const dylib_command* dylibCmd; |
48479956 | 479 | const load_command* cmd = startCmds; |
2fd3f4e8 | 480 | const char* dylibName; |
df9d6cf7 | 481 | #if __IPHONE_OS_VERSION_MIN_REQUIRED |
2fd3f4e8 | 482 | uint32_t foundationVers = 0; |
df9d6cf7 | 483 | #else |
832b6fce | 484 | uint32_t libSystemVers = 0; |
df9d6cf7 | 485 | #endif |
832b6fce | 486 | for(uint32_t i = 0; i < mh->ncmds; ++i) { |
19894a12 A |
487 | const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize); |
488 | // <rdar://problem/14381579&16050962> sanity check size of command | |
489 | if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) { | |
490 | return 0; | |
491 | } | |
492 | switch ( cmd->cmd ) { | |
832b6fce A |
493 | case LC_LOAD_DYLIB: |
494 | case LC_LOAD_WEAK_DYLIB: | |
495 | case LC_LOAD_UPWARD_DYLIB: | |
496 | dylibCmd = (dylib_command*)cmd; | |
19894a12 A |
497 | // sanity check dylib command layout |
498 | if ( dylibCmd->dylib.name.offset > cmd->cmdsize ) | |
499 | return 0; | |
2fd3f4e8 | 500 | dylibName = (char*)dylibCmd + dylibCmd->dylib.name.offset; |
df9d6cf7 | 501 | #if __IPHONE_OS_VERSION_MIN_REQUIRED |
2fd3f4e8 A |
502 | if ( strcmp(dylibName, "/System/Library/Frameworks/Foundation.framework/Foundation") == 0 ) |
503 | foundationVers = dylibCmd->dylib.current_version; | |
df9d6cf7 | 504 | #else |
2fd3f4e8 | 505 | if ( strcmp(dylibName, "/usr/lib/libSystem.B.dylib") == 0 ) |
832b6fce | 506 | libSystemVers = dylibCmd->dylib.current_version; |
df9d6cf7 | 507 | #endif |
832b6fce A |
508 | break; |
509 | } | |
19894a12 | 510 | cmd = nextCmd; |
832b6fce | 511 | } |
2fd3f4e8 A |
512 | |
513 | struct DylibToOSMapping { | |
514 | uint32_t dylibVersion; | |
515 | uint32_t osVersion; | |
516 | }; | |
832b6fce | 517 | |
df9d6cf7 | 518 | #if __IPHONE_OS_VERSION_MIN_REQUIRED |
2fd3f4e8 A |
519 | static const DylibToOSMapping foundationMapping[] = { |
520 | { PACKED_VERSION(678,24,0), DYLD_IOS_VERSION_2_0 }, | |
521 | { PACKED_VERSION(678,26,0), DYLD_IOS_VERSION_2_1 }, | |
522 | { PACKED_VERSION(678,29,0), DYLD_IOS_VERSION_2_2 }, | |
523 | { PACKED_VERSION(678,47,0), DYLD_IOS_VERSION_3_0 }, | |
524 | { PACKED_VERSION(678,51,0), DYLD_IOS_VERSION_3_1 }, | |
525 | { PACKED_VERSION(678,60,0), DYLD_IOS_VERSION_3_2 }, | |
526 | { PACKED_VERSION(751,32,0), DYLD_IOS_VERSION_4_0 }, | |
527 | { PACKED_VERSION(751,37,0), DYLD_IOS_VERSION_4_1 }, | |
528 | { PACKED_VERSION(751,49,0), DYLD_IOS_VERSION_4_2 }, | |
529 | { PACKED_VERSION(751,58,0), DYLD_IOS_VERSION_4_3 }, | |
530 | { PACKED_VERSION(881,0,0), DYLD_IOS_VERSION_5_0 }, | |
531 | { PACKED_VERSION(890,1,0), DYLD_IOS_VERSION_5_1 }, | |
532 | { PACKED_VERSION(992,0,0), DYLD_IOS_VERSION_6_0 }, | |
533 | { PACKED_VERSION(993,0,0), DYLD_IOS_VERSION_6_1 }, | |
df9d6cf7 A |
534 | { PACKED_VERSION(1038,14,0),DYLD_IOS_VERSION_7_0 }, |
535 | { PACKED_VERSION(0,0,0), DYLD_IOS_VERSION_7_0 } | |
536 | // We don't need to expand this table because all recent | |
537 | // binaries have LC_VERSION_MIN_ load command. | |
2fd3f4e8 A |
538 | }; |
539 | ||
540 | if ( foundationVers != 0 ) { | |
541 | uint32_t lastOsVersion = 0; | |
542 | for (const DylibToOSMapping* p=foundationMapping; ; ++p) { | |
543 | if ( p->dylibVersion == 0 ) | |
544 | return p->osVersion; | |
545 | if ( foundationVers < p->dylibVersion ) | |
546 | return lastOsVersion; | |
547 | lastOsVersion = p->osVersion; | |
548 | } | |
549 | } | |
550 | ||
df9d6cf7 | 551 | #else |
2fd3f4e8 A |
552 | // Note: versions are for the GM release. The last entry should |
553 | // always be zero. At the start of the next major version, | |
554 | // a new last entry needs to be added and the previous zero | |
555 | // updated to the GM dylib version. | |
556 | static const DylibToOSMapping libSystemMapping[] = { | |
557 | { PACKED_VERSION(88,1,3), DYLD_MACOSX_VERSION_10_4 }, | |
558 | { PACKED_VERSION(111,0,0), DYLD_MACOSX_VERSION_10_5 }, | |
559 | { PACKED_VERSION(123,0,0), DYLD_MACOSX_VERSION_10_6 }, | |
560 | { PACKED_VERSION(159,0,0), DYLD_MACOSX_VERSION_10_7 }, | |
561 | { PACKED_VERSION(169,3,0), DYLD_MACOSX_VERSION_10_8 }, | |
562 | { PACKED_VERSION(1197,0,0), DYLD_MACOSX_VERSION_10_9 }, | |
563 | { PACKED_VERSION(0,0,0), DYLD_MACOSX_VERSION_10_9 } | |
df9d6cf7 A |
564 | // We don't need to expand this table because all recent |
565 | // binaries have LC_VERSION_MIN_ load command. | |
2fd3f4e8 A |
566 | }; |
567 | ||
568 | if ( libSystemVers != 0 ) { | |
569 | uint32_t lastOsVersion = 0; | |
570 | for (const DylibToOSMapping* p=libSystemMapping; ; ++p) { | |
571 | if ( p->dylibVersion == 0 ) | |
572 | return p->osVersion; | |
573 | if ( libSystemVers < p->dylibVersion ) | |
574 | return lastOsVersion; | |
575 | lastOsVersion = p->osVersion; | |
576 | } | |
832b6fce | 577 | } |
df9d6cf7 A |
578 | #endif |
579 | return 0; | |
580 | } | |
2fd3f4e8 | 581 | #endif |
df9d6cf7 A |
582 | |
583 | ||
584 | #if __WATCH_OS_VERSION_MIN_REQUIRED | |
585 | static uint32_t watchVersToIOSVers(uint32_t vers) | |
586 | { | |
587 | return vers + 0x00070000; | |
588 | } | |
589 | ||
590 | uint32_t dyld_get_program_sdk_watch_os_version() | |
591 | { | |
592 | const mach_header* mh = (mach_header*)_NSGetMachExecuteHeader(); | |
593 | uint32_t loadCommand; | |
594 | uint32_t minOS; | |
595 | uint32_t sdk; | |
596 | ||
597 | if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { | |
598 | if ( loadCommand == LC_VERSION_MIN_WATCHOS ) | |
599 | return sdk; | |
600 | } | |
601 | return 0; | |
602 | } | |
9f83892a A |
603 | |
604 | uint32_t dyld_get_program_min_watch_os_version() | |
605 | { | |
606 | const mach_header* mh = (mach_header*)_NSGetMachExecuteHeader(); | |
607 | uint32_t loadCommand; | |
608 | uint32_t minOS; | |
609 | uint32_t sdk; | |
610 | ||
611 | if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { | |
612 | if ( loadCommand == LC_VERSION_MIN_WATCHOS ) | |
613 | return minOS; // return raw minOS (not mapped to iOS version) | |
614 | } | |
615 | return 0; | |
616 | } | |
617 | ||
df9d6cf7 A |
618 | #endif |
619 | ||
620 | /* | |
621 | * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the | |
622 | * specified binary was built against. | |
623 | * | |
624 | * First looks for LC_VERSION_MIN_* in binary and if sdk field is | |
625 | * not zero, return that value. | |
626 | * Otherwise, looks for the libSystem.B.dylib the binary linked | |
627 | * against and uses a table to convert that to an sdk version. | |
628 | */ | |
629 | uint32_t dyld_get_sdk_version(const mach_header* mh) | |
630 | { | |
631 | uint32_t loadCommand; | |
632 | uint32_t minOS; | |
633 | uint32_t sdk; | |
634 | ||
635 | if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { | |
636 | switch (loadCommand) { | |
637 | #if __WATCH_OS_VERSION_MIN_REQUIRED | |
638 | case LC_VERSION_MIN_WATCHOS: | |
639 | // new binary. sdk version looks like "2.0" but API wants "9.0" | |
640 | return watchVersToIOSVers(sdk); | |
641 | case LC_VERSION_MIN_IPHONEOS: | |
642 | // old binary. sdk matches API semantics so can return directly. | |
643 | return sdk; | |
644 | #elif __TV_OS_VERSION_MIN_REQUIRED | |
645 | case LC_VERSION_MIN_TVOS: | |
646 | case LC_VERSION_MIN_IPHONEOS: | |
647 | return sdk; | |
648 | #elif __IPHONE_OS_VERSION_MIN_REQUIRED | |
649 | case LC_VERSION_MIN_IPHONEOS: | |
650 | if ( sdk != 0 ) // old binaries might not have SDK set | |
651 | return sdk; | |
652 | break; | |
653 | #else | |
654 | case LC_VERSION_MIN_MACOSX: | |
655 | if ( sdk != 0 ) // old binaries might not have SDK set | |
656 | return sdk; | |
657 | break; | |
658 | #endif | |
659 | } | |
660 | } | |
661 | ||
662 | #if __WATCH_OS_VERSION_MIN_REQUIRED ||__TV_OS_VERSION_MIN_REQUIRED | |
663 | // All WatchOS and tv OS binaries should have version load command. | |
832b6fce | 664 | return 0; |
df9d6cf7 A |
665 | #else |
666 | // MacOSX and iOS have old binaries without version load commmand. | |
667 | return deriveSDKVersFromDylibs(mh); | |
668 | #endif | |
832b6fce A |
669 | } |
670 | ||
671 | uint32_t dyld_get_program_sdk_version() | |
672 | { | |
673 | return dyld_get_sdk_version((mach_header*)_NSGetMachExecuteHeader()); | |
674 | } | |
675 | ||
832b6fce A |
676 | uint32_t dyld_get_min_os_version(const struct mach_header* mh) |
677 | { | |
df9d6cf7 A |
678 | uint32_t loadCommand; |
679 | uint32_t minOS; | |
680 | uint32_t sdk; | |
681 | ||
682 | if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { | |
683 | switch (loadCommand) { | |
684 | #if __WATCH_OS_VERSION_MIN_REQUIRED | |
685 | case LC_VERSION_MIN_WATCHOS: | |
686 | // new binary. OS version looks like "2.0" but API wants "9.0" | |
687 | return watchVersToIOSVers(minOS); | |
688 | case LC_VERSION_MIN_IPHONEOS: | |
689 | // old binary. OS matches API semantics so can return directly. | |
690 | return minOS; | |
691 | #elif __TV_OS_VERSION_MIN_REQUIRED | |
692 | case LC_VERSION_MIN_TVOS: | |
693 | case LC_VERSION_MIN_IPHONEOS: | |
694 | return minOS; | |
695 | #elif __IPHONE_OS_VERSION_MIN_REQUIRED | |
832b6fce | 696 | case LC_VERSION_MIN_IPHONEOS: |
df9d6cf7 | 697 | return minOS; |
2fd3f4e8 A |
698 | #else |
699 | case LC_VERSION_MIN_MACOSX: | |
df9d6cf7 | 700 | return minOS; |
2fd3f4e8 | 701 | #endif |
832b6fce | 702 | } |
832b6fce A |
703 | } |
704 | return 0; | |
705 | } | |
706 | ||
707 | ||
708 | uint32_t dyld_get_program_min_os_version() | |
709 | { | |
710 | return dyld_get_min_os_version((mach_header*)_NSGetMachExecuteHeader()); | |
711 | } | |
712 | ||
713 | ||
9f83892a A |
714 | bool _dyld_get_image_uuid(const struct mach_header* mh, uuid_t uuid) |
715 | { | |
716 | const load_command* startCmds = NULL; | |
717 | if ( mh->magic == MH_MAGIC_64 ) | |
718 | startCmds = (load_command*)((char *)mh + sizeof(mach_header_64)); | |
719 | else if ( mh->magic == MH_MAGIC ) | |
720 | startCmds = (load_command*)((char *)mh + sizeof(mach_header)); | |
721 | else | |
722 | return false; // not a mach-o file, or wrong endianness | |
723 | ||
724 | const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds); | |
725 | const load_command* cmd = startCmds; | |
726 | for(uint32_t i = 0; i < mh->ncmds; ++i) { | |
727 | const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize); | |
728 | if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) { | |
729 | return false; | |
730 | } | |
731 | if ( cmd->cmd == LC_UUID ) { | |
732 | const uuid_command* uuidCmd = (uuid_command*)cmd; | |
733 | memcpy(uuid, uuidCmd->uuid, 16); | |
734 | return true; | |
735 | } | |
736 | cmd = nextCmd; | |
737 | } | |
738 | bzero(uuid, 16); | |
739 | return false; | |
740 | } | |
741 | ||
742 | ||
743 | ||
39a8cd10 | 744 | #if DEPRECATED_APIS_SUPPORTED |
0959b6d4 A |
745 | /* |
746 | * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the | |
747 | * specified file name if the file is a correct Mach-O file that can be loaded | |
748 | * with NSloadModule(). For return codes of NSObjectFileImageFailure and | |
749 | * NSObjectFileImageFormat an error message is printed to stderr. All | |
750 | * other codes cause no printing. | |
751 | */ | |
752 | NSObjectFileImageReturnCode | |
753 | NSCreateObjectFileImageFromFile( | |
754 | const char* pathName, | |
755 | NSObjectFileImage *objectFileImage) | |
756 | { | |
bac542e6 | 757 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
758 | static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; |
759 | ||
760 | if(p == NULL) | |
761 | _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromFile", (void**)&p); | |
762 | return p(pathName, objectFileImage); | |
763 | } | |
764 | ||
765 | ||
766 | /* | |
767 | * NSCreateObjectFileImageFromMemory() creates an NSObjectFileImage for the | |
768 | * object file mapped into memory at address of size length if the object file | |
769 | * is a correct Mach-O file that can be loaded with NSloadModule(). For return | |
770 | * codes of NSObjectFileImageFailure and NSObjectFileImageFormat an error | |
771 | * message is printed to stderr. All other codes cause no printing. | |
772 | */ | |
773 | NSObjectFileImageReturnCode | |
774 | NSCreateObjectFileImageFromMemory( | |
775 | const void* address, | |
776 | size_t size, | |
777 | NSObjectFileImage *objectFileImage) | |
778 | { | |
bac542e6 | 779 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
780 | static NSObjectFileImageReturnCode (*p)(const void*, size_t, NSObjectFileImage*) = NULL; |
781 | ||
782 | if(p == NULL) | |
783 | _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromMemory", (void**)&p); | |
784 | return p(address, size, objectFileImage); | |
785 | } | |
786 | ||
bac542e6 | 787 | #if OBSOLETE_DYLD_API |
0959b6d4 A |
788 | /* |
789 | * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the | |
790 | * specified core file name if the file is a correct Mach-O core file. | |
791 | * For return codes of NSObjectFileImageFailure and NSObjectFileImageFormat | |
792 | * an error message is printed to stderr. All other codes cause no printing. | |
793 | */ | |
794 | NSObjectFileImageReturnCode | |
795 | NSCreateCoreFileImageFromFile( | |
796 | const char* pathName, | |
797 | NSObjectFileImage *objectFileImage) | |
798 | { | |
bac542e6 | 799 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
800 | static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; |
801 | ||
802 | if(p == NULL) | |
803 | _dyld_func_lookup("__dyld_NSCreateCoreFileImageFromFile", (void**)&p); | |
804 | return p(pathName, objectFileImage); | |
805 | } | |
bac542e6 | 806 | #endif |
0959b6d4 A |
807 | |
808 | bool | |
809 | NSDestroyObjectFileImage( | |
810 | NSObjectFileImage objectFileImage) | |
811 | { | |
bac542e6 | 812 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
813 | static bool (*p)(NSObjectFileImage) = NULL; |
814 | ||
815 | if(p == NULL) | |
816 | _dyld_func_lookup("__dyld_NSDestroyObjectFileImage", (void**)&p); | |
817 | return p(objectFileImage); | |
818 | } | |
819 | ||
820 | ||
821 | NSModule | |
822 | NSLinkModule( | |
823 | NSObjectFileImage objectFileImage, | |
824 | const char* moduleName, | |
825 | uint32_t options) | |
826 | { | |
bac542e6 | 827 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
828 | static NSModule (*p)(NSObjectFileImage, const char*, unsigned long) = NULL; |
829 | ||
830 | if(p == NULL) | |
831 | _dyld_func_lookup("__dyld_NSLinkModule", (void**)&p); | |
832 | ||
833 | return p(objectFileImage, moduleName, options); | |
834 | } | |
835 | ||
836 | ||
0959b6d4 A |
837 | |
838 | ||
839 | /* | |
840 | * NSSymbolDefinitionCountInObjectFileImage() returns the number of symbol | |
841 | * definitions in the NSObjectFileImage. | |
842 | */ | |
843 | uint32_t | |
844 | NSSymbolDefinitionCountInObjectFileImage( | |
845 | NSObjectFileImage objectFileImage) | |
846 | { | |
bac542e6 | 847 | DYLD_LOCK_THIS_BLOCK; |
9f83892a | 848 | static uint32_t (*p)(NSObjectFileImage) = NULL; |
0959b6d4 A |
849 | |
850 | if(p == NULL) | |
851 | _dyld_func_lookup("__dyld_NSSymbolDefinitionCountInObjectFileImage", (void**)&p); | |
852 | ||
853 | return p(objectFileImage); | |
854 | } | |
855 | ||
856 | /* | |
857 | * NSSymbolDefinitionNameInObjectFileImage() returns the name of the i'th | |
858 | * symbol definitions in the NSObjectFileImage. If the ordinal specified is | |
859 | * outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will | |
860 | * be returned. | |
861 | */ | |
862 | const char* | |
863 | NSSymbolDefinitionNameInObjectFileImage( | |
864 | NSObjectFileImage objectFileImage, | |
865 | uint32_t ordinal) | |
866 | { | |
bac542e6 | 867 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
868 | static const char* (*p)(NSObjectFileImage, uint32_t) = NULL; |
869 | ||
870 | if(p == NULL) | |
871 | _dyld_func_lookup("__dyld_NSSymbolDefinitionNameInObjectFileImage", (void**)&p); | |
872 | ||
873 | return p(objectFileImage, ordinal); | |
874 | } | |
875 | ||
876 | /* | |
877 | * NSSymbolReferenceCountInObjectFileImage() returns the number of references | |
878 | * to undefined symbols the NSObjectFileImage. | |
879 | */ | |
880 | uint32_t | |
881 | NSSymbolReferenceCountInObjectFileImage( | |
882 | NSObjectFileImage objectFileImage) | |
883 | { | |
bac542e6 | 884 | DYLD_LOCK_THIS_BLOCK; |
9f83892a | 885 | static uint32_t (*p)(NSObjectFileImage) = NULL; |
0959b6d4 A |
886 | |
887 | if(p == NULL) | |
888 | _dyld_func_lookup("__dyld_NSSymbolReferenceCountInObjectFileImage", (void**)&p); | |
889 | ||
890 | return p(objectFileImage); | |
891 | } | |
892 | ||
893 | /* | |
894 | * NSSymbolReferenceNameInObjectFileImage() returns the name of the i'th | |
895 | * undefined symbol in the NSObjectFileImage. If the ordinal specified is | |
896 | * outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be | |
897 | * returned. | |
898 | */ | |
899 | const char* | |
900 | NSSymbolReferenceNameInObjectFileImage( | |
901 | NSObjectFileImage objectFileImage, | |
902 | uint32_t ordinal, | |
903 | bool *tentative_definition) /* can be NULL */ | |
904 | { | |
bac542e6 | 905 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
906 | static const char* (*p)(NSObjectFileImage, uint32_t, bool*) = NULL; |
907 | ||
908 | if(p == NULL) | |
909 | _dyld_func_lookup("__dyld_NSSymbolReferenceNameInObjectFileImage", (void**)&p); | |
910 | ||
911 | return p(objectFileImage, ordinal, tentative_definition); | |
912 | } | |
913 | ||
914 | /* | |
915 | * NSIsSymbolDefinedInObjectFileImage() returns TRUE if the specified symbol | |
916 | * name has a definition in the NSObjectFileImage and FALSE otherwise. | |
917 | */ | |
918 | bool | |
919 | NSIsSymbolDefinedInObjectFileImage( | |
920 | NSObjectFileImage objectFileImage, | |
921 | const char* symbolName) | |
922 | { | |
bac542e6 | 923 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
924 | static bool (*p)(NSObjectFileImage, const char*) = NULL; |
925 | ||
926 | if(p == NULL) | |
927 | _dyld_func_lookup("__dyld_NSIsSymbolDefinedInObjectFileImage", (void**)&p); | |
928 | ||
929 | return p(objectFileImage, symbolName); | |
930 | } | |
931 | ||
932 | /* | |
933 | * NSGetSectionDataInObjectFileImage() returns a pointer to the section contents | |
934 | * in the NSObjectFileImage for the specified segmentName and sectionName if | |
935 | * it exists and it is not a zerofill section. If not it returns NULL. If | |
936 | * the parameter size is not NULL the size of the section is also returned | |
937 | * indirectly through that pointer. | |
938 | */ | |
939 | void * | |
940 | NSGetSectionDataInObjectFileImage( | |
941 | NSObjectFileImage objectFileImage, | |
942 | const char* segmentName, | |
943 | const char* sectionName, | |
944 | unsigned long *size) /* can be NULL */ | |
945 | { | |
bac542e6 | 946 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
947 | static void* (*p)(NSObjectFileImage, const char*, const char*, unsigned long*) = NULL; |
948 | ||
949 | if(p == NULL) | |
950 | _dyld_func_lookup("__dyld_NSGetSectionDataInObjectFileImage", (void**)&p); | |
951 | ||
952 | return p(objectFileImage, segmentName, sectionName, size); | |
953 | } | |
954 | ||
0959b6d4 A |
955 | |
956 | void | |
957 | NSLinkEditError( | |
958 | NSLinkEditErrors *c, | |
959 | int *errorNumber, | |
960 | const char* *fileName, | |
961 | const char* *errorString) | |
962 | { | |
bac542e6 | 963 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
964 | static void (*p)(NSLinkEditErrors *c, |
965 | int *errorNumber, | |
966 | const char* *fileName, | |
967 | const char* *errorString) = NULL; | |
968 | ||
969 | if(p == NULL) | |
970 | _dyld_func_lookup("__dyld_link_edit_error", (void**)&p); | |
971 | if(p != NULL) | |
972 | p(c, errorNumber, fileName, errorString); | |
973 | } | |
974 | ||
975 | bool | |
976 | NSUnLinkModule( | |
977 | NSModule module, | |
978 | uint32_t options) | |
979 | { | |
bac542e6 | 980 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
981 | static bool (*p)(NSModule module, uint32_t options) = NULL; |
982 | ||
983 | if(p == NULL) | |
984 | _dyld_func_lookup("__dyld_unlink_module", (void**)&p); | |
985 | ||
986 | return p(module, options); | |
987 | } | |
988 | ||
bac542e6 | 989 | #if OBSOLETE_DYLD_API |
0959b6d4 A |
990 | NSModule |
991 | NSReplaceModule( | |
992 | NSModule moduleToReplace, | |
993 | NSObjectFileImage newObjectFileImage, | |
994 | uint32_t options) | |
995 | { | |
996 | return(NULL); | |
997 | } | |
bac542e6 | 998 | #endif |
0959b6d4 | 999 | |
39a8cd10 A |
1000 | |
1001 | #endif // DEPRECATED_APIS_SUPPORTED | |
1002 | ||
0959b6d4 A |
1003 | /* |
1004 | *_NSGetExecutablePath copies the path of the executable into the buffer and | |
1005 | * returns 0 if the path was successfully copied in the provided buffer. If the | |
1006 | * buffer is not large enough, -1 is returned and the expected buffer size is | |
1007 | * copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to | |
1008 | * the executable not a "real path" to the executable. That is the path may be | |
1009 | * a symbolic link and not the real file. And with deep directories the total | |
1010 | * bufsize needed could be more than MAXPATHLEN. | |
1011 | */ | |
1012 | int | |
1013 | _NSGetExecutablePath( | |
1014 | char *buf, | |
1015 | uint32_t *bufsize) | |
1016 | { | |
9f83892a | 1017 | DYLD_NO_LOCK_THIS_BLOCK; |
0959b6d4 A |
1018 | static int (*p)(char *buf, uint32_t *bufsize) = NULL; |
1019 | ||
1020 | if(p == NULL) | |
1021 | _dyld_func_lookup("__dyld__NSGetExecutablePath", (void**)&p); | |
1022 | return(p(buf, bufsize)); | |
1023 | } | |
1024 | ||
39a8cd10 | 1025 | #if DEPRECATED_APIS_SUPPORTED |
0959b6d4 A |
1026 | void |
1027 | _dyld_lookup_and_bind( | |
1028 | const char* symbol_name, | |
1029 | void** address, | |
1030 | NSModule* module) | |
1031 | { | |
bac542e6 | 1032 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1033 | static void (*p)(const char*, void** , NSModule*) = NULL; |
1034 | ||
1035 | if(p == NULL) | |
1036 | _dyld_func_lookup("__dyld_lookup_and_bind", (void**)&p); | |
1037 | p(symbol_name, address, module); | |
1038 | } | |
1039 | ||
1040 | void | |
1041 | _dyld_lookup_and_bind_with_hint( | |
1042 | const char* symbol_name, | |
1043 | const char* library_name_hint, | |
1044 | void** address, | |
1045 | NSModule* module) | |
1046 | { | |
bac542e6 | 1047 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1048 | static void (*p)(const char*, const char*, void**, NSModule*) = NULL; |
1049 | ||
1050 | if(p == NULL) | |
1051 | _dyld_func_lookup("__dyld_lookup_and_bind_with_hint", (void**)&p); | |
1052 | p(symbol_name, library_name_hint, address, module); | |
1053 | } | |
1054 | ||
bac542e6 | 1055 | #if OBSOLETE_DYLD_API |
0959b6d4 A |
1056 | void |
1057 | _dyld_lookup_and_bind_objc( | |
1058 | const char* symbol_name, | |
1059 | void** address, | |
1060 | NSModule* module) | |
1061 | { | |
bac542e6 | 1062 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1063 | static void (*p)(const char* , void**, NSModule*) = NULL; |
1064 | ||
1065 | if(p == NULL) | |
1066 | _dyld_func_lookup("__dyld_lookup_and_bind_objc", (void**)&p); | |
1067 | p(symbol_name, address, module); | |
1068 | } | |
bac542e6 | 1069 | #endif |
0959b6d4 A |
1070 | |
1071 | void | |
1072 | _dyld_lookup_and_bind_fully( | |
1073 | const char* symbol_name, | |
1074 | void** address, | |
1075 | NSModule* module) | |
1076 | { | |
bac542e6 | 1077 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1078 | static void (*p)(const char*, void**, NSModule*) = NULL; |
1079 | ||
1080 | if(p == NULL) | |
1081 | _dyld_func_lookup("__dyld_lookup_and_bind_fully", (void**)&p); | |
1082 | p(symbol_name, address, module); | |
1083 | } | |
1084 | ||
1085 | bool | |
1086 | _dyld_bind_fully_image_containing_address( | |
1087 | const void* address) | |
1088 | { | |
bac542e6 | 1089 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1090 | static bool (*p)(const void*) = NULL; |
1091 | ||
1092 | if(p == NULL) | |
1093 | _dyld_func_lookup("__dyld_bind_fully_image_containing_address", (void**)&p); | |
1094 | return p(address); | |
1095 | } | |
39a8cd10 | 1096 | #endif // DEPRECATED_APIS_SUPPORTED |
0959b6d4 A |
1097 | |
1098 | ||
1099 | /* | |
1100 | * _dyld_register_func_for_add_image registers the specified function to be | |
1101 | * called when a new image is added (a bundle or a dynamic shared library) to | |
1102 | * the program. When this function is first registered it is called for once | |
1103 | * for each image that is currently part of the program. | |
1104 | */ | |
1105 | void | |
1106 | _dyld_register_func_for_add_image( | |
1107 | void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) | |
1108 | { | |
bac542e6 | 1109 | DYLD_LOCK_THIS_BLOCK; |
412ebb8e A |
1110 | typedef void (*callback_t)(const struct mach_header *mh, intptr_t vmaddr_slide); |
1111 | static void (*p)(callback_t func) = NULL; | |
0959b6d4 A |
1112 | |
1113 | if(p == NULL) | |
1114 | _dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p); | |
1115 | p(func); | |
1116 | } | |
1117 | ||
1118 | /* | |
1119 | * _dyld_register_func_for_remove_image registers the specified function to be | |
1120 | * called when an image is removed (a bundle or a dynamic shared library) from | |
1121 | * the program. | |
1122 | */ | |
1123 | void | |
1124 | _dyld_register_func_for_remove_image( | |
1125 | void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) | |
1126 | { | |
bac542e6 | 1127 | DYLD_LOCK_THIS_BLOCK; |
412ebb8e A |
1128 | typedef void (*callback_t)(const struct mach_header *mh, intptr_t vmaddr_slide); |
1129 | static void (*p)(callback_t func) = NULL; | |
0959b6d4 A |
1130 | |
1131 | if(p == NULL) | |
1132 | _dyld_func_lookup("__dyld_register_func_for_remove_image", (void**)&p); | |
1133 | p(func); | |
1134 | } | |
1135 | ||
bac542e6 | 1136 | #if OBSOLETE_DYLD_API |
0959b6d4 A |
1137 | /* |
1138 | * _dyld_register_func_for_link_module registers the specified function to be | |
1139 | * called when a module is bound into the program. When this function is first | |
1140 | * registered it is called for once for each module that is currently bound into | |
1141 | * the program. | |
1142 | */ | |
1143 | void | |
1144 | _dyld_register_func_for_link_module( | |
1145 | void (*func)(NSModule module)) | |
1146 | { | |
bac542e6 | 1147 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1148 | static void (*p)(void (*func)(NSModule module)) = NULL; |
1149 | ||
1150 | if(p == NULL) | |
1151 | _dyld_func_lookup("__dyld_register_func_for_link_module", (void**)&p); | |
1152 | p(func); | |
1153 | } | |
1154 | ||
1155 | /* | |
1156 | * _dyld_register_func_for_unlink_module registers the specified function to be | |
1157 | * called when a module is unbound from the program. | |
1158 | */ | |
1159 | void | |
1160 | _dyld_register_func_for_unlink_module( | |
1161 | void (*func)(NSModule module)) | |
1162 | { | |
bac542e6 | 1163 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1164 | static void (*p)(void (*func)(NSModule module)) = NULL; |
1165 | ||
1166 | if(p == NULL) | |
1167 | _dyld_func_lookup("__dyld_register_func_for_unlink_module", (void**)&p); | |
1168 | p(func); | |
1169 | } | |
1170 | ||
1171 | /* | |
1172 | * _dyld_register_func_for_replace_module registers the specified function to be | |
1173 | * called when a module is to be replace with another module in the program. | |
1174 | */ | |
1175 | void | |
1176 | _dyld_register_func_for_replace_module( | |
1177 | void (*func)(NSModule oldmodule, NSModule newmodule)) | |
1178 | { | |
bac542e6 | 1179 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1180 | static void (*p)(void (*func)(NSModule oldmodule, |
1181 | NSModule newmodule)) = NULL; | |
1182 | ||
1183 | if(p == NULL) | |
1184 | _dyld_func_lookup("__dyld_register_func_for_replace_module", (void**)&p); | |
1185 | p(func); | |
1186 | } | |
1187 | ||
1188 | ||
1189 | /* | |
1190 | * _dyld_get_objc_module_sect_for_module is passed a module and sets a | |
1191 | * pointer to the (__OBJC,__module) section and its size for the specified | |
1192 | * module. | |
1193 | */ | |
1194 | void | |
1195 | _dyld_get_objc_module_sect_for_module( | |
1196 | NSModule module, | |
1197 | void **objc_module, | |
1198 | unsigned long *size) | |
1199 | { | |
bac542e6 | 1200 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1201 | static void (*p)(NSModule module, |
1202 | void **objc_module, | |
1203 | unsigned long *size) = NULL; | |
1204 | ||
1205 | if(p == NULL) | |
1206 | _dyld_func_lookup("__dyld_get_objc_module_sect_for_module", (void**)&p); | |
1207 | p(module, objc_module, size); | |
1208 | } | |
1209 | ||
1210 | /* | |
1211 | * _dyld_bind_objc_module() is passed a pointer to something in an (__OBJC, | |
1212 | * __module) section and causes the module that is associated with that address | |
1213 | * to be bound. | |
1214 | */ | |
1215 | void | |
bac542e6 | 1216 | _dyld_bind_objc_module(const void* objc_module) |
0959b6d4 | 1217 | { |
bac542e6 | 1218 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1219 | static void (*p)(const void *objc_module) = NULL; |
1220 | ||
1221 | if(p == NULL) | |
1222 | _dyld_func_lookup("__dyld_bind_objc_module", (void**)&p); | |
1223 | p(objc_module); | |
1224 | } | |
bac542e6 | 1225 | #endif |
0959b6d4 | 1226 | |
39a8cd10 | 1227 | #if DEPRECATED_APIS_SUPPORTED |
0959b6d4 | 1228 | bool |
bac542e6 | 1229 | _dyld_present(void) |
0959b6d4 | 1230 | { |
bac542e6 | 1231 | // this function exists for compatiblity only |
0959b6d4 A |
1232 | return true; |
1233 | } | |
39a8cd10 | 1234 | #endif |
0959b6d4 A |
1235 | |
1236 | uint32_t | |
bac542e6 | 1237 | _dyld_image_count(void) |
0959b6d4 A |
1238 | { |
1239 | DYLD_NO_LOCK_THIS_BLOCK; | |
19894a12 | 1240 | static uint32_t (*p)(void) = NULL; |
0959b6d4 | 1241 | |
0959b6d4 A |
1242 | if(p == NULL) |
1243 | _dyld_func_lookup("__dyld_image_count", (void**)&p); | |
1244 | return(p()); | |
1245 | } | |
1246 | ||
1247 | const struct mach_header * | |
bac542e6 | 1248 | _dyld_get_image_header(uint32_t image_index) |
0959b6d4 A |
1249 | { |
1250 | DYLD_NO_LOCK_THIS_BLOCK; | |
1251 | static struct mach_header * (*p)(uint32_t image_index) = NULL; | |
1252 | ||
1253 | if(p == NULL) | |
1254 | _dyld_func_lookup("__dyld_get_image_header", (void**)&p); | |
1255 | return(p(image_index)); | |
1256 | } | |
1257 | ||
1258 | intptr_t | |
bac542e6 | 1259 | _dyld_get_image_vmaddr_slide(uint32_t image_index) |
0959b6d4 A |
1260 | { |
1261 | DYLD_NO_LOCK_THIS_BLOCK; | |
1262 | static unsigned long (*p)(uint32_t image_index) = NULL; | |
1263 | ||
1264 | if(p == NULL) | |
1265 | _dyld_func_lookup("__dyld_get_image_vmaddr_slide", (void**)&p); | |
1266 | return(p(image_index)); | |
1267 | } | |
1268 | ||
1269 | const char* | |
bac542e6 | 1270 | _dyld_get_image_name(uint32_t image_index) |
0959b6d4 A |
1271 | { |
1272 | DYLD_NO_LOCK_THIS_BLOCK; | |
1273 | static const char* (*p)(uint32_t image_index) = NULL; | |
1274 | ||
1275 | if(p == NULL) | |
1276 | _dyld_func_lookup("__dyld_get_image_name", (void**)&p); | |
1277 | return(p(image_index)); | |
1278 | } | |
1279 | ||
39a8cd10 A |
1280 | // SPI in Mac OS X 10.6 |
1281 | intptr_t _dyld_get_image_slide(const struct mach_header* mh) | |
1282 | { | |
1283 | DYLD_NO_LOCK_THIS_BLOCK; | |
1284 | static intptr_t (*p)(const struct mach_header*) = NULL; | |
1285 | ||
1286 | if(p == NULL) | |
1287 | _dyld_func_lookup("__dyld_get_image_slide", (void**)&p); | |
1288 | return(p(mh)); | |
1289 | } | |
1290 | ||
1291 | ||
0959b6d4 | 1292 | bool |
bac542e6 | 1293 | _dyld_image_containing_address(const void* address) |
0959b6d4 | 1294 | { |
bac542e6 | 1295 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1296 | static bool (*p)(const void*) = NULL; |
1297 | ||
1298 | if(p == NULL) | |
1299 | _dyld_func_lookup("__dyld_image_containing_address", (void**)&p); | |
1300 | return(p(address)); | |
1301 | } | |
1302 | ||
1303 | const struct mach_header * | |
1304 | _dyld_get_image_header_containing_address( | |
1305 | const void* address) | |
1306 | { | |
bac542e6 | 1307 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1308 | static const struct mach_header * (*p)(const void*) = NULL; |
1309 | ||
1310 | if(p == NULL) | |
1311 | _dyld_func_lookup("__dyld_get_image_header_containing_address", (void**)&p); | |
1312 | return p(address); | |
1313 | } | |
1314 | ||
0959b6d4 | 1315 | |
39a8cd10 | 1316 | #if DEPRECATED_APIS_SUPPORTED |
bac542e6 | 1317 | bool _dyld_launched_prebound(void) |
0959b6d4 | 1318 | { |
bac542e6 | 1319 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1320 | static bool (*p)(void) = NULL; |
1321 | ||
1322 | if(p == NULL) | |
1323 | _dyld_func_lookup("__dyld_launched_prebound", (void**)&p); | |
1324 | return(p()); | |
1325 | } | |
1326 | ||
bac542e6 | 1327 | bool _dyld_all_twolevel_modules_prebound(void) |
0959b6d4 | 1328 | { |
bac542e6 | 1329 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1330 | static bool (*p)(void) = NULL; |
1331 | ||
1332 | if(p == NULL) | |
1333 | _dyld_func_lookup("__dyld_all_twolevel_modules_prebound", (void**)&p); | |
1334 | return(p()); | |
1335 | } | |
39a8cd10 | 1336 | #endif // DEPRECATED_APIS_SUPPORTED |
0959b6d4 A |
1337 | |
1338 | ||
1339 | #include <dlfcn.h> | |
1340 | #include <stddef.h> | |
1341 | #include <pthread.h> | |
1342 | #include <stdlib.h> | |
1343 | #include <mach-o/dyld.h> | |
bac542e6 A |
1344 | #include <servers/bootstrap.h> |
1345 | #include "dyldLibSystemInterface.h" | |
bac542e6 | 1346 | |
0959b6d4 A |
1347 | |
1348 | // pthread key used to access per-thread dlerror message | |
1349 | static pthread_key_t dlerrorPerThreadKey; | |
bac542e6 | 1350 | static bool dlerrorPerThreadKeyInitialized = false; |
0959b6d4 A |
1351 | |
1352 | // data kept per-thread | |
1353 | struct dlerrorPerThreadData | |
1354 | { | |
19894a12 | 1355 | size_t sizeAllocated; |
0959b6d4 A |
1356 | char message[1]; |
1357 | }; | |
1358 | ||
1359 | // function called by dyld to get buffer to store dlerror message | |
19894a12 | 1360 | static char* getPerThreadBufferFor_dlerror(size_t sizeRequired) |
0959b6d4 | 1361 | { |
bac542e6 A |
1362 | // ok to create key lazily because this function is called within dyld lock, so there is no race condition |
1363 | if (!dlerrorPerThreadKeyInitialized ) { | |
1364 | // create key and tell pthread package to call free() on any data associated with key if thread dies | |
1365 | pthread_key_create(&dlerrorPerThreadKey, &free); | |
1366 | dlerrorPerThreadKeyInitialized = true; | |
1367 | } | |
1368 | ||
19894a12 | 1369 | const size_t size = (sizeRequired < 256) ? 256 : sizeRequired; |
0959b6d4 A |
1370 | dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey); |
1371 | if ( data == NULL ) { | |
1372 | //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); | |
19894a12 | 1373 | const size_t mallocSize = sizeof(dlerrorPerThreadData)+size; |
0959b6d4 A |
1374 | data = (dlerrorPerThreadData*)malloc(mallocSize); |
1375 | data->sizeAllocated = size; | |
1376 | pthread_setspecific(dlerrorPerThreadKey, data); | |
1377 | } | |
1378 | else if ( data->sizeAllocated < sizeRequired ) { | |
1379 | free(data); | |
1380 | //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); | |
19894a12 | 1381 | const size_t mallocSize = sizeof(dlerrorPerThreadData)+size; |
0959b6d4 A |
1382 | data = (dlerrorPerThreadData*)malloc(mallocSize); |
1383 | data->sizeAllocated = size; | |
1384 | pthread_setspecific(dlerrorPerThreadKey, data); | |
1385 | } | |
1386 | return data->message; | |
1387 | } | |
1388 | ||
2fd3f4e8 A |
1389 | // <rdar://problem/10595338> dlerror buffer leak |
1390 | // Only allocate buffer if an actual error message needs to be set | |
1391 | static bool hasPerThreadBufferFor_dlerror() | |
1392 | { | |
1393 | if (!dlerrorPerThreadKeyInitialized ) | |
1394 | return false; | |
1395 | ||
1396 | return (pthread_getspecific(dlerrorPerThreadKey) != NULL); | |
1397 | } | |
1398 | ||
1399 | // use non-lazy pointer to vproc_swap_integer so that lazy binding does not recurse | |
1400 | typedef vproc_err_t (*vswapproc)(vproc_t vp, vproc_gsk_t key,int64_t *inval, int64_t *outval); | |
1401 | static vswapproc swapProc = &vproc_swap_integer; | |
1402 | ||
9f83892a A |
1403 | static bool isLaunchdOwned() |
1404 | { | |
1405 | int64_t val = 0; | |
1406 | (*swapProc)(NULL, VPROC_GSK_IS_MANAGED, NULL, &val); | |
1407 | return ( val != 0 ); | |
2fd3f4e8 A |
1408 | } |
1409 | ||
39a8cd10 | 1410 | #if DYLD_SHARED_CACHE_SUPPORT |
bac542e6 A |
1411 | static void shared_cache_missing() |
1412 | { | |
39a8cd10 | 1413 | // leave until dyld's that might call this are rare |
bac542e6 A |
1414 | } |
1415 | ||
1416 | static void shared_cache_out_of_date() | |
1417 | { | |
39a8cd10 | 1418 | // leave until dyld's that might call this are rare |
bac542e6 | 1419 | } |
39a8cd10 | 1420 | #endif // DYLD_SHARED_CACHE_SUPPORT |
bac542e6 A |
1421 | |
1422 | ||
39a8cd10 | 1423 | // the table passed to dyld containing thread helpers |
19894a12 | 1424 | static dyld::LibSystemHelpers sHelpers = { 13, &dyldGlobalLockAcquire, &dyldGlobalLockRelease, |
bac542e6 | 1425 | &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit, |
39a8cd10 | 1426 | #if DYLD_SHARED_CACHE_SUPPORT |
bac542e6 | 1427 | &shared_cache_missing, &shared_cache_out_of_date, |
39a8cd10 A |
1428 | #else |
1429 | NULL, NULL, | |
1430 | #endif | |
1431 | NULL, NULL, | |
1432 | &pthread_key_create, &pthread_setspecific, | |
412ebb8e A |
1433 | &malloc_size, |
1434 | &pthread_getspecific, | |
832b6fce | 1435 | &__cxa_finalize, |
2fd3f4e8 A |
1436 | address_of_start, |
1437 | &hasPerThreadBufferFor_dlerror, | |
1438 | &isLaunchdOwned, | |
1439 | &vm_allocate, | |
19894a12 | 1440 | &mmap, |
9f83892a A |
1441 | &__cxa_finalize_ranges |
1442 | }; | |
bac542e6 | 1443 | |
0959b6d4 A |
1444 | |
1445 | // | |
1446 | // during initialization of libSystem this routine will run | |
bac542e6 | 1447 | // and call dyld, registering the helper functions. |
0959b6d4 | 1448 | // |
412ebb8e A |
1449 | extern "C" void tlv_initializer(); |
1450 | extern "C" void _dyld_initializer(); | |
bac542e6 | 1451 | void _dyld_initializer() |
2fd3f4e8 | 1452 | { |
bac542e6 A |
1453 | void (*p)(dyld::LibSystemHelpers*); |
1454 | ||
1455 | _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p); | |
0959b6d4 | 1456 | if(p != NULL) |
bac542e6 | 1457 | p(&sHelpers); |
412ebb8e A |
1458 | |
1459 | tlv_initializer(); | |
0959b6d4 A |
1460 | } |
1461 | ||
0959b6d4 A |
1462 | |
1463 | char* dlerror() | |
1464 | { | |
bac542e6 | 1465 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1466 | static char* (*p)() = NULL; |
1467 | ||
1468 | if(p == NULL) | |
1469 | _dyld_func_lookup("__dyld_dlerror", (void**)&p); | |
1470 | return(p()); | |
1471 | } | |
1472 | ||
1473 | int dladdr(const void* addr, Dl_info* info) | |
1474 | { | |
bac542e6 | 1475 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1476 | static int (*p)(const void* , Dl_info*) = NULL; |
1477 | ||
1478 | if(p == NULL) | |
1479 | _dyld_func_lookup("__dyld_dladdr", (void**)&p); | |
1480 | return(p(addr, info)); | |
1481 | } | |
1482 | ||
1483 | int dlclose(void* handle) | |
1484 | { | |
bac542e6 | 1485 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1486 | static int (*p)(void* handle) = NULL; |
1487 | ||
1488 | if(p == NULL) | |
1489 | _dyld_func_lookup("__dyld_dlclose", (void**)&p); | |
1490 | return(p(handle)); | |
1491 | } | |
1492 | ||
1493 | void* dlopen(const char* path, int mode) | |
bac542e6 A |
1494 | { |
1495 | // dlopen is special. locking is done inside dyld to allow initializer to run without lock | |
1496 | DYLD_NO_LOCK_THIS_BLOCK; | |
1497 | ||
0959b6d4 A |
1498 | static void* (*p)(const char* path, int) = NULL; |
1499 | ||
1500 | if(p == NULL) | |
1501 | _dyld_func_lookup("__dyld_dlopen", (void**)&p); | |
bac542e6 A |
1502 | void* result = p(path, mode); |
1503 | // use asm block to prevent tail call optimization | |
1504 | // this is needed because dlopen uses __builtin_return_address() and depends on this glue being in the frame chain | |
1505 | // <rdar://problem/5313172 dlopen() looks too far up stack, can cause crash> | |
1506 | __asm__ volatile(""); | |
1507 | ||
1508 | return result; | |
1509 | } | |
1510 | ||
1511 | bool dlopen_preflight(const char* path) | |
1512 | { | |
1513 | DYLD_LOCK_THIS_BLOCK; | |
1514 | static bool (*p)(const char* path) = NULL; | |
1515 | ||
1516 | if(p == NULL) | |
1517 | _dyld_func_lookup("__dyld_dlopen_preflight", (void**)&p); | |
1518 | return(p(path)); | |
0959b6d4 A |
1519 | } |
1520 | ||
1521 | void* dlsym(void* handle, const char* symbol) | |
1522 | { | |
bac542e6 | 1523 | DYLD_LOCK_THIS_BLOCK; |
0959b6d4 A |
1524 | static void* (*p)(void* handle, const char* symbol) = NULL; |
1525 | ||
1526 | if(p == NULL) | |
1527 | _dyld_func_lookup("__dyld_dlsym", (void**)&p); | |
1528 | return(p(handle, symbol)); | |
1529 | } | |
1530 | ||
1531 | ||
39a8cd10 A |
1532 | const struct dyld_all_image_infos* _dyld_get_all_image_infos() |
1533 | { | |
1534 | DYLD_NO_LOCK_THIS_BLOCK; | |
1535 | static struct dyld_all_image_infos* (*p)() = NULL; | |
1536 | ||
1537 | if(p == NULL) | |
1538 | _dyld_func_lookup("__dyld_get_all_image_infos", (void**)&p); | |
1539 | return p(); | |
1540 | } | |
1541 | ||
19894a12 | 1542 | #if SUPPORT_ZERO_COST_EXCEPTIONS |
39a8cd10 A |
1543 | bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) |
1544 | { | |
1545 | DYLD_NO_LOCK_THIS_BLOCK; | |
1546 | static void* (*p)(void*, dyld_unwind_sections*) = NULL; | |
1547 | ||
1548 | if(p == NULL) | |
1549 | _dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p); | |
1550 | return p(addr, info); | |
1551 | } | |
1552 | #endif | |
1553 | ||
1554 | ||
19894a12 | 1555 | #if __i386__ || __x86_64__ || __arm__ || __arm64__ |
39a8cd10 A |
1556 | __attribute__((visibility("hidden"))) |
1557 | void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo) | |
1558 | { | |
1559 | DYLD_NO_LOCK_THIS_BLOCK; | |
1560 | static void* (*p)(void*, long) = NULL; | |
1561 | ||
1562 | if(p == NULL) | |
1563 | _dyld_func_lookup("__dyld_fast_stub_entry", (void**)&p); | |
1564 | return p(loadercache, lazyinfo); | |
1565 | } | |
1566 | #endif | |
1567 | ||
1568 | ||
1569 | const char* dyld_image_path_containing_address(const void* addr) | |
1570 | { | |
1571 | DYLD_NO_LOCK_THIS_BLOCK; | |
1572 | static const char* (*p)(const void*) = NULL; | |
0959b6d4 | 1573 | |
39a8cd10 A |
1574 | if(p == NULL) |
1575 | _dyld_func_lookup("__dyld_image_path_containing_address", (void**)&p); | |
1576 | return p(addr); | |
1577 | } | |
0959b6d4 | 1578 | |
df9d6cf7 A |
1579 | const struct mach_header* dyld_image_header_containing_address(const void* addr) |
1580 | { | |
1581 | DYLD_NO_LOCK_THIS_BLOCK; | |
1582 | static const mach_header* (*p)(const void*) = NULL; | |
1583 | ||
1584 | if(p == NULL) | |
1585 | _dyld_func_lookup("__dyld_get_image_header_containing_address", (void**)&p); | |
1586 | return p(addr); | |
1587 | } | |
1588 | ||
1589 | ||
412ebb8e A |
1590 | bool dyld_shared_cache_some_image_overridden() |
1591 | { | |
1592 | DYLD_NO_LOCK_THIS_BLOCK; | |
1593 | static bool (*p)() = NULL; | |
1594 | ||
1595 | if(p == NULL) | |
1596 | _dyld_func_lookup("__dyld_shared_cache_some_image_overridden", (void**)&p); | |
1597 | return p(); | |
1598 | } | |
412ebb8e | 1599 | |
9f83892a A |
1600 | bool _dyld_get_shared_cache_uuid(uuid_t uuid) |
1601 | { | |
1602 | DYLD_NO_LOCK_THIS_BLOCK; | |
1603 | static bool (*p)(uuid_t) = NULL; | |
1604 | ||
1605 | if(p == NULL) | |
1606 | _dyld_func_lookup("__dyld_get_shared_cache_uuid", (void**)&p); | |
1607 | return p(uuid); | |
1608 | } | |
1609 | ||
412ebb8e | 1610 | |
2fd3f4e8 A |
1611 | bool dyld_process_is_restricted() |
1612 | { | |
1613 | DYLD_NO_LOCK_THIS_BLOCK; | |
1614 | static bool (*p)() = NULL; | |
1615 | ||
1616 | if(p == NULL) | |
1617 | _dyld_func_lookup("__dyld_process_is_restricted", (void**)&p); | |
1618 | return p(); | |
1619 | } | |
1620 | ||
df9d6cf7 A |
1621 | #if DYLD_SHARED_CACHE_SUPPORT |
1622 | const char* dyld_shared_cache_file_path() | |
1623 | { | |
1624 | DYLD_NO_LOCK_THIS_BLOCK; | |
1625 | static const char* (*p)() = NULL; | |
1626 | ||
1627 | if(p == NULL) | |
1628 | _dyld_func_lookup("__dyld_shared_cache_file_path", (void**)&p); | |
1629 | return p(); | |
1630 | } | |
1631 | #endif | |
2fd3f4e8 | 1632 | |
19894a12 A |
1633 | void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count) |
1634 | { | |
1635 | DYLD_LOCK_THIS_BLOCK; | |
1636 | static void (*p)(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count) = NULL; | |
1637 | ||
1638 | if (p == NULL) | |
1639 | _dyld_func_lookup("__dyld_dynamic_interpose", (void**)&p); | |
1640 | p(mh, array, count); | |
1641 | } | |
2fd3f4e8 A |
1642 | |
1643 | ||
412ebb8e A |
1644 | // SPI called __fork |
1645 | void _dyld_fork_child() | |
1646 | { | |
1647 | DYLD_NO_LOCK_THIS_BLOCK; | |
1648 | static void (*p)() = NULL; | |
1649 | ||
1650 | if(p == NULL) | |
1651 | _dyld_func_lookup("__dyld_fork_child", (void**)&p); | |
1652 | return p(); | |
1653 | } | |
1654 | ||
1655 | ||
1656 | ||
9f83892a A |
1657 | static void* mapStartOfCache(const char* path, size_t length) |
1658 | { | |
1659 | struct stat statbuf; | |
1660 | if ( ::stat(path, &statbuf) == -1 ) | |
1661 | return NULL; | |
1662 | ||
1663 | if ( statbuf.st_size < length ) | |
1664 | return NULL; | |
1665 | ||
1666 | int cache_fd = ::open(path, O_RDONLY); | |
1667 | if ( cache_fd < 0 ) | |
1668 | return NULL; | |
1669 | ||
1670 | void* result = ::mmap(NULL, length, PROT_READ, MAP_PRIVATE, cache_fd, 0); | |
1671 | close(cache_fd); | |
1672 | ||
1673 | if ( result == MAP_FAILED ) | |
1674 | return NULL; | |
1675 | ||
1676 | return result; | |
1677 | } | |
1678 | ||
1679 | ||
1680 | static const dyld_cache_header* findCacheInDirAndMap(const uuid_t cacheUuid, const char* dirPath) | |
1681 | { | |
1682 | DIR* dirp = ::opendir(dirPath); | |
1683 | if ( dirp != NULL) { | |
1684 | dirent entry; | |
1685 | dirent* entp = NULL; | |
1686 | char cachePath[PATH_MAX]; | |
1687 | while ( ::readdir_r(dirp, &entry, &entp) == 0 ) { | |
1688 | if ( entp == NULL ) | |
1689 | break; | |
1690 | if ( entp->d_type != DT_REG ) | |
1691 | continue; | |
1692 | if ( strlcpy(cachePath, dirPath, PATH_MAX) >= PATH_MAX ) | |
1693 | continue; | |
1694 | if ( strlcat(cachePath, "/", PATH_MAX) >= PATH_MAX ) | |
1695 | continue; | |
1696 | if ( strlcat(cachePath, entp->d_name, PATH_MAX) >= PATH_MAX ) | |
1697 | continue; | |
1698 | if ( const dyld_cache_header* cacheHeader = (dyld_cache_header*)mapStartOfCache(cachePath, 0x00100000) ) { | |
1699 | if ( ::memcmp(cacheHeader->uuid, cacheUuid, 16) != 0 ) { | |
1700 | // wrong uuid, unmap and keep looking | |
1701 | ::munmap((void*)cacheHeader, 0x00100000); | |
1702 | } | |
1703 | else { | |
1704 | // found cache | |
1705 | closedir(dirp); | |
1706 | return cacheHeader; | |
1707 | } | |
1708 | } | |
1709 | } | |
1710 | closedir(dirp); | |
1711 | } | |
1712 | return NULL; | |
1713 | } | |
1714 | ||
1715 | int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info)) | |
1716 | { | |
1717 | const dyld_cache_header* cacheHeader = NULL; | |
1718 | bool needToUnmap = true; | |
1719 | ||
1720 | // get info from dyld about this process, to see if requested cache is already mapped into this process | |
1721 | const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos(); | |
1722 | if ( (allInfo != NULL) && (memcmp(allInfo->sharedCacheUUID, cacheUuid, 16) == 0) ) { | |
1723 | // requested cache is already mapped, just re-use it | |
1724 | cacheHeader = (dyld_cache_header*)(SHARED_REGION_BASE + allInfo->sharedCacheSlide); | |
1725 | needToUnmap = false; | |
1726 | } | |
1727 | else { | |
1728 | // look first is default location for cache files | |
1729 | #if __IPHONE_OS_VERSION_MIN_REQUIRED | |
1730 | const char* defaultSearchDir = IPHONE_DYLD_SHARED_CACHE_DIR; | |
1731 | #else | |
1732 | const char* defaultSearchDir = MACOSX_DYLD_SHARED_CACHE_DIR; | |
1733 | #endif | |
1734 | cacheHeader = findCacheInDirAndMap(cacheUuid, defaultSearchDir); | |
1735 | // if not there, look in extra search locations | |
1736 | if ( cacheHeader == NULL ) { | |
1737 | for (const char** p = extraSearchDirs; *p != NULL; ++p) { | |
1738 | cacheHeader = findCacheInDirAndMap(cacheUuid, *p); | |
1739 | if ( cacheHeader != NULL ) | |
1740 | break; | |
1741 | } | |
1742 | } | |
1743 | } | |
1744 | ||
1745 | if ( cacheHeader == NULL ) | |
1746 | return -1; | |
1747 | ||
1748 | if ( cacheHeader->mappingOffset < sizeof(dyld_cache_header) ) { | |
1749 | // old cache without imagesText array | |
1750 | if ( needToUnmap ) | |
1751 | ::munmap((void*)cacheHeader, 0x00100000); | |
1752 | return -1; | |
1753 | } | |
1754 | ||
1755 | // walk imageText table and call callback for each entry | |
1756 | const dyld_cache_image_text_info* imagesText = (dyld_cache_image_text_info*)((char*)cacheHeader + cacheHeader->imagesTextOffset); | |
1757 | const dyld_cache_image_text_info* imagesTextEnd = &imagesText[cacheHeader->imagesTextCount]; | |
1758 | for (const dyld_cache_image_text_info* p=imagesText; p < imagesTextEnd; ++p) { | |
1759 | dyld_shared_cache_dylib_text_info dylibTextInfo; | |
1760 | dylibTextInfo.version = 1; | |
1761 | dylibTextInfo.loadAddressUnslid = p->loadAddress; | |
1762 | dylibTextInfo.textSegmentSize = p->textSegmentSize; | |
1763 | dylibTextInfo.path = (char*)cacheHeader + p->pathOffset; | |
1764 | ::memcpy(dylibTextInfo.dylibUuid, p->uuid, 16); | |
1765 | callback(&dylibTextInfo); | |
1766 | } | |
1767 | ||
1768 | if ( needToUnmap ) | |
1769 | ::munmap((void*)cacheHeader, 0x00100000); | |
1770 | ||
1771 | return 0; | |
1772 | } | |
1773 | ||
1774 | int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info)) | |
1775 | { | |
1776 | const char* extraSearchDirs[] = { NULL }; | |
1777 | return dyld_shared_cache_find_iterate_text(cacheUuid, extraSearchDirs, callback); | |
1778 | } | |
1779 | ||
1780 | ||
1781 | bool _dyld_is_memory_immutable(const void* addr, size_t length) | |
1782 | { | |
1783 | DYLD_NO_LOCK_THIS_BLOCK; | |
1784 | static bool (*p)(const void*, size_t) = NULL; | |
1785 | ||
1786 | if(p == NULL) | |
1787 | _dyld_func_lookup("__dyld_is_memory_immutable", (void**)&p); | |
1788 | return p(addr, length); | |
1789 | } | |
1790 | ||
1791 | ||
1792 | void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped, | |
1793 | _dyld_objc_notify_init init, | |
1794 | _dyld_objc_notify_unmapped unmapped) | |
1795 | { | |
1796 | DYLD_LOCK_THIS_BLOCK; | |
1797 | static bool (*p)(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped) = NULL; | |
1798 | ||
1799 | if(p == NULL) | |
1800 | _dyld_func_lookup("__dyld_objc_notify_register", (void**)&p); | |
1801 | p(mapped, init, unmapped); | |
1802 | } | |
1803 | ||
1804 | ||
1805 | ||
1806 | ||
0959b6d4 | 1807 |