]>
Commit | Line | Data |
---|---|---|
0959b6d4 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #include <stddef.h> | |
26 | #include <string.h> | |
27 | #include <crt_externs.h> | |
28 | ||
29 | #include "mach-o/dyld.h" | |
30 | #include "mach-o/dyld_priv.h" | |
31 | ||
32 | #include "dyldLock.h" | |
33 | ||
34 | /* | |
35 | * names_match() takes an install_name from an LC_LOAD_DYLIB command and a | |
36 | * libraryName (which is -lx or -framework Foo argument passed to the static | |
37 | * link editor for the same library) and determines if they match. This depends | |
38 | * on conventional use of names including major versioning. | |
39 | */ | |
40 | static | |
41 | bool | |
42 | names_match( | |
43 | char *install_name, | |
44 | const char* libraryName) | |
45 | { | |
46 | char *basename; | |
47 | unsigned long n; | |
48 | ||
49 | /* | |
50 | * Conventional install names have these forms: | |
51 | * /System/Library/Frameworks/AppKit.framework/Versions/A/Appkit | |
52 | * /Local/Library/Frameworks/AppKit.framework/Appkit | |
53 | * /lib/libsys_s.A.dylib | |
54 | * /usr/lib/libsys_s.dylib | |
55 | */ | |
56 | basename = strrchr(install_name, '/'); | |
57 | if(basename == NULL) | |
58 | basename = install_name; | |
59 | else | |
60 | basename++; | |
61 | ||
62 | /* | |
63 | * By checking the base name matching the library name we take care | |
64 | * of the -framework cases. | |
65 | */ | |
66 | if(strcmp(basename, libraryName) == 0) | |
67 | return(TRUE); | |
68 | ||
69 | /* | |
70 | * Now check the base name for "lib" if so proceed to check for the | |
71 | * -lx case dealing with a possible .X.dylib and a .dylib extension. | |
72 | */ | |
73 | if(strncmp(basename, "lib", 3) ==0){ | |
74 | n = strlen(libraryName); | |
75 | if(strncmp(basename+3, libraryName, n) == 0){ | |
76 | if(strncmp(basename+3+n, ".dylib", 6) == 0) | |
77 | return(TRUE); | |
78 | if(basename[3+n] == '.' && | |
79 | basename[3+n+1] != '\0' && | |
80 | strncmp(basename+3+n+2, ".dylib", 6) == 0) | |
81 | return(TRUE); | |
82 | } | |
83 | } | |
84 | return(FALSE); | |
85 | } | |
86 | ||
87 | void NSInstallLinkEditErrorHandlers( | |
88 | const NSLinkEditErrorHandlers* handlers) | |
89 | { | |
90 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
91 | static void (*p)( | |
92 | void (*undefined)(const char* symbol_name), | |
93 | NSModule (*multiple)(NSSymbol s, NSModule old, NSModule newhandler), | |
94 | void (*linkEdit)(NSLinkEditErrors c, int errorNumber, | |
95 | const char* fileName, const char* errorString)) = NULL; | |
96 | ||
97 | if(p == NULL) | |
98 | _dyld_func_lookup("__dyld_install_handlers", (void**)&p); | |
99 | p(handlers->undefined, handlers->multiple, handlers->linkEdit); | |
100 | } | |
101 | ||
102 | const char* | |
103 | NSNameOfModule( | |
104 | NSModule module) | |
105 | { | |
106 | DYLD_READER_LOCK_THIS_BLOCK; | |
107 | static const char* (*p)(NSModule module) = NULL; | |
108 | ||
109 | if(p == NULL) | |
110 | _dyld_func_lookup("__dyld_NSNameOfModule", (void**)&p); | |
111 | return(p(module)); | |
112 | } | |
113 | ||
114 | const char* | |
115 | NSLibraryNameForModule( | |
116 | NSModule module) | |
117 | { | |
118 | DYLD_READER_LOCK_THIS_BLOCK; | |
119 | static const char* (*p)(NSModule module) = NULL; | |
120 | ||
121 | if(p == NULL) | |
122 | _dyld_func_lookup("__dyld_NSLibraryNameForModule", (void**)&p); | |
123 | return(p(module)); | |
124 | } | |
125 | ||
126 | bool | |
127 | NSIsSymbolNameDefined( | |
128 | const char* symbolName) | |
129 | { | |
130 | DYLD_READER_LOCK_THIS_BLOCK; | |
131 | static bool (*p)(const char* symbolName) = NULL; | |
132 | ||
133 | if(p == NULL) | |
134 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefined", (void**)&p); | |
135 | return(p(symbolName)); | |
136 | } | |
137 | ||
138 | bool | |
139 | NSIsSymbolNameDefinedWithHint( | |
140 | const char* symbolName, | |
141 | const char* libraryNameHint) | |
142 | { | |
143 | DYLD_READER_LOCK_THIS_BLOCK; | |
144 | static bool (*p)(const char* symbolName, | |
145 | const char* libraryNameHint) = NULL; | |
146 | ||
147 | if(p == NULL) | |
148 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedWithHint", (void**)&p); | |
149 | return(p(symbolName, libraryNameHint)); | |
150 | } | |
151 | ||
152 | bool | |
153 | NSIsSymbolNameDefinedInImage( | |
154 | const struct mach_header *image, | |
155 | const char* symbolName) | |
156 | { | |
157 | DYLD_READER_LOCK_THIS_BLOCK; | |
158 | static bool (*p)(const struct mach_header *image, | |
159 | const char* symbolName) = NULL; | |
160 | ||
161 | if(p == NULL) | |
162 | _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", (void**)&p); | |
163 | return(p(image, symbolName)); | |
164 | } | |
165 | ||
166 | NSSymbol | |
167 | NSLookupAndBindSymbol( | |
168 | const char* symbolName) | |
169 | { | |
170 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
171 | static NSSymbol (*p)(const char* symbolName) = NULL; | |
172 | ||
173 | if(p == NULL) | |
174 | _dyld_func_lookup("__dyld_NSLookupAndBindSymbol", (void**)&p); | |
175 | return(p(symbolName)); | |
176 | } | |
177 | ||
178 | NSSymbol | |
179 | NSLookupAndBindSymbolWithHint( | |
180 | const char* symbolName, | |
181 | const char* libraryNameHint) | |
182 | { | |
183 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
184 | static NSSymbol (*p)(const char* symbolName, | |
185 | const char* libraryNameHint) = NULL; | |
186 | ||
187 | if(p == NULL) | |
188 | _dyld_func_lookup("__dyld_NSLookupAndBindSymbolWithHint", (void**)&p); | |
189 | return(p(symbolName, libraryNameHint)); | |
190 | } | |
191 | ||
192 | NSSymbol | |
193 | NSLookupSymbolInModule( | |
194 | NSModule module, | |
195 | const char* symbolName) | |
196 | { | |
197 | DYLD_READER_LOCK_THIS_BLOCK; | |
198 | static NSSymbol (*p)(NSModule module, const char* symbolName) = NULL; | |
199 | ||
200 | if(p == NULL) | |
201 | _dyld_func_lookup("__dyld_NSLookupSymbolInModule", (void**)&p); | |
202 | return(p(module, symbolName)); | |
203 | } | |
204 | ||
205 | NSSymbol | |
206 | NSLookupSymbolInImage( | |
207 | const struct mach_header *image, | |
208 | const char* symbolName, | |
209 | uint32_t options) | |
210 | { | |
211 | DYLD_READER_LOCK_THIS_BLOCK; | |
212 | static NSSymbol (*p)(const struct mach_header *image, | |
213 | const char* symbolName, | |
214 | uint32_t options) = NULL; | |
215 | ||
216 | if(p == NULL) | |
217 | _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void**)&p); | |
218 | return(p(image, symbolName, options)); | |
219 | } | |
220 | ||
221 | const char* | |
222 | NSNameOfSymbol( | |
223 | NSSymbol symbol) | |
224 | { | |
225 | DYLD_READER_LOCK_THIS_BLOCK; | |
226 | static char * (*p)(NSSymbol symbol) = NULL; | |
227 | ||
228 | if(p == NULL) | |
229 | _dyld_func_lookup("__dyld_NSNameOfSymbol",(void**)&p); | |
230 | return(p(symbol)); | |
231 | } | |
232 | ||
233 | void * | |
234 | NSAddressOfSymbol( | |
235 | NSSymbol symbol) | |
236 | { | |
237 | DYLD_READER_LOCK_THIS_BLOCK; | |
238 | static void * (*p)(NSSymbol symbol) = NULL; | |
239 | ||
240 | if(p == NULL) | |
241 | _dyld_func_lookup("__dyld_NSAddressOfSymbol", (void**)&p); | |
242 | return(p(symbol)); | |
243 | } | |
244 | ||
245 | NSModule | |
246 | NSModuleForSymbol( | |
247 | NSSymbol symbol) | |
248 | { | |
249 | DYLD_READER_LOCK_THIS_BLOCK; | |
250 | static NSModule (*p)(NSSymbol symbol) = NULL; | |
251 | ||
252 | if(p == NULL) | |
253 | _dyld_func_lookup("__dyld_NSModuleForSymbol", (void**)&p); | |
254 | return(p(symbol)); | |
255 | } | |
256 | ||
257 | bool | |
258 | NSAddLibrary( | |
259 | const char* pathName) | |
260 | { | |
261 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
262 | static bool (*p)(const char* pathName) = NULL; | |
263 | ||
264 | if(p == NULL) | |
265 | _dyld_func_lookup("__dyld_NSAddLibrary", (void**)&p); | |
266 | return(p(pathName)); | |
267 | } | |
268 | ||
269 | bool | |
270 | NSAddLibraryWithSearching( | |
271 | const char* pathName) | |
272 | { | |
273 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
274 | static bool (*p)(const char* pathName) = NULL; | |
275 | ||
276 | if(p == NULL) | |
277 | _dyld_func_lookup("__dyld_NSAddLibraryWithSearching", (void**)&p); | |
278 | return(p(pathName)); | |
279 | } | |
280 | ||
281 | const struct mach_header * | |
282 | NSAddImage( | |
283 | const char* image_name, | |
284 | uint32_t options) | |
285 | { | |
286 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
287 | static const struct mach_header * (*p)(const char* image_name, | |
288 | uint32_t options) = NULL; | |
289 | ||
290 | if(p == NULL) | |
291 | _dyld_func_lookup("__dyld_NSAddImage", (void**)&p); | |
292 | return(p(image_name, options)); | |
293 | } | |
294 | ||
295 | /* | |
296 | * This routine returns the current version of the named shared library the | |
297 | * executable it was built with. The libraryName parameter is the same as the | |
298 | * -lx or -framework Foo argument passed to the static link editor when building | |
299 | * the executable (with -lx it would be "x" and with -framework Foo it would be | |
300 | * "Foo"). If this the executable was not built against the specified library | |
301 | * it returns -1. It should be noted that if this only returns the value the | |
302 | * current version of the named shared library the executable was built with | |
303 | * and not a list of current versions that dependent libraries and bundles the | |
304 | * program is using were built with. | |
305 | */ | |
306 | int32_t | |
307 | NSVersionOfLinkTimeLibrary( | |
308 | const char* libraryName) | |
309 | { | |
310 | unsigned long i; | |
311 | struct load_command *load_commands, *lc; | |
312 | struct dylib_command *dl; | |
313 | char *install_name; | |
314 | #ifndef __OPENSTEP__ | |
315 | static struct mach_header *mh = NULL; | |
316 | if(mh == NULL) | |
317 | mh = _NSGetMachExecuteHeader(); | |
318 | #else /* defined(__OPENSTEP__) */ | |
319 | #ifdef __DYNAMIC__ | |
320 | static struct mach_header *mh = NULL; | |
321 | if(mh == NULL) | |
322 | _dyld_lookup_and_bind("__mh_execute_header", &mh, NULL); | |
323 | #else | |
324 | struct mach_header *mh; | |
325 | mh = (struct mach_header *)&_mh_execute_header; | |
326 | #endif | |
327 | #endif /* __OPENSTEP__ */ | |
328 | load_commands = (struct load_command *) | |
329 | ((char *)mh + sizeof(struct mach_header)); | |
330 | lc = load_commands; | |
331 | for(i = 0; i < mh->ncmds; i++){ | |
332 | if(lc->cmd == LC_LOAD_DYLIB){ | |
333 | dl = (struct dylib_command *)lc; | |
334 | install_name = (char *)dl + dl->dylib.name.offset; | |
335 | if(names_match(install_name, libraryName) == TRUE) | |
336 | return(dl->dylib.current_version); | |
337 | } | |
338 | lc = (struct load_command *)((char *)lc + lc->cmdsize); | |
339 | } | |
340 | return(-1); | |
341 | } | |
342 | ||
343 | /* | |
344 | * This routine returns the current version of the named shared library the | |
345 | * program it is running against. The libraryName parameter is the same as | |
346 | * would be static link editor using the -lx or -framework Foo flags (with -lx | |
347 | * it would be "x" and with -framework Foo it would be "Foo"). If the program | |
348 | * is not using the specified library it returns -1. | |
349 | */ | |
350 | int32_t | |
351 | NSVersionOfRunTimeLibrary( | |
352 | const char* libraryName) | |
353 | { | |
354 | unsigned long i, j, n; | |
355 | char *install_name; | |
356 | struct load_command *load_commands, *lc; | |
357 | struct dylib_command *dl; | |
358 | const struct mach_header *mh; | |
359 | ||
360 | n = _dyld_image_count(); | |
361 | for(i = 0; i < n; i++){ | |
362 | mh = _dyld_get_image_header(i); | |
363 | if(mh->filetype != MH_DYLIB) | |
364 | continue; | |
365 | load_commands = (struct load_command *) | |
366 | ((char *)mh + sizeof(struct mach_header)); | |
367 | lc = load_commands; | |
368 | for(j = 0; j < mh->ncmds; j++){ | |
369 | if(lc->cmd == LC_ID_DYLIB){ | |
370 | dl = (struct dylib_command *)lc; | |
371 | install_name = (char *)dl + dl->dylib.name.offset; | |
372 | if(names_match(install_name, libraryName) == TRUE) | |
373 | return(dl->dylib.current_version); | |
374 | } | |
375 | lc = (struct load_command *)((char *)lc + lc->cmdsize); | |
376 | } | |
377 | } | |
378 | return(-1); | |
379 | } | |
380 | ||
381 | /* | |
382 | * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the | |
383 | * specified file name if the file is a correct Mach-O file that can be loaded | |
384 | * with NSloadModule(). For return codes of NSObjectFileImageFailure and | |
385 | * NSObjectFileImageFormat an error message is printed to stderr. All | |
386 | * other codes cause no printing. | |
387 | */ | |
388 | NSObjectFileImageReturnCode | |
389 | NSCreateObjectFileImageFromFile( | |
390 | const char* pathName, | |
391 | NSObjectFileImage *objectFileImage) | |
392 | { | |
393 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
394 | static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; | |
395 | ||
396 | if(p == NULL) | |
397 | _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromFile", (void**)&p); | |
398 | return p(pathName, objectFileImage); | |
399 | } | |
400 | ||
401 | ||
402 | /* | |
403 | * NSCreateObjectFileImageFromMemory() creates an NSObjectFileImage for the | |
404 | * object file mapped into memory at address of size length if the object file | |
405 | * is a correct Mach-O file that can be loaded with NSloadModule(). For return | |
406 | * codes of NSObjectFileImageFailure and NSObjectFileImageFormat an error | |
407 | * message is printed to stderr. All other codes cause no printing. | |
408 | */ | |
409 | NSObjectFileImageReturnCode | |
410 | NSCreateObjectFileImageFromMemory( | |
411 | const void* address, | |
412 | size_t size, | |
413 | NSObjectFileImage *objectFileImage) | |
414 | { | |
415 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
416 | static NSObjectFileImageReturnCode (*p)(const void*, size_t, NSObjectFileImage*) = NULL; | |
417 | ||
418 | if(p == NULL) | |
419 | _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromMemory", (void**)&p); | |
420 | return p(address, size, objectFileImage); | |
421 | } | |
422 | ||
423 | /* | |
424 | * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the | |
425 | * specified core file name if the file is a correct Mach-O core file. | |
426 | * For return codes of NSObjectFileImageFailure and NSObjectFileImageFormat | |
427 | * an error message is printed to stderr. All other codes cause no printing. | |
428 | */ | |
429 | NSObjectFileImageReturnCode | |
430 | NSCreateCoreFileImageFromFile( | |
431 | const char* pathName, | |
432 | NSObjectFileImage *objectFileImage) | |
433 | { | |
434 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
435 | static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; | |
436 | ||
437 | if(p == NULL) | |
438 | _dyld_func_lookup("__dyld_NSCreateCoreFileImageFromFile", (void**)&p); | |
439 | return p(pathName, objectFileImage); | |
440 | } | |
441 | ||
442 | bool | |
443 | NSDestroyObjectFileImage( | |
444 | NSObjectFileImage objectFileImage) | |
445 | { | |
446 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
447 | static bool (*p)(NSObjectFileImage) = NULL; | |
448 | ||
449 | if(p == NULL) | |
450 | _dyld_func_lookup("__dyld_NSDestroyObjectFileImage", (void**)&p); | |
451 | return p(objectFileImage); | |
452 | } | |
453 | ||
454 | ||
455 | NSModule | |
456 | NSLinkModule( | |
457 | NSObjectFileImage objectFileImage, | |
458 | const char* moduleName, | |
459 | uint32_t options) | |
460 | { | |
461 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
462 | static NSModule (*p)(NSObjectFileImage, const char*, unsigned long) = NULL; | |
463 | ||
464 | if(p == NULL) | |
465 | _dyld_func_lookup("__dyld_NSLinkModule", (void**)&p); | |
466 | ||
467 | return p(objectFileImage, moduleName, options); | |
468 | } | |
469 | ||
470 | ||
471 | /* | |
472 | * NSFindSectionAndOffsetInObjectFileImage() takes the specified imageOffset | |
473 | * into the specified ObjectFileImage and returns the segment/section name and | |
474 | * offset into that section of that imageOffset. Returns FALSE if the | |
475 | * imageOffset is not in any section. You can used the resulting sectionOffset | |
476 | * to index into the data returned by NSGetSectionDataInObjectFileImage. | |
477 | * | |
478 | * SPI: currently only used by ZeroLink to detect +load methods | |
479 | */ | |
480 | bool | |
481 | NSFindSectionAndOffsetInObjectFileImage( | |
482 | NSObjectFileImage objectFileImage, | |
483 | unsigned long imageOffset, | |
484 | const char** segmentName, /* can be NULL */ | |
485 | const char** sectionName, /* can be NULL */ | |
486 | unsigned long* sectionOffset) /* can be NULL */ | |
487 | { | |
488 | DYLD_READER_LOCK_THIS_BLOCK; | |
489 | static bool (*p)(NSObjectFileImage, unsigned long, const char**, const char**, unsigned long*) = NULL; | |
490 | ||
491 | if(p == NULL) | |
492 | _dyld_func_lookup("__dyld_NSFindSectionAndOffsetInObjectFileImage", (void**)&p); | |
493 | ||
494 | return p(objectFileImage, imageOffset, segmentName, sectionName, sectionOffset); | |
495 | } | |
496 | ||
497 | ||
498 | /* | |
499 | * NSSymbolDefinitionCountInObjectFileImage() returns the number of symbol | |
500 | * definitions in the NSObjectFileImage. | |
501 | */ | |
502 | uint32_t | |
503 | NSSymbolDefinitionCountInObjectFileImage( | |
504 | NSObjectFileImage objectFileImage) | |
505 | { | |
506 | DYLD_READER_LOCK_THIS_BLOCK; | |
507 | static unsigned long (*p)(NSObjectFileImage) = NULL; | |
508 | ||
509 | if(p == NULL) | |
510 | _dyld_func_lookup("__dyld_NSSymbolDefinitionCountInObjectFileImage", (void**)&p); | |
511 | ||
512 | return p(objectFileImage); | |
513 | } | |
514 | ||
515 | /* | |
516 | * NSSymbolDefinitionNameInObjectFileImage() returns the name of the i'th | |
517 | * symbol definitions in the NSObjectFileImage. If the ordinal specified is | |
518 | * outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will | |
519 | * be returned. | |
520 | */ | |
521 | const char* | |
522 | NSSymbolDefinitionNameInObjectFileImage( | |
523 | NSObjectFileImage objectFileImage, | |
524 | uint32_t ordinal) | |
525 | { | |
526 | DYLD_READER_LOCK_THIS_BLOCK; | |
527 | static const char* (*p)(NSObjectFileImage, uint32_t) = NULL; | |
528 | ||
529 | if(p == NULL) | |
530 | _dyld_func_lookup("__dyld_NSSymbolDefinitionNameInObjectFileImage", (void**)&p); | |
531 | ||
532 | return p(objectFileImage, ordinal); | |
533 | } | |
534 | ||
535 | /* | |
536 | * NSSymbolReferenceCountInObjectFileImage() returns the number of references | |
537 | * to undefined symbols the NSObjectFileImage. | |
538 | */ | |
539 | uint32_t | |
540 | NSSymbolReferenceCountInObjectFileImage( | |
541 | NSObjectFileImage objectFileImage) | |
542 | { | |
543 | DYLD_READER_LOCK_THIS_BLOCK; | |
544 | static unsigned long (*p)(NSObjectFileImage) = NULL; | |
545 | ||
546 | if(p == NULL) | |
547 | _dyld_func_lookup("__dyld_NSSymbolReferenceCountInObjectFileImage", (void**)&p); | |
548 | ||
549 | return p(objectFileImage); | |
550 | } | |
551 | ||
552 | /* | |
553 | * NSSymbolReferenceNameInObjectFileImage() returns the name of the i'th | |
554 | * undefined symbol in the NSObjectFileImage. If the ordinal specified is | |
555 | * outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be | |
556 | * returned. | |
557 | */ | |
558 | const char* | |
559 | NSSymbolReferenceNameInObjectFileImage( | |
560 | NSObjectFileImage objectFileImage, | |
561 | uint32_t ordinal, | |
562 | bool *tentative_definition) /* can be NULL */ | |
563 | { | |
564 | DYLD_READER_LOCK_THIS_BLOCK; | |
565 | static const char* (*p)(NSObjectFileImage, uint32_t, bool*) = NULL; | |
566 | ||
567 | if(p == NULL) | |
568 | _dyld_func_lookup("__dyld_NSSymbolReferenceNameInObjectFileImage", (void**)&p); | |
569 | ||
570 | return p(objectFileImage, ordinal, tentative_definition); | |
571 | } | |
572 | ||
573 | /* | |
574 | * NSIsSymbolDefinedInObjectFileImage() returns TRUE if the specified symbol | |
575 | * name has a definition in the NSObjectFileImage and FALSE otherwise. | |
576 | */ | |
577 | bool | |
578 | NSIsSymbolDefinedInObjectFileImage( | |
579 | NSObjectFileImage objectFileImage, | |
580 | const char* symbolName) | |
581 | { | |
582 | DYLD_READER_LOCK_THIS_BLOCK; | |
583 | static bool (*p)(NSObjectFileImage, const char*) = NULL; | |
584 | ||
585 | if(p == NULL) | |
586 | _dyld_func_lookup("__dyld_NSIsSymbolDefinedInObjectFileImage", (void**)&p); | |
587 | ||
588 | return p(objectFileImage, symbolName); | |
589 | } | |
590 | ||
591 | /* | |
592 | * NSGetSectionDataInObjectFileImage() returns a pointer to the section contents | |
593 | * in the NSObjectFileImage for the specified segmentName and sectionName if | |
594 | * it exists and it is not a zerofill section. If not it returns NULL. If | |
595 | * the parameter size is not NULL the size of the section is also returned | |
596 | * indirectly through that pointer. | |
597 | */ | |
598 | void * | |
599 | NSGetSectionDataInObjectFileImage( | |
600 | NSObjectFileImage objectFileImage, | |
601 | const char* segmentName, | |
602 | const char* sectionName, | |
603 | unsigned long *size) /* can be NULL */ | |
604 | { | |
605 | DYLD_READER_LOCK_THIS_BLOCK; | |
606 | static void* (*p)(NSObjectFileImage, const char*, const char*, unsigned long*) = NULL; | |
607 | ||
608 | if(p == NULL) | |
609 | _dyld_func_lookup("__dyld_NSGetSectionDataInObjectFileImage", (void**)&p); | |
610 | ||
611 | return p(objectFileImage, segmentName, sectionName, size); | |
612 | } | |
613 | ||
614 | /* | |
615 | * NSHasModInitObjectFileImage() returns TRUE if the NSObjectFileImage has any | |
616 | * module initialization sections and FALSE it it does not. | |
617 | * | |
618 | * SPI: currently only used by ZeroLink to detect C++ initializers | |
619 | */ | |
620 | bool | |
621 | NSHasModInitObjectFileImage( | |
622 | NSObjectFileImage objectFileImage) | |
623 | { | |
624 | DYLD_READER_LOCK_THIS_BLOCK; | |
625 | static bool (*p)(NSObjectFileImage) = NULL; | |
626 | ||
627 | if(p == NULL) | |
628 | _dyld_func_lookup("__dyld_NSHasModInitObjectFileImage", (void**)&p); | |
629 | ||
630 | return p(objectFileImage); | |
631 | } | |
632 | ||
633 | void | |
634 | NSLinkEditError( | |
635 | NSLinkEditErrors *c, | |
636 | int *errorNumber, | |
637 | const char* *fileName, | |
638 | const char* *errorString) | |
639 | { | |
640 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
641 | static void (*p)(NSLinkEditErrors *c, | |
642 | int *errorNumber, | |
643 | const char* *fileName, | |
644 | const char* *errorString) = NULL; | |
645 | ||
646 | if(p == NULL) | |
647 | _dyld_func_lookup("__dyld_link_edit_error", (void**)&p); | |
648 | if(p != NULL) | |
649 | p(c, errorNumber, fileName, errorString); | |
650 | } | |
651 | ||
652 | bool | |
653 | NSUnLinkModule( | |
654 | NSModule module, | |
655 | uint32_t options) | |
656 | { | |
657 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
658 | static bool (*p)(NSModule module, uint32_t options) = NULL; | |
659 | ||
660 | if(p == NULL) | |
661 | _dyld_func_lookup("__dyld_unlink_module", (void**)&p); | |
662 | ||
663 | return p(module, options); | |
664 | } | |
665 | ||
666 | NSModule | |
667 | NSReplaceModule( | |
668 | NSModule moduleToReplace, | |
669 | NSObjectFileImage newObjectFileImage, | |
670 | uint32_t options) | |
671 | { | |
672 | return(NULL); | |
673 | } | |
674 | ||
675 | /* | |
676 | *_NSGetExecutablePath copies the path of the executable into the buffer and | |
677 | * returns 0 if the path was successfully copied in the provided buffer. If the | |
678 | * buffer is not large enough, -1 is returned and the expected buffer size is | |
679 | * copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to | |
680 | * the executable not a "real path" to the executable. That is the path may be | |
681 | * a symbolic link and not the real file. And with deep directories the total | |
682 | * bufsize needed could be more than MAXPATHLEN. | |
683 | */ | |
684 | int | |
685 | _NSGetExecutablePath( | |
686 | char *buf, | |
687 | uint32_t *bufsize) | |
688 | { | |
689 | DYLD_READER_LOCK_THIS_BLOCK; | |
690 | static int (*p)(char *buf, uint32_t *bufsize) = NULL; | |
691 | ||
692 | if(p == NULL) | |
693 | _dyld_func_lookup("__dyld__NSGetExecutablePath", (void**)&p); | |
694 | return(p(buf, bufsize)); | |
695 | } | |
696 | ||
697 | void | |
698 | _dyld_lookup_and_bind( | |
699 | const char* symbol_name, | |
700 | void** address, | |
701 | NSModule* module) | |
702 | { | |
703 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
704 | static void (*p)(const char*, void** , NSModule*) = NULL; | |
705 | ||
706 | if(p == NULL) | |
707 | _dyld_func_lookup("__dyld_lookup_and_bind", (void**)&p); | |
708 | p(symbol_name, address, module); | |
709 | } | |
710 | ||
711 | void | |
712 | _dyld_lookup_and_bind_with_hint( | |
713 | const char* symbol_name, | |
714 | const char* library_name_hint, | |
715 | void** address, | |
716 | NSModule* module) | |
717 | { | |
718 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
719 | static void (*p)(const char*, const char*, void**, NSModule*) = NULL; | |
720 | ||
721 | if(p == NULL) | |
722 | _dyld_func_lookup("__dyld_lookup_and_bind_with_hint", (void**)&p); | |
723 | p(symbol_name, library_name_hint, address, module); | |
724 | } | |
725 | ||
726 | void | |
727 | _dyld_lookup_and_bind_objc( | |
728 | const char* symbol_name, | |
729 | void** address, | |
730 | NSModule* module) | |
731 | { | |
732 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
733 | static void (*p)(const char* , void**, NSModule*) = NULL; | |
734 | ||
735 | if(p == NULL) | |
736 | _dyld_func_lookup("__dyld_lookup_and_bind_objc", (void**)&p); | |
737 | p(symbol_name, address, module); | |
738 | } | |
739 | ||
740 | void | |
741 | _dyld_lookup_and_bind_fully( | |
742 | const char* symbol_name, | |
743 | void** address, | |
744 | NSModule* module) | |
745 | { | |
746 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
747 | static void (*p)(const char*, void**, NSModule*) = NULL; | |
748 | ||
749 | if(p == NULL) | |
750 | _dyld_func_lookup("__dyld_lookup_and_bind_fully", (void**)&p); | |
751 | p(symbol_name, address, module); | |
752 | } | |
753 | ||
754 | bool | |
755 | _dyld_bind_fully_image_containing_address( | |
756 | const void* address) | |
757 | { | |
758 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
759 | static bool (*p)(const void*) = NULL; | |
760 | ||
761 | if(p == NULL) | |
762 | _dyld_func_lookup("__dyld_bind_fully_image_containing_address", (void**)&p); | |
763 | return p(address); | |
764 | } | |
765 | ||
766 | ||
767 | /* | |
768 | * _dyld_register_func_for_add_image registers the specified function to be | |
769 | * called when a new image is added (a bundle or a dynamic shared library) to | |
770 | * the program. When this function is first registered it is called for once | |
771 | * for each image that is currently part of the program. | |
772 | */ | |
773 | void | |
774 | _dyld_register_func_for_add_image( | |
775 | void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) | |
776 | { | |
777 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
778 | static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL; | |
779 | ||
780 | if(p == NULL) | |
781 | _dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p); | |
782 | p(func); | |
783 | } | |
784 | ||
785 | /* | |
786 | * _dyld_register_func_for_remove_image registers the specified function to be | |
787 | * called when an image is removed (a bundle or a dynamic shared library) from | |
788 | * the program. | |
789 | */ | |
790 | void | |
791 | _dyld_register_func_for_remove_image( | |
792 | void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) | |
793 | { | |
794 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
795 | static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL; | |
796 | ||
797 | if(p == NULL) | |
798 | _dyld_func_lookup("__dyld_register_func_for_remove_image", (void**)&p); | |
799 | p(func); | |
800 | } | |
801 | ||
802 | /* | |
803 | * _dyld_register_func_for_link_module registers the specified function to be | |
804 | * called when a module is bound into the program. When this function is first | |
805 | * registered it is called for once for each module that is currently bound into | |
806 | * the program. | |
807 | */ | |
808 | void | |
809 | _dyld_register_func_for_link_module( | |
810 | void (*func)(NSModule module)) | |
811 | { | |
812 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
813 | static void (*p)(void (*func)(NSModule module)) = NULL; | |
814 | ||
815 | if(p == NULL) | |
816 | _dyld_func_lookup("__dyld_register_func_for_link_module", (void**)&p); | |
817 | p(func); | |
818 | } | |
819 | ||
820 | /* | |
821 | * _dyld_register_func_for_unlink_module registers the specified function to be | |
822 | * called when a module is unbound from the program. | |
823 | */ | |
824 | void | |
825 | _dyld_register_func_for_unlink_module( | |
826 | void (*func)(NSModule module)) | |
827 | { | |
828 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
829 | static void (*p)(void (*func)(NSModule module)) = NULL; | |
830 | ||
831 | if(p == NULL) | |
832 | _dyld_func_lookup("__dyld_register_func_for_unlink_module", (void**)&p); | |
833 | p(func); | |
834 | } | |
835 | ||
836 | /* | |
837 | * _dyld_register_func_for_replace_module registers the specified function to be | |
838 | * called when a module is to be replace with another module in the program. | |
839 | */ | |
840 | void | |
841 | _dyld_register_func_for_replace_module( | |
842 | void (*func)(NSModule oldmodule, NSModule newmodule)) | |
843 | { | |
844 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
845 | static void (*p)(void (*func)(NSModule oldmodule, | |
846 | NSModule newmodule)) = NULL; | |
847 | ||
848 | if(p == NULL) | |
849 | _dyld_func_lookup("__dyld_register_func_for_replace_module", (void**)&p); | |
850 | p(func); | |
851 | } | |
852 | ||
853 | ||
854 | /* | |
855 | * _dyld_get_objc_module_sect_for_module is passed a module and sets a | |
856 | * pointer to the (__OBJC,__module) section and its size for the specified | |
857 | * module. | |
858 | */ | |
859 | void | |
860 | _dyld_get_objc_module_sect_for_module( | |
861 | NSModule module, | |
862 | void **objc_module, | |
863 | unsigned long *size) | |
864 | { | |
865 | DYLD_READER_LOCK_THIS_BLOCK; | |
866 | static void (*p)(NSModule module, | |
867 | void **objc_module, | |
868 | unsigned long *size) = NULL; | |
869 | ||
870 | if(p == NULL) | |
871 | _dyld_func_lookup("__dyld_get_objc_module_sect_for_module", (void**)&p); | |
872 | p(module, objc_module, size); | |
873 | } | |
874 | ||
875 | /* | |
876 | * _dyld_bind_objc_module() is passed a pointer to something in an (__OBJC, | |
877 | * __module) section and causes the module that is associated with that address | |
878 | * to be bound. | |
879 | */ | |
880 | void | |
881 | _dyld_bind_objc_module( | |
882 | const void* objc_module) | |
883 | { | |
884 | DYLD_READER_LOCK_THIS_BLOCK; | |
885 | static void (*p)(const void *objc_module) = NULL; | |
886 | ||
887 | if(p == NULL) | |
888 | _dyld_func_lookup("__dyld_bind_objc_module", (void**)&p); | |
889 | p(objc_module); | |
890 | } | |
891 | ||
892 | ||
893 | #if __DYNAMIC__ | |
894 | bool | |
895 | _dyld_present( | |
896 | void) | |
897 | { | |
898 | // hmmm, this code is in libSystem.dylib, which is loaded by dyld... | |
899 | return true; | |
900 | } | |
901 | #endif | |
902 | ||
903 | uint32_t | |
904 | _dyld_image_count( | |
905 | void) | |
906 | { | |
907 | DYLD_NO_LOCK_THIS_BLOCK; | |
908 | static unsigned long (*p)(void) = NULL; | |
909 | ||
910 | if(_dyld_present() == 0) | |
911 | return(0); | |
912 | if(p == NULL) | |
913 | _dyld_func_lookup("__dyld_image_count", (void**)&p); | |
914 | return(p()); | |
915 | } | |
916 | ||
917 | const struct mach_header * | |
918 | _dyld_get_image_header( | |
919 | uint32_t image_index) | |
920 | { | |
921 | DYLD_NO_LOCK_THIS_BLOCK; | |
922 | static struct mach_header * (*p)(uint32_t image_index) = NULL; | |
923 | ||
924 | if(p == NULL) | |
925 | _dyld_func_lookup("__dyld_get_image_header", (void**)&p); | |
926 | return(p(image_index)); | |
927 | } | |
928 | ||
929 | intptr_t | |
930 | _dyld_get_image_vmaddr_slide( | |
931 | uint32_t image_index) | |
932 | { | |
933 | DYLD_NO_LOCK_THIS_BLOCK; | |
934 | static unsigned long (*p)(uint32_t image_index) = NULL; | |
935 | ||
936 | if(p == NULL) | |
937 | _dyld_func_lookup("__dyld_get_image_vmaddr_slide", (void**)&p); | |
938 | return(p(image_index)); | |
939 | } | |
940 | ||
941 | const char* | |
942 | _dyld_get_image_name( | |
943 | uint32_t image_index) | |
944 | { | |
945 | DYLD_NO_LOCK_THIS_BLOCK; | |
946 | static const char* (*p)(uint32_t image_index) = NULL; | |
947 | ||
948 | if(p == NULL) | |
949 | _dyld_func_lookup("__dyld_get_image_name", (void**)&p); | |
950 | return(p(image_index)); | |
951 | } | |
952 | ||
953 | bool | |
954 | _dyld_image_containing_address( | |
955 | const void* address) | |
956 | { | |
957 | DYLD_READER_LOCK_THIS_BLOCK; | |
958 | static bool (*p)(const void*) = NULL; | |
959 | ||
960 | if(p == NULL) | |
961 | _dyld_func_lookup("__dyld_image_containing_address", (void**)&p); | |
962 | return(p(address)); | |
963 | } | |
964 | ||
965 | const struct mach_header * | |
966 | _dyld_get_image_header_containing_address( | |
967 | const void* address) | |
968 | { | |
969 | DYLD_READER_LOCK_THIS_BLOCK; | |
970 | static const struct mach_header * (*p)(const void*) = NULL; | |
971 | ||
972 | if(p == NULL) | |
973 | _dyld_func_lookup("__dyld_get_image_header_containing_address", (void**)&p); | |
974 | return p(address); | |
975 | } | |
976 | ||
977 | void _dyld_moninit( | |
978 | void (*monaddition)(char *lowpc, char *highpc)) | |
979 | { | |
980 | DYLD_READER_LOCK_THIS_BLOCK; | |
981 | static void (*p)(void (*monaddition)(char *lowpc, char *highpc)) = NULL; | |
982 | ||
983 | if(p == NULL) | |
984 | _dyld_func_lookup("__dyld_moninit", (void**)&p); | |
985 | p(monaddition); | |
986 | } | |
987 | ||
988 | bool _dyld_launched_prebound( | |
989 | void) | |
990 | { | |
991 | DYLD_READER_LOCK_THIS_BLOCK; | |
992 | static bool (*p)(void) = NULL; | |
993 | ||
994 | if(p == NULL) | |
995 | _dyld_func_lookup("__dyld_launched_prebound", (void**)&p); | |
996 | return(p()); | |
997 | } | |
998 | ||
999 | bool _dyld_all_twolevel_modules_prebound( | |
1000 | void) | |
1001 | { | |
1002 | DYLD_READER_LOCK_THIS_BLOCK; | |
1003 | static bool (*p)(void) = NULL; | |
1004 | ||
1005 | if(p == NULL) | |
1006 | _dyld_func_lookup("__dyld_all_twolevel_modules_prebound", (void**)&p); | |
1007 | return(p()); | |
1008 | } | |
1009 | ||
1010 | ||
1011 | #include <dlfcn.h> | |
1012 | #include <stddef.h> | |
1013 | #include <pthread.h> | |
1014 | #include <stdlib.h> | |
1015 | #include <mach-o/dyld.h> | |
1016 | #include "dyldLock.h" | |
1017 | #include "dyldLibSystemThreadHelpers.h" | |
1018 | ||
1019 | // pthread key used to access per-thread dlerror message | |
1020 | static pthread_key_t dlerrorPerThreadKey; | |
1021 | ||
1022 | // data kept per-thread | |
1023 | struct dlerrorPerThreadData | |
1024 | { | |
1025 | uint32_t sizeAllocated; | |
1026 | char message[1]; | |
1027 | }; | |
1028 | ||
1029 | // function called by dyld to get buffer to store dlerror message | |
1030 | static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired) | |
1031 | { | |
1032 | const int size = (sizeRequired < 256) ? 256 : sizeRequired; | |
1033 | dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey); | |
1034 | if ( data == NULL ) { | |
1035 | //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); | |
1036 | const int mallocSize = sizeof(dlerrorPerThreadData)+size; | |
1037 | data = (dlerrorPerThreadData*)malloc(mallocSize); | |
1038 | data->sizeAllocated = size; | |
1039 | pthread_setspecific(dlerrorPerThreadKey, data); | |
1040 | } | |
1041 | else if ( data->sizeAllocated < sizeRequired ) { | |
1042 | free(data); | |
1043 | //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); | |
1044 | const int mallocSize = sizeof(dlerrorPerThreadData)+size; | |
1045 | data = (dlerrorPerThreadData*)malloc(mallocSize); | |
1046 | data->sizeAllocated = size; | |
1047 | pthread_setspecific(dlerrorPerThreadKey, data); | |
1048 | } | |
1049 | return data->message; | |
1050 | } | |
1051 | ||
1052 | // that table passed to dyld containing thread helpers | |
1053 | static dyld::ThreadingHelpers sThreadHelpers = { 1, &lockForLazyBinding, &unlockForLazyBinding, &getPerThreadBufferFor_dlerror }; | |
1054 | ||
1055 | // | |
1056 | // during initialization of libSystem this routine will run | |
1057 | // and call dyld, registering the threading helpers. | |
1058 | // | |
1059 | // | |
1060 | static int registerWithDyld() | |
1061 | { | |
1062 | static void (*p)(dyld::ThreadingHelpers*) = NULL; | |
1063 | ||
1064 | // create key and tell pthread package to call free() on any data associated with key if thread dies | |
1065 | pthread_key_create(&dlerrorPerThreadKey, &free); | |
1066 | ||
1067 | if(p == NULL) | |
1068 | _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p); | |
1069 | if(p != NULL) | |
1070 | p(&sThreadHelpers); | |
1071 | ||
1072 | return 0; | |
1073 | } | |
1074 | ||
1075 | // should be able to use __attribute__((constructor)) on registerWithDyld, but compiler has bug (3679135) | |
1076 | // instead use initialization of global to force it to run. | |
1077 | static int hack = registerWithDyld(); | |
1078 | ||
1079 | ||
1080 | char* dlerror() | |
1081 | { | |
1082 | DYLD_READER_LOCK_THIS_BLOCK; | |
1083 | static char* (*p)() = NULL; | |
1084 | ||
1085 | if(p == NULL) | |
1086 | _dyld_func_lookup("__dyld_dlerror", (void**)&p); | |
1087 | return(p()); | |
1088 | } | |
1089 | ||
1090 | int dladdr(const void* addr, Dl_info* info) | |
1091 | { | |
1092 | DYLD_READER_LOCK_THIS_BLOCK; | |
1093 | static int (*p)(const void* , Dl_info*) = NULL; | |
1094 | ||
1095 | if(p == NULL) | |
1096 | _dyld_func_lookup("__dyld_dladdr", (void**)&p); | |
1097 | return(p(addr, info)); | |
1098 | } | |
1099 | ||
1100 | int dlclose(void* handle) | |
1101 | { | |
1102 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
1103 | static int (*p)(void* handle) = NULL; | |
1104 | ||
1105 | if(p == NULL) | |
1106 | _dyld_func_lookup("__dyld_dlclose", (void**)&p); | |
1107 | return(p(handle)); | |
1108 | } | |
1109 | ||
1110 | void* dlopen(const char* path, int mode) | |
1111 | { | |
1112 | DYLD_WRITER_LOCK_THIS_BLOCK; | |
1113 | static void* (*p)(const char* path, int) = NULL; | |
1114 | ||
1115 | if(p == NULL) | |
1116 | _dyld_func_lookup("__dyld_dlopen", (void**)&p); | |
1117 | return(p(path, mode)); | |
1118 | } | |
1119 | ||
1120 | void* dlsym(void* handle, const char* symbol) | |
1121 | { | |
1122 | DYLD_READER_LOCK_THIS_BLOCK; | |
1123 | static void* (*p)(void* handle, const char* symbol) = NULL; | |
1124 | ||
1125 | if(p == NULL) | |
1126 | _dyld_func_lookup("__dyld_dlsym", (void**)&p); | |
1127 | return(p(handle, symbol)); | |
1128 | } | |
1129 | ||
1130 | ||
1131 | ||
1132 | ||
1133 |