]> git.saurik.com Git - apple/dyld.git/blob - src/dyld.cpp
1be09730eae6d9655a35b32fe9c9cc0fcbf69d48
[apple/dyld.git] / src / dyld.cpp
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 <stdint.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/param.h>
30 #include <mach/mach_time.h> // mach_absolute_time()
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <mach-o/fat.h>
34 #include <mach-o/loader.h>
35 #include <libkern/OSByteOrder.h>
36 #include <mach/mach.h>
37 #include <sys/sysctl.h>
38
39 #include <vector>
40
41 #include "mach-o/dyld_gdb.h"
42
43 #include "dyld.h"
44 #include "ImageLoader.h"
45 #include "ImageLoaderMachO.h"
46 #include "dyldLibSystemThreadHelpers.h"
47
48
49 #define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */
50
51
52 /* implemented in dyld_gdb.cpp */
53 void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
54 void removeImageFromAllImages(const mach_header* mh);
55 #if OLD_GDB_DYLD_INTERFACE
56 void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath);
57 void removeImageForgdb(const struct mach_header* mh);
58 #endif
59
60 // magic so CrashReporter logs message
61 extern "C" {
62 char error_string[1024];
63 }
64
65
66 //
67 // The file contains the core of dyld used to get a process to main().
68 // The API's that dyld supports are implemented in dyldAPIs.cpp.
69 //
70 //
71 //
72 //
73 //
74
75
76 namespace dyld {
77
78
79 //
80 // state of all environment variables dyld uses
81 //
82 struct EnvironmentVariables {
83 const char* const * DYLD_FRAMEWORK_PATH;
84 const char* const * DYLD_FALLBACK_FRAMEWORK_PATH;
85 const char* const * DYLD_LIBRARY_PATH;
86 const char* const * DYLD_FALLBACK_LIBRARY_PATH;
87 const char* const * DYLD_ROOT_PATH;
88 const char* const * DYLD_INSERT_LIBRARIES;
89 const char* const * LD_LIBRARY_PATH; // for unix conformance
90 bool DYLD_PRINT_LIBRARIES;
91 bool DYLD_PRINT_LIBRARIES_POST_LAUNCH;
92 bool DYLD_BIND_AT_LAUNCH;
93 bool DYLD_PRINT_STATISTICS;
94 bool DYLD_PRINT_OPTS;
95 bool DYLD_PRINT_ENV;
96 // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix
97 // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts
98 // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv
99 // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat
100 // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit
101 // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping
102 // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind
103 // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase
104 // DYLD_PRINT_APIS ==> gLogAPIs
105 // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage
106 // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding
107 // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode
108 // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode
109 // DYLD_SLIDE_AND_PACK_DYLIBS ==> gLinkContext.slideAndPackDylibs
110 // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings
111 };
112
113 // all global state
114 static const char* sExecPath = NULL;
115 static const struct mach_header* sMainExecutableMachHeader = NULL;
116 static cpu_type_t sHostCPU;
117 static cpu_subtype_t sHostCPUsubtype;
118 static ImageLoader* sMainExecutable = NULL;
119 static std::vector<ImageLoader*> sAllImages;
120 static std::vector<ImageLoader*> sImageRoots;
121 static std::vector<ImageLoader*> sImageFilesNeedingTermination;
122 static std::vector<ImageLoader*> sImagesToNotifyAboutOtherImages;
123 static std::vector<ImageCallback> sAddImageCallbacks;
124 static std::vector<ImageCallback> sRemoveImageCallbacks;
125 static ImageLoader* sLastImageByAddressCache;
126 static EnvironmentVariables sEnv;
127 static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
128 static const char* sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
129 static BundleNotificationCallBack sBundleNotifier = NULL;
130 static BundleLocatorCallBack sBundleLocation = NULL;
131 static UndefinedHandler sUndefinedHandler = NULL;
132 ImageLoader::LinkContext gLinkContext;
133 bool gLogAPIs = false;
134 const struct ThreadingHelpers* gThreadHelpers = NULL;
135
136
137
138 // utility class to assure files are closed when an exception is thrown
139 class FileOpener {
140 public:
141 FileOpener(const char* path);
142 ~FileOpener();
143 int getFileDescriptor() { return fd; }
144 private:
145 int fd;
146 };
147
148 FileOpener::FileOpener(const char* path)
149 {
150 fd = open(path, O_RDONLY, 0);
151 }
152
153 FileOpener::~FileOpener()
154 {
155 close(fd);
156 }
157
158
159
160 // Objective-C installs an addImage hook to dyld to get notified about new images
161 // The callback needs to be run after the image is rebased and bound, but before its initializers are called
162 static uint32_t imageNotification(ImageLoader* image, uint32_t startIndex)
163 {
164 // tell all register add image handlers about this
165 const uint32_t callbackCount = sAddImageCallbacks.size();
166 for (uint32_t i=startIndex; i < callbackCount; ++i) {
167 ImageCallback cb = sAddImageCallbacks[i];
168 //fprintf(stderr, "dyld: calling add-image-callback[%d]=%p for %s\n", i, cb, image->getPath());
169 (cb)(image->machHeader(), image->getSlide());
170 }
171 return callbackCount;
172 }
173
174
175
176 // notify gdb et al about these new images
177 static void notifyAdding(std::vector<ImageLoader*>& images)
178 {
179 // build array
180 unsigned int len = images.size();
181 if ( len != 0 ) {
182 dyld_image_info infos[len];
183 for (unsigned int i=0; i < len; ++i) {
184 dyld_image_info* p = &infos[i];
185 ImageLoader* image = images[i];
186 p->imageLoadAddress = image->machHeader();
187 p->imageFilePath = image->getPath();
188 p->imageFileModDate = image->lastModified();
189 //fprintf(stderr, "notifying objc about %s\n", image->getPath());
190 }
191
192 // tell gdb
193 addImagesToAllImages(len, infos);
194
195 // tell all interested images (after gdb, so you can debug anything the notification does)
196 for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
197 (*it)->doNotification(dyld_image_adding, len, infos);
198 }
199 }
200 }
201
202
203
204 // In order for register_func_for_add_image() callbacks to to be called bottom up,
205 // we need to maintain a list of root images. The main executable is usally the
206 // first root. Any images dynamically added are also roots (unless already loaded).
207 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
208 static void addRootImage(ImageLoader* image)
209 {
210 //fprintf(stderr, "addRootImage(%p, %s)\n", image, image->getPath());
211 // add to list of roots
212 sImageRoots.push_back(image);
213 }
214
215 // Objective-C will contain a __DATA/__image_notify section which contains pointers to a function to call
216 // whenever any new image is loaded.
217 static void addImageNeedingNotification(ImageLoader* image)
218 {
219 sImagesToNotifyAboutOtherImages.push_back(image);
220 }
221
222 static void addImage(ImageLoader* image)
223 {
224 // add to master list
225 sAllImages.push_back(image);
226
227 if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
228 uint64_t offset = image->getOffsetInFatFile();
229 if ( offset == 0 )
230 fprintf(stderr, "dyld: loaded: %s\n", image->getPath());
231 else
232 fprintf(stderr, "dyld: loaded: %s, cpu-sub-type: %d\n", image->getPath(), image->machHeader()->cpusubtype);
233 }
234
235 #if OLD_GDB_DYLD_INTERFACE
236 // let gdb find out about this
237 addImageForgdb(image->machHeader(), image->getSlide(), image->getPath(), image->getLogicalPath());
238 #endif
239 }
240
241 void removeImage(ImageLoader* image)
242 {
243 // flush find-by-address cache
244 if ( sLastImageByAddressCache == image )
245 sLastImageByAddressCache = NULL;
246
247 // if in termination list, pull it out and run terminator
248 for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
249 if ( *it == image ) {
250 sImageFilesNeedingTermination.erase(it);
251 image->doTermination(gLinkContext);
252 break;
253 }
254 }
255
256 // tell all register add image handlers about this
257 // do this before removing image from internal data structures so that the callback can querey dyld about the image
258 for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
259 (*it)(image->machHeader(), image->getSlide());
260 }
261
262 // remove from master list
263 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
264 if ( *it == image ) {
265 sAllImages.erase(it);
266 break;
267 }
268 }
269
270 // if in announcement list, pull it out
271 for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
272 if ( *it == image ) {
273 sImagesToNotifyAboutOtherImages.erase(it);
274 break;
275 }
276 }
277
278 // if in root list, pull it out
279 for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
280 if ( *it == image ) {
281 sImageRoots.erase(it);
282 break;
283 }
284 }
285
286 // tell gdb, new way
287 removeImageFromAllImages(image->machHeader());
288
289 #if OLD_GDB_DYLD_INTERFACE
290 // tell gdb, old way
291 removeImageForgdb(image->machHeader());
292 gdb_dyld_state_changed();
293 #endif
294 }
295
296
297 static void terminationRecorder(ImageLoader* image)
298 {
299 sImageFilesNeedingTermination.push_back(image);
300 }
301
302 const char* getExecutablePath()
303 {
304 return sExecPath;
305 }
306
307
308 void initializeMainExecutable()
309 {
310 const int rootCount = sImageRoots.size();
311 for(int i=0; i < rootCount; ++i) {
312 ImageLoader* image = sImageRoots[i];
313 //fprintf(stderr, "initializeMainExecutable: image = %p\n", image);
314 image->runInitializers(gLinkContext);
315 }
316 /*
317 // this does not work???
318 for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
319 ImageLoader* image = *it;
320 fprintf(stderr, "initializeMainExecutable: image = %p\n", image);
321 // don't know why vector sometimes starts with NULL element???
322 if ( image != NULL )
323 image->runInitializers(gLinkContext);
324 }
325 */
326 if ( sEnv.DYLD_PRINT_STATISTICS )
327 ImageLoaderMachO::printStatistics(sAllImages.size());
328 }
329
330 bool mainExecutablePrebound()
331 {
332 return sMainExecutable->usablePrebinding(gLinkContext);
333 }
334
335 ImageLoader* mainExecutable()
336 {
337 return sMainExecutable;
338 }
339
340
341 void runTerminators()
342 {
343 const unsigned int imageCount = sImageFilesNeedingTermination.size();
344 for(unsigned int i=imageCount; i > 0; --i){
345 ImageLoader* image = sImageFilesNeedingTermination[i-1];
346 image->doTermination(gLinkContext);
347 }
348 sImageFilesNeedingTermination.clear();
349 }
350
351
352 //
353 // Turns a colon separated list of strings
354 // into a NULL terminated array of string
355 // pointers.
356 //
357 static const char** parseColonList(const char* list)
358 {
359 if ( list[0] == '\0' )
360 return NULL;
361
362 int colonCount = 0;
363 for(const char* s=list; *s != '\0'; ++s) {
364 if (*s == ':')
365 ++colonCount;
366 }
367
368 int index = 0;
369 const char* start = list;
370 char** result = new char*[colonCount+2];
371 for(const char* s=list; *s != '\0'; ++s) {
372 if (*s == ':') {
373 int len = s-start;
374 char* str = new char[len+1];
375 strncpy(str, start, len);
376 str[len] = '\0';
377 start = &s[1];
378 result[index++] = str;
379 }
380 }
381 int len = strlen(start);
382 char* str = new char[len+1];
383 strcpy(str, start);
384 result[index++] = str;
385 result[index] = NULL;
386
387 return (const char**)result;
388 }
389
390 /*
391 * Library path searching is not done for setuid programs
392 * which are not run by the real user. Futher the
393 * evironment varaible for the library path is cleared so
394 * that if this program executes a non-set uid program this
395 * part of the evironment will not be passed along so that
396 * that program also will not have it's libraries searched
397 * for.
398 */
399 static bool riskyUser()
400 {
401 static bool checked = false;
402 static bool risky = false;
403 if ( !checked ) {
404 risky = ( getuid() != 0 && (getuid() != geteuid() || getgid() != getegid()) );
405 checked = true;
406 }
407 return risky;
408 }
409
410
411 static bool disableIfBadUser(char* rhs)
412 {
413 bool didDisable = false;
414 if ( riskyUser() ) {
415 *rhs ='\0';
416 didDisable = true;
417 }
418 return didDisable;
419 }
420
421 static void paths_expand_roots(const char **paths, const char *key, const char *val)
422 {
423 // assert(val != NULL);
424 // assert(paths != NULL);
425 if(NULL != key) {
426 size_t keyLen = strlen(key);
427 for(int i=0; paths[i] != NULL; ++i) {
428 if ( strncmp(paths[i], key, keyLen) == 0 ) {
429 char* newPath = new char[strlen(val) + (strlen(paths[i]) - keyLen) + 1];
430 strcpy(newPath, val);
431 strcat(newPath, &paths[i][keyLen]);
432 paths[i] = newPath;
433 }
434 }
435 }
436 return;
437 }
438
439 static void removePathWithPrefix(const char* paths[], const char* prefix)
440 {
441 size_t prefixLen = strlen(prefix);
442 for(int s=0,d=0; (paths[d] != NULL) && (paths[s] != NULL); ++s, ++d) {
443 if ( strncmp(paths[s], prefix, prefixLen) == 0 )
444 ++s;
445 paths[d] = paths[s];
446 }
447 }
448
449 #if 0
450 static void paths_dump(const char **paths)
451 {
452 // assert(paths != NULL);
453 const char **strs = paths;
454 while(*strs != NULL)
455 {
456 fprintf(stderr, "\"%s\"\n", *strs);
457 strs++;
458 }
459 return;
460 }
461 #endif
462
463 static void printOptions(const char* argv[])
464 {
465 uint32_t i = 0;
466 while ( NULL != argv[i] ) {
467 fprintf(stderr, "opt[%i] = \"%s\"\n", i, argv[i]);
468 i++;
469 }
470 }
471
472 static void printEnvironmentVariables(const char* envp[])
473 {
474 while ( NULL != *envp ) {
475 fprintf(stderr, "%s\n", *envp);
476 envp++;
477 }
478 }
479
480
481
482 void processDyldEnvironmentVarible(const char* key, const char* value)
483 {
484 if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
485 if ( !disableIfBadUser((char*)value) )
486 sEnv.DYLD_FRAMEWORK_PATH = parseColonList(value);
487 }
488 else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
489 if ( !disableIfBadUser((char*)value) )
490 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = parseColonList(value);
491 }
492 else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
493 if ( !disableIfBadUser((char*)value) )
494 sEnv.DYLD_LIBRARY_PATH = parseColonList(value);
495 }
496 else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
497 if ( !disableIfBadUser((char*)value) )
498 sEnv.DYLD_FALLBACK_LIBRARY_PATH = parseColonList(value);
499 }
500 else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
501 if ( !disableIfBadUser((char*)value) ) {
502 if ( strcmp(value, "/") != 0 ) {
503 sEnv.DYLD_ROOT_PATH = parseColonList(value);
504 for (int i=0; sEnv.DYLD_ROOT_PATH[i] != NULL; ++i) {
505 if ( sEnv.DYLD_ROOT_PATH[i][0] != '/' ) {
506 fprintf(stderr, "dyld: warning DYLD_ROOT_PATH not used because it contains a non-absolute path");
507 sEnv.DYLD_ROOT_PATH = NULL;
508 }
509 }
510 }
511 }
512 }
513 else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) {
514 if ( !disableIfBadUser((char*)value) )
515 gLinkContext.imageSuffix = value;
516 }
517 else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
518 if ( !disableIfBadUser((char*)value) )
519 sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value);
520 }
521 else if ( strcmp(key, "DYLD_DEBUG_TRACE") == 0 ) {
522 fprintf(stderr, "dyld: warning DYLD_DEBUG_TRACE not supported\n");
523 }
524 else if ( strcmp(key, "DYLD_ERROR_PRINT") == 0 ) {
525 fprintf(stderr, "dyld: warning DYLD_ERROR_PRINT not supported\n");
526 }
527 else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
528 sEnv.DYLD_PRINT_OPTS = true;
529 }
530 else if ( strcmp(key, "DYLD_PRINT_ENV") == 0 ) {
531 sEnv.DYLD_PRINT_ENV = true;
532 }
533 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) {
534 sEnv.DYLD_PRINT_LIBRARIES = true;
535 }
536 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
537 sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH = true;
538 }
539 else if ( strcmp(key, "DYLD_TRACE") == 0 ) {
540 fprintf(stderr, "dyld: warning DYLD_TRACE not supported\n");
541 }
542 else if ( strcmp(key, "DYLD_EBADEXEC_ONLY") == 0 ) {
543 fprintf(stderr, "dyld: warning DYLD_EBADEXEC_ONLY not supported\n");
544 }
545 else if ( strcmp(key, "DYLD_BIND_AT_LAUNCH") == 0 ) {
546 sEnv.DYLD_BIND_AT_LAUNCH = true;
547 }
548 else if ( strcmp(key, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
549 gLinkContext.bindFlat = true;
550 }
551 else if ( strcmp(key, "DYLD_DEAD_LOCK_HANG") == 0 ) {
552 fprintf(stderr, "dyld: warning DYLD_DEAD_LOCK_HANG not supported\n");
553 }
554 else if ( strcmp(key, "DYLD_ABORT_MULTIPLE_INITS") == 0 ) {
555 fprintf(stderr, "dyld: warning DYLD_ABORT_MULTIPLE_INITS not supported\n");
556 }
557 else if ( strcmp(key, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
558 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
559 }
560 else if ( strcmp(key, "DYLD_SLIDE_AND_PACK_DYLIBS") == 0 ) {
561 gLinkContext.slideAndPackDylibs = true;
562 }
563 else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) {
564 // since the new dyld never runs fix_prebinding, no need to warn if someone does not want it run
565 //fprintf(stderr, "dyld: warning DYLD_NO_FIX_PREBINDING not supported\n");
566 }
567 else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) {
568 gLinkContext.verbosePrebinding = true;
569 }
570 else if ( strcmp(key, "DYLD_HINTS_DEBUG") == 0 ) {
571 fprintf(stderr, "dyld: warning DYLD_HINTS_DEBUG not supported\n");
572 }
573 else if ( strcmp(key, "DYLD_SAMPLE_DEBUG") == 0 ) {
574 fprintf(stderr, "dyld: warning DYLD_SAMPLE_DEBUG not supported\n");
575 }
576 else if ( strcmp(key, "DYLD_EXECUTABLE_PATH_DEBUG") == 0 ) {
577 fprintf(stderr, "dyld: warning DYLD_EXECUTABLE_PATH_DEBUG not supported\n");
578 }
579 else if ( strcmp(key, "DYLD_TWO_LEVEL_DEBUG") == 0 ) {
580 fprintf(stderr, "dyld: warning DYLD_TWO_LEVEL_DEBUG not supported\n");
581 }
582 else if ( strcmp(key, "DYLD_LAZY_INITIALIZERS") == 0 ) {
583 fprintf(stderr, "dyld: warning DYLD_LAZY_INITIALIZERS not supported\n");
584 }
585 else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) {
586 gLinkContext.verboseInit = true;
587 }
588 else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) {
589 sEnv.DYLD_PRINT_STATISTICS = true;
590 }
591 else if ( strcmp(key, "DYLD_PRINT_SEGMENTS") == 0 ) {
592 gLinkContext.verboseMapping = true;
593 }
594 else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) {
595 gLinkContext.verboseBind = true;
596 }
597 else if ( strcmp(key, "DYLD_PRINT_REBASINGS") == 0 ) {
598 gLinkContext.verboseRebase = true;
599 }
600 else if ( strcmp(key, "DYLD_PRINT_APIS") == 0 ) {
601 gLogAPIs = true;
602 }
603 else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) {
604 gLinkContext.verboseWarnings = true;
605 }
606 else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
607 if ( strcmp(value, "private") == 0 ) {
608 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
609 }
610 else if ( strcmp(value, "avoid") == 0 ) {
611 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
612 }
613 else if ( strcmp(value, "use") == 0 ) {
614 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
615 }
616 else if ( value[0] == '\0' ) {
617 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
618 }
619 else {
620 fprintf(stderr, "dyld: warning unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n");
621 }
622 }
623 else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) {
624 if ( strcmp(value, "all") == 0 ) {
625 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
626 }
627 else if ( strcmp(value, "app") == 0 ) {
628 gLinkContext.prebindUsage = ImageLoader::kUseAllButAppPredbinding;
629 }
630 else if ( strcmp(value, "nonsplit") == 0 ) {
631 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
632 }
633 else if ( value[0] == '\0' ) {
634 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
635 }
636 else {
637 fprintf(stderr, "dyld: warning unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n");
638 }
639 }
640 else {
641 fprintf(stderr, "dyld: warning, unknown environment variable: %s\n", key);
642 }
643 }
644
645 static void checkEnvironmentVariables(const char* envp[])
646 {
647 const char* home = NULL;
648 const char** p;
649 for(p = envp; *p != NULL; p++) {
650 const char* keyEqualsValue = *p;
651 if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) {
652 const char* equals = strchr(keyEqualsValue, '=');
653 if ( equals != NULL ) {
654 const char* value = &equals[1];
655 const int keyLen = equals-keyEqualsValue;
656 char key[keyLen];
657 strncpy(key, keyEqualsValue, keyLen);
658 key[keyLen] = '\0';
659 processDyldEnvironmentVarible(key, value);
660 }
661 }
662 else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) {
663 home = &keyEqualsValue[5];
664 }
665 else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
666 const char* path = &keyEqualsValue[16];
667 if ( !disableIfBadUser((char*)path) )
668 sEnv.LD_LIBRARY_PATH = parseColonList(path);
669 }
670 }
671
672 // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
673 if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
674 const char** paths = sFrameworkFallbackPaths;
675 if ( home != NULL ) {
676 if ( riskyUser() )
677 removePathWithPrefix(paths, "$HOME");
678 else
679 paths_expand_roots(paths, "$HOME", home);
680 }
681 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths;
682 }
683
684 // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
685 if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
686 const char** paths = sLibraryFallbackPaths;
687 if ( home != NULL ) {
688 if ( riskyUser() )
689 removePathWithPrefix(paths, "$HOME");
690 else
691 paths_expand_roots(paths, "$HOME", home);
692 }
693 sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
694 }
695 }
696
697
698 static void getHostInfo()
699 {
700 #if 0
701 struct host_basic_info info;
702 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
703 mach_port_t hostPort = mach_host_self();
704 kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
705 mach_port_deallocate(mach_task_self(), hostPort);
706 if ( result != KERN_SUCCESS )
707 throw "host_info() failed";
708
709 sHostCPU = info.cpu_type;
710 sHostCPUsubtype = info.cpu_subtype;
711 #endif
712
713 size_t valSize = sizeof(sHostCPU);
714 if (sysctlbyname ("hw.cputype", &sHostCPU, &valSize, NULL, 0) != 0)
715 throw "sysctlbyname(hw.cputype) failed";
716 valSize = sizeof(sHostCPUsubtype);
717 if (sysctlbyname ("hw.cpusubtype", &sHostCPUsubtype, &valSize, NULL, 0) != 0)
718 throw "sysctlbyname(hw.cpusubtype) failed";
719 }
720
721 bool validImage(ImageLoader* possibleImage)
722 {
723 const unsigned int imageCount = sAllImages.size();
724 for(unsigned int i=0; i < imageCount; ++i) {
725 if ( possibleImage == sAllImages[i] ) {
726 return true;
727 }
728 }
729 return false;
730 }
731
732 uint32_t getImageCount()
733 {
734 return sAllImages.size();
735 }
736
737 ImageLoader* getIndexedImage(unsigned int index)
738 {
739 if ( index < sAllImages.size() )
740 return sAllImages[index];
741 else
742 return NULL;
743 }
744
745 ImageLoader* findImageByMachHeader(const struct mach_header* target)
746 {
747 const unsigned int imageCount = sAllImages.size();
748 for(unsigned int i=0; i < imageCount; ++i) {
749 ImageLoader* anImage = sAllImages[i];
750 if ( anImage->machHeader() == target )
751 return anImage;
752 }
753 return NULL;
754 }
755
756
757 ImageLoader* findImageContainingAddress(const void* addr)
758 {
759 #if FIND_STATS
760 static int cacheHit = 0;
761 static int cacheMiss = 0;
762 static int cacheNotMacho = 0;
763 if ( ((cacheHit+cacheMiss+cacheNotMacho) % 100) == 0 )
764 fprintf(stderr, "findImageContainingAddress(): cache hit = %d, miss = %d, unknown = %d\n", cacheHit, cacheMiss, cacheNotMacho);
765 #endif
766 // first look in image where last address was found rdar://problem/3685517
767 if ( (sLastImageByAddressCache != NULL) && sLastImageByAddressCache->containsAddress(addr) ) {
768 #if FIND_STATS
769 ++cacheHit;
770 #endif
771 return sLastImageByAddressCache;
772 }
773 // do exhastive search
774 // todo: consider maintaining a list sorted by address ranges and do a binary search on that
775 const unsigned int imageCount = sAllImages.size();
776 for(unsigned int i=0; i < imageCount; ++i) {
777 ImageLoader* anImage = sAllImages[i];
778 if ( anImage->containsAddress(addr) ) {
779 sLastImageByAddressCache = anImage;
780 #if FIND_STATS
781 ++cacheMiss;
782 #endif
783 return anImage;
784 }
785 }
786 #if FIND_STATS
787 ++cacheNotMacho;
788 #endif
789 return NULL;
790 }
791
792
793 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
794 {
795 const unsigned int imageCount = sAllImages.size();
796 for(unsigned int i=0; i < imageCount; ++i) {
797 ImageLoader* anImage = sAllImages[i];
798 (*callback)(anImage, userData);
799 }
800 }
801
802 ImageLoader* findLoadedImage(const struct stat& stat_buf)
803 {
804 const unsigned int imageCount = sAllImages.size();
805 for(unsigned int i=0; i < imageCount; ++i){
806 ImageLoader* anImage = sAllImages[i];
807 if ( anImage->statMatch(stat_buf) )
808 return anImage;
809 }
810 return NULL;
811 }
812
813 // based on ANSI-C strstr()
814 static const char* strrstr(const char* str, const char* sub)
815 {
816 const int sublen = strlen(sub);
817 for(const char* p = &str[strlen(str)]; p != str; --p) {
818 if ( strncmp(p, sub, sublen) == 0 )
819 return p;
820 }
821 return NULL;
822 }
823
824
825 //
826 // Find framework path
827 //
828 // /path/foo.framework/foo => foo.framework/foo
829 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
830 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
831 // /path/foo.framework/Libraries/bar.dylb => NULL
832 // /path/foo.framework/bar => NULL
833 //
834 // Returns NULL if not a framework path
835 //
836 static const char* getFrameworkPartialPath(const char* path)
837 {
838 const char* dirDot = strrstr(path, ".framework/");
839 if ( dirDot != NULL ) {
840 const char* dirStart = dirDot;
841 for ( ; dirStart >= path; --dirStart) {
842 if ( (*dirStart == '/') || (dirStart == path) ) {
843 const char* frameworkStart = &dirStart[1];
844 if ( dirStart == path )
845 --frameworkStart;
846 int len = dirDot - frameworkStart;
847 char framework[len+1];
848 strncpy(framework, frameworkStart, len);
849 framework[len] = '\0';
850 const char* leaf = strrchr(path, '/');
851 if ( leaf != NULL ) {
852 if ( strcmp(framework, &leaf[1]) == 0 ) {
853 return frameworkStart;
854 }
855 if ( gLinkContext.imageSuffix != NULL ) {
856 // some debug frameworks have install names that end in _debug
857 if ( strncmp(framework, &leaf[1], len) == 0 ) {
858 if ( strcmp( gLinkContext.imageSuffix, &leaf[len+1]) == 0 )
859 return frameworkStart;
860 }
861 }
862 }
863 }
864 }
865 }
866 return NULL;
867 }
868
869
870 static const char* getLibraryLeafName(const char* path)
871 {
872 const char* start = strrchr(path, '/');
873 if ( start != NULL )
874 return &start[1];
875 else
876 return path;
877 }
878
879
880
881 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
882
883
884 //
885 // A fat file may contain multiple sub-images for the same CPU type.
886 // In that case, dyld picks which sub-image to use by scanning a table
887 // of preferred cpu-sub-types for the running cpu.
888 //
889 // There is one row in the table for each cpu-sub-type on which dyld might run.
890 // The first entry in a row is that cpu-sub-type. It is followed by all
891 // cpu-sub-types that can run on that cpu, if preferred order. Each row ends with
892 // a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),
893 // followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row.
894 //
895
896
897 //
898 // 32-bit PowerPC sub-type lists
899 //
900 const int kPPC_RowCount = 4;
901 static const cpu_subtype_t kPPC32[kPPC_RowCount][6] = {
902 // G5 can run any code
903 { CPU_SUBTYPE_POWERPC_970, CPU_SUBTYPE_POWERPC_7450, CPU_SUBTYPE_POWERPC_7400, CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST },
904
905 // G4 can run all but G5 code
906 { CPU_SUBTYPE_POWERPC_7450, CPU_SUBTYPE_POWERPC_7400, CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
907 { CPU_SUBTYPE_POWERPC_7400, CPU_SUBTYPE_POWERPC_7450, CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
908
909 // G3 cannot run G4 or G5 code
910 { CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST }
911 };
912
913
914 //
915 // 64-bit PowerPC sub-type lists
916 //
917 const int kPPC64_RowCount = 1;
918 static const cpu_subtype_t kPPC64[kPPC64_RowCount][3] = {
919 // G5 can run any 64-bit code
920 { CPU_SUBTYPE_POWERPC_970, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST },
921 };
922
923
924
925 //
926 // 32-bit x86 sub-type lists
927 //
928 // TO-DO
929
930
931
932 // scan the tables above to find the cpu-sub-type-list for this machine
933 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
934 {
935 switch (cpu) {
936 case CPU_TYPE_POWERPC:
937 for (int i=0; i < kPPC_RowCount ; ++i) {
938 if ( kPPC32[i][0] == subtype )
939 return kPPC32[i];
940 }
941 break;
942 case CPU_TYPE_POWERPC64:
943 for (int i=0; i < kPPC64_RowCount ; ++i) {
944 if ( kPPC64[i][0] == subtype )
945 return kPPC64[i];
946 }
947 break;
948 case CPU_TYPE_I386:
949 // To do
950 break;
951 }
952 return NULL;
953 }
954
955
956
957
958 // scan fat table-of-contents for best most preferred subtype
959 static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, uint64_t* offset, uint64_t* len)
960 {
961 const fat_arch* const archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
962 for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) {
963 for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) {
964 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu)
965 && (list[subTypeIndex] == archs[fatIndex].cpusubtype) ) {
966 *offset = OSSwapBigToHostInt32(archs[fatIndex].offset);
967 *len = OSSwapBigToHostInt32(archs[fatIndex].size);
968 return true;
969 }
970 }
971 }
972 return false;
973 }
974
975 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
976 static bool fatFindExactMatch(cpu_type_t cpu, cpu_subtype_t subtype, const fat_header* fh, uint64_t* offset, uint64_t* len)
977 {
978 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
979 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
980 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu)
981 && ((cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == subtype) ) {
982 *offset = OSSwapBigToHostInt32(archs[i].offset);
983 *len = OSSwapBigToHostInt32(archs[i].size);
984 return true;
985 }
986 }
987 return false;
988 }
989
990 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
991 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t* offset, uint64_t* len)
992 {
993 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
994 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
995 if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
996 switch (cpu) {
997 case CPU_TYPE_POWERPC:
998 case CPU_TYPE_POWERPC64:
999 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_POWERPC_ALL ) {
1000 *offset = OSSwapBigToHostInt32(archs[i].offset);
1001 *len = OSSwapBigToHostInt32(archs[i].size);
1002 return true;
1003 }
1004 break;
1005 case CPU_TYPE_I386:
1006 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_I386_ALL ) {
1007 *offset = OSSwapBigToHostInt32(archs[i].offset);
1008 *len = OSSwapBigToHostInt32(archs[i].size);
1009 return true;
1010 }
1011 break;
1012 }
1013 }
1014 }
1015 return false;
1016 }
1017
1018
1019 //
1020 // A fat file may contain multiple sub-images for the same cpu-type,
1021 // each optimized for a different cpu-sub-type (e.g G3 or G5).
1022 // This routine picks the optimal sub-image.
1023 //
1024 static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
1025 {
1026 // assume all dylibs loaded must have same cpu type as main executable
1027 const cpu_type_t cpu = sMainExecutableMachHeader->cputype;
1028
1029 // We only know the subtype to use if the main executable cpu type matches the host
1030 if ( (cpu & CPU_TYPE_MASK) == sHostCPU ) {
1031 // get preference ordered list of subtypes
1032 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(cpu, sHostCPUsubtype);
1033
1034 // use ordered list to find best sub-image in fat file
1035 if ( subTypePreferenceList != NULL )
1036 return fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, offset, len);
1037
1038 // if running cpu is not in list, try for an exact match
1039 if ( fatFindExactMatch(cpu, sHostCPUsubtype, fh, offset, len) )
1040 return true;
1041 }
1042
1043 // running on an uknown cpu, can only load generic code
1044 return fatFindRunsOnAllCPUs(cpu, fh, offset, len);
1045 }
1046
1047
1048
1049 //
1050 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
1051 // on the current processor. It is deemed compatible if any of the following are true:
1052 // 1) mach_header subtype is in list of compatible subtypes for running processor
1053 // 2) mach_header subtype is same as running processor subtype
1054 // 3) mach_header subtype runs on all processor variants
1055 //
1056 //
1057 bool isCompatibleMachO(const uint8_t* firstPage)
1058 {
1059 const mach_header* mh = (mach_header*)firstPage;
1060 if ( mh->magic == sMainExecutableMachHeader->magic ) {
1061 if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
1062 if ( (mh->cputype & CPU_TYPE_MASK) == sHostCPU ) {
1063 // get preference ordered list of subtypes that this machine can use
1064 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(mh->cputype, sHostCPUsubtype);
1065 if ( subTypePreferenceList != NULL ) {
1066 // if image's subtype is in the list, it is compatible
1067 for (const cpu_subtype_t* p = subTypePreferenceList; *p != CPU_SUBTYPE_END_OF_LIST; ++p) {
1068 if ( *p == mh->cpusubtype )
1069 return true;
1070 }
1071 // have list and not in list, so not compatible
1072 throw "incompatible cpu-subtype";
1073 }
1074 // unknown cpu sub-type, but if exact match for current subtype then ok to use
1075 if ( mh->cpusubtype == sHostCPUsubtype )
1076 return true;
1077 }
1078
1079 // cpu unknown, so don't know if subtype is compatible
1080 // only load _ALL variant
1081 switch (mh->cputype) {
1082 case CPU_TYPE_POWERPC:
1083 case CPU_TYPE_POWERPC64:
1084 if ( mh->cpusubtype == CPU_SUBTYPE_POWERPC_ALL )
1085 return true;
1086 break;
1087 case CPU_TYPE_I386:
1088 if ( mh->cpusubtype == CPU_SUBTYPE_I386_ALL )
1089 return true;
1090 break;
1091 }
1092 }
1093 }
1094 return false;
1095 }
1096
1097
1098 // The kernel maps in main executable before dyld gets control. We need to
1099 // make an ImageLoader* for the already mapped in main executable.
1100 static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, const char* path)
1101 {
1102 // try mach-o loader
1103 if ( isCompatibleMachO((const uint8_t*)mh) ) {
1104 ImageLoader* image = new ImageLoaderMachO(path, mh, 0, gLinkContext);
1105 addImage(image);
1106 return image;
1107 }
1108
1109 return NULL;
1110 }
1111
1112
1113
1114
1115 // map in file and instantiate an ImageLoader
1116 static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path, const LoadContext& context)
1117 {
1118 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1119 uint64_t fileOffset = 0;
1120 uint64_t fileLength = stat_buf.st_size;
1121 #if __ppc64__
1122 if ( *((uint32_t*)((char*)(&stat_buf)+0x60)) == 0xFEFEFEFE )
1123 fileLength = *((uint64_t*)((char*)(&stat_buf)+0x30)); // HACK work around for kernel stat bug rdar://problem/3845883
1124 #endif
1125
1126 // validate it is a file (not directory)
1127 if ( (stat_buf.st_mode & S_IFMT) != S_IFREG )
1128 throw "not a file";
1129
1130 // min file is 4K
1131 if ( fileLength < 4096 ) {
1132 throw "file to short";
1133 }
1134
1135 uint8_t firstPage[4096];
1136 pread(fd, firstPage, 4096,0);
1137
1138 // if fat wrapper, find usable sub-file
1139 const fat_header* fileStartAsFat = (fat_header*)firstPage;
1140 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1141 if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
1142 pread(fd, firstPage, 4096, fileOffset);
1143 }
1144 else {
1145 throw "no matching architecture in fat wrapper";
1146 }
1147 }
1148
1149 // try mach-o loader
1150 if ( isCompatibleMachO(firstPage) ) {
1151 char realFilePath[PATH_MAX];
1152 if ( gLinkContext.slideAndPackDylibs ) {
1153 // when prebinding, we always want to track the real path of images
1154 if ( realpath(path, realFilePath) != NULL )
1155 path = realFilePath;
1156 }
1157
1158 // instantiate an image
1159 ImageLoader* image = new ImageLoaderMachO(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
1160
1161 // now sanity check that this loaded image does not have the same install path as any existing image
1162 const char* loadedImageInstallPath = image->getInstallPath();
1163 if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) {
1164 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
1165 ImageLoader* anImage = *it;
1166 const char* installPath = anImage->getInstallPath();
1167 if ( installPath != NULL) {
1168 if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
1169 //fprintf(stderr, "duplicate(%s) => %p\n", installPath, anImage);
1170 delete image;
1171 return anImage;
1172 }
1173 }
1174 }
1175 }
1176
1177 // some API's restrict what they can load
1178 if ( context.mustBeBundle && !image->isBundle() )
1179 throw "not a bundle";
1180 if ( context.mustBeDylib && !image->isDylib() )
1181 throw "not a dylib";
1182
1183 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
1184 if ( ! image->isBundle() )
1185 addImage(image);
1186
1187 return image;
1188 }
1189
1190 // try other file formats...
1191
1192 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
1193 firstPage[0], firstPage[1], firstPage[2], firstPage[3], firstPage[4], firstPage[5], firstPage[6],firstPage[7]);
1194 }
1195
1196
1197 // try to open file
1198 static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1199 {
1200 //fprintf(stdout, "%s(%s)\n", __func__, path);
1201 ImageLoader* image = NULL;
1202
1203 // open file (automagically closed when this function exits)
1204 FileOpener file(path);
1205
1206 //fprintf(stderr, "open(%s) => %d\n", path, file.getFileDescriptor() );
1207
1208 if ( file.getFileDescriptor() == -1 )
1209 return NULL;
1210
1211 struct stat stat_buf;
1212 #if __ppc64__
1213 memset(&stat_buf, 254, sizeof(struct stat)); // hack until rdar://problem/3845883 is fixed
1214 #endif
1215 if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
1216 throw "stat error";
1217
1218 // in case image was renamed or found via symlinks, check for inode match
1219 image = findLoadedImage(stat_buf);
1220 if ( image != NULL )
1221 return image;
1222
1223 // needed to implement NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
1224 if ( context.dontLoad )
1225 return NULL;
1226
1227 try {
1228 return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
1229 }
1230 catch (const char* msg) {
1231 char* newMsg = new char[strlen(msg) + strlen(path) + 8];
1232 sprintf(newMsg, "%s: %s", path, msg);
1233 exceptions->push_back(newMsg);
1234 return NULL;
1235 }
1236 }
1237
1238 // look for path match with existing loaded images
1239 static ImageLoader* loadPhase5check(const char* path, const LoadContext& context)
1240 {
1241 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1242 // search path against load-path and install-path of all already loaded images
1243 uint32_t hash = ImageLoader::hash(path);
1244 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
1245 ImageLoader* anImage = *it;
1246 // check has first to cut down on strcmp calls
1247 if ( anImage->getPathHash() == hash )
1248 if ( strcmp(path, anImage->getPath()) == 0 ) {
1249 // if we are looking for a dylib don't return something else
1250 if ( !context.mustBeDylib || anImage->isDylib() )
1251 return anImage;
1252 }
1253 if ( context.matchByInstallName || anImage->matchInstallPath() ) {
1254 const char* installPath = anImage->getInstallPath();
1255 if ( installPath != NULL) {
1256 if ( strcmp(path, installPath) == 0 ) {
1257 // if we are looking for a dylib don't return something else
1258 if ( !context.mustBeDylib || anImage->isDylib() )
1259 return anImage;
1260 }
1261 }
1262 }
1263 }
1264
1265 //fprintf(stderr, "check(%s) => NULL\n", path);
1266 return NULL;
1267 }
1268
1269
1270 // open or check existing
1271 static ImageLoader* loadPhase5(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1272 {
1273 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1274 if ( exceptions != NULL )
1275 return loadPhase5open(path, context, exceptions);
1276 else
1277 return loadPhase5check(path, context);
1278 }
1279
1280 // try with and without image suffix
1281 static ImageLoader* loadPhase4(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1282 {
1283 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1284 ImageLoader* image = NULL;
1285 if ( gLinkContext.imageSuffix != NULL ) {
1286 char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2];
1287 ImageLoader::addSuffix(path, gLinkContext.imageSuffix, pathWithSuffix);
1288 image = loadPhase5(pathWithSuffix, context, exceptions);
1289 }
1290 if ( image == NULL )
1291 image = loadPhase5(path, context, exceptions);
1292 return image;
1293 }
1294
1295
1296 // expand @ variables
1297 static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1298 {
1299 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1300 ImageLoader* image = NULL;
1301 if ( strncmp(path, "@executable_path/", 17) == 0 ) {
1302 // handle @executable_path path prefix
1303 const char* executablePath = sExecPath;
1304 char newPath[strlen(executablePath) + strlen(path)];
1305 strcpy(newPath, executablePath);
1306 char* addPoint = strrchr(newPath,'/');
1307 if ( addPoint != NULL )
1308 strcpy(&addPoint[1], &path[17]);
1309 else
1310 strcpy(newPath, &path[17]);
1311 image = loadPhase4(newPath, context, exceptions);
1312 if ( image != NULL )
1313 return image;
1314
1315 // perhaps main executable path is a sym link, find realpath and retry
1316 char resolvedPath[PATH_MAX];
1317 if ( realpath(sExecPath, resolvedPath) != NULL ) {
1318 char newRealPath[strlen(resolvedPath) + strlen(path)];
1319 strcpy(newRealPath, resolvedPath);
1320 char* addPoint = strrchr(newRealPath,'/');
1321 if ( addPoint != NULL )
1322 strcpy(&addPoint[1], &path[17]);
1323 else
1324 strcpy(newRealPath, &path[17]);
1325 image = loadPhase4(newRealPath, context, exceptions);
1326 if ( image != NULL )
1327 return image;
1328 }
1329 }
1330 else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) {
1331 // handle @loader_path path prefix
1332 char newPath[strlen(context.origin) + strlen(path)];
1333 strcpy(newPath, context.origin);
1334 char* addPoint = strrchr(newPath,'/');
1335 if ( addPoint != NULL )
1336 strcpy(&addPoint[1], &path[13]);
1337 else
1338 strcpy(newPath, &path[13]);
1339 image = loadPhase4(newPath, context, exceptions);
1340 if ( image != NULL )
1341 return image;
1342
1343 // perhaps loader path is a sym link, find realpath and retry
1344 char resolvedPath[PATH_MAX];
1345 if ( realpath(context.origin, resolvedPath) != NULL ) {
1346 char newRealPath[strlen(resolvedPath) + strlen(path)];
1347 strcpy(newRealPath, resolvedPath);
1348 char* addPoint = strrchr(newRealPath,'/');
1349 if ( addPoint != NULL )
1350 strcpy(&addPoint[1], &path[13]);
1351 else
1352 strcpy(newRealPath, &path[13]);
1353 image = loadPhase4(newRealPath, context, exceptions);
1354 if ( image != NULL )
1355 return image;
1356 }
1357 }
1358
1359 return loadPhase4(path, context, exceptions);
1360 }
1361
1362
1363 // try search paths
1364 static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
1365 const char* const frameworkPaths[], const char* const libraryPaths[],
1366 std::vector<const char*>* exceptions)
1367 {
1368 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1369 ImageLoader* image = NULL;
1370 const char* frameworkPartialPath = getFrameworkPartialPath(path);
1371 if ( frameworkPaths != NULL ) {
1372 if ( frameworkPartialPath != NULL ) {
1373 const int frameworkPartialPathLen = strlen(frameworkPartialPath);
1374 for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) {
1375 char npath[strlen(*fp)+frameworkPartialPathLen+8];
1376 strcpy(npath, *fp);
1377 strcat(npath, "/");
1378 strcat(npath, frameworkPartialPath);
1379 //fprintf(stderr, "dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
1380 image = loadPhase4(npath, context, exceptions);
1381 if ( image != NULL )
1382 return image;
1383 }
1384 }
1385 }
1386 if ( libraryPaths != NULL ) {
1387 const char* libraryLeafName = getLibraryLeafName(path);
1388 const int libraryLeafNameLen = strlen(libraryLeafName);
1389 for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
1390 char libpath[strlen(*lp)+libraryLeafNameLen+8];
1391 strcpy(libpath, *lp);
1392 strcat(libpath, "/");
1393 strcat(libpath, libraryLeafName);
1394 //fprintf(stderr, "dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
1395 image = loadPhase4(libpath, context, exceptions);
1396 if ( image != NULL )
1397 return image;
1398 }
1399 }
1400 return NULL;
1401 }
1402
1403 // try search overrides and fallbacks
1404 static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1405 {
1406 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1407 ImageLoader* image = NULL;
1408
1409 // handle LD_LIBRARY_PATH environment variables that force searching
1410 if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) {
1411 image = loadPhase2(path, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
1412 if ( image != NULL )
1413 return image;
1414 }
1415
1416 // handle DYLD_ environment variables that force searching
1417 if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) {
1418 image = loadPhase2(path, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, exceptions);
1419 if ( image != NULL )
1420 return image;
1421 }
1422
1423 // try raw path
1424 image = loadPhase3(path, context, exceptions);
1425 if ( image != NULL )
1426 return image;
1427
1428 // try fallback paths
1429 if ( (sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_FALLBACK_LIBRARY_PATH != NULL) ) {
1430 image = loadPhase2(path, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, sEnv.DYLD_FALLBACK_LIBRARY_PATH, exceptions);
1431 if ( image != NULL )
1432 return image;
1433 }
1434
1435 return NULL;
1436 }
1437
1438 // try root substitutions
1439 static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
1440 {
1441 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1442
1443 // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
1444 if ( (sEnv.DYLD_ROOT_PATH != NULL) && (path[0] == '/') ) {
1445 for(const char* const* rootPath = sEnv.DYLD_ROOT_PATH ; *rootPath != NULL; ++rootPath) {
1446 char newPath[strlen(*rootPath) + strlen(path)+2];
1447 strcpy(newPath, *rootPath);
1448 strcat(newPath, path);
1449 ImageLoader* image = loadPhase1(newPath, context, exceptions);
1450 if ( image != NULL )
1451 return image;
1452 }
1453 }
1454
1455 // try raw path
1456 return loadPhase1(path, context, exceptions);
1457 }
1458
1459 //
1460 // Given all the DYLD_ environment variables, the general case for loading libraries
1461 // is that any given path expands into a list of possible locations to load. We
1462 // also must take care to ensure two copies of the "same" library are never loaded.
1463 //
1464 // The algorithm used here is that there is a separate function for each "phase" of the
1465 // path expansion. Each phase function calls the next phase with each possible expansion
1466 // of that phase. The result is the last phase is called with all possible paths.
1467 //
1468 // To catch duplicates the algorithm is run twice. The first time, the last phase checks
1469 // the path against all loaded images. The second time, the last phase calls open() on
1470 // the path. Either time, if an image is found, the phases all unwind without checking
1471 // for other paths.
1472 //
1473 ImageLoader* load(const char* path, const LoadContext& context)
1474 {
1475 //fprintf(stderr, "%s(%s)\n", __func__ , path);
1476 char realPath[PATH_MAX];
1477 // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
1478 if ( context.useSearchPaths && ( gLinkContext.imageSuffix != NULL) ) {
1479 if ( realpath(path, realPath) != NULL )
1480 path = realPath;
1481 }
1482
1483 // try all path permutations and check against existing loaded images
1484 ImageLoader* image = loadPhase0(path, context, NULL);
1485 if ( image != NULL )
1486 return image;
1487
1488 // try all path permutations and try open() until first sucesss
1489 std::vector<const char*> exceptions;
1490 image = loadPhase0(path, context, &exceptions);
1491 if ( image != NULL )
1492 return image;
1493 else if ( context.dontLoad )
1494 return NULL;
1495 else if ( exceptions.size() == 0 )
1496 throw "image not found";
1497 else {
1498 const char* msgStart = "no suitable image found. Did find:";
1499 const char* delim = "\n\t";
1500 size_t allsizes = strlen(msgStart)+8;
1501 for (unsigned int i=0; i < exceptions.size(); ++i)
1502 allsizes += (strlen(exceptions[i]) + strlen(delim));
1503 char* fullMsg = new char[allsizes];
1504 strcpy(fullMsg, msgStart);
1505 for (unsigned int i=0; i < exceptions.size(); ++i) {
1506 strcat(fullMsg, delim);
1507 strcat(fullMsg, exceptions[i]);
1508 }
1509 throw (const char*)fullMsg;
1510 }
1511 }
1512
1513
1514
1515
1516 // create when NSLinkModule is called for a second time on a bundle
1517 ImageLoader* cloneImage(ImageLoader* image)
1518 {
1519 const uint64_t offsetInFat = image->getOffsetInFatFile();
1520
1521 // open file (automagically closed when this function exits)
1522 FileOpener file(image->getPath());
1523
1524 struct stat stat_buf;
1525 #if __ppc64__
1526 memset(&stat_buf, 254, sizeof(struct stat)); // hack until rdar://problem/3845883 is fixed
1527 #endif
1528 if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
1529 throw "stat error";
1530
1531 // read first page of file
1532 uint8_t firstPage[4096];
1533 pread(file.getFileDescriptor(), firstPage, 4096, offsetInFat);
1534
1535 // fat length is only used for sanity checking, since this image was already loaded once, just use upper bound
1536 uint64_t lenInFat = stat_buf.st_size - offsetInFat;
1537
1538 // try mach-o loader
1539 if ( isCompatibleMachO(firstPage) ) {
1540 ImageLoader* clone = new ImageLoaderMachO(image->getPath(), file.getFileDescriptor(), firstPage, offsetInFat, lenInFat, stat_buf, gLinkContext);
1541 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
1542 if ( ! image->isBundle() )
1543 addImage(clone);
1544 return clone;
1545 }
1546
1547 // try other file formats...
1548 throw "can't clone image";
1549 }
1550
1551
1552 ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName)
1553 {
1554 // try mach-o each loader
1555 if ( isCompatibleMachO(mem) ) {
1556 ImageLoader* image = new ImageLoaderMachO(moduleName, (mach_header*)mem, len, gLinkContext);
1557 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
1558 if ( ! image->isBundle() )
1559 addImage(image);
1560 return image;
1561 }
1562
1563 // try other file formats...
1564
1565 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
1566 mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6],mem[7]);
1567 }
1568
1569
1570 void registerAddCallback(ImageCallback func)
1571 {
1572 // now add to list to get notified when any more images are added
1573 sAddImageCallbacks.push_back(func);
1574
1575 // call callback with all existing images, starting at roots
1576 const int rootCount = sImageRoots.size();
1577 for(int i=0; i < rootCount; ++i) {
1578 ImageLoader* image = sImageRoots[i];
1579 image->runNotification(gLinkContext, sAddImageCallbacks.size());
1580 }
1581
1582 // for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
1583 // ImageLoader* image = *it;
1584 // image->runNotification(gLinkContext, sAddImageCallbacks.size());
1585 // }
1586 }
1587
1588 void registerRemoveCallback(ImageCallback func)
1589 {
1590 sRemoveImageCallbacks.push_back(func);
1591 }
1592
1593 void clearErrorMessage()
1594 {
1595 error_string[0] = '\0';
1596 }
1597
1598 void setErrorMessage(const char* message)
1599 {
1600 // save off error message in global buffer for CrashReporter to find
1601 strncpy(error_string, message, sizeof(error_string)-1);
1602 error_string[sizeof(error_string)-1] = '\0';
1603 }
1604
1605 const char* getErrorMessage()
1606 {
1607 return error_string;
1608 }
1609
1610 void halt(const char* message)
1611 {
1612 fprintf(stderr, "dyld: %s\n", message);
1613 setErrorMessage(message);
1614 strncpy(error_string, message, sizeof(error_string)-1);
1615 error_string[sizeof(error_string)-1] = '\0';
1616
1617 #if __ppc__ || __ppc64__
1618 __asm__ ("trap");
1619 #elif __i386__
1620 __asm__ ("int3");
1621 #else
1622 #error unknown architecture
1623 #endif
1624 abort(); // needed to suppress warning that noreturn function returns
1625 }
1626
1627
1628 uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
1629 {
1630 uintptr_t result = 0;
1631 // acquire read-lock on dyld's data structures
1632 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
1633 if ( gThreadHelpers != NULL )
1634 (*gThreadHelpers->lockForReading)();
1635 #endif
1636 // lookup and bind lazy pointer and get target address
1637 try {
1638 // note, target should always be mach-o, because only mach-o lazy handler wired up to this
1639 ImageLoader* target = dyld::findImageByMachHeader(mh);
1640 if ( target == NULL )
1641 throw "image not found for lazy pointer";
1642 result = target->doBindLazySymbol(lazyPointer, gLinkContext);
1643 }
1644 catch (const char* message) {
1645 fprintf(stderr, "dyld: lazy symbol binding failed: %s\n", message);
1646 halt(message);
1647 }
1648 // release read-lock on dyld's data structures
1649 #if 0
1650 if ( gThreadHelpers != NULL )
1651 (*gThreadHelpers->unlockForReading)();
1652 #endif
1653 // return target address to glue which jumps to it with real parameters restored
1654 return result;
1655 }
1656
1657
1658 // SPI used by ZeroLink to lazy load bundles
1659 void registerZeroLinkHandlers(BundleNotificationCallBack notify, BundleLocatorCallBack locate)
1660 {
1661 sBundleNotifier = notify;
1662 sBundleLocation = locate;
1663 }
1664
1665 void registerUndefinedHandler(UndefinedHandler handler)
1666 {
1667 sUndefinedHandler = handler;
1668 }
1669
1670 static void undefinedHandler(const char* symboName)
1671 {
1672 if ( sUndefinedHandler != NULL ) {
1673 (*sUndefinedHandler)(symboName);
1674 }
1675 }
1676
1677 static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, ImageLoader** image)
1678 {
1679 // try ZeroLink short cut to finding bundle which exports this symbol
1680 if ( sBundleLocation != NULL ) {
1681 ImageLoader* zlImage = (*sBundleLocation)(name);
1682 if ( zlImage == ((ImageLoader*)(-1)) ) {
1683 // -1 is magic value that request symbol is in a bundle not yet linked into process
1684 // try calling handler to link in that symbol
1685 undefinedHandler(name);
1686 // call locator again
1687 zlImage = (*sBundleLocation)(name);
1688 }
1689 // if still not found, then ZeroLink has no idea where to find it
1690 if ( zlImage == ((ImageLoader*)(-1)) )
1691 return false;
1692 if ( zlImage != NULL ) {
1693 // ZeroLink cache knows where the symbol is
1694 *sym = zlImage->findExportedSymbol(name, NULL, false, image);
1695 if ( *sym != NULL ) {
1696 *image = zlImage;
1697 return true;
1698 }
1699 }
1700 else {
1701 // ZeroLink says it is in some bundle already loaded, but not linked, walk them all
1702 const unsigned int imageCount = sAllImages.size();
1703 for(unsigned int i=0; i < imageCount; ++i){
1704 ImageLoader* anImage = sAllImages[i];
1705 if ( anImage->isBundle() && !anImage->hasHiddenExports() ) {
1706 //fprintf(stderr, "dyld: search for %s in %s\n", name, anImage->getPath());
1707 *sym = anImage->findExportedSymbol(name, NULL, false, image);
1708 if ( *sym != NULL ) {
1709 return true;
1710 }
1711 }
1712 }
1713 }
1714 }
1715
1716 // search all images in order
1717 ImageLoader* firstWeakImage = NULL;
1718 const ImageLoader::Symbol* firstWeakSym = NULL;
1719 const unsigned int imageCount = sAllImages.size();
1720 for(unsigned int i=0; i < imageCount; ++i){
1721 ImageLoader* anImage = sAllImages[i];
1722 if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) {
1723 *sym = anImage->findExportedSymbol(name, NULL, false, image);
1724 if ( *sym != NULL ) {
1725 // if weak definition found, record first one found
1726 if ( ((*image)->getExportedSymbolInfo(*sym) & ImageLoader::kWeakDefinition) != 0 ) {
1727 if ( firstWeakImage == NULL ) {
1728 firstWeakImage = *image;
1729 firstWeakSym = *sym;
1730 }
1731 }
1732 else {
1733 // found non-weak, so immediately return with it
1734 return true;
1735 }
1736 }
1737 }
1738 }
1739 if ( firstWeakSym != NULL ) {
1740 // found a weak definition, but no non-weak, so return first weak found
1741 *sym = firstWeakSym;
1742 *image = firstWeakImage;
1743 return true;
1744 }
1745
1746 return false;
1747 }
1748
1749 bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image)
1750 {
1751 return findExportedSymbol(name, false, sym, image);
1752 }
1753
1754 bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image)
1755 {
1756 return findExportedSymbol(name, true, sym, image);
1757 }
1758
1759
1760 bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, ImageLoader** image)
1761 {
1762 // search all images in order
1763 const unsigned int imageCount = sAllImages.size();
1764 for(unsigned int i=0; i < imageCount; ++i){
1765 ImageLoader* anImage = sAllImages[i];
1766 // only look at images whose paths contain the hint string (NULL hint string is wildcard)
1767 if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
1768 *sym = anImage->findExportedSymbol(name, NULL, false, image);
1769 if ( *sym != NULL ) {
1770 return true;
1771 }
1772 }
1773 }
1774 return false;
1775 }
1776
1777 static void getMappedRegions(ImageLoader::RegionsVector& regions)
1778 {
1779 const unsigned int imageCount = sAllImages.size();
1780 for(unsigned int i=0; i < imageCount; ++i){
1781 ImageLoader* anImage = sAllImages[i];
1782 anImage->addMappedRegions(regions);
1783 }
1784 }
1785
1786
1787 static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const char* rpath[])
1788 {
1789 dyld::LoadContext context;
1790 context.useSearchPaths = search;
1791 context.useLdLibraryPath = false;
1792 context.dontLoad = false;
1793 context.mustBeBundle = false;
1794 context.mustBeDylib = true;
1795 context.matchByInstallName = false;
1796 context.origin = origin;
1797 context.rpath = rpath;
1798 return load(libraryName, context);
1799 }
1800
1801
1802 static void setContext(int argc, const char* argv[], const char* envp[], const char* apple[])
1803 {
1804 gLinkContext.loadLibrary = &libraryLocator;
1805 gLinkContext.imageNotification = &imageNotification;
1806 gLinkContext.terminationRecorder = &terminationRecorder;
1807 gLinkContext.flatExportFinder = &flatFindExportedSymbol;
1808 gLinkContext.coalescedExportFinder = &findCoalescedExportedSymbol;
1809 gLinkContext.undefinedHandler = &undefinedHandler;
1810 gLinkContext.addImageNeedingNotification = &addImageNeedingNotification;
1811 gLinkContext.notifyAdding = &notifyAdding;
1812 gLinkContext.getAllMappedRegions = &getMappedRegions;
1813 gLinkContext.bindingHandler = NULL;
1814 gLinkContext.bindingOptions = ImageLoader::kBindingNone;
1815 gLinkContext.mainExecutable = sMainExecutable;
1816 gLinkContext.argc = argc;
1817 gLinkContext.argv = argv;
1818 gLinkContext.envp = envp;
1819 gLinkContext.apple = apple;
1820 }
1821
1822
1823
1824 void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader::InitializerRunning runInitializers)
1825 {
1826 // add to list of known images. This did not happen at creation time for bundles
1827 if ( image->isBundle() )
1828 addImage(image);
1829
1830 // we detect root images as those not linked in yet
1831 if ( !image->isLinked() )
1832 addRootImage(image);
1833
1834 // notify ZeroLink of new image with concat of logical and physical name
1835 if ( sBundleNotifier != NULL && image->isBundle() ) {
1836 const int logicalLen = strlen(image->getLogicalPath());
1837 char logAndPhys[strlen(image->getPath())+logicalLen+2];
1838 strcpy(logAndPhys, image->getLogicalPath());
1839 strcpy(&logAndPhys[logicalLen+1], image->getPath());
1840 (*sBundleNotifier)(logAndPhys, image);
1841 }
1842
1843 // process images
1844 image->link(gLinkContext, bindness, runInitializers, sAddImageCallbacks.size());
1845
1846 #if OLD_GDB_DYLD_INTERFACE
1847 // notify gdb that loaded libraries have changed
1848 gdb_dyld_state_changed();
1849 #endif
1850 }
1851
1852
1853 //
1854 // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
1855 // sets up some registers and call this function.
1856 //
1857 // Returns address of main() in target program which __dyld_start jumps to
1858 //
1859 uintptr_t
1860 _main(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
1861 {
1862 // Pickup the pointer to the exec path.
1863 const char* executable = apple[0];
1864 if ( executable[0] == '/' ) {
1865 // have full path, use it
1866 sExecPath = executable;
1867 }
1868 else {
1869 // have relative path, use cwd to make absolute
1870 char cwdbuff[MAXPATHLEN];
1871 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
1872 // maybe use static buffer to avoid calling malloc so early...
1873 char* s = new char[strlen(cwdbuff) + strlen(executable) + 2];
1874 strcpy(s, cwdbuff);
1875 strcat(s, "/");
1876 strcat(s, executable);
1877 sExecPath = s;
1878 }
1879 }
1880 uintptr_t result = 0;
1881 sMainExecutableMachHeader = mainExecutableMH;
1882 checkEnvironmentVariables(envp);
1883 if ( sEnv.DYLD_PRINT_OPTS )
1884 printOptions(argv);
1885 if ( sEnv.DYLD_PRINT_ENV )
1886 printEnvironmentVariables(envp);
1887 getHostInfo();
1888 setContext(argc, argv, envp, apple);
1889 ImageLoader::BindingLaziness bindness = sEnv.DYLD_BIND_AT_LAUNCH ? ImageLoader::kLazyAndNonLazy : ImageLoader::kNonLazyOnly;
1890
1891 // load any inserted libraries before loading the main executable so that they are first in flat namespace
1892 int insertLibrariesCount = 0;
1893 if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
1894 for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) {
1895 insertLibrariesCount++;
1896 }
1897 }
1898 ImageLoader* insertedImages[insertLibrariesCount];
1899 if ( insertLibrariesCount > 0 ) {
1900 for (int i=0; i < insertLibrariesCount; ++i) {
1901 try {
1902 LoadContext context;
1903 context.useSearchPaths = false;
1904 context.useLdLibraryPath = false;
1905 context.dontLoad = false;
1906 context.mustBeBundle = false;
1907 context.mustBeDylib = true;
1908 context.matchByInstallName = false;
1909 context.origin = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
1910 context.rpath = NULL;
1911 insertedImages[i] = load(sEnv.DYLD_INSERT_LIBRARIES[i], context);
1912 }
1913 catch (...) {
1914 char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50];
1915 sprintf(buf, "could not load inserted library: %s\n", sEnv.DYLD_INSERT_LIBRARIES[i]);
1916 insertedImages[i] = NULL;
1917 halt(buf);
1918 }
1919 }
1920 }
1921
1922 // load and link main executable
1923 try {
1924 sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, sExecPath);
1925 gLinkContext.mainExecutable = sMainExecutable;
1926 if ( sMainExecutable->forceFlat() ) {
1927 gLinkContext.bindFlat = true;
1928 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
1929 }
1930 link(sMainExecutable, bindness, ImageLoader::kDontRunInitializers);
1931 result = (uintptr_t)sMainExecutable->getMain();
1932 }
1933 catch(const char* message) {
1934 halt(message);
1935 }
1936 catch(...) {
1937 fprintf(stderr, "dyld: launch failed\n");
1938 }
1939
1940 // Link in any inserted libraries.
1941 // Do this after link main executable so any extra libraries pulled in by inserted libraries are at end of flat namespace
1942 if ( insertLibrariesCount > 0 ) {
1943 for (int i=0; i < insertLibrariesCount; ++i) {
1944 try {
1945 if ( insertedImages[i] != NULL )
1946 link(insertedImages[i], bindness, ImageLoader::kDontRunInitializers);
1947 }
1948 catch (const char* message) {
1949 char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50+strlen(message)];
1950 sprintf(buf, "could not link inserted library: %s\n%s\n", sEnv.DYLD_INSERT_LIBRARIES[i], message);
1951 halt(buf);
1952 }
1953 }
1954 }
1955
1956 return result;
1957 }
1958
1959
1960
1961
1962 }; // namespace
1963
1964
1965