From 0959b6d4289bd106fddb7fe7d84a346159895fdd Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 13 Apr 2005 15:47:24 +0000 Subject: [PATCH 1/1] dyld-43.tar.gz --- APPLE_LICENSE | 367 +++ doc/man/man1/dyld.1 | 253 ++ doc/man/man3/NSModule.3 | 610 ++++ doc/man/man3/NSObjectFileImage.3 | 151 + doc/man/man3/NSObjectFileImage_priv.3 | 42 + doc/man/man3/dladdr.3 | 73 + doc/man/man3/dlclose.3 | 38 + doc/man/man3/dlerror.3 | 32 + doc/man/man3/dlopen.3 | 128 + doc/man/man3/dlsym.3 | 65 + doc/man/man3/dyld.3 | 200 ++ dyld.xcode/project.pbxproj | 1044 +++++++ include/dlfcn.h | 78 + include/mach-o/dyld.h | 321 +++ include/mach-o/dyld_debug.h | 247 ++ include/mach-o/dyld_gdb.h | 167 ++ include/mach-o/dyld_priv.h | 60 + src/ImageLoader.cpp | 1015 +++++++ src/ImageLoader.h | 460 +++ src/ImageLoaderMachO.cpp | 2463 +++++++++++++++++ src/ImageLoaderMachO.h | 209 ++ src/dyld.cpp | 1965 +++++++++++++ src/dyld.exp | 52 + src/dyld.h | 94 + src/dyldAPIs.cpp | 1608 +++++++++++ src/dyldAPIsInLibSystem.cpp | 1133 ++++++++ src/dyldExceptions.c | 212 ++ src/dyldInitialization.cpp | 256 ++ src/dyldLibSystemThreadHelpers.h | 52 + src/dyldLock.cpp | 287 ++ src/dyldLock.h | 87 + src/dyldNew.cpp | 74 + src/dyldStartup.s | 191 ++ src/dyld_debug.c | 249 ++ src/dyld_gdb.cpp | 227 ++ src/glue.c | 129 + src/stub_binding_helper.s | 123 + unit-tests/bin/exit-non-zero-pass.pl | 33 + unit-tests/bin/exit-zero-pass.pl | 33 + unit-tests/bin/make-recursive.pl | 119 + unit-tests/bin/result-filter.pl | 120 + unit-tests/include/common.makefile | 12 + unit-tests/include/test.h | 35 + unit-tests/run-all-unit-tests | 28 + .../NSAddImage-MATCH_BY_INSTALLNAME/Makefile | 41 + .../NSAddImage-MATCH_BY_INSTALLNAME/bar.c | 23 + .../NSAddImage-MATCH_BY_INSTALLNAME/foo.c | 23 + .../NSAddImage-MATCH_BY_INSTALLNAME/main.c | 41 + .../NSAddImage-RETURN_ONLY_IF_LOADED/Makefile | 35 + .../NSAddImage-RETURN_ONLY_IF_LOADED/main.c | 40 + .../test-cases/NSAddImage-leafname/Makefile | 40 + .../test-cases/NSAddImage-leafname/main.c | 40 + .../test-cases/NSAddImage-leafname/zzz.c | 23 + unit-tests/test-cases/bundle-basic/Makefile | 39 + unit-tests/test-cases/bundle-basic/bundle.c | 32 + unit-tests/test-cases/bundle-basic/main.c | 69 + .../test-cases/bundle-memory-load/Makefile | 39 + .../test-cases/bundle-memory-load/bundle.c | 32 + .../test-cases/bundle-memory-load/main.c | 96 + .../test-cases/bundle-multi-link/Makefile | 40 + .../test-cases/bundle-multi-link/bundle.c | 35 + .../test-cases/bundle-multi-link/main.c | 178 ++ .../test-cases/bundle-multi-load/Makefile | 40 + .../test-cases/bundle-multi-load/bundle.c | 27 + .../test-cases/bundle-multi-load/main.c | 154 ++ unit-tests/test-cases/bundle-private/Makefile | 39 + unit-tests/test-cases/bundle-private/bundle.c | 28 + unit-tests/test-cases/bundle-private/main.c | 95 + .../test-cases/bundle-unlinkable/Makefile | 42 + .../test-cases/bundle-unlinkable/bundle.c | 30 + unit-tests/test-cases/bundle-unlinkable/lib.c | 29 + .../test-cases/bundle-unlinkable/main.c | 67 + .../bundle-unload-keep-mapped/Makefile | 39 + .../bundle-unload-keep-mapped/bundle.c | 32 + .../bundle-unload-keep-mapped/main.c | 73 + unit-tests/test-cases/bundle-v-dylib/Makefile | 45 + unit-tests/test-cases/bundle-v-dylib/bar.c | 29 + unit-tests/test-cases/bundle-v-dylib/foo.c | 29 + unit-tests/test-cases/bundle-v-dylib/main.c | 66 + unit-tests/test-cases/deadlock/Makefile | 42 + unit-tests/test-cases/deadlock/bar.c | 28 + unit-tests/test-cases/deadlock/foo.c | 28 + unit-tests/test-cases/deadlock/main.c | 115 + unit-tests/test-cases/dladdr/Makefile | 34 + unit-tests/test-cases/dladdr/main.c | 111 + unit-tests/test-cases/dlclose-basic/Makefile | 41 + unit-tests/test-cases/dlclose-basic/foo.c | 26 + unit-tests/test-cases/dlclose-basic/main.c | 63 + .../test-cases/dlclose-bundle-unload/Makefile | 42 + .../test-cases/dlclose-bundle-unload/foo.c | 28 + .../test-cases/dlclose-bundle-unload/main.c | 84 + unit-tests/test-cases/dlerror/Makefile | 38 + unit-tests/test-cases/dlerror/main.c | 93 + .../dlopen-DYLD_LIBRARY_PATH/Makefile | 47 + .../test-cases/dlopen-DYLD_LIBRARY_PATH/foo.c | 32 + .../dlopen-DYLD_LIBRARY_PATH/main.c | 61 + .../dlopen-LD_LIBRARY_PATH/Makefile | 70 + .../test-cases/dlopen-LD_LIBRARY_PATH/foo.c | 28 + .../test-cases/dlopen-LD_LIBRARY_PATH/main.c | 64 + .../test-cases/dlopen-RTLD_GLOBAL/Makefile | 47 + .../test-cases/dlopen-RTLD_GLOBAL/bar.c | 31 + .../test-cases/dlopen-RTLD_GLOBAL/foo.c | 25 + .../test-cases/dlopen-RTLD_GLOBAL/main.c | 51 + .../dlopen-RTLD_LOCAL-ignore/Makefile | 44 + .../test-cases/dlopen-RTLD_LOCAL-ignore/bar.c | 30 + .../test-cases/dlopen-RTLD_LOCAL-ignore/foo.c | 28 + .../dlopen-RTLD_LOCAL-ignore/main.c | 93 + .../test-cases/dlopen-RTLD_LOCAL/Makefile | 47 + unit-tests/test-cases/dlopen-RTLD_LOCAL/bar.c | 31 + unit-tests/test-cases/dlopen-RTLD_LOCAL/foo.c | 25 + .../test-cases/dlopen-RTLD_LOCAL/main.c | 61 + .../test-cases/dlopen-RTLD_NODELETE/Makefile | 45 + .../test-cases/dlopen-RTLD_NODELETE/foo.c | 25 + .../test-cases/dlopen-RTLD_NODELETE/main.c | 74 + .../test-cases/dlopen-RTLD_NOLOAD/Makefile | 42 + .../test-cases/dlopen-RTLD_NOLOAD/foo.c | 28 + .../test-cases/dlopen-RTLD_NOLOAD/main.c | 67 + .../test-cases/dlopen-RTLD_NOW/Makefile | 47 + .../test-cases/dlopen-RTLD_NOW/bundle.c | 32 + unit-tests/test-cases/dlopen-RTLD_NOW/foo.c | 35 + unit-tests/test-cases/dlopen-RTLD_NOW/main.c | 53 + unit-tests/test-cases/dlopen-basic/Makefile | 45 + unit-tests/test-cases/dlopen-basic/foo.c | 28 + unit-tests/test-cases/dlopen-basic/main.c | 67 + .../test-cases/dlopen-initializer/Makefile | 45 + .../test-cases/dlopen-initializer/bar.c | 37 + .../test-cases/dlopen-initializer/foo.c | 38 + .../test-cases/dlopen-initializer/main.c | 63 + .../dlopen-local-and-global/Makefile | 46 + .../test-cases/dlopen-local-and-global/bar.c | 31 + .../test-cases/dlopen-local-and-global/foo.c | 25 + .../test-cases/dlopen-local-and-global/main.c | 76 + unit-tests/test-cases/dlopen-multi/Makefile | 45 + unit-tests/test-cases/dlopen-multi/foo.c | 28 + unit-tests/test-cases/dlopen-multi/main.c | 72 + unit-tests/test-cases/dlopen-zero/Makefile | 37 + unit-tests/test-cases/dlopen-zero/main.c | 59 + .../test-cases/dlsym-RTLD_DEFAULT/Makefile | 45 + .../test-cases/dlsym-RTLD_DEFAULT/foo.c | 52 + .../test-cases/dlsym-RTLD_DEFAULT/main.c | 71 + .../test-cases/dlsym-RTLD_NEXT/Makefile | 49 + unit-tests/test-cases/dlsym-RTLD_NEXT/foo.c | 28 + unit-tests/test-cases/dlsym-RTLD_NEXT/main.c | 93 + unit-tests/test-cases/dlsym-RTLD_NEXT/test.c | 36 + .../test-cases/dlsym-RTLD_SELF/Makefile | 49 + unit-tests/test-cases/dlsym-RTLD_SELF/foo.c | 28 + unit-tests/test-cases/dlsym-RTLD_SELF/main.c | 84 + unit-tests/test-cases/dlsym-RTLD_SELF/test.c | 40 + unit-tests/test-cases/dlsym-error/Makefile | 37 + unit-tests/test-cases/dlsym-error/main.c | 55 + unit-tests/test-cases/dlsym-indirect/Makefile | 53 + unit-tests/test-cases/dlsym-indirect/foo.c | 28 + unit-tests/test-cases/dlsym-indirect/foo1.c | 28 + unit-tests/test-cases/dlsym-indirect/foo2.c | 28 + unit-tests/test-cases/dlsym-indirect/foo3.c | 28 + unit-tests/test-cases/dlsym-indirect/main.c | 80 + .../dyld-launched-prebound/Makefile | 34 + .../test-cases/dyld-launched-prebound/main.c | 34 + unit-tests/test-cases/dyld-slide/Makefile | 33 + unit-tests/test-cases/dyld-slide/main.c | 46 + .../test-cases/fallback-with-suid/Makefile | 46 + .../test-cases/fallback-with-suid/foo.c | 23 + .../test-cases/fallback-with-suid/main.c | 53 + unit-tests/test-cases/flat-data/Makefile | 42 + unit-tests/test-cases/flat-data/bar.c | 24 + unit-tests/test-cases/flat-data/getbar.c | 30 + unit-tests/test-cases/flat-data/main.c | 46 + .../flat-lookup-everywhere/Makefile | 34 + .../test-cases/flat-lookup-everywhere/main.c | 35 + unit-tests/test-cases/flat-prebound/Makefile | 46 + unit-tests/test-cases/flat-prebound/bar.c | 28 + unit-tests/test-cases/flat-prebound/foo.c | 29 + unit-tests/test-cases/flat-prebound/main.c | 48 + .../test-cases/framework-fallback/Makefile | 37 + .../test-cases/framework-fallback/main.c | 51 + .../test-cases/ignore-bad-files/Makefile | 71 + unit-tests/test-cases/ignore-bad-files/foo.c | 23 + unit-tests/test-cases/ignore-bad-files/main.c | 35 + unit-tests/test-cases/image-suffix/Makefile | 152 + unit-tests/test-cases/image-suffix/foo.c | 28 + unit-tests/test-cases/image-suffix/main.c | 45 + unit-tests/test-cases/init-order/Makefile | 41 + unit-tests/test-cases/init-order/base.c | 63 + unit-tests/test-cases/init-order/base.h | 27 + unit-tests/test-cases/init-order/foo1.c | 51 + unit-tests/test-cases/init-order/foo2.c | 33 + unit-tests/test-cases/init-order/foo3.c | 35 + unit-tests/test-cases/init-order/main.c | 37 + .../test-cases/initializer-args/Makefile | 34 + unit-tests/test-cases/initializer-args/main.c | 58 + .../Makefile | 35 + .../insert-libraries-with-initializer/foo.c | 35 + .../insert-libraries-with-initializer/main.c | 33 + .../insert-libraries-with-suid/Makefile | 38 + .../insert-libraries-with-suid/main.c | 44 + .../test-cases/lazy-pointer-binding/Makefile | 41 + .../test-cases/lazy-pointer-binding/foo.c | 75 + .../test-cases/lazy-pointer-binding/main.c | 52 + .../test-cases/lib-name-overload/Makefile | 59 + unit-tests/test-cases/lib-name-overload/foo.c | 25 + .../test-cases/lib-name-overload/foo2.c | 26 + .../test-cases/lib-name-overload/main.c | 39 + .../test-cases/loader_path-dup/Makefile | 66 + unit-tests/test-cases/loader_path-dup/bar.c | 30 + unit-tests/test-cases/loader_path-dup/base.c | 29 + unit-tests/test-cases/loader_path-dup/foo.c | 31 + unit-tests/test-cases/loader_path-dup/main.c | 40 + unit-tests/test-cases/loader_path/Makefile | 52 + unit-tests/test-cases/loader_path/bar.c | 23 + unit-tests/test-cases/loader_path/foo.c | 25 + unit-tests/test-cases/loader_path/main.c | 36 + .../Foo.c | 22 + .../Makefile | 48 + .../main.c | 33 + .../test-cases/non-weak-library/Makefile | 39 + unit-tests/test-cases/non-weak-library/foo.c | 26 + unit-tests/test-cases/non-weak-library/main.c | 39 + .../test-cases/partial-library-load/Makefile | 57 + .../test-cases/partial-library-load/bar.c | 30 + .../test-cases/partial-library-load/bundle.c | 30 + .../test-cases/partial-library-load/foo.c | 33 + .../test-cases/partial-library-load/main.c | 65 + unit-tests/test-cases/sym-link-load/Makefile | 83 + unit-tests/test-cases/sym-link-load/base.c | 52 + unit-tests/test-cases/sym-link-load/base.h | 27 + unit-tests/test-cases/sym-link-load/link.c | 25 + unit-tests/test-cases/sym-link-load/main.c | 37 + unit-tests/test-cases/sym-link-load/test.c | 36 + unit-tests/test-cases/text-relocs/Makefile | 46 + unit-tests/test-cases/text-relocs/bar.c | 35 + unit-tests/test-cases/text-relocs/foo.s | 30 + unit-tests/test-cases/text-relocs/main.c | 40 + .../test-cases/weak-coalesce-c++/Makefile | 53 + unit-tests/test-cases/weak-coalesce-c++/a.h | 28 + unit-tests/test-cases/weak-coalesce-c++/a1.cc | 4 + unit-tests/test-cases/weak-coalesce-c++/a2.cc | 4 + .../test-cases/weak-coalesce-c++/main.cc | 20 + unit-tests/test-cases/weak-coalesce/Makefile | 52 + unit-tests/test-cases/weak-coalesce/base.c | 83 + unit-tests/test-cases/weak-coalesce/base.h | 31 + unit-tests/test-cases/weak-coalesce/foo1.c | 39 + unit-tests/test-cases/weak-coalesce/foo2.c | 35 + unit-tests/test-cases/weak-coalesce/foo3.c | 35 + unit-tests/test-cases/weak-coalesce/main.c | 42 + unit-tests/test-cases/weak-library/Makefile | 39 + unit-tests/test-cases/weak-library/foo.c | 28 + unit-tests/test-cases/weak-library/foo.h | 23 + unit-tests/test-cases/weak-library/main.c | 32 + unit-tests/test-cases/weak-override/Makefile | 41 + unit-tests/test-cases/weak-override/foo.c | 35 + unit-tests/test-cases/weak-override/main.c | 47 + .../test-cases/weak-symbol-flat/Makefile | 44 + unit-tests/test-cases/weak-symbol-flat/foo.c | 32 + unit-tests/test-cases/weak-symbol-flat/foo.h | 25 + unit-tests/test-cases/weak-symbol-flat/main.c | 48 + unit-tests/test-cases/weak-symbol/Makefile | 35 + unit-tests/test-cases/weak-symbol/foo.c | 28 + unit-tests/test-cases/weak-symbol/foo.h | 25 + unit-tests/test-cases/weak-symbol/main.c | 36 + 259 files changed, 24625 insertions(+) create mode 100644 APPLE_LICENSE create mode 100644 doc/man/man1/dyld.1 create mode 100644 doc/man/man3/NSModule.3 create mode 100644 doc/man/man3/NSObjectFileImage.3 create mode 100644 doc/man/man3/NSObjectFileImage_priv.3 create mode 100644 doc/man/man3/dladdr.3 create mode 100644 doc/man/man3/dlclose.3 create mode 100644 doc/man/man3/dlerror.3 create mode 100644 doc/man/man3/dlopen.3 create mode 100644 doc/man/man3/dlsym.3 create mode 100644 doc/man/man3/dyld.3 create mode 100644 dyld.xcode/project.pbxproj create mode 100644 include/dlfcn.h create mode 100644 include/mach-o/dyld.h create mode 100644 include/mach-o/dyld_debug.h create mode 100644 include/mach-o/dyld_gdb.h create mode 100644 include/mach-o/dyld_priv.h create mode 100644 src/ImageLoader.cpp create mode 100644 src/ImageLoader.h create mode 100644 src/ImageLoaderMachO.cpp create mode 100644 src/ImageLoaderMachO.h create mode 100644 src/dyld.cpp create mode 100644 src/dyld.exp create mode 100644 src/dyld.h create mode 100644 src/dyldAPIs.cpp create mode 100644 src/dyldAPIsInLibSystem.cpp create mode 100644 src/dyldExceptions.c create mode 100644 src/dyldInitialization.cpp create mode 100644 src/dyldLibSystemThreadHelpers.h create mode 100644 src/dyldLock.cpp create mode 100644 src/dyldLock.h create mode 100644 src/dyldNew.cpp create mode 100644 src/dyldStartup.s create mode 100644 src/dyld_debug.c create mode 100644 src/dyld_gdb.cpp create mode 100644 src/glue.c create mode 100644 src/stub_binding_helper.s create mode 100755 unit-tests/bin/exit-non-zero-pass.pl create mode 100755 unit-tests/bin/exit-zero-pass.pl create mode 100755 unit-tests/bin/make-recursive.pl create mode 100755 unit-tests/bin/result-filter.pl create mode 100644 unit-tests/include/common.makefile create mode 100644 unit-tests/include/test.h create mode 100755 unit-tests/run-all-unit-tests create mode 100644 unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/Makefile create mode 100644 unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/bar.c create mode 100644 unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/foo.c create mode 100644 unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/main.c create mode 100644 unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/Makefile create mode 100644 unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/main.c create mode 100644 unit-tests/test-cases/NSAddImage-leafname/Makefile create mode 100644 unit-tests/test-cases/NSAddImage-leafname/main.c create mode 100644 unit-tests/test-cases/NSAddImage-leafname/zzz.c create mode 100644 unit-tests/test-cases/bundle-basic/Makefile create mode 100644 unit-tests/test-cases/bundle-basic/bundle.c create mode 100644 unit-tests/test-cases/bundle-basic/main.c create mode 100644 unit-tests/test-cases/bundle-memory-load/Makefile create mode 100644 unit-tests/test-cases/bundle-memory-load/bundle.c create mode 100644 unit-tests/test-cases/bundle-memory-load/main.c create mode 100644 unit-tests/test-cases/bundle-multi-link/Makefile create mode 100644 unit-tests/test-cases/bundle-multi-link/bundle.c create mode 100644 unit-tests/test-cases/bundle-multi-link/main.c create mode 100644 unit-tests/test-cases/bundle-multi-load/Makefile create mode 100644 unit-tests/test-cases/bundle-multi-load/bundle.c create mode 100644 unit-tests/test-cases/bundle-multi-load/main.c create mode 100644 unit-tests/test-cases/bundle-private/Makefile create mode 100644 unit-tests/test-cases/bundle-private/bundle.c create mode 100644 unit-tests/test-cases/bundle-private/main.c create mode 100644 unit-tests/test-cases/bundle-unlinkable/Makefile create mode 100644 unit-tests/test-cases/bundle-unlinkable/bundle.c create mode 100644 unit-tests/test-cases/bundle-unlinkable/lib.c create mode 100644 unit-tests/test-cases/bundle-unlinkable/main.c create mode 100644 unit-tests/test-cases/bundle-unload-keep-mapped/Makefile create mode 100644 unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c create mode 100644 unit-tests/test-cases/bundle-unload-keep-mapped/main.c create mode 100644 unit-tests/test-cases/bundle-v-dylib/Makefile create mode 100644 unit-tests/test-cases/bundle-v-dylib/bar.c create mode 100644 unit-tests/test-cases/bundle-v-dylib/foo.c create mode 100644 unit-tests/test-cases/bundle-v-dylib/main.c create mode 100644 unit-tests/test-cases/deadlock/Makefile create mode 100644 unit-tests/test-cases/deadlock/bar.c create mode 100644 unit-tests/test-cases/deadlock/foo.c create mode 100644 unit-tests/test-cases/deadlock/main.c create mode 100644 unit-tests/test-cases/dladdr/Makefile create mode 100644 unit-tests/test-cases/dladdr/main.c create mode 100644 unit-tests/test-cases/dlclose-basic/Makefile create mode 100644 unit-tests/test-cases/dlclose-basic/foo.c create mode 100644 unit-tests/test-cases/dlclose-basic/main.c create mode 100644 unit-tests/test-cases/dlclose-bundle-unload/Makefile create mode 100644 unit-tests/test-cases/dlclose-bundle-unload/foo.c create mode 100644 unit-tests/test-cases/dlclose-bundle-unload/main.c create mode 100644 unit-tests/test-cases/dlerror/Makefile create mode 100644 unit-tests/test-cases/dlerror/main.c create mode 100644 unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/Makefile create mode 100644 unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/foo.c create mode 100644 unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/main.c create mode 100644 unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/Makefile create mode 100644 unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/foo.c create mode 100644 unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_GLOBAL/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_GLOBAL/bar.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_GLOBAL/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_GLOBAL/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/bar.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL/bar.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_LOCAL/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NODELETE/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_NODELETE/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NODELETE/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOLOAD/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOLOAD/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOLOAD/main.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOW/Makefile create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOW/bundle.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOW/foo.c create mode 100644 unit-tests/test-cases/dlopen-RTLD_NOW/main.c create mode 100644 unit-tests/test-cases/dlopen-basic/Makefile create mode 100644 unit-tests/test-cases/dlopen-basic/foo.c create mode 100644 unit-tests/test-cases/dlopen-basic/main.c create mode 100644 unit-tests/test-cases/dlopen-initializer/Makefile create mode 100644 unit-tests/test-cases/dlopen-initializer/bar.c create mode 100644 unit-tests/test-cases/dlopen-initializer/foo.c create mode 100644 unit-tests/test-cases/dlopen-initializer/main.c create mode 100644 unit-tests/test-cases/dlopen-local-and-global/Makefile create mode 100644 unit-tests/test-cases/dlopen-local-and-global/bar.c create mode 100644 unit-tests/test-cases/dlopen-local-and-global/foo.c create mode 100644 unit-tests/test-cases/dlopen-local-and-global/main.c create mode 100644 unit-tests/test-cases/dlopen-multi/Makefile create mode 100644 unit-tests/test-cases/dlopen-multi/foo.c create mode 100644 unit-tests/test-cases/dlopen-multi/main.c create mode 100644 unit-tests/test-cases/dlopen-zero/Makefile create mode 100644 unit-tests/test-cases/dlopen-zero/main.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_DEFAULT/Makefile create mode 100644 unit-tests/test-cases/dlsym-RTLD_DEFAULT/foo.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_DEFAULT/main.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_NEXT/Makefile create mode 100644 unit-tests/test-cases/dlsym-RTLD_NEXT/foo.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_NEXT/main.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_NEXT/test.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_SELF/Makefile create mode 100644 unit-tests/test-cases/dlsym-RTLD_SELF/foo.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_SELF/main.c create mode 100644 unit-tests/test-cases/dlsym-RTLD_SELF/test.c create mode 100644 unit-tests/test-cases/dlsym-error/Makefile create mode 100644 unit-tests/test-cases/dlsym-error/main.c create mode 100644 unit-tests/test-cases/dlsym-indirect/Makefile create mode 100644 unit-tests/test-cases/dlsym-indirect/foo.c create mode 100644 unit-tests/test-cases/dlsym-indirect/foo1.c create mode 100644 unit-tests/test-cases/dlsym-indirect/foo2.c create mode 100644 unit-tests/test-cases/dlsym-indirect/foo3.c create mode 100644 unit-tests/test-cases/dlsym-indirect/main.c create mode 100644 unit-tests/test-cases/dyld-launched-prebound/Makefile create mode 100644 unit-tests/test-cases/dyld-launched-prebound/main.c create mode 100644 unit-tests/test-cases/dyld-slide/Makefile create mode 100644 unit-tests/test-cases/dyld-slide/main.c create mode 100644 unit-tests/test-cases/fallback-with-suid/Makefile create mode 100644 unit-tests/test-cases/fallback-with-suid/foo.c create mode 100644 unit-tests/test-cases/fallback-with-suid/main.c create mode 100644 unit-tests/test-cases/flat-data/Makefile create mode 100644 unit-tests/test-cases/flat-data/bar.c create mode 100644 unit-tests/test-cases/flat-data/getbar.c create mode 100644 unit-tests/test-cases/flat-data/main.c create mode 100644 unit-tests/test-cases/flat-lookup-everywhere/Makefile create mode 100644 unit-tests/test-cases/flat-lookup-everywhere/main.c create mode 100644 unit-tests/test-cases/flat-prebound/Makefile create mode 100644 unit-tests/test-cases/flat-prebound/bar.c create mode 100644 unit-tests/test-cases/flat-prebound/foo.c create mode 100644 unit-tests/test-cases/flat-prebound/main.c create mode 100644 unit-tests/test-cases/framework-fallback/Makefile create mode 100644 unit-tests/test-cases/framework-fallback/main.c create mode 100644 unit-tests/test-cases/ignore-bad-files/Makefile create mode 100644 unit-tests/test-cases/ignore-bad-files/foo.c create mode 100644 unit-tests/test-cases/ignore-bad-files/main.c create mode 100644 unit-tests/test-cases/image-suffix/Makefile create mode 100644 unit-tests/test-cases/image-suffix/foo.c create mode 100644 unit-tests/test-cases/image-suffix/main.c create mode 100644 unit-tests/test-cases/init-order/Makefile create mode 100644 unit-tests/test-cases/init-order/base.c create mode 100644 unit-tests/test-cases/init-order/base.h create mode 100644 unit-tests/test-cases/init-order/foo1.c create mode 100644 unit-tests/test-cases/init-order/foo2.c create mode 100644 unit-tests/test-cases/init-order/foo3.c create mode 100644 unit-tests/test-cases/init-order/main.c create mode 100644 unit-tests/test-cases/initializer-args/Makefile create mode 100644 unit-tests/test-cases/initializer-args/main.c create mode 100644 unit-tests/test-cases/insert-libraries-with-initializer/Makefile create mode 100644 unit-tests/test-cases/insert-libraries-with-initializer/foo.c create mode 100644 unit-tests/test-cases/insert-libraries-with-initializer/main.c create mode 100644 unit-tests/test-cases/insert-libraries-with-suid/Makefile create mode 100644 unit-tests/test-cases/insert-libraries-with-suid/main.c create mode 100644 unit-tests/test-cases/lazy-pointer-binding/Makefile create mode 100644 unit-tests/test-cases/lazy-pointer-binding/foo.c create mode 100644 unit-tests/test-cases/lazy-pointer-binding/main.c create mode 100644 unit-tests/test-cases/lib-name-overload/Makefile create mode 100644 unit-tests/test-cases/lib-name-overload/foo.c create mode 100644 unit-tests/test-cases/lib-name-overload/foo2.c create mode 100644 unit-tests/test-cases/lib-name-overload/main.c create mode 100644 unit-tests/test-cases/loader_path-dup/Makefile create mode 100644 unit-tests/test-cases/loader_path-dup/bar.c create mode 100644 unit-tests/test-cases/loader_path-dup/base.c create mode 100644 unit-tests/test-cases/loader_path-dup/foo.c create mode 100644 unit-tests/test-cases/loader_path-dup/main.c create mode 100644 unit-tests/test-cases/loader_path/Makefile create mode 100644 unit-tests/test-cases/loader_path/bar.c create mode 100644 unit-tests/test-cases/loader_path/foo.c create mode 100644 unit-tests/test-cases/loader_path/main.c create mode 100644 unit-tests/test-cases/missing-symlink-framework-fallback-path/Foo.c create mode 100644 unit-tests/test-cases/missing-symlink-framework-fallback-path/Makefile create mode 100644 unit-tests/test-cases/missing-symlink-framework-fallback-path/main.c create mode 100644 unit-tests/test-cases/non-weak-library/Makefile create mode 100644 unit-tests/test-cases/non-weak-library/foo.c create mode 100644 unit-tests/test-cases/non-weak-library/main.c create mode 100644 unit-tests/test-cases/partial-library-load/Makefile create mode 100644 unit-tests/test-cases/partial-library-load/bar.c create mode 100644 unit-tests/test-cases/partial-library-load/bundle.c create mode 100644 unit-tests/test-cases/partial-library-load/foo.c create mode 100644 unit-tests/test-cases/partial-library-load/main.c create mode 100644 unit-tests/test-cases/sym-link-load/Makefile create mode 100644 unit-tests/test-cases/sym-link-load/base.c create mode 100644 unit-tests/test-cases/sym-link-load/base.h create mode 100644 unit-tests/test-cases/sym-link-load/link.c create mode 100644 unit-tests/test-cases/sym-link-load/main.c create mode 100644 unit-tests/test-cases/sym-link-load/test.c create mode 100644 unit-tests/test-cases/text-relocs/Makefile create mode 100644 unit-tests/test-cases/text-relocs/bar.c create mode 100644 unit-tests/test-cases/text-relocs/foo.s create mode 100644 unit-tests/test-cases/text-relocs/main.c create mode 100644 unit-tests/test-cases/weak-coalesce-c++/Makefile create mode 100644 unit-tests/test-cases/weak-coalesce-c++/a.h create mode 100644 unit-tests/test-cases/weak-coalesce-c++/a1.cc create mode 100644 unit-tests/test-cases/weak-coalesce-c++/a2.cc create mode 100644 unit-tests/test-cases/weak-coalesce-c++/main.cc create mode 100644 unit-tests/test-cases/weak-coalesce/Makefile create mode 100644 unit-tests/test-cases/weak-coalesce/base.c create mode 100644 unit-tests/test-cases/weak-coalesce/base.h create mode 100644 unit-tests/test-cases/weak-coalesce/foo1.c create mode 100644 unit-tests/test-cases/weak-coalesce/foo2.c create mode 100644 unit-tests/test-cases/weak-coalesce/foo3.c create mode 100644 unit-tests/test-cases/weak-coalesce/main.c create mode 100644 unit-tests/test-cases/weak-library/Makefile create mode 100644 unit-tests/test-cases/weak-library/foo.c create mode 100644 unit-tests/test-cases/weak-library/foo.h create mode 100644 unit-tests/test-cases/weak-library/main.c create mode 100644 unit-tests/test-cases/weak-override/Makefile create mode 100644 unit-tests/test-cases/weak-override/foo.c create mode 100644 unit-tests/test-cases/weak-override/main.c create mode 100644 unit-tests/test-cases/weak-symbol-flat/Makefile create mode 100644 unit-tests/test-cases/weak-symbol-flat/foo.c create mode 100644 unit-tests/test-cases/weak-symbol-flat/foo.h create mode 100644 unit-tests/test-cases/weak-symbol-flat/main.c create mode 100644 unit-tests/test-cases/weak-symbol/Makefile create mode 100644 unit-tests/test-cases/weak-symbol/foo.c create mode 100644 unit-tests/test-cases/weak-symbol/foo.h create mode 100644 unit-tests/test-cases/weak-symbol/main.c diff --git a/APPLE_LICENSE b/APPLE_LICENSE new file mode 100644 index 0000000..fe81a60 --- /dev/null +++ b/APPLE_LICENSE @@ -0,0 +1,367 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. +By downloading or using this software, you are agreeing to be bound by +the terms of this License. If you do not or cannot agree to the terms +of this License, please do not download or use the software. + +1. General; Definitions. This License applies to any program or other +work which Apple Computer, Inc. ("Apple") makes publicly available and +which contains a notice placed by Apple identifying such program or +work as "Original Code" and stating that it is subject to the terms of +this Apple Public Source License version 2.0 ("License"). As used in +this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is +the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to Apple and (ii) that cover subject +matter contained in the Original Code, but only to the extent +necessary to use, reproduce and/or distribute the Original Code +without infringement; and (b) in the case where You are the grantor of +rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to You and (ii) that cover subject matter in Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or +contributes to the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the +combination of Original Code and any Modifications, and/or any +respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or +otherwise make Covered Code available, directly or indirectly, to +anyone other than You; and/or (b) to use Covered Code, alone or as +part of a Larger Work, in any way to provide a service, including but +not limited to delivery of content, through electronic communication +with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change +to, the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous +Modifications, and/or any respective portions thereof. When code is +released as a series of files, a Modification is: (a) any addition to +or deletion from the contents of a file containing Covered Code; +and/or (b) any new file or other representation of computer program +statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other +work as originally made available by Apple under this License, +including the Source Code of any updates or upgrades to such programs +or works made available by Apple under this License, and that has been +expressly identified by Apple as such in the header file(s) of such +work; and (b) the object code compiled from such Source Code and +originally made available by Apple under this License. + +1.8 "Source Code" means the human readable form of a program or other +work that is suitable for making modifications to it, including all +modules it contains, plus any associated interface definition files, +scripts used to control compilation and installation of an executable +(object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising +rights under this License. For legal entities, "You" or "Your" +includes any entity which controls, is controlled by, or is under +common control with, You, where "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of fifty percent +(50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms +and conditions of this License, Apple hereby grants You, effective on +the date You accept this License and download the Original Code, a +world-wide, royalty-free, non-exclusive license, to the extent of +Apple's Applicable Patent Rights and copyrights covering the Original +Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, +internally distribute within Your organization, and Externally Deploy +verbatim, unmodified copies of the Original Code, for commercial or +non-commercial purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as +they appear in the Original Code, and keep intact all notices in the +Original Code that refer to this License; and + +(b) You must include a copy of this License with every copy of Source +Code of Covered Code and documentation You distribute or Externally +Deploy, and You may not offer or impose any terms on such Source Code +that alter or restrict this License or the recipients' rights +hereunder, except as permitted under Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial +or non-commercial purposes, provided that in each instance You also +meet all of these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to +the Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the +notice in Exhibit A in each file of the Source Code of all Your +Modifications, and cause the modified files to carry prominent notices +stating that You changed the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make +Source Code of all Your Externally Deployed Modifications either +available to those to whom You have Externally Deployed Your +Modifications, or publicly available. Source Code of Your Externally +Deployed Modifications must be released under the terms set forth in +this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve +(12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your +Externally Deployed Modifications electronically (e.g. download from a +web site). + +2.3 Distribution of Executable Versions. In addition, if You +Externally Deploy Covered Code (Original Code and/or Modifications) in +object code, executable form only, You must include a prominent +notice, in the code itself as well as in related documentation, +stating that Source Code of the Covered Code is available under the +terms of this License with information on how and where to obtain such +Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that +although Apple and each Contributor grants the licenses to their +respective portions of the Covered Code set forth herein, no +assurances are provided by Apple or any Contributor that the Covered +Code does not infringe the patent or other intellectual property +rights of any other entity. Apple and each Contributor disclaim any +liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a +condition to exercising the rights and licenses granted hereunder, You +hereby assume sole responsibility to secure any other intellectual +property rights needed, if any. For example, if a third party patent +license is required to allow You to distribute the Covered Code, it is +Your responsibility to acquire that license before distributing the +Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the +licenses granted to You under this License, You hereby grant to any +person or entity receiving or distributing Covered Code under this +License a non-exclusive, royalty-free, perpetual, irrevocable license, +under Your Applicable Patent Rights and other intellectual property +rights (other than patent) owned or controlled by You, to use, +reproduce, display, perform, modify, sublicense, distribute and +Externally Deploy Your Modifications of the same scope and extent as +Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered +Code with other code not governed by the terms of this License and +distribute the Larger Work as a single product. In each such instance, +You must make sure the requirements of this License are fulfilled for +the Covered Code or any portion thereof. + +5. Limitations on Patent License. Except as expressly stated in +Section 2, no other patent rights, express or implied, are granted by +Apple herein. Modifications and/or Larger Works may require additional +patent licenses from Apple which Apple may grant in its sole +discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other +rights consistent with the scope of the license granted herein +("Additional Terms") to one or more recipients of Covered Code. +However, You may do so only on Your own behalf and as Your sole +responsibility, and not on behalf of Apple or any Contributor. You +must obtain the recipient's agreement that any such Additional Terms +are offered by You alone, and You hereby agree to indemnify, defend +and hold Apple and every Contributor harmless for any liability +incurred by or claims asserted against Apple or such Contributor by +reason of any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new +versions of this License from time to time. Each version will be given +a distinguishing version number. Once Original Code has been published +under a particular version of this License, You may continue to use it +under the terms of that version. You may also choose to use such +Original Code under the terms of any subsequent version of this +License published by Apple. No one other than Apple has the right to +modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered +Code may contain errors that could cause failures or loss of data, and +may be incomplete or contain inaccuracies. You expressly acknowledge +and agree that use of the Covered Code, or any portion thereof, is at +Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND +WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND +APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE +PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF +MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR +PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST +INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE +FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, +THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO +ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. +You acknowledge that the Covered Code is not intended for use in the +operation of nuclear facilities, aircraft navigation, communication +systems, or air traffic control machines in which case the failure of +the Covered Code could lead to death, personal injury, or severe +physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING +TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR +ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, +TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF +APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY +REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY +TO YOU. In no event shall Apple's total liability to You for all +damages (other than as may be required by applicable law) under this +License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", +"QuickTime", "QuickTime Streaming Server" or any other trademarks, +service marks, logos or trade names belonging to Apple (collectively +"Apple Marks") or to any trademark, service mark, logo or trade name +belonging to any Contributor. You agree not to use any Apple Marks in +or as part of the name of products derived from the Original Code or +to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times +with Apple's third party trademark usage guidelines which are posted +at http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, +each Contributor retains all rights, title and interest in and to any +Modifications made by such Contributor. Apple retains all rights, +title and interest in and to the Original Code and any Modifications +made by or on behalf of Apple ("Apple Modifications"), and such Apple +Modifications will not be automatically subject to this License. Apple +may, at its sole discretion, choose to license such Apple +Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with +any term(s) of this License and fail to cure such breach within 30 +days of becoming aware of such breach; + +(b) immediately in the event of the circumstances described in Section +13.5(b); or + +(c) automatically without notice from Apple if You, at any time during +the term of this License, commence an action for patent infringement +against Apple; provided that Apple did not first commence +an action for patent infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately +stop any further use, reproduction, modification, sublicensing and +distribution of the Covered Code. All sublicenses to the Covered Code +which have been properly granted prior to termination shall survive +any termination of this License. Provisions which, by their nature, +should remain in effect beyond the termination of this License shall +survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, +12.2 and 13. No party will be liable to any other for compensation, +indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of +any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in +the Covered Code include only those rights customarily provided to the +public as defined in this License. This customary commercial license +in technical data and software is provided in accordance with FAR +12.211 (Technical Data) and 12.212 (Computer Software) and, for +Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- +Commercial Items) and 227.7202-3 (Rights in Commercial Computer +Software or Computer Software Documentation). Accordingly, all U.S. +Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of +legal association between or among You, Apple or any Contributor, and +You will not represent to the contrary, whether expressly, by +implication, appearance or otherwise. + +13.3 Independent Development. Nothing in this License will impair +Apple's right to acquire, license, develop, have others develop for +it, market and/or distribute technology or products that perform the +same or similar functions as, or otherwise compete with, +Modifications, Larger Works, technology or products that You may +develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to +enforce any provision of this License will not be deemed a waiver of +future enforcement of that or any other provision. Any law or +regulation which provides that the language of a contract shall be +construed against the drafter will not apply to this License. + +13.5 Severability. (a) If for any reason a court of competent +jurisdiction finds any provision of this License, or portion thereof, +to be unenforceable, that provision of the License will be enforced to +the maximum extent permissible so as to effect the economic benefits +and intent of the parties, and the remainder of this License will +continue in full force and effect. (b) Notwithstanding the foregoing, +if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the +enforceability of either of those Sections, this License will +immediately terminate and You must immediately discontinue any use of +the Covered Code and destroy all copies of it that are in your +possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution +between You and Apple relating to this License shall take place in the +Northern District of California, and You and Apple hereby consent to +the personal jurisdiction of, and venue in, the state and federal +courts within that District with respect to this License. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the +entire agreement between the parties with respect to the subject +matter hereof. This License shall be governed by the laws of the +United States and the State of California, except that body of +California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following +clause applies: The parties hereby confirm that they have requested +that this License and all related documents be drafted in English. Les +parties ont exige que le present contrat et tous les documents +connexes soient rediges en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights +Reserved. + +This file contains Original Code and/or Modifications of Original Code +as defined in and that are subject to the Apple Public Source License +Version 2.0 (the 'License'). You may not use this file except in +compliance with the License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this +file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +Please see the License for the specific language governing rights and +limitations under the License." diff --git a/doc/man/man1/dyld.1 b/doc/man/man1/dyld.1 new file mode 100644 index 0000000..9e0b776 --- /dev/null +++ b/doc/man/man1/dyld.1 @@ -0,0 +1,253 @@ +.TH DYLD 1 "January 15, 2005" "Apple Computer, Inc." +.SH NAME +dyld \- the dynamic link editor +.SH SYNOPSIS +DYLD_FRAMEWORK_PATH +.br +DYLD_FALLBACK_FRAMEWORK_PATH +.br +DYLD_LIBRARY_PATH +.br +DYLD_FALLBACK_LIBRARY_PATH +.br +DYLD_ROOT_PATH +.br +DYLD_INSERT_LIBRARIES +.br +DYLD_FORCE_FLAT_NAMESPACE +.br +DYLD_IMAGE_SUFFIX +.br +DYLD_PRINT_OPTS +.br +DYLD_PRINT_ENV +.br +DYLD_PRINT_LIBRARIES +.br +DYLD_PRINT_LIBRARIES_POST_LAUNCH +.br +DYLD_BIND_AT_LAUNCH +.br +DYLD_PREBIND_DEBUG +.br +DYLD_NEW_LOCAL_SHARED_REGIONS +.br +DYLD_IGNORE_PREBINDING +.br +DYLD_PRINT_APIS +.br +DYLD_PRINT_BINDINGS +.br +DYLD_PRINT_INITIALIZERS +.br +DYLD_PRINT_REBASINGS +.br +DYLD_PRINT_SEGMENTS +.br +DYLD_PRINT_STATISTICS +.SH DESCRIPTION +The dynamic linker uses the following environment variables. +They affect any program that uses the dynamic linker. +.TP +.B DYLD_FRAMEWORK_PATH +This is a colon separated list of directories that contain frameworks. +The dynamic linker searches these directories before it searches for the +framework by its install name. +It allows you to test new versions of existing +frameworks. (A framework is a library install name that ends in the form +XXX.framework/Versions/YYY/XXX or XXX.framework/XXX, where XXX and YYY are any +name.) +.IP +For each framework that a program uses, the dynamic linker looks for the +framework in each directory in +.SM DYLD_FRAMEWORK_PATH +in turn. If it looks in all the directories and can't find the framework, it +searches the directories in +.SM DYLD_LIBRARY_PATH +in turn. If it still can't find the framework, it then searches +.SM DYLD_FALLBACK_FRAMEWORK_PATH +and +.SM DYLD_FALLBACK_LIBRARY_PATH +in turn. +.IP +Use the +.B \-L +option to +.IR otool (1). +to discover the frameworks and shared libraries that the executable +is linked against. +.TP +.B DYLD_FALLBACK_FRAMEWORK_PATH +This is a colon separated list of directories that contain frameworks. +It is used as the default location for frameworks not found in their install +path. + +By default, it is set to +/Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks +.TP +.B DYLD_LIBRARY_PATH +This is a colon separated list of directories that contain libraries. The +dynamic linker searches these directories before it searches the default +locations for libraries. It allows you to test new versions of existing +libraries. +.IP +For each library that a program uses, the dynamic linker looks for it in each +directory in +.SM DYLD_LIBRARY_PATH +in turn. If it still can't find the library, it then searches +.SM DYLD_FALLBACK_FRAMEWORK_PATH +and +.SM DYLD_FALLBACK_LIBRARY_PATH +in turn. +.IP +Use the +.B \-L +option to +.IR otool (1). +to discover the frameworks and shared libraries that the executable +is linked against. +.TP +.B DYLD_FALLBACK_LIBRARY_PATH +This is a colon separated list of directories that contain libraries. +It is used as the default location for libraries not found in their install +path. +By default, it is set +to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib. +.TP +.B DYLD_ROOT_PATH +This is a colon separated list of directories. The dynamic linker will prepend each of +this directory paths to every image access until a file is found. +.TP +.B DYLD_INSERT_LIBRARIES +This is a colon separated list of dynamic libraries to load before the ones +specified in the program. This lets you test new modules of existing dynamic +shared libraries that are used in flat-namespace images by loading a temporary +dynamic shared library with just the new modules. Note that this has no +effect on images built a two-level namespace images using a dynamic shared +library unless +.SM DYLD_FORCE_FLAT_NAMESPACE +is also used. +.TP +.B DYLD_FORCE_FLAT_NAMESPACE +Force all images in the program to be linked as flat-namespace images and ignore +any two-level namespace bindings. This may cause programs to fail to execute +with a multiply defined symbol error if two-level namespace images are used to +allow the images to have multiply defined symbols. +.TP +.B DYLD_IMAGE_SUFFIX +This is set to a string of a suffix to try to be used for all shared libraries +used by the program. For libraries ending in ".dylib" the suffix is applied +just before the ".dylib". For all other libraries the suffix is appended to the +library name. This is useful for using conventional "_profile" and "_debug" +libraries and frameworks. +.TP +.B DYLD_PRINT_OPTS +When this is set, the dynamic linker writes to file descriptor 2 (normally +standard error) the command line options. +.TP +.B DYLD_PRINT_ENV +When this is set, the dynamic linker writes to file descriptor 2 (normally +standard error) the environment variables. +.TP +.B DYLD_PRINT_LIBRARIES +When this is set, the dynamic linker writes to file descriptor 2 (normally +standard error) the filenames of the libraries the program is using. +This is useful to make sure that the use of +.SM DYLD_LIBRARY_PATH +is getting what you want. +.TP +.B DYLD_PRINT_LIBRARIES_POST_LAUNCH +This does the same as +.SM DYLD_PRINT_LIBRARIES +but the printing starts after the program gets to its entry point. +.TP +.B DYLD_BIND_AT_LAUNCH +When this is set, the dynamic linker binds all undefined symbols +the program needs at launch time. This includes function symbols that can are normally lazily bound at the time of their first call. +.TP +.B DYLD_PREBIND_DEBUG +When this is set, the dynamic linker prints diagnostics about +launching prebound programs and libraries. This lets you determine why a +program is not being launched prebound. +You can view the recorded library time stamps with the +.B \-Lv +option to +.IR otool (1). +.TP +.PP +For secure programs that are UNIX set uid or set gid, the dynamic linker will +not use the dyld environment variables for path searching and library insertion, +unless the program is run as the real user. For secure programs, the dynamic +linker clears out the value of the dyld path and insertion environment +variables. This is so that if a program is +.IR exec (2)'ed +from a secure program too will not have it's libraries searched for, as well. +For statically linked secure programs that +.IR exec (2) +other programs that might use the dynamic linker, they too should clear out the +values of the dyld path and insertion environment variables. +.TP +.B DYLD_NEW_LOCAL_SHARED_REGIONS +When set, the dynamic linker directs the system to provide a new set of shared +regions as the repository for library load requests for dynamic libraries +built with +.SM MH_SPLIT_SEGS +(split shared libraries). + +Split shared libraries reside in a defined contiguous region of address space +in all dynamic linker runtime processes. This space is backed by named regions +or sub-maps. These sub-maps are owned by the system and items which are to +mapped into them must be mapped via the +.IR load_shared_file (2) +call. The use of +sub-maps promotes a high degree of system resource sharing between the +processes which incorporate and use them. However, some processes require +either additional or different libraries to be loaded into the shared region. +While there is some space available within the shared region for alternate and +new shared libraries, it is inappropriate to use that area for temporary or +private libraries. Setting the +.SM DYLD_NEW_LOCAL_SHARED_REGIONS +flag will cause +all children of the current process to have their own set of sub-maps. In this +way the libraries found in the children's submaps will not be caused to be +present in the submaps shared by the rest of the system. + +.SM DYLD_NEW_LOCAL_SHARED_REGIONS +should be set by anyone wishing to run +non-standard or temporary split shared libraries by setting an explicit path to +point to them. i.e. by using the DYLD_LIBRARY_PATH environment variable +instead of changing the root by executing a +.IR chroot (2) +call. +.TP +.B DYLD_PRINT_STATISTICS +Right before the process's main() is called, dyld prints out information about how +dyld spent its time. Useful for analyzing launch performance. +.TP +.B DYLD_IGNORE_PREBINDING { app | all } +Valid values are "app", "all", and "" (empty). The variable is useful for testing +how various mixes of prebound and unprebound libraries perform. When set to "all", +all prebinding is ignored. That is, dyld fixes up any prebound images as if the prebinding +in it was invalid. When set to "all", just the prebinding information in main +executables is ignored. When set the nothing, the prebinding in split-seg libraries +is used, by all other prebinding is ignored. +.TP +.B DYLD_PRINT_INITIALIZERS +Causes dyld to print out a line when running each initializers in every image. Initializers +run by dyld included constructors for C++ statically allocated objects, functions marked with +__attribute__((constructor)), and -init functions. +.TP +.B DYLD_PRINT_APIS +Causes dyld to print a line whenever a dyld API is called (e.g. NSAddImage()). +.TP +.B DYLD_PRINT_SEGMENTS +Causes dyld to print out a line containing the name and address range of each mach-o segment +that dyld maps in. +.TP +.B DYLD_PRINT_BINDINGS +Causes dyld to print a line each time a symbolic name is bound. + + + +.SH "SEE ALSO" +libtool(1), ld(1), otool(1) diff --git a/doc/man/man3/NSModule.3 b/doc/man/man3/NSModule.3 new file mode 100644 index 0000000..3677477 --- /dev/null +++ b/doc/man/man3/NSModule.3 @@ -0,0 +1,610 @@ +.TH NSModule 3 "October 6, 2003" "Apple Computer, Inc." +.SH NAME +NSModule \- programmatic interface for working with modules and symbols +.SH SYNOPSIS +.nf +.PP +#include +.sp .5 +typedef void * NSModule; +.sp .5 +extern NSModule NSLinkModule( + NSObjectFileImage objectFileImage, + const char *moduleName, + unsigned long options); +.sp .5 +extern enum DYLD_BOOL NSUnLinkModule( + NSModule module, + unsigned long options); +.sp .5 +extern const char * NSNameOfModule( + NSModule m); +.sp .5 +extern const char * NSLibraryNameForModule( + NSModule m); +.sp 2 +typedef void * NSSymbol; +.sp .5 +extern enum DYLD_BOOL NSIsSymbolNameDefined( + const char *symbolName); +.sp .5 +extern enum DYLD_BOOL NSIsSymbolNameDefinedWithHint( + const char *symbolName + const char *libraryNameHint); +.sp .5 +extern enum DYLD_BOOL NSIsSymbolNameDefinedInImage( + const struct mach_header *image, + const char *symbolName); +.sp .5 +extern NSSymbol NSLookupAndBindSymbol( + const char *symbolName); +.sp .5 +extern NSSymbol NSLookupAndBindSymbolWithHint( + const char *symbolName + const char *libraryNameHint); +.sp .5 +extern NSSymbol NSLookupSymbolInModule( + NSModule module, + const char *symbolName); +.sp .5 +extern NSSymbol NSLookupSymbolInImage( + const struct mach_header *image, + const char *symbolName, + unsigned long options); +.sp .5 +extern const char * NSNameOfSymbol( + NSSymbol symbol); +.sp .5 +extern void * NSAddressOfSymbol( + NSSymbol symbol); +.sp .5 +extern NSModule NSModuleForSymbol( + NSSymbol symbol); +.sp .5 +extern enum DYLD_BOOL NSAddLibrary( + const char *pathName); +.sp .5 +extern enum DYLD_BOOL NSAddLibraryWithSearching( + const char *pathName); +.sp .5 +extern const struct mach_header * NSAddImage( + const char *image_name, + unsigned long options); +.sp .5 +extern long NSVersionOfRunTimeLibrary( + const char *libraryName); +.sp .5 +extern long NSVersionOfLinkTimeLibrary( + const char *libraryName); +.sp .5 +extern int _NSGetExecutablePath( + char *buf, + unsigned long *bufsize) +.sp 2 +extern void NSInstallLinkEditErrorHandlers( + NSLinkEditErrorHandlers *handlers); +.sp .5 +extern void NSLinkEditError( + NSLinkEditErrors *c, + int *errorNumber, + const char **fileName, + const char **errorString); +.if +.SH "FUTURE SYNOPSIS" +.nf +.PP +extern NSModule NSReplaceModule( + NSModule moduleToReplace, + NSObjectFileImage newObjectFileImage, + unsigned long options); +.fi +.PP +These routines are the programmatic interface for working with modules and +symbols in a program. A program is composed of a set of images, an executable, +plugins, and dynamic shared libraries. An image which is an executable or a +plugin is composed of one module containing a collection of symbols. A dynamic +shared library is composed of one or more modules with each of those modules +containing a separate collection of symbols. If a symbol is used from a module +then all the symbols from that module are used. +.PP +When a program is executed it selectively binds the symbols it needs from the +modules in the dynamic libraries that are loaded. Normally a program is +staticly linked against a set of dynamic shared libraries when it is built. +So when the program is executed the dynamic linker will automaticly load those +dynamic shared libraries. +.PP +A program may programmatically load plugins after it starts executing and that +is done with two sets of API's. The first is the API's of +.IR NSObjectFileImage (3) +and the second is +.I NSLinkModule. +Unlike modules in the dynamic libraries when a plugin is loaded it is not +selectively bound to but always bound into the program. +.PP +.I NSLinkModule +links the specified object file image into the program and returns the module +handle for it. +Currently the implementation is limited to only Mach-O MH_BUNDLE types which +are used for plugins. +A module name is specified when a module is linked so that later +.I NSNameOfModule +can be used with the module handle and to do things like report errors. +If you want +.IR gdb (1) +to be able to debug your module, when calling +.I NSLinkModule +you should pass the image path as the module name. +When a module is linked, all libraries referenced by the module are added to +the list of libraries to be searched. +The parameter, +.I options, +can have a set of options or'ed together. The options for +.I NSLinkModule +are as follows: +.TP +.B NSLINKMODULE_OPTION_NONE +This specifies no options. With this the global symbols from the module are +made part of the global symbol table of the program. If any errors occur the +handlers installed with +.I NSInstallLinkEditErrorHandlers +are called or the default action is taken if there are no handlers. +.TP +.B NSLINKMODULE_OPTION_BINDNOW +This option causes the dynamic link editor to bind all undefined references for +the loaded module and not allow references to be bound as needed. This affects +all the references in the module and all of the dependent references. +.TP +.B NSLINKMODULE_OPTION_PRIVATE +With this option the global symbols from the module are not made part of +the global symbol table of the program. The global symbols of the +module can then be looked up using +.I NSLookupSymbolInModule. +.TP +.B NSLINKMODULE_OPTION_RETURN_ON_ERROR +With this option if errors occur while binding this module it is automaticly +unloaded and +.SM NULL +is returned as the module handle. To get the error information for the module +that failed to load the routine +.I NSLinkEditError +is then used. It has the same parameters as the link edit error handler (see +below) except all the parameters are pointers in which the information is +returned indirectly. +.TP +.B NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES +With this option the module init routines are not called. This is only useful +to the fix-and-continue implementation. +.TP +.B NSLINKMODULE_OPTION_TRAILING_PHYS_NAME +With this option the parameter, +.I moduleName +is assumed to be a string with the logical name of the image with the physical +name of the object file tailing after the NULL character of the logical name. +This is only useful to the zero-link implementation. +.PP +.I NSUnLinkModule +unlinks the specified module handle from the program. Currently the +implementation is limited to only allow modules linked with +.I NSLinkModule +to be unlinked. The parameter, +.I options, +can have a set of options or'ed together. The options for +.I NSUnLinkModule +are as follows: +.TP +.B NSUNLINKMODULE_OPTION_NONE +This specifies no options. With this the module is unlinked from the program +and the memory for the module is deallocated. If any errors occur the +handlers installed with +.I NSInstallLinkEditErrorHandlers +are called or the default action is taken if there are no handlers. +.TP +.B NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED +With this option the memory for the module is not deallocated allowing pointers +into the module to still be valid. +.TP +.B NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES +With this option any lazy references (direct function calls) to symbols defined +in the module are reset to be bound on first call again and not cause any +undefined symbol errors. Currently this is only implemented for the PowerPC +architecture. +.PP +.I NSNameOfModule +is passed a module handle and returns the name of the module. If the module +handle is invalid +.SM NULL +is returned. +.PP +.I NSLibraryNameForModule +is passed a module handle and returns the name of the library the module is in +if any. If the module handle is for a module that is not in a library (in the +executable or a plugin) or the module handle is invalid +.SM NULL +is returned. +.PP +.I NSIsSymbolNameDefined +is passed a global symbol name (global 'C' symbols names are preceded with an +underbar '\_') and returns +.SM TRUE +or +.SM FALSE +based on if the symbol is defined in the program's global symbol table. +If the symbol is not defined no error occurs. +.PP +.I NSIsSymbolNameDefinedWithHint +is the same as +.I NSIsSymbolNameDefined +but the +.I libraryNameHint +parameter provides a hint as to where to start the lookup in a prebound +program. The +.I libraryNameHint +parameter is matched up with the actual library install names with +.IR strstr (3). +.PP +.I NSIsSymbolNameDefinedInImage +is passed a pointer to the mach_header of a mach_header structure of a +dynamic library being used by the program and a symbol name. This returns +.SM TRUE +or FALSE +based on if the symbol is defined in the specified image or one of the image's +sub-frameworks or sub-umbrellas. +If the program was built with the +.IR ld (1) +.B \-force_flat_namespace +flag or executed with the environment variable +.SM DYLD_FORCE_FLAT_NAMESPACE +set and the pointer to a mach_header structure is not of a bundle loaded with +the +.B NSLINKMODULE_OPTION_PRIVATE +option of +.IR NSLinkModule (3) +then the pointer to a mach_header is ignored and the symbol is looked up in +all the images using the first definition if found. +.PP +The image handle parameter for +.I NSLookupSymbolInImage +and +.I NSIsSymbolNameDefinedInImage +is a pointer to a read-only mach header structure of a dynamic library being +used by the program. Besides the +.IR NSAddImage (3) +routine the pointer to a mach header can also be obtained by using a link editor +defined symbol as in and described on the +.IR ld (1) +man page. +Also the +.IR dyld (3) +routine +.IR _dyld_get_image_header (3) +and the mach_header pointer arguments to the call back routines called from +.IR _dyld_register_func_for_add_image (3) +routines can also be used. +.PP +.I NSLookupAndBindSymbol +is passed a global symbol name and looks up and binds the symbol into the +program. +It returns an NSSymbol for the symbol. If any errors occur the handlers +installed with +.I NSInstallLinkEditErrorHandlers +are called or the default action is taken if there are no handlers. +.PP +.I NSLookupAndBindSymbolWithHint +is the same as +.I NSLookupAndBindSymbol +but the +.I libraryNameHint +parameter provides a hint as to where to start the lookup in a prebound +program. The +.I libraryNameHint +parameter is matched up with the actual library install names with +.IR strstr (3). +.PP +.I NSLookupSymbolInModule +is passed a symbol name and a module handle and looks up the symbol in that +module. Currently this is only implemented for module handles returned with +.I NSLinkModule. +If the symbol is found an NSSymbol for the symbol is returned otherwise +.SM NULL +is returned and no error occurs. +.PP +.I NSLookupSymbolInImage +is passed a pointer to a mach_header structure of a dynamic library being used +by the program and a symbol name. It returns an NSSymbol for the symbol for +defined in the specified image or the image's sub-frameworks or sub-umbrellas. +If the program was built with the +.IR ld (1) +.B \-force_flat_namespace +flag or executed with the environment variable +.SM DYLD_FORCE_FLAT_NAMESPACE +set and the pointer to a mach_header structure is not of a bundle loaded with +the +.B NSLINKMODULE_OPTION_PRIVATE +option of +.IR NSLinkModule (3) +then the pointer to a mach_header is ignored and the symbol is looked up in +all the images using the first definition found. +If the option +.SM NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR +is not used if any errors occur the handlers installed with +.I NSInstallLinkEditErrorHandlers +are called or the default action is taken if there are no handlers. +The options of +.I NSLookupSymbolInImage +are as follows: +.TP +.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND +Just bind the non-lazy symbols of module that defines the +.I symbolName +and let all lazy symbols in the module be bound on first call. This should be +used in the normal case for a trusted module expected to bind without any errors +like a module in a system supplied library. +.TP +.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW +Bind all the non-lazy and lazy symbols of module that defines the +.I symbolName +and let all dependent symbols in the needed libraries be bound as needed. This +would be used for a module that might not be expected bind without errors but +links against only system supplied libraries which are expected to bind without +any errors. +.TP +.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY +Bind all the symbols of the module that defines the +.I symbolName +and all the dependent symbols of all needed libraries. This should only be +used for things like signal handlers and linkedit error handlers that can't +bind other symbols when executing to handle the signal or error. +.TP +.B NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR +With this option if errors occur while binding the module that defines the +.I symbolName +then the module is automaticly unloaded and +.SM NULL +is returned as the NSSymbol. To get the error information for why the module +that failed to bind the routine +.I NSLinkEditError +is then used. It has the same parameters as the link edit error handler (see +below) except all the parameters are pointers in which the information is +returned indirectly. +.PP +.I NSNameOfSymbol +is passed an NSSymbol and returns the name of the symbol. +.PP +.I NSAddressOfSymbol +is passed an NSSymbol and returns the address of the symbol. +.PP +.I NSModuleForSymbol +is passed an NSSymbol and returns the NSModule that symbol is defined in. +.PP +.I NSAddLibrary +is passed the file name of a dynamic shared library to be added to the search +list. If it is successful it returns +.SM TRUE +else it returns +.SM FALSE. +.PP +.I NSAddLibraryWithSearching +is passed the file name of a dynamic shared library to be added to the search +list the file name passed will be effected by the various +.SM DYLD +environment variables as if this library were linked into the program. If it +is successful it returns +.SM TRUE +else it returns +.SM FALSE. +.PP +.I NSAddImage +is passed the file name of a dynamic shared library to be added to the search +list of the program if not already loaded. It returns a pointer to the +mach_header structure of the dynamic library being used by the program. +For best performance of this routine if the library is expected to be already +loaded by the program the +.I image_name +should be a full path name and the same as the name recorded by the program. +If it is a symlink then an +.IR open (2) +and an +.IR fstat (2) +are needed to determine it is the same file as one already loaded. +.PP +If the dynamic shared library has not already been loaded it along with all the +needed dependent libraries are loaded. With the options parameter +.SM NSADDIMAGE_OPTION_NONE +then any error in loading will cause the linkEdit error handler set by +.IR NSInstallLinkEditErrorHandlers (3) +to be called or the default action of printing the error and exiting to be +taken. The other options of +.I NSAddImage +are as follows: +.TP +.B NSADDIMAGE_OPTION_RETURN_ON_ERROR +With this option if errors occur while loading this library it is automatically +unloaded and +.SM NULL +is returned. To get the error information for the library that failed to load +the routine +.I NSLinkEditError +is then used. It has the same parameters as the link edit error handler (see +below) except all the parameters are pointers in which the information is +returned indirectly. +.TP +.B NSADDIMAGE_OPTION_WITH_SEARCHING +With this option the +.I image_name +passed for the library and all its dependents will be effected by the various +.SM DYLD +environment variables as if this library were linked into the program. +.TP +.B NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED +With this option if the +.I image_name +passed for the library has not already been loaded it is not loaded. Only if +it has been loaded the pointer to the mach_header will not be +.SM NULL. +.TP +.B NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME +When this option is specified if a later load of a dependent dynamic library +with a file system path is needed by an image that matches the install name of +the dynamic library loaded with this option, then the dynamic library loaded +with the call to NSAddImage() is used in place of the dependent dynamic library. +.PP +.I NSVersionOfRunTimeLibrary +is passed the install name of a dynamic shared library and returns +current_version number of the library the program is using or \-1 if the +program is not using that library. +.PP +.I NSVersionOfLinkTimeLibrary +is passed the install name of a dynamic shared library and returns the +current_version number of the library the executable program was built +with or \-1 if the program was not built with that library. +.PP +.I _NSGetExecutablePath +copies the path of the executable into the buffer and +returns 0 if the path was successfully copied in the provided buffer. If the +buffer is not large enough, \-1 is returned and the expected buffer size is +copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to +the executable not a "real path" to the executable. That is the path may be +a symbolic link and not the real file. And with deep directories the total +bufsize needed could be more than MAXPATHLEN. +.SH ERROR HANDLING +.PP +.I NSInstallLinkEditErrorHandlers +is passed a pointer to a NSLinkEditErrorHandlers which contains three function +pointers to be used for handling dynamic link errors. The prototypes for these +functions are given in the following typedef: +.RS +.nf +typedef struct { + void (*undefined)(const char *symbolName); + NSModule (*multiple)(NSSymbol s, NSModule oldModule, NSModule newModule); + void (*linkEdit)(NSLinkEditErrors errorClass, int errorNumber, + const char *fileName, const char *errorString); +} NSLinkEditErrorHandlers; +.fi +.RE +.PP +The first two functions allow the programmer to direct the link edit processing +of undefined symbols and multiply defined symbols. +The third function allows the programmer to catch all other link editor +errors. +.PP +The state when one of the user error functions gets called will be such that no +module will be partially loaded (except in the case of resource errors like out +of memory and other relocation errors). +However, with undefined symbol errors those modules referencing undefined +symbols will be partially bound, and use of such modules can and will crash the +program. +.PP +Great care should be taken when implementing these functions, as the program is +running in a state that will crash if it uses an unbound symbol. +To be safe, these functions should only rely on other things in the same module +or in the executable. +.PP +If the user does not supply these functions, the default will be to write an +error message on to file descriptor 2 (usually stderr) and exit the program +(except for the +.I linkEdit +error handler when the +.I NSLinkEditErrors +is NSLinkEditWarningError, then the default is to do nothing). +.PP +The specified undefined handler may make calls to any of the runtime loading +functions to add modules based on the undefined symbol name. +After dealing with this symbol name successfully (by doing a runtime loading +operation to resolve the undefined reference) the handler simply returns. +If more symbol's names remain undefined the handler will be called repeatedly +with an undefined symbol name. +If the handler can't deal with the symbol it should not return (put up a panel, +abort, etc) and cause the program to exit. +Or it can remove itself as the undefined handler and return which will cause +the default action of printing the undefined symbol names and exiting. +.PP +The specified multiply defined symbol handler is called during the process of +runtime linking and thus it may not call any of the runtime loading functions +as only one set of linking operations can be performed in the task at a time. +The only programmatic functions that can be called from a multiply defined +symbol handler are +.I NSNameOfSymbol, +.I NSNameOfModule +and +.I NSLibraryNameForModule +(provided they are linked into the program before the handler is called). +This handler returns the module handle for the symbol that is to be used for +further link editing, either the +.I oldModule +or the +.I newModule. +It may also record one of the module handles to later take action after the +runtime linking process has completed (for example later unlink the module). +The dynamic link editor updates the references to the symbol if the handler +specifies the new symbol is to be used. +The references which are updated are those that the compiler system generated +as indirect references. Initialized data and references that were created at +runtime are not effected. +.PP +The specified +.I linkEdit +error handler is called for all other runtime linking errors. +These other runtime linking errors are either warnings or fatal errors. +If the user's link edit error handler function returns +for a fatal error it will cause the program to exit. +There is small set of major error classes which have specific error numbers. +These numbers are be passed in the parameter +.I errorClass. +These major error classes include: +.RS +.nf +typedef enum { + NSLinkEditFileAccessError, + NSLinkEditFileFormatError, + NSLinkEditMachResourceError, + NSLinkEditUnixResourceError, + NSLinkEditOtherError, + NSLinkEditWarningError, + NSLinkEditMultiplyDefinedError, + NSLinkEditUndefinedError +} NSLinkEditErrors; +.fi +.RE +.PP +For the error class NSLinkEditUnixResourceError the +.I errorNumber +parameter will be an +.I errno +value (see +.IR intro (2)). +For the error class NSLinkEditMachResourceError the +.I errorNumber +parameter will be a +.I kern_return_t +value. +For the error class NSLinkEditOtherError the +.I errorNumber +parameter will be a one of the following values: +.RS +.nf +typedef enum { + NSOtherErrorRelocation, + NSOtherErrorLazyBind, + NSOtherErrorIndrLoop, + NSOtherErrorLazyInit, + NSOtherErrorInvalidArgs +} NSOtherErrorNumbers; +.fi +.RE +.PP +For all errors, an attempt to pass an error string will be made. +In some cases such as resource errors, it may not be possible to return a +string. +In those cases the +.I errorString +parameter will be +.sm NULL. +.PP +For file access errors and file format errors, an attempt to return a file name +will also be passed, and if that is not possible the +.I filename +parameter will be +.sm NULL. +.SH ALSO SEE +NSObjectFileImage(3), dyld(3) diff --git a/doc/man/man3/NSObjectFileImage.3 b/doc/man/man3/NSObjectFileImage.3 new file mode 100644 index 0000000..c235960 --- /dev/null +++ b/doc/man/man3/NSObjectFileImage.3 @@ -0,0 +1,151 @@ +.TH NSObjectFileImage 3 "March 14, 2003" "Apple Computer, Inc." +.SH NAME +NSObjectFileImage \- programmatic interface for working with Mach-O files +.SH SYNOPSIS +.nf +.PP +#include +.sp .5 +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage); +.sp .5 +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory( + void *address, + unsigned long size, + NSObjectFileImage *objectFileImage); +.sp .5 +extern NSObjectFileImageReturnCode NSCreateCoreFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage); +.sp .5 +extern enum DYLD_BOOL NSDestroyObjectFileImage( + NSObjectFileImage objectFileImage); +.sp .5 +extern unsigned long NSSymbolDefinitionCountInObjectFileImage( + NSObjectFileImage objectFileImage); +.sp .5 +extern const char * NSSymbolDefinitionNameInObjectFileImage( + NSObjectFileImage objectFileImage, + unsigned long ordinal); +.sp .5 +extern unsigned long NSSymbolReferenceCountInObjectFileImage( + NSObjectFileImage objectFileImage); +.sp .5 +extern const char * NSSymbolReferenceNameInObjectFileImage( + NSObjectFileImage objectFileImage, + unsigned long ordinal, + enum DYLD_BOOL *tentative_definition); /* can be NULL */ +.sp .5 +extern enum DYLD_BOOL NSIsSymbolDefinedInObjectFileImage( + NSObjectFileImage objectFileImage, + const char *symbolName); +.sp .5 +extern void * NSGetSectionDataInObjectFileImage( + NSObjectFileImage objectFileImage, + const char *segmentName, + const char *sectionName, + unsigned long* size); /* can be NULL */ +.sp .5 +extern enum DYLD_BOOL NSHasModInitObjectFileImage( + NSObjectFileImage objectFileImage); +.fi +.SH DESCRIPTION +.PP +These routines are the programmatic interface for working with Mach-O files. +They bring the Mach-O file into memory and the API allows the file to +be inspected or loaded into the program. On creation of an object file image +it is checked to insure it is a valid format and it is compatible with the host +machine's cpu architecture. +.PP +.I NSCreateObjectFileImageFromFile +takes the parameter +.I pathName +as the path name to the file name in the file system and creates and returns +an NSObjectFileImage. Currently only +.SM MH_BUNDLE +files can be used with +.I NSCreateObjectFileImageFromFile +which can then be loaded into the program using +.IR NSLinkModule (3). +If the file is valid an NSObjectFileImage is returned and the return code is +NSObjectFileImageSuccess. +.I NSCreateObjectFileImageFromMemory +does the same as +.I NSCreateObjectFileImageFromFile +but takes two parameters +.I address +and +.I size +for the Mach-O file that is in memory. +.PP +.I NSCreateCoreFileImageFromFile +takes the parameter +.I pathName +as the path name to a core file in the file system and creates and returns +an NSObjectFileImage. This NSObjectFileImage can then can be loaded into a +task with +.IR _dyld_debug_task_from_core (3) +to determine what libraries were loaded and which modules were linked. +.PP +.I NSSymbolDefinitionCountInObjectFileImage +returns the number of symbol definitions in the NSObjectFileImage. +.PP +.I NSSymbolDefinitionNameInObjectFileImage +returns the name of the i'th symbol definitions in the NSObjectFileImage. +The 'C' string returned should not be freed. If the ordinal specified is +outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will be +returned. +.PP +.I NSSymbolReferenceCountInObjectFileImage +returns the number of references to undefined symbols the NSObjectFileImage. +.PP +.I NSSymbolReferenceNameInObjectFileImage +returns the name of the i'th undefined symbol in the NSObjectFileImage. +The 'C' string returned should not be freed. If the ordinal specified is +outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be +returned. +.PP +.I NSIsSymbolDefinedInObjectFileImage +returns TRUE if the specified symbol name has a definition in the +NSObjectFileImage. +.PP +.I NSGetSectionDataInObjectFileImage +returns the address of the data for the named section in the named segment in +the NSObjectFileImage. If the parameter size is not NULL, the size of the +section is returned in size. If the section cannot be found or a zerofill +section, NULL is returned and the size returned is zero. +.PP +.I NSHasModInitObjectFileImage +returns TRUE if the NSObjectFileImage has any module initialization routines +and FALSE otherwise. + +.SH RETURN CODES +The API's that create NSObjectFileImage's return an NSObjectFileImageReturnCode +with the following possible values: +.TP +.B NSObjectFileImageSuccess +Indicates the API was successful and it returned a valid NSObjectFileImage for +the host machine's cpu architecture. +.TP +.B NSObjectFileImageFailure +Indicates the API failed and no NSObjectFileImage was returned. If this is +returned an error message is printed on stderr as to the reason for the +failure. +.TP +.B NSObjectFileImageInappropriateFile +Indicates the API failed because the file passed to it was not an appropriate +type of object file. +.TP +.B NSObjectFileImageArch +Indicates the API failed because the host machine's cpu architecture could not +be found in the file. +.TP +.B NSObjectFileImageFormat +Indicates the API failed because the Mach-O format was malformed. If this is +returned an error message is printed on stderr as to the format error. +.TP +.B NSObjectFileImageAccess +Indicates the API failed because the file could not be accessed. +.SH ALSO SEE +NSModule(3), dyld(3) diff --git a/doc/man/man3/NSObjectFileImage_priv.3 b/doc/man/man3/NSObjectFileImage_priv.3 new file mode 100644 index 0000000..aeddd1c --- /dev/null +++ b/doc/man/man3/NSObjectFileImage_priv.3 @@ -0,0 +1,42 @@ +.TH NSObjectFileImage 3 "July 9, 2003" "Apple Computer, Inc." +.SH NAME +NSObjectFileImage_priv \- programmatic interface for working with Mach-O files +.SH SYNOPSIS +.nf +.PP +#include +.sp .5 +extern enum DYLD_BOOL +NSFindSectionAndOffsetInObjectFileImage( + NSObjectFileImage objectFileImage, + unsigned long imageOffset, + const char** segmentName, /* can be NULL */ + const char** sectionName, /* can be NULL */ + unsigned long* sectionOffset) /* can be NULL */ +.sp .5 +extern enum DYLD_BOOL +NSHasModInitObjectFileImage( + NSObjectFileImage objectFileImage); +.fi +.SH DESCRIPTION +.PP +These routines are the programmatic interface for working with Mach-O files. +They bring the Mach-O file into memory and the API allows the file to +be inspected or loaded into the program. On creation of an object file image +it is checked to insure it is a valid format and it is compatible with the host +machine's cpu architecture. +.PP +.PP +.I NSFindSectionAndOffsetInObjectFileImage +is supplied an imageOffset into an ObjectFileImage and returns +via parameters the segment/section name and offset into that section of +that imageOffset. It returns FALSE if the imageOffset is not +in any section, otherwise TRUE. You can used the resulting sectionOffset to +index into the data returned by NSGetSectionDataInObjectFileImage. +.PP +.I NSHasModInitObjectFileImage +returns TRUE if the NSObjectFileImage has any module initialization routines +and FALSE otherwise. + +.SH ALSO SEE +NSObjectFileImage(3), NSModule(3), dyld(3) diff --git a/doc/man/man3/dladdr.3 b/doc/man/man3/dladdr.3 new file mode 100644 index 0000000..bca4462 --- /dev/null +++ b/doc/man/man3/dladdr.3 @@ -0,0 +1,73 @@ +.Dd September 24, 2004 +.Os +.Dt DLADDR 3 +.Sh NAME +.Nm dladdr +.Nd find the image containing a given address +.Sh SYNOPSIS +.In dlfcn.h +.Ft int +.Fn dladdr "const void* addr" "Dl_info* info" +.Sh DESCRIPTION +The +.Fn dladdr +function +queries dyld (the dynamic linker) for information about the image +containing the address +.Fa addr . +The information is returned in the structure specified by +.Fa info . +The structure contains at least the following members: +.Bl -tag -width "XXXconst char *dli_fname" +.It Li "const char* dli_fname" +The pathname of the shared object containing the address. +.It Li "void* dli_fbase" +The base address (mach_header) at which the image is mapped into the +address space of the calling process. +.It Li "const char* dli_sname" +The name of the nearest run-time symbol with a value less than or +equal to +.Fa addr . +.It Li "void* dli_saddr" +The value of the symbol returned in +.Li dli_sname . +.El +.Pp +The +.Fn dladdr +function +is available only in dynamically linked programs. +.Sh ERRORS +If an image containing +.Fa addr +cannot be found, +.Fn dladdr +returns 0. +On success, a non-zero value is returned. +.Pp +If the image containing +.Fa addr +is found, but no nearest symbol was found, +the dli_sname and dli_saddr fields are set to NULL. +.Sh SEE ALSO +.Xr dyld 3 , +.Xr dlopen 3 +.Sh HISTORY +The +.Fn dladdr +function first appeared in the Solaris operating system. +.Sh AUTHORS +Mac OS X 10.3 incorporated the dlcompat package written by Jorge Acereda +and Peter O'Gorman . +.Pp +In Mac OS X 10.4, dlopen was rewritten to be a native part of dyld. +.Pp +This man page was borrowed from FreeBSD and modified. +.Sh BUGS +This implementation is almost bug-compatible with the Solaris +implementation. The following bugs are present: +.Bl -bullet +.It +Returning 0 as an indication of failure goes against long-standing +Unix tradition. +.El diff --git a/doc/man/man3/dlclose.3 b/doc/man/man3/dlclose.3 new file mode 100644 index 0000000..c966d6a --- /dev/null +++ b/doc/man/man3/dlclose.3 @@ -0,0 +1,38 @@ +.Dd Sept 25, 2004 +.Dt DLCLOSE 3 +.Sh NAME +.Nm dlclose +.Nd close a dynamic library or bundle +.Sh SYNOPSIS +.In dlfcn.h +.Ft int +.Fn dlclose "void* handle" +.Sh DESCRIPTION +.Fn dlclose +releases a reference to the dynamic library or bundle referenced by +.Fa handle . +If the reference count drops to 0, the bundle is removed from the +address space, and +.Fa handle +is rendered invalid. +Just before removing a dynamic library or bundle in this way, any +termination routines in it are called. +.Fa handle +is the value returned by a previous call to dlopen. +.Sh RETURN VALUES +If +.Fn dlclose +is successful, it returns a value of 0. +Otherwise it returns -1, and sets an error string that can be +retrived with +.Fn dlerror . +.Pp +.Sh SEE ALSO +.Xr dlopen 3 +.Xr dlsym 3 +.Xr dlerror 3 +.Xr dyld 3 +.Xr NSModule 3 +.Xr NSObjectFileImage 3 +.Xr ld 1 +.Xr cc 1 diff --git a/doc/man/man3/dlerror.3 b/doc/man/man3/dlerror.3 new file mode 100644 index 0000000..67594b3 --- /dev/null +++ b/doc/man/man3/dlerror.3 @@ -0,0 +1,32 @@ +.Dd Sept 25, 2004 +.Dt DLERROR 3 +.Sh NAME +.Nm dlerror +.Nd get diagnostic information +.Sh SYNOPSIS +.In dlfcn.h +.Ft const char* +.Fn dlerror "void" +.Sh DESCRIPTION +.Fn dlerror +returns a null-terminated character string describing the last error that +occurred on this thread during a call to +.Fn dlopen , +.Fn dlsym , +or +.Fn dlclose . +If no such error has occurred, +.Fn dlerror +returns a null pointer. +At each call to +.Fn dlerror , +the error indication is reset. Thus in the case of two calls +to +.Fn dlerror , +where the second call follows the first immediately, the second call +will always return a null pointer. +.Sh SEE ALSO +.Xr dlopen 3 +.Xr dlclose 3 +.Xr dlsym 3 +.Xr dyld 3 diff --git a/doc/man/man3/dlopen.3 b/doc/man/man3/dlopen.3 new file mode 100644 index 0000000..e4ef8f2 --- /dev/null +++ b/doc/man/man3/dlopen.3 @@ -0,0 +1,128 @@ +.Dd February 8, 2005 +.Os +.Dt DLOPEN 3 +.Sh NAME +.Nm dlopen +.Nd load and link a dynamic library or bundle +.Sh SYNOPSIS +.In dlfcn.h +.Ft void* +.Fn dlopen "const char* path" "int mode" +.Sh DESCRIPTION +.Fn dlopen +examines the mach-o file specified by +.Fa path . +If the file is compatible with the current process and has not already been +loaded into the current process, it is loaded and linked. After being linked, +if it contains any initializer functions, they are called, before +.Fn dlopen +returns. +.Fn dlopen +can load dynamic libraries and bundles. It returns a handle that can +be used with +.Fn dlsym +and +.Fn dlclose . +A second call to +.Fn dlopen +with the same path will return the same handle, but the internal reference +count for the handle will be incremented. Therefore all +.Fn dlopen +calls should be balanced with a +.Fn dlclose +call. +.Pp +If a null pointer is passed in +.Fa path , +.Fn dlopen +returns a handle equivalent to RTLD_DEFAULT. +.Pp +.Fa mode +contains options to +.Fn dlopen . +It must contain one or more of the following values, possibly ORed together: +.Pp +.Bl -tag -width RTLD_LAZYX +.It Dv RTLD_LAZY +Each external function reference is bound the first time the function is called. +.It Dv RTLD_NOW +All external function references are bound immediately during the call to +.Fn dlopen . +.El +.Pp +.Dv RTLD_LAZY +is normally preferred, for reasons of efficiency. +However, +.Dv RTLD_NOW +is useful to ensure that any undefined symbols are discovered during the +call to +.Fn dlopen . +If neither +RTLD_LAZY nor RTLD_NOW is specified, the default is RTLD_LAZY. +.Pp +One of the following flags may be ORed into the +.Fa mode +argument: +.Bl -tag -width RTLD_GLOBALX +.It Dv RTLD_GLOBAL +Symbols exported from this image (dynamic library or bundle) will be available to any +images build with -flat_namespace option to +.Xr ld 1 +or to calls to +.Fn dlsym +when using a special handle. +.It Dv RTLD_LOCAL +Symbols exported from this image (dynamic library or bundle) are generally hidden +and only availble to +.Fn dlsym +when directly using the handle returned by this call to +.Fn dlopen . +If neither +RTLD_GLOBAL nor RTLD_LOCAL is specified, the default is RTLD_GLOBAL. +.El +.Sh SEARCHING +.Fn dlopen +uses a series of steps to find a compatible mach-o file. The first compatible file found is used. +.Pp +1) If the directory specified by +.Fa path +does not contain a slash '/' (i.e. it is a leaf name) then the environment variable LD_LIBRARY_PATH is +used. LD_LIBRARY_PATH should be a colon seperated list of directories. +.Fn dlopen +searches each directory, in the order specified, for the leaf name +.Fa path . +.Pp +2) If DYLD_LIBRARY_PATH is set, then those directories are searched, in order, +with the leaf name of +.Fa path . +.Pp +3) If DYLD_FALLBACK_LIBRARY_PATH is set, then those directories are searched, in order +with the leaf name of +.Fa path . +If DYLD_FALLBACK_LIBRARY_PATH is not set, then the following directories are searched: $HOME/lib, /usr/local/lib, /usr/lib +.Pp +4) Lastly, +.Fa path +is tried as-is as a regular file path. That means it might resolve relative to the current working directory. +.Pp +Note: There are no configuration files to control dlopen searching. +.Pp +Note: Mac OS X uses "fat" files to combine 32-bit and 64-bit libraries. This means there are no separate 32-bit and 64-bit search paths. +.Pp +.Sh RETURN VALUES +If +.Fn dlopen +fails, it returns a null pointer, and sets an error condition which may be interrogated with +.Fn dlerror . +.Sh AUTHORS +Mac OS X 10.3 incorporated the dlcompat package written by Jorge Acereda +and Peter O'Gorman . +.Pp +In Mac OS X 10.4, dlopen was rewritten to be a native part of dyld. +.Pp +.Sh SEE ALSO +.Xr dlclose 3 +.Xr dlsym 3 +.Xr dlerror 3 +.Xr dyld 3 +.Xr ld 1 diff --git a/doc/man/man3/dlsym.3 b/doc/man/man3/dlsym.3 new file mode 100644 index 0000000..6072b92 --- /dev/null +++ b/doc/man/man3/dlsym.3 @@ -0,0 +1,65 @@ +.Dd Sept 25, 2004 +.Dt DLSYM 3 +.Sh NAME +.Nm dlsym +.Nd get address of a symbol +.Sh SYNOPSIS +.In dlfcn.h +.Ft void* +.Fn dlsym "void* handle" "const char* symbol" +.Sh DESCRIPTION +.Fn dlsym +returns the address of the code or data location +specified by the null-terminated character string +.Fa symbol . +Which libraries and bundles are searched depends on the +.Fa handle +parameter. +.Pp +If +.Fn dlsym +is called with a +.Fa handle , +returned by +.Fn dlopen +then only that image and any libraries it depends on are searched for +.Fa symbol . +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_DEFAULT , +then every mach-o image in the process is searched in the order they were loaded. +This can be a costly search and should be avoided. +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_NEXT , +then the search for the symbol is limited to the images which were loaded +after the one issuing the call to +.Fn dlsym . +.Pp +.Sh RETURN VALUES +The +.Fn dlsym +function +returns a null pointer if the symbol cannot be found, and sets an error +condition which may be queried with +.Fn dlerror . +.Pp +.Sh NOTES +Unlike other dyld API's, the symbol name passed to +.Fn dlsym +must NOT be prepended with an underscore. +.Sh SEE ALSO +.Xr dlopen 3 +.Xr dlsym 3 +.Xr dlerror 3 +.Xr dyld 3 +.Xr NSModule 3 +.Xr NSObjectFileImage 3 +.Xr ld 1 +.Xr cc 1 diff --git a/doc/man/man3/dyld.3 b/doc/man/man3/dyld.3 new file mode 100644 index 0000000..9e10b90 --- /dev/null +++ b/doc/man/man3/dyld.3 @@ -0,0 +1,200 @@ +.TH DYLD 3 "January 15, 2005" "Apple Computer, Inc." +.SH NAME +dyld \- low level programatic interface to the dynamic link editor +.SH SYNOPSIS +.nf +.PP +#include +bool _dyld_present(void); +.sp .5 +uint32_t _dyld_image_count(void); +.sp .5 +const struct mach_header *_dyld_get_image_header( + uint32_t image_index); +.sp .5 +intptr_t _dyld_get_image_vmaddr_slide( + uint32_t image_index); +.sp .5 +const char *_dyld_get_image_name( + uint32_t image_index); +.sp .5 +void _dyld_lookup_and_bind( + const char *symbol_name, + void **address, + NSModule *module); +.sp .5 +void _dyld_lookup_and_bind_with_hint( + const char *symbol_name, + const char *library_name_hint, + void **address, + NSModule *module); +.sp .5 +void _dyld_lookup_and_bind_fully( + const char *symbol_name, + void **address, + NSModule *module); +.sp .5 +bool _dyld_bind_fully_image_containing_address( + const void *address); +.sp .5 +bool _dyld_image_containing_address( + const void* address); +.sp .5 +const struct mach_header * _dyld_get_image_header_containing_address( + const void* address); +.sp .5 +bool _dyld_launched_prebound(void); +.sp .5 +bool _dyld_all_twolevel_modules_prebound(void); +.sp .5 +int _dyld_func_lookup( + const char *dyld_func_name, + void **address); +.sp .5 +extern void _dyld_bind_objc_module( + const void *objc_module); +.sp .5 +extern void _dyld_get_objc_module_sect_for_module( + NSModule module, + void **objc_module, + size_t *size); +.sp .5 +extern void _dyld_lookup_and_bind_objc( + const char *symbol_name, + void **address, + NSModule *module); +.sp .5 +extern void _dyld_moninit( + void (*monaddition)(char *lowpc, char *highpc)); +.sp .5 + +extern void _dyld_register_func_for_add_image( + void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)); +.sp .5 +extern void _dyld_register_func_for_remove_image( + void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)); +.sp .5 +extern void _dyld_register_func_for_link_module( + void (*func)(NSModule module)); +.fi +.SH DESCRIPTION +These routines are the low level programatic interface to the dynamic link +editor. +.PP +.I _dyld_present returns non-zero if the dynamic linker is being used in the +program and zero otherwise. If this returns zero this rest of these functions +should not be called and most likely crash the program if called. +.PP +.I _dyld_image_count +returns the current number of images mapped in by the dynamic link editor. +.PP +.I _dyld_get_image_header +returns the mach header of the image indexed by image_index. If image_index is +out of range NULL is returned. +.PP +.I _dyld_get_image_vmaddr_slide +returns the virtural memory address slide amount of the image indexed by +.I image_index. +If image_index is out of range zero is returned. +.PP +.I _dyld_get_image_name +returns the name of the image indexed by +.I image_index. +If image_index is out of range NULL is returned. +.PP +.I _dyld_lookup_and_bind +looks up the +.I symbol_name +and binds it into the program. It indirectly returns the +.I address +and and a pointer to the +.I module +that defined the symbol. +.PP +.I _dyld_lookup_and_bind_with_hint +is the same as +.I _dyld_lookup_and_bind +but the +.I library_name_hint +parameter provides a hint as to where to start the lookup in a prebound +program. The +.I library_name_hint +parameter is matched up with the actual library install names with +.IR strstr (3). +.PP +.I _dyld_lookup_and_bind_fully +looks up the +.I symbol_name +and binds it and all of its references into the program. It indirectly returns +the +.I address +and and a pointer to the +.I module +that defined the symbol. +.PP +.I _dyld_bind_fully_image_containing_address +fully binds the image containing the specified address. It returns TRUE if the +address is contained in a loaded image and FALSE otherwise. +.PP +.I _dyld_image_containing_address +It returns TRUE if the address is contained in an image dyld loaded and FALSE +otherwise. +.PP +.I _dyld_get_image_header_containing_address +It returns a pointer to the mach header of the image if the address is contained +in an image dyld loaded and NULL otherwise. +.PP +.I _dyld_launched_prebound +returns TRUE if the program was launched using the prebound state and FALSE +otherwise. +.PP +.I_dyld_all_twolevel_modules_prebound(void); +returns TRUE if all the libraries currently in use by the program are being used +as two-level namespace libraries, are prebound and have all their modules bound. +Otherwise it returns FALSE. +.PP +.I _dyld_func_lookup +is passed a name, +.I dyld_func_name, +of a dynamic link editor function and returns the +.I address +of the function indirectly. It returns non-zero if the function is found +and zero otherwise. +.PP +.I _dyld_bind_objc_module +is passed a pointer to something in an (__OBJC,__module) section and causes the +module that is associated with that address to be bound. +.PP +.I _dyld_get_objc_module_sect_for_module +is passed a module and sets a pointer to the (__OBJC,__module) section and its +size for the specified module. +.PP +.I _dyld_lookup_and_bind_objc() +is the same as _dyld_lookup_and_bind() but does not update the symbol pointers +if the symbol is in a bound module. The reason for this is that an objc symbol +like +.I .objc_class_name_Object +is never used by a symbol pointer. Since this is done a lot by the objc +runtime and updating symbol pointers is not cheep it should not be done. +.PP +.I _dyld_moninit +is called from the profiling runtime routine +.IR moninit(3) +to cause the dyld loaded code to be profiled. It is passed a pointer to the +the profiling runtime routine +.IR monaddtion(3) +to be called after an image had been mapped in. +.PP +.I _dyld_register_func_for_add_image +registers the specified function to be called when a new image is added +(a bundle or a dynamic shared library) to the program. When this function is +first registered it is called for once for each image that is currently part of +the program. +.PP +.I _dyld_register_func_for_remove_image +registers the specified function to be called when an image is removed +(a bundle or a dynamic shared library) from the program. +.I _dyld_register_func_for_link_module +registers the specified function to be called when a module is bound into the +program. When this function is first registered it is called for once for each +module that is currently bound into the program. diff --git a/dyld.xcode/project.pbxproj b/dyld.xcode/project.pbxproj new file mode 100644 index 0000000..bdddd37 --- /dev/null +++ b/dyld.xcode/project.pbxproj @@ -0,0 +1,1044 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + EF799FE7070D27BB00F78484 = { + children = ( + EF799FE8070D27BB00F78484, + EF799FEA070D27BB00F78484, + ); + isa = PBXGroup; + name = man; + path = doc/man; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FE8070D27BB00F78484 = { + children = ( + EF799FE9070D27BB00F78484, + ); + isa = PBXGroup; + name = man1; + path = doc/man/man1; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FE9070D27BB00F78484 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.man; + name = dyld.1; + path = doc/man/man1/dyld.1; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FEA070D27BB00F78484 = { + children = ( + EF799FEB070D27BB00F78484, + EF799FEC070D27BB00F78484, + EF799FED070D27BB00F78484, + EF799FEE070D27BB00F78484, + EF799FEF070D27BB00F78484, + EF799FF0070D27BB00F78484, + EF799FF1070D27BB00F78484, + EF799FF2070D27BB00F78484, + EF799FF3070D27BB00F78484, + ); + isa = PBXGroup; + name = man3; + path = doc/man/man3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FEB070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dladdr.3; + path = doc/man/man3/dladdr.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FEC070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dlclose.3; + path = doc/man/man3/dlclose.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FED070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dlerror.3; + path = doc/man/man3/dlerror.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FEE070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dlopen.3; + path = doc/man/man3/dlopen.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FEF070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dlsym.3; + path = doc/man/man3/dlsym.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FF0070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = dyld.3; + path = doc/man/man3/dyld.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FF1070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = NSModule.3; + path = doc/man/man3/NSModule.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FF2070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = NSObjectFileImage.3; + path = doc/man/man3/NSObjectFileImage.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF799FF3070D27BB00F78484 = { + explicitFileType = text.man; + fileEncoding = 30; + isa = PBXFileReference; + name = NSObjectFileImage_priv.3; + path = doc/man/man3/NSObjectFileImage_priv.3; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + EF79A010070D293E00F78484 = { + fileRef = EF799FE9070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A011070D295200F78484 = { + fileRef = EF799FEB070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A012070D295200F78484 = { + fileRef = EF799FEC070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A013070D295200F78484 = { + fileRef = EF799FED070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A014070D295200F78484 = { + fileRef = EF799FEE070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A015070D295200F78484 = { + fileRef = EF799FEF070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A016070D295200F78484 = { + fileRef = EF799FF0070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A017070D295200F78484 = { + fileRef = EF799FF1070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A018070D295200F78484 = { + fileRef = EF799FF2070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; + EF79A019070D295200F78484 = { + fileRef = EF799FF3070D27BB00F78484; + isa = PBXBuildFile; + settings = { + }; + }; +//EF0 +//EF1 +//EF2 +//EF3 +//EF4 +//F90 +//F91 +//F92 +//F93 +//F94 + F906E2230639E96400B13DB2 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = dyld_debug.c; + path = src/dyld_debug.c; + refType = 4; + sourceTree = ""; + }; + F906E2240639E96400B13DB2 = { + fileRef = F906E2230639E96400B13DB2; + isa = PBXBuildFile; + settings = { + }; + }; + F913FAD90630A8AE00B7AE9D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyldAPIsInLibSystem.cpp; + path = src/dyldAPIsInLibSystem.cpp; + refType = 4; + sourceTree = ""; + }; + F913FADA0630A8AE00B7AE9D = { + fileRef = F913FAD90630A8AE00B7AE9D; + isa = PBXBuildFile; + settings = { + }; + }; + F921D3160703769A000D1056 = { + compilerSpec = com.apple.compilers.gcc.3_5; + fileType = sourcecode.c; + isEditable = 1; + isa = PBXBuildRule; + outputFiles = ( + ); + }; + F921D317070376A6000D1056 = { + compilerSpec = com.apple.compilers.gcc.3_5; + fileType = sourcecode.c; + isEditable = 1; + isa = PBXBuildRule; + outputFiles = ( + ); + }; + F921D318070376B0000D1056 = { + compilerSpec = com.apple.compilers.gcc.3_5; + fileType = sourcecode.asm; + isEditable = 1; + isa = PBXBuildRule; + outputFiles = ( + ); + }; + F921D31E070376F1000D1056 = { + compilerSpec = com.apple.compilers.gcc.3_5; + fileType = sourcecode.cpp; + isEditable = 1; + isa = PBXBuildRule; + outputFiles = ( + ); + }; + F939F219078F1A2100AC144F = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyld_debug.h; + path = "include/mach-o/dyld_debug.h"; + refType = 4; + sourceTree = ""; + }; + F939F21A078F1A2100AC144F = { + fileRef = F939F219078F1A2100AC144F; + isa = PBXBuildFile; + settings = { + }; + }; + F939F21B078F1A2C00AC144F = { + fileRef = F939F219078F1A2100AC144F; + isa = PBXBuildFile; + settings = { + }; + }; + F93AA9A30630AE1E00301D9F = { + fileRef = F9ED4CE80630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F93AA9A40630AE1E00301D9F = { + fileRef = F9ED4CE90630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F93AA9A50630AE1E00301D9F = { + fileRef = F9ED4CEA0630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F93AA9B30630AE8200301D9F = { + buildActionMask = 8; + dstPath = "/usr/include/mach-o"; + dstSubfolderSpec = 0; + files = ( + F939F21B078F1A2C00AC144F, + F93AA9A50630AE1E00301D9F, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + F93AA9B60630AEB100301D9F = { + buildActionMask = 8; + dstPath = "/usr/local/include/mach-o"; + dstSubfolderSpec = 0; + files = ( + F93AA9A30630AE1E00301D9F, + F93AA9A40630AE1E00301D9F, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + F93AA9C20630AF0700301D9F = { + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + EF79A010070D293E00F78484, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + F93AA9C60630AF1F00301D9F = { + buildActionMask = 8; + dstPath = /usr/share/man/man3; + dstSubfolderSpec = 0; + files = ( + EF79A011070D295200F78484, + EF79A012070D295200F78484, + EF79A013070D295200F78484, + EF79A014070D295200F78484, + EF79A015070D295200F78484, + EF79A016070D295200F78484, + EF79A017070D295200F78484, + EF79A018070D295200F78484, + EF79A019070D295200F78484, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + F9574C4906C94DA700142BFA = { + compilerSpec = com.apple.compilers.gcc.3_5; + fileType = sourcecode.c; + isEditable = 1; + isa = PBXBuildRule; + outputFiles = ( + ); + }; + F9574CB206C95C0D00142BFA = { + buildActionMask = 8; + dstPath = /usr/include; + dstSubfolderSpec = 0; + files = ( + F9574CB306C95C1B00142BFA, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + F9574CB306C95C1B00142BFA = { + fileRef = F99EE6AE06B48D4200BF1992; + isa = PBXBuildFile; + settings = { + }; + }; + F99EE6AE06B48D4200BF1992 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dlfcn.h; + path = include/dlfcn.h; + refType = 4; + sourceTree = ""; + }; + F99EE6AF06B48D4200BF1992 = { + fileRef = F99EE6AE06B48D4200BF1992; + isa = PBXBuildFile; + settings = { + }; + }; + F9B01E3D0739ABDE00CF981B = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.exports; + name = dyld.exp; + path = src/dyld.exp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9B01E3E0739ABDE00CF981B = { + fileRef = F9B01E3D0739ABDE00CF981B; + isa = PBXBuildFile; + settings = { + }; + }; + F9CA205D06CBF578000BA084 = { + buildActionMask = 8; + files = ( + ); + inputPaths = ( + "${DSTROOT}/usr/local/lib/system/ldyldapis.a", + ); + isa = PBXShellScriptBuildPhase; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "cd ${DSTROOT}/usr/local/lib/system\nln -s libdyldapis.a libdyldapis_profile.a\nln -s libdyldapis.a libdyldapis_debug.a\n"; + }; + F9ED4C870630A72200DF4E74 = { + children = ( + F9ED4CBB0630A7AA00DF4E74, + F9ED4CC30630A7BE00DF4E74, + F9ED4CBE0630A7B100DF4E74, + F9ED4C990630A76000DF4E74, + ); + isa = PBXGroup; + refType = 4; + sourceTree = ""; + }; + F9ED4C890630A72300DF4E74 = { + buildSettings = { + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = NO; + GCC_OPTIMIZATION_LEVEL = 0; + }; + isa = PBXBuildStyle; + name = Development; + }; + F9ED4C8A0630A72300DF4E74 = { + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_CPP_RTTI = NO; + }; + isa = PBXBuildStyle; + name = Deployment; + }; + F9ED4C8B0630A72300DF4E74 = { + buildSettings = { + }; + buildStyles = ( + F9ED4C890630A72300DF4E74, + F9ED4C8A0630A72300DF4E74, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = F9ED4C870630A72200DF4E74; + productRefGroup = F9ED4C990630A76000DF4E74; + projectDirPath = ""; + targets = ( + F9ED4C920630A73900DF4E74, + F9ED4C970630A76000DF4E74, + F9ED4C9E0630A76B00DF4E74, + ); + }; + F9ED4C920630A73900DF4E74 = { + buildPhases = ( + ); + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = all; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + F9ED4CA70630A78A00DF4E74, + F9ED4CA90630A78A00DF4E74, + ); + isa = PBXAggregateTarget; + name = all; + productName = all; + }; + F9ED4C950630A76000DF4E74 = { + buildActionMask = 2147483647; + files = ( + F9ED4CDF0630A7F100DF4E74, + F9ED4CD60630A7F100DF4E74, + F9ED4CD70630A7F100DF4E74, + F9ED4CD80630A7F100DF4E74, + F9ED4CD90630A7F100DF4E74, + F9ED4CDA0630A7F100DF4E74, + F9ED4CDB0630A7F100DF4E74, + F9ED4CDE0630A7F100DF4E74, + F9ED4CE00630A7F100DF4E74, + F9ED4CE10630A7F100DF4E74, + F9ED4CE20630A7F100DF4E74, + F9ED4CE30630A7F100DF4E74, + F9ED4CE40630A7F100DF4E74, + F9ED4CE50630A7F100DF4E74, + F9ED4CEB0630A80600DF4E74, + F9ED4CEC0630A80600DF4E74, + F9ED4CED0630A80600DF4E74, + F99EE6AF06B48D4200BF1992, + F9B01E3E0739ABDE00CF981B, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + F9ED4C960630A76000DF4E74 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + F9ED4C970630A76000DF4E74 = { + buildPhases = ( + F9ED4C950630A76000DF4E74, + F9ED4C960630A76000DF4E74, + ); + buildRules = ( + F921D318070376B0000D1056, + F921D317070376A6000D1056, + F921D3160703769A000D1056, + ); + buildSettings = { + ARCHS = ppc; + CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEAD_CODE_STRIPPING = YES; + EXPORTED_SYMBOLS_FILE = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_MODEL_TUNING = G4; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ./include; + INSTALL_PATH = /usr/lib; + LIBRARY_SEARCH_PATHS = ""; + MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = "-v -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib -lstdc++ /usr/local/lib/system/libc.a -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld"; + OTHER_REZFLAGS = ""; + PER_ARCH_CFLAGS_ppc = ""; + PER_ARCH_CFLAGS_ppc64 = "-msoft-float"; + PREBINDING = NO; + PRODUCT_NAME = dyld; + STRIPFLAGS = "-S"; + UNSTRIPPED_PRODUCT = NO; + VALID_ARCHS = "ppc ppc64 i386"; + VERSIONING_SYSTEM = "apple-generic"; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = dyld; + productName = dyld; + productReference = F9ED4C980630A76000DF4E74; + productType = "com.apple.product-type.tool"; + }; + F9ED4C980630A76000DF4E74 = { + explicitFileType = "compiled.mach-o.executable"; + includeInIndex = 0; + isa = PBXFileReference; + path = dyld; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F9ED4C990630A76000DF4E74 = { + children = ( + F9ED4C980630A76000DF4E74, + F9ED4C9F0630A76B00DF4E74, + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; + F9ED4C9B0630A76B00DF4E74 = { + buildActionMask = 2147483647; + files = ( + F9FE429C06C82066001D8CE5, + F939F21A078F1A2100AC144F, + ); + isa = PBXHeadersBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + F9ED4C9C0630A76B00DF4E74 = { + buildActionMask = 2147483647; + files = ( + F9F256360639DBCC00A7427D, + F9F256370639DBCC00A7427D, + F913FADA0630A8AE00B7AE9D, + F906E2240639E96400B13DB2, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + F9ED4C9D0630A76B00DF4E74 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + F9ED4C9E0630A76B00DF4E74 = { + buildPhases = ( + F9ED4C9C0630A76B00DF4E74, + F9ED4C9B0630A76B00DF4E74, + F93AA9B30630AE8200301D9F, + F9574CB206C95C0D00142BFA, + F93AA9B60630AEB100301D9F, + F93AA9C20630AF0700301D9F, + F93AA9C60630AF1F00301D9F, + F9CA205D06CBF578000BA084, + F9ED4C9D0630A76B00DF4E74, + ); + buildRules = ( + F921D31E070376F1000D1056, + F9574C4906C94DA700142BFA, + ); + buildSettings = { + ARCHS = ppc; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + HEADER_SEARCH_PATHS = ./include; + INSTALL_PATH = /usr/local/lib/system; + LIBRARY_STYLE = STATIC; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = dyldapis; + SECTORDER_FLAGS = ""; + VALID_ARCHS = "ppc ppc64 i386"; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = libdyld; + productName = libdyld; + productReference = F9ED4C9F0630A76B00DF4E74; + productType = "com.apple.product-type.library.static"; + }; + F9ED4C9F0630A76B00DF4E74 = { + explicitFileType = archive.ar; + includeInIndex = 0; + isa = PBXFileReference; + path = libdyldapis.a; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F9ED4CA60630A78A00DF4E74 = { + containerPortal = F9ED4C8B0630A72300DF4E74; + isa = PBXContainerItemProxy; + proxyType = 1; + remoteGlobalIDString = F9ED4C970630A76000DF4E74; + remoteInfo = dyld; + }; + F9ED4CA70630A78A00DF4E74 = { + isa = PBXTargetDependency; + target = F9ED4C970630A76000DF4E74; + targetProxy = F9ED4CA60630A78A00DF4E74; + }; + F9ED4CA80630A78A00DF4E74 = { + containerPortal = F9ED4C8B0630A72300DF4E74; + isa = PBXContainerItemProxy; + proxyType = 1; + remoteGlobalIDString = F9ED4C9E0630A76B00DF4E74; + remoteInfo = libdyld; + }; + F9ED4CA90630A78A00DF4E74 = { + isa = PBXTargetDependency; + target = F9ED4C9E0630A76B00DF4E74; + targetProxy = F9ED4CA80630A78A00DF4E74; + }; + F9ED4CBB0630A7AA00DF4E74 = { + children = ( + F9ED4CC60630A7F100DF4E74, + F9ED4CC70630A7F100DF4E74, + F9ED4CC80630A7F100DF4E74, + F9FE429B06C82066001D8CE5, + F9ED4CC90630A7F100DF4E74, + F9ED4CCA0630A7F100DF4E74, + F913FAD90630A8AE00B7AE9D, + F9ED4CCB0630A7F100DF4E74, + F9ED4CCC0630A7F100DF4E74, + F9ED4CCD0630A7F100DF4E74, + F9ED4CCE0630A7F100DF4E74, + F9ED4CCF0630A7F100DF4E74, + F9ED4CD00630A7F100DF4E74, + F9ED4CD10630A7F100DF4E74, + F9ED4CD20630A7F100DF4E74, + F9ED4CD30630A7F100DF4E74, + F9ED4CD40630A7F100DF4E74, + F9ED4CD50630A7F100DF4E74, + F9B01E3D0739ABDE00CF981B, + F906E2230639E96400B13DB2, + ); + isa = PBXGroup; + name = src; + refType = 4; + sourceTree = ""; + }; + F9ED4CBE0630A7B100DF4E74 = { + children = ( + F9ED4CE80630A80600DF4E74, + F9ED4CE90630A80600DF4E74, + F939F219078F1A2100AC144F, + F9ED4CEA0630A80600DF4E74, + F99EE6AE06B48D4200BF1992, + ); + isa = PBXGroup; + name = include; + path = ""; + refType = 4; + sourceTree = ""; + }; + F9ED4CC30630A7BE00DF4E74 = { + children = ( + EF799FE7070D27BB00F78484, + ); + isa = PBXGroup; + name = doc; + path = ""; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CC60630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyld_gdb.cpp; + path = src/dyld_gdb.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CC70630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyld.cpp; + path = src/dyld.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CC80630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyld.h; + path = src/dyld.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CC90630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyldAPIs.cpp; + path = src/dyldAPIs.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCA0630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = dyldExceptions.c; + path = src/dyldExceptions.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCB0630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyldInitialization.cpp; + path = src/dyldInitialization.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCC0630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyldLock.cpp; + path = src/dyldLock.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCD0630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyldLock.h; + path = src/dyldLock.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCE0630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = dyldNew.cpp; + path = src/dyldNew.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CCF0630A7F100DF4E74 = { + fileEncoding = 30; + indentWidth = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.asm; + name = dyldStartup.s; + path = src/dyldStartup.s; + refType = 2; + sourceTree = SOURCE_ROOT; + tabWidth = 8; + usesTabs = 1; + }; + F9ED4CD00630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = glue.c; + path = src/glue.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CD10630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = ImageLoader.cpp; + path = src/ImageLoader.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CD20630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ImageLoader.h; + path = src/ImageLoader.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CD30630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = ImageLoaderMachO.cpp; + path = src/ImageLoaderMachO.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CD40630A7F100DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ImageLoaderMachO.h; + path = src/ImageLoaderMachO.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CD50630A7F100DF4E74 = { + fileEncoding = 30; + indentWidth = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.asm; + name = stub_binding_helper.s; + path = src/stub_binding_helper.s; + refType = 2; + sourceTree = SOURCE_ROOT; + tabWidth = 8; + usesTabs = 1; + }; + F9ED4CD60630A7F100DF4E74 = { + fileRef = F9ED4CC60630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CD70630A7F100DF4E74 = { + fileRef = F9ED4CC70630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CD80630A7F100DF4E74 = { + fileRef = F9ED4CC80630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CD90630A7F100DF4E74 = { + fileRef = F9ED4CC90630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CDA0630A7F100DF4E74 = { + fileRef = F9ED4CCA0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CDB0630A7F100DF4E74 = { + fileRef = F9ED4CCB0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CDE0630A7F100DF4E74 = { + fileRef = F9ED4CCE0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CDF0630A7F100DF4E74 = { + fileRef = F9ED4CCF0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE00630A7F100DF4E74 = { + fileRef = F9ED4CD00630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE10630A7F100DF4E74 = { + fileRef = F9ED4CD10630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE20630A7F100DF4E74 = { + fileRef = F9ED4CD20630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE30630A7F100DF4E74 = { + fileRef = F9ED4CD30630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE40630A7F100DF4E74 = { + fileRef = F9ED4CD40630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE50630A7F100DF4E74 = { + fileRef = F9ED4CD50630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CE80630A80600DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyld_gdb.h; + path = "include/mach-o/dyld_gdb.h"; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CE90630A80600DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyld_priv.h; + path = "include/mach-o/dyld_priv.h"; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CEA0630A80600DF4E74 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyld.h; + path = "include/mach-o/dyld.h"; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + F9ED4CEB0630A80600DF4E74 = { + fileRef = F9ED4CE80630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CEC0630A80600DF4E74 = { + fileRef = F9ED4CE90630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9ED4CED0630A80600DF4E74 = { + fileRef = F9ED4CEA0630A80600DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9F256360639DBCC00A7427D = { + fileRef = F9ED4CCC0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9F256370639DBCC00A7427D = { + fileRef = F9ED4CCD0630A7F100DF4E74; + isa = PBXBuildFile; + settings = { + }; + }; + F9FE429B06C82066001D8CE5 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = dyldLibSystemThreadHelpers.h; + path = src/dyldLibSystemThreadHelpers.h; + refType = 4; + sourceTree = ""; + }; + F9FE429C06C82066001D8CE5 = { + fileRef = F9FE429B06C82066001D8CE5; + isa = PBXBuildFile; + settings = { + }; + }; + }; + rootObject = F9ED4C8B0630A72300DF4E74; +} diff --git a/include/dlfcn.h b/include/dlfcn.h new file mode 100644 index 0000000..77d7521 --- /dev/null +++ b/include/dlfcn.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + Based on the dlcompat work done by: + Jorge Acereda & + Peter O'Gorman +*/ + +#ifndef _DLFCN_H_ +#define _DLFCN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef _POSIX_C_SOURCE +/* + * Structure filled in by dladdr(). + */ +typedef struct dl_info { + const char *dli_fname; /* Pathname of shared object */ + void *dli_fbase; /* Base address of shared object */ + const char *dli_sname; /* Name of nearest symbol */ + void *dli_saddr; /* Address of nearest symbol */ +} Dl_info; + +extern int dladdr(const void *, Dl_info *); +#endif /* not POSIX */ + +extern int dlclose(void * __handle); +extern char * dlerror(void); +extern void * dlopen(const char * __path, int __mode); +extern void * dlsym(void * __handle, const char * __symbol); + +#define RTLD_LAZY 0x1 +#define RTLD_NOW 0x2 +#define RTLD_LOCAL 0x4 +#define RTLD_GLOBAL 0x8 + +#ifndef _POSIX_C_SOURCE +#define RTLD_NOLOAD 0x10 +#define RTLD_NODELETE 0x80 + +/* + * Special handle arguments for dlsym(). + */ +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */ +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */ +#endif /* not POSIX */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DLFCN_H_ */ diff --git a/include/mach-o/dyld.h b/include/mach-o/dyld.h new file mode 100644 index 0000000..62cb9a7 --- /dev/null +++ b/include/mach-o/dyld.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _MACH_O_DYLD_H_ +#define _MACH_O_DYLD_H_ + +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#if __cplusplus + /* C++ has bool type built in */ +#else + #include +#endif +#include +#include + +#ifndef ENUM_DYLD_BOOL +#define ENUM_DYLD_BOOL +#undef FALSE +#undef TRUE +enum DYLD_BOOL { + FALSE, + TRUE +}; +#endif /* ENUM_DYLD_BOOL */ + +/* + * The high level NS... API. + */ + +/* Object file image API */ +typedef enum { + NSObjectFileImageFailure, /* for this a message is printed on stderr */ + NSObjectFileImageSuccess, + NSObjectFileImageInappropriateFile, + NSObjectFileImageArch, + NSObjectFileImageFormat, /* for this a message is printed on stderr */ + NSObjectFileImageAccess +} NSObjectFileImageReturnCode; + +typedef struct __NSObjectFileImage* NSObjectFileImage; + +/* limited implementation, only MH_BUNDLE files can be used */ +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage); +extern NSObjectFileImageReturnCode NSCreateCoreFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage); +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory( + const void *address, + size_t size, + NSObjectFileImage *objectFileImage); +extern bool NSDestroyObjectFileImage( + NSObjectFileImage objectFileImage); +/* + * API on NSObjectFileImage's for: + * "for Each Symbol Definition In Object File Image" (for Dynamic Bundles) + * and the same thing for references + */ +extern uint32_t NSSymbolDefinitionCountInObjectFileImage( + NSObjectFileImage objectFileImage); +extern const char * NSSymbolDefinitionNameInObjectFileImage( + NSObjectFileImage objectFileImage, + uint32_t ordinal); +extern uint32_t NSSymbolReferenceCountInObjectFileImage( + NSObjectFileImage objectFileImage); +extern const char * NSSymbolReferenceNameInObjectFileImage( + NSObjectFileImage objectFileImage, + uint32_t ordinal, + bool *tentative_definition); /* can be NULL */ +/* + * API on NSObjectFileImage: + * "does Object File Image define symbol name X" (using sorted symbol table) + * and a way to get the named objective-C section + */ +extern bool NSIsSymbolDefinedInObjectFileImage( + NSObjectFileImage objectFileImage, + const char *symbolName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern void * NSGetSectionDataInObjectFileImage( + NSObjectFileImage objectFileImage, + const char *segmentName, + const char *sectionName, + size_t *size); /* can be NULL */ +/* SPI first appeared in Mac OS X 10.3 */ +extern bool NSHasModInitObjectFileImage( + NSObjectFileImage objectFileImage) + AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +/* module API */ +typedef struct __NSModule* NSModule; +extern const char * NSNameOfModule( + NSModule m); +extern const char * NSLibraryNameForModule( + NSModule m); + +/* limited implementation, only MH_BUNDLE files can be linked */ +extern NSModule NSLinkModule( + NSObjectFileImage objectFileImage, + const char *moduleName, + uint32_t options); +#define NSLINKMODULE_OPTION_NONE 0x0 +#define NSLINKMODULE_OPTION_BINDNOW 0x1 +#define NSLINKMODULE_OPTION_PRIVATE 0x2 +#define NSLINKMODULE_OPTION_RETURN_ON_ERROR 0x4 +#define NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES 0x8 +#define NSLINKMODULE_OPTION_TRAILING_PHYS_NAME 0x10 + +/* limited implementation, only modules loaded with NSLinkModule() can be + unlinked */ +extern bool NSUnLinkModule( + NSModule module, + uint32_t options); +#define NSUNLINKMODULE_OPTION_NONE 0x0 +#define NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED 0x1 +#define NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES 0x2 + +/* not yet implemented */ +extern NSModule NSReplaceModule( + NSModule moduleToReplace, + NSObjectFileImage newObjectFileImage, + uint32_t options); + +/* symbol API */ +typedef struct __NSSymbol* NSSymbol; +extern bool NSIsSymbolNameDefined( + const char *symbolName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern bool NSIsSymbolNameDefinedWithHint( + const char *symbolName, + const char *libraryNameHint) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern bool NSIsSymbolNameDefinedInImage( + const struct mach_header *image, + const char *symbolName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern NSSymbol NSLookupAndBindSymbol( + const char *symbolName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern NSSymbol NSLookupAndBindSymbolWithHint( + const char *symbolName, + const char *libraryNameHint) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern NSSymbol NSLookupSymbolInModule( + NSModule module, + const char *symbolName); +extern NSSymbol NSLookupSymbolInImage( + const struct mach_header *image, + const char *symbolName, + uint32_t options); +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2 +#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 +extern const char * NSNameOfSymbol( + NSSymbol symbol); +extern void * NSAddressOfSymbol( + NSSymbol symbol); +extern NSModule NSModuleForSymbol( + NSSymbol symbol); + +/* error handling API */ +typedef enum { + NSLinkEditFileAccessError, + NSLinkEditFileFormatError, + NSLinkEditMachResourceError, + NSLinkEditUnixResourceError, + NSLinkEditOtherError, + NSLinkEditWarningError, + NSLinkEditMultiplyDefinedError, + NSLinkEditUndefinedError +} NSLinkEditErrors; + +/* + * For the NSLinkEditErrors value NSLinkEditOtherError these are the values + * passed to the link edit error handler as the errorNumber (what would be an + * errno value for NSLinkEditUnixResourceError or a kern_return_t value for + * NSLinkEditMachResourceError). + */ +typedef enum { + NSOtherErrorRelocation, + NSOtherErrorLazyBind, + NSOtherErrorIndrLoop, + NSOtherErrorLazyInit, + NSOtherErrorInvalidArgs +} NSOtherErrorNumbers; + +extern void NSLinkEditError( + NSLinkEditErrors *c, + int *errorNumber, + const char **fileName, + const char **errorString); + +typedef struct { + void (*undefined)(const char *symbolName); + NSModule (*multiple)(NSSymbol s, NSModule oldModule, NSModule newModule); + void (*linkEdit)(NSLinkEditErrors errorClass, int errorNumber, + const char *fileName, const char *errorString); +} NSLinkEditErrorHandlers; + +extern void NSInstallLinkEditErrorHandlers( + const NSLinkEditErrorHandlers *handlers); + +/* other API */ +extern bool NSAddLibrary( + const char *pathName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern bool NSAddLibraryWithSearching( + const char *pathName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern const struct mach_header * NSAddImage( + const char *image_name, + uint32_t options); +#define NSADDIMAGE_OPTION_NONE 0x0 +#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 +#define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2 +#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 +#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 +extern int32_t NSVersionOfRunTimeLibrary( + const char *libraryName); +extern int32_t NSVersionOfLinkTimeLibrary( + const char *libraryName); +extern int _NSGetExecutablePath( /* SPI first appeared in Mac OS X 10.2 */ + char *buf, + uint32_t *bufsize); + +/* + * The low level _dyld_... API. + * (used by the objective-C runtime primarily) + */ +extern bool _dyld_present( + void); + +extern uint32_t _dyld_image_count( + void); +extern const struct mach_header * _dyld_get_image_header( + uint32_t image_index); +extern intptr_t _dyld_get_image_vmaddr_slide( + uint32_t image_index); +extern const char * _dyld_get_image_name( + uint32_t image_index); + +extern void _dyld_register_func_for_add_image( + void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)); +extern void _dyld_register_func_for_remove_image( + void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)); +extern void _dyld_register_func_for_link_module( + void (*func)(NSModule module)); +/* not yet implemented */ +extern void _dyld_register_func_for_unlink_module( + void (*func)(NSModule module)); +/* not yet implemented */ +extern void _dyld_register_func_for_replace_module( + void (*func)(NSModule oldmodule, NSModule newmodule)); +extern void _dyld_get_objc_module_sect_for_module( + NSModule module, + void **objc_module, + size_t *size); +extern void _dyld_bind_objc_module( + const void *objc_module); +extern bool _dyld_bind_fully_image_containing_address( + const void *address); +extern bool _dyld_image_containing_address( + const void* address); +/* SPI first appeared in Mac OS X 10.3 */ +extern const struct mach_header * _dyld_get_image_header_containing_address( + const void* address) + AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +extern void _dyld_moninit( + void (*monaddition)(char *lowpc, char *highpc)); +extern bool _dyld_launched_prebound( + void); +/* SPI first appeared in Mac OS X 10.3 */ +extern bool _dyld_all_twolevel_modules_prebound( + void) + AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +extern void _dyld_lookup_and_bind( + const char *symbol_name, + void **address, + NSModule* module) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern void _dyld_lookup_and_bind_with_hint( + const char *symbol_name, + const char *library_name_hint, + void **address, + NSModule* module) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; +extern void _dyld_lookup_and_bind_objc( + const char *symbol_name, + void **address, + NSModule* module); +extern void _dyld_lookup_and_bind_fully( + const char *symbol_name, + void **address, + NSModule* module); + +extern int _dyld_func_lookup( + const char *dyld_func_name, + void **address); + +#if __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _MACH_O_DYLD_H_ */ diff --git a/include/mach-o/dyld_debug.h b/include/mach-o/dyld_debug.h new file mode 100644 index 0000000..a0590f5 --- /dev/null +++ b/include/mach-o/dyld_debug.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _DYLD_DEBUG_ +#define _DYLD_DEBUG_ + +#include +#ifndef DYLD_BUILD /* do not include this when building dyld itself */ +#include +#endif /* !defined(DYLD_BUILD) */ + +#include + +/* + * The dyld debugging API is deprecated as of Mac OS X 10.4 + */ +enum dyld_debug_return { + DYLD_SUCCESS, + DYLD_INCONSISTENT_DATA, + DYLD_INVALID_ARGUMENTS, + DYLD_FAILURE +}; + +struct dyld_debug_module { + struct mach_header *header; + unsigned long vmaddr_slide; + unsigned long module_index; +}; + +enum dyld_event_type { + DYLD_IMAGE_ADDED, + DYLD_MODULE_BOUND, + DYLD_MODULE_REMOVED, + DYLD_MODULE_REPLACED, + DYLD_PAST_EVENTS_END, + DYLD_IMAGE_REMOVED +}; + +struct dyld_event { + enum dyld_event_type type; + struct dyld_debug_module arg[2]; +}; + +extern enum dyld_debug_return _dyld_debug_defining_module( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + char *name, + struct dyld_debug_module *module) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +extern enum dyld_debug_return _dyld_debug_is_module_bound( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + struct dyld_debug_module module, + boolean_t *bound) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +extern enum dyld_debug_return _dyld_debug_bind_module( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + struct dyld_debug_module module) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +extern enum dyld_debug_return _dyld_debug_module_name( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + struct dyld_debug_module module, + char **image_name, + unsigned long *image_nameCnt, + char **module_name, + unsigned long *module_nameCnt) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +extern enum dyld_debug_return _dyld_debug_subscribe_to_events( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + void (*dyld_event_routine)(struct dyld_event event)) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +/* + * _dyld_debug_add_event_subscriber() uses the mig interface functions below + * to dispatch the dyld event messages from the subscriber port specified. + */ +extern enum dyld_debug_return _dyld_debug_add_event_subscriber( + mach_port_t target_task, + unsigned long send_timeout, + unsigned long rcv_timeout, + boolean_t inconsistent_data_ok, + mach_port_t subscriber) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +/* + * These structures should be produced by mig(1) from the mig generated files + * but they are not. These are really only needed so the correct size of the + * request and reply messages can be allocated. + */ +struct _dyld_event_message_request { +#ifdef __MACH30__ + mach_msg_header_t head; + NDR_record_t NDR; + struct dyld_event event; + mach_msg_trailer_t trailer; +#else + msg_header_t head; + msg_type_t eventType; + struct dyld_event event; +#endif +}; +struct _dyld_event_message_reply { +#ifdef __MACH30__ + mach_msg_header_t head; + NDR_record_t NDR; + struct dyld_event event; +#else + msg_header_t head; + msg_type_t RetCodeType; + kern_return_t RetCode; +#endif +}; +#ifndef mig_internal +/* + * _dyld_event_server() is the mig generated routine to dispatch dyld event + * messages. + */ +extern boolean_t _dyld_event_server( +#ifdef __MACH30__ + mach_msg_header_t *request, + mach_msg_header_t *reply); +#else + struct _dyld_event_message_request *request, + struct _dyld_event_message_reply *reply); +#endif +#endif /* mig_internal */ + +#ifndef SHLIB +/* + * _dyld_event_server_callback() is the routine called by _dyld_event_server() + * that must be written by users of _dyld_event_server(). + */ +extern +#ifdef __MACH30__ +kern_return_t +#else +void +#endif +_dyld_event_server_callback( +#ifdef __MACH30__ + mach_port_t subscriber, +#else + port_t subscriber, +#endif + struct dyld_event event); +#endif /* SHLIB */ + +/* + * This is the state of the target task while we are sending a message to it. + */ +struct _dyld_debug_task_state { + mach_port_t debug_port; + mach_port_t debug_thread; + unsigned int debug_thread_resume_count; + unsigned int task_resume_count; + mach_port_t *threads; + unsigned int thread_count; +}; + +/* + * _dyld_debug_make_runnable() is called before sending messages to the + * dynamic link editor. Basically it assures that the debugging + * thread is the only runnable thread in the task to receive the + * message. It also assures that the debugging thread is indeed + * runnable if it was suspended. The function will make sure each + * thread in the remote task is suspended and resumed the same number + * of times, so in the end the suspend count of each individual thread + * is the same. + */ +extern enum dyld_debug_return _dyld_debug_make_runnable( + mach_port_t target_task, + struct _dyld_debug_task_state *state) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +/* + * _dyld_debug_restore_runnable() is called after sending messages to the + * dynamic link editor. It undoes what _dyld_debug_make_runnable() did to the + * task and put it back the way it was. + */ +extern enum dyld_debug_return _dyld_debug_restore_runnable( + mach_port_t target_task, + struct _dyld_debug_task_state *state) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +/* + * To provide more detailed information when the APIs of the dyld debug + * interfaces fail (return DYLD_FAILURE) the following structure is filled in. + * After it is filled in the function registered with + * set_dyld_debug_error_func() is called with a pointer to that struct. + * + * The local_error field is a unique number for each possible error condition + * in the source code in that makes up the dyld debug APIs. The source file + * and line number in the cctools libdyld directory where the dyld debug APIs + * are implemented are set into the file_name and line_number fields. The + * field dyld_debug_return is filled in with that would be returned by the + * API (usually DYLD_FAILURE). The other fields will be zero or filled in by + * the error code from the mach system call, or UNIX system call that failed. + */ +struct dyld_debug_error_data { + enum dyld_debug_return dyld_debug_return; + kern_return_t mach_error; + int dyld_debug_errno; + unsigned long local_error; + char *file_name; + unsigned long line_number; +}; + +extern void _dyld_debug_set_error_func( + void (*func)(struct dyld_debug_error_data *e)) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +#ifndef DYLD_BUILD /* do not include this when building dyld itself */ + +extern enum dyld_debug_return _dyld_debug_task_from_core( + NSObjectFileImage coreFileImage, + mach_port_t *core_task) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; + +#endif /* !defined(DYLD_BUILD) */ + +#endif /* _DYLD_DEBUG_ */ diff --git a/include/mach-o/dyld_gdb.h b/include/mach-o/dyld_gdb.h new file mode 100644 index 0000000..9910dcd --- /dev/null +++ b/include/mach-o/dyld_gdb.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _DYLD_GDB_ +#define _DYLD_GDB_ +/* + * This file describes the interface between gdb and dyld created for + * MacOS X GM. Prior to MacOS X GM gdb used the dyld_debug interfaces + * described in . + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__ + +#if OLD_GDB_DYLD_INTERFACE +/* + * gdb_dyld_version is the version of gdb interface that dyld is currently + * exporting. For the interface described in this header file gdb_dyld_version + * is 2. As the gdb/dyld interface changes this number will be incremented and + * comments will be added as to what are the are changes for the various + * versions. + */ +extern unsigned int gdb_dyld_version; + +/* + * gdb_dyld_state_changed is the internal dyld routine called by dyld to notify + * gdb that the state of the data structures has changed. gdb is expected to + * put a break point on this routine and re-read the internal dyld data + * structures below when this break point is hit. + */ +extern void gdb_dyld_state_changed(void); + +/* + * gdb looks directly at parts of two of dyld's internal data structures. The + * list of object file images and the list of library images. The parts of + * these structures that gdb looks at will not change unless the value of + * gdb_dyld_version changes. The size of these structures and the other fields + * that gdb does not look at may change. + * + * struct object_images { + * struct object_image images[NOBJECT_IMAGES]; + * unsigned long nimages; + * struct object_images *next_images; + * ... + * }; + * + * struct library_images { + * struct library_image images[NLIBRARY_IMAGES]; + * unsigned long nimages; + * struct library_images *next_images; + * ... + * }; + * + * Both the object_image structure and the library_image structure + * start with a structure containing the following fields: + * + * struct image { + * char *physical_name; physical image name (file name) + * unsigned long vmaddr_slide; the slide from the staticly linked address + * struct mach_header *mh; address of the mach header of the image + * unsigned long valid; TRUE if this is struct is valid + * char *name; image name for reporting errors + * ... + * }; + * + * In gdb_dyld_version 1 the first field was "name". In gdb_dyld_version 2 the + * first field was changed to "physical_name" and a new fifth field "name" was + * added. These two fields are set to the same values except in the case of + * zero-link. In zero-link the NSLinkModule() option + * NSLINKMODULE_OPTION_TRAILING_PHYS_NAME is used and then the physical_name is + * the file name of the module zero-link loaded that is part of the logical + * image "name". + */ + +/* object_images is the global object_images structure */ + +/* the number of gdb_object_image structures present per bucket */ +extern unsigned int gdb_nobject_images; + +/* the size of each gdb_object_image structure */ +extern unsigned int gdb_object_image_size; + +/* library_images is the global library_images structure */ + +/* the number of gdb_library_image structures present per bucket */ +extern unsigned int gdb_nlibrary_images; + +/* the size of each gdb_library_image structure */ +extern unsigned int gdb_library_image_size; + +#endif /* OLD_GDB_DYLD_INTERFACE */ + + +/* + * Beginning in Mac OS X 10.4, there is a new mechanism for dyld to notify gdb and other about new images. + * + * + */ + +enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 }; + +struct dyld_image_info { + const struct mach_header* imageLoadAddress; /* base address image is mapped into */ + const char* imageFilePath; /* path dyld used to load the image */ + uintptr_t imageFileModDate; /* time_t of image file */ + /* if stat().st_mtime of imageFilePath does not match imageFileModDate, */ + /* then file has been modified since dyld loaded it */ +}; + + +typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]); + +/* + * gdb looks for the symbol "_dyld_all_image_infos" in dyld. It contains the fields below. + * + * For a snap shot of what images are currently loaded, the infoArray fields contain a pointer + * to an array of all images. If infoArray is NULL, it means it is being modified, come back later. + * + * To be notified of changes, gdb sets a break point on the notification field. The function + * it points to is called by dyld with an array of information about what images have been added + * (dyld_image_adding) or are about to be removed (dyld_image_removing). + * + * The notification is called after infoArray is updated. This means that if gdb attaches to a process + * and infoArray is NULL, gdb can set a break point on notification and let the proccess continue to + * run until the break point. Then gdb can inspect the full infoArray. + */ + struct dyld_all_image_infos { + uint32_t version; /* == 1 in Mac OS X 10.4 */ + uint32_t infoArrayCount; + const struct dyld_image_info* infoArray; + dyld_image_notifier notification; + bool processDetachedFromSharedRegion; +}; +extern struct dyld_all_image_infos dyld_all_image_infos; + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _DYLD_GDB_ */ diff --git a/include/mach-o/dyld_priv.h b/include/mach-o/dyld_priv.h new file mode 100644 index 0000000..5111ebb --- /dev/null +++ b/include/mach-o/dyld_priv.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _MACH_O_DYLD_PRIV_H_ +#define _MACH_O_DYLD_PRIV_H_ + + +#include + +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* + * Given an imageOffset into an ObjectFileImage, returns + * the segment/section name and offset into that section of + * that imageOffset. Returns FALSE if the imageOffset is not + * in any section. You can used the resulting sectionOffset to + * index into the data returned by NSGetSectionDataInObjectFileImage. + * + * First appeared in Mac OS X 10.3 + * + * SPI: currently only used by ZeroLink to detect +load methods + */ +bool +NSFindSectionAndOffsetInObjectFileImage( + NSObjectFileImage objectFileImage, + unsigned long imageOffset, + const char** segmentName, /* can be NULL */ + const char** sectionName, /* can be NULL */ + unsigned long* sectionOffset); /* can be NULL */ + + + + +#if __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _MACH_O_DYLD_PRIV_H_ */ diff --git a/src/ImageLoader.cpp b/src/ImageLoader.cpp new file mode 100644 index 0000000..663ac98 --- /dev/null +++ b/src/ImageLoader.cpp @@ -0,0 +1,1015 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#define __STDC_LIMIT_MACROS +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ImageLoader.h" + + +uint32_t ImageLoader::fgImagesWithUsedPrebinding = 0; +uint32_t ImageLoader::fgTotalRebaseFixups = 0; +uint32_t ImageLoader::fgTotalBindFixups = 0; +uint32_t ImageLoader::fgTotalLazyBindFixups = 0; +uint32_t ImageLoader::fgTotalPossibleLazyBindFixups = 0; +uint64_t ImageLoader::fgTotalLoadLibrariesTime; +uint64_t ImageLoader::fgTotalRebaseTime; +uint64_t ImageLoader::fgTotalBindTime; +uint64_t ImageLoader::fgTotalNotifyTime; +uint64_t ImageLoader::fgTotalInitTime; +uintptr_t ImageLoader::fgNextSplitSegAddress = 0x90000000; +uintptr_t Segment::fgNextNonSplitSegAddress = 0x8FE00000; + + + +__attribute__((noreturn)) +void throwf(const char* format, ...) +{ + va_list list; + char* p; + va_start(list, format); + vasprintf(&p, format, list); + va_end(list); + + const char* t = p; + throw t; +} + +void ImageLoader::init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate) +{ + fPathHash = 0; + fPath = NULL; + if ( path != NULL ) + this->setPath(path); + fLogicalPath = NULL; + fDevice = device; + fInode = inode; + fLastModified = modDate; + fOffsetInFatFile = offsetInFat; + //fSegments = NULL; + fLibraries = NULL; + fLibrariesCount = 0; + fReferenceCount = 0; + fAllLibraryChecksumsAndLoadAddressesMatch = false; + fLeaveMapped = false; + fHideSymbols = false; + fMatchByInstallName = false; + fLibrariesLoaded = false; + fBased = false; + fBoundAllNonLazy = false; + fBoundAllLazy = false; + fAnnounced = false; + fInitialized = false; + fNextAddImageIndex = 0; +} + + +ImageLoader::ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info) +{ + init(path, offsetInFat, info.st_dev, info.st_ino, info.st_mtime); +} + +ImageLoader::ImageLoader(const char* moduleName) +{ + init(moduleName, 0, 0, 0, 0); +} + + +ImageLoader::~ImageLoader() +{ + // need to read up on STL and see if this is right way to destruct vector contents + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + delete seg; + } + if ( fPath != NULL ) + delete [] fPath; + if ( fLogicalPath != NULL ) + delete [] fLogicalPath; +} + + +void ImageLoader::setPath(const char* path) +{ + if ( fPath != NULL ) { + // if duplicate path, do nothing + if ( strcmp(path, fPath) == 0 ) + return; + delete [] fPath; + } + fPath = new char[strlen(path)+1]; + strcpy((char*)fPath, path); + fPathHash = hash(fPath); +} + +void ImageLoader::setLogicalPath(const char* path) +{ + if ( fPath == NULL ) { + // no physical path set yet, so use this path as physical + this->setPath(path); + } + else if ( strcmp(path, fPath) == 0 ) { + // do not set logical path because it is the same as the physical path + fLogicalPath = NULL; + } + else { + fLogicalPath = new char[strlen(path)+1]; + strcpy((char*)fLogicalPath, path); + } +} + +const char* ImageLoader::getLogicalPath() const +{ + if ( fLogicalPath != NULL ) + return fLogicalPath; + else + return fPath; +} + +uint32_t ImageLoader::hash(const char* path) +{ + // this does not need to be a great hash + // it is just used to reduce the number of strcmp() calls + // of existing images when loading a new image + uint32_t h = 0; + for (const char* s=path; *s != '\0'; ++s) + h = h*5 + *s; + return h; +} + +bool ImageLoader::matchInstallPath() const +{ + return fMatchByInstallName; +} + +void ImageLoader::setMatchInstallPath(bool match) +{ + fMatchByInstallName = match; +} + +bool ImageLoader::statMatch(const struct stat& stat_buf) const +{ + return ( (this->fDevice == stat_buf.st_dev) && (this->fInode == stat_buf.st_ino) ); +} + +const char* ImageLoader::getShortName() const +{ + // try to return leaf name + if ( fPath != NULL ) { + const char* s = strrchr(fPath, '/'); + if ( s != NULL ) + return &s[1]; + } + return fPath; +} + +uint64_t ImageLoader::getOffsetInFatFile() const +{ + return fOffsetInFatFile; +} + +void ImageLoader::setLeaveMapped() +{ + fLeaveMapped = true; + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + fSegments[i]->setUnMapWhenDestructed(false); + } +} + +void ImageLoader::setHideExports(bool hide) +{ + fHideSymbols = hide; +} + +bool ImageLoader::hasHiddenExports() const +{ + return fHideSymbols; +} + +bool ImageLoader::isLinked() const +{ + return fBoundAllNonLazy; +} + +time_t ImageLoader::lastModified() +{ + return fLastModified; +} + +bool ImageLoader::containsAddress(const void* addr) const +{ + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + const uint8_t* start = (const uint8_t*)seg->getActualLoadAddress(); + const uint8_t* end = start + seg->getSize(); + if ( (start <= addr) && (addr < end) && !seg->unaccessible() ) + return true; + } + return false; +} + +void ImageLoader::addMappedRegions(RegionsVector& regions) const +{ + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + MappedRegion region; + region.address = seg->getActualLoadAddress(); + region.size = seg->getSize(); + regions.push_back(region); + } +} + + +void ImageLoader::incrementReferenceCount() +{ + ++fReferenceCount; +} + +bool ImageLoader::decrementReferenceCount() +{ + return ( --fReferenceCount == 0 ); +} + + +const ImageLoader::Symbol* ImageLoader::resolveSymbol(const char* name, bool searchSelf, ImageLoader** foundIn) const +{ + const ImageLoader::Symbol* sym; + // search self + if ( searchSelf ) { + sym = this->findExportedSymbol(name, NULL, false, foundIn); + if ( sym != NULL ) + return sym; + } + + // search directly dependent libraries + for (uint32_t i=0; i < fLibrariesCount; ++i) { + ImageLoader* dependentImage = fLibraries[i].image; + if ( dependentImage != NULL ) { + const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, NULL, false, foundIn); + if ( sym != NULL ) + return sym; + } + } + + // search indirectly dependent libraries + for (uint32_t i=0; i < fLibrariesCount; ++i) { + ImageLoader* dependentImage = fLibraries[i].image; + if ( dependentImage != NULL ) { + const ImageLoader::Symbol* sym = dependentImage->resolveSymbol(name, false, foundIn); + if ( sym != NULL ) + return sym; + } + } + + return NULL; +} + + + +void ImageLoader::link(const LinkContext& context, BindingLaziness bindness, InitializerRunning inits, uint32_t notifyCount) +{ + uint64_t t1 = mach_absolute_time(); + this->recursiveLoadLibraries(context); + + uint64_t t2 = mach_absolute_time(); + this->recursiveRebase(context); + + uint64_t t3 = mach_absolute_time(); + this->recursiveBind(context, bindness); + + uint64_t t4 = mach_absolute_time(); + this->recursiveImageNotification(context, notifyCount); + + if ( (inits == kRunInitializers) || (inits == kDontRunInitializersButTellObjc) ) { + std::vector newImages; + this->recursiveImageAnnouncement(context, newImages); // build bottom up list images being added + context.notifyAdding(newImages); // tell gdb or anyone who cares about these + } + + uint64_t t5 = mach_absolute_time(); + if ( inits == kRunInitializers ) { + this->recursiveInitialization(context); + uint64_t t6 = mach_absolute_time(); + fgTotalInitTime += t6 - t5; + } + fgTotalLoadLibrariesTime += t2 - t1; + fgTotalRebaseTime += t3 - t2; + fgTotalBindTime += t4 - t3; + fgTotalNotifyTime += t5 - t4; +} + + +// only called pre-main on main executable +// if crt.c is ever cleaned up, this could go away +void ImageLoader::runInitializers(const LinkContext& context) +{ + std::vector newImages; + this->recursiveImageAnnouncement(context, newImages); // build bottom up list images being added + context.notifyAdding(newImages); // tell gdb or anyone who cares about these + + this->recursiveInitialization(context); +} + +// called inside _dyld_register_func_for_add_image() +void ImageLoader::runNotification(const LinkContext& context, uint32_t notifyCount) +{ + this->recursiveImageNotification(context, notifyCount); +} + + +intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context) +{ + // preflight and calculate slide if needed + const unsigned int segmentCount = fSegments.size(); + intptr_t slide = 0; + if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) { + bool needsToSlide = false; + uintptr_t lowAddr = UINTPTR_MAX; + uintptr_t highAddr = 0; + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + const uintptr_t segLow = seg->getPreferredLoadAddress(); + const uintptr_t segHigh = segLow + seg->getSize(); + if ( segLow < lowAddr ) + lowAddr = segLow; + if ( segHigh > highAddr ) + highAddr = segHigh; + + if ( context.slideAndPackDylibs || !seg->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) ) + needsToSlide = true; + } + if ( needsToSlide ) { + // find a chunk of address space to hold all segments + uintptr_t addr = Segment::reserveAnAddressRange(highAddr-lowAddr, context); + slide = addr - lowAddr; + } + } + else if ( ! this->segmentsCanSlide() ) { + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + if ( strcmp(seg->getName(), "__PAGEZERO") == 0 ) + continue; + if ( !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) ) + throw "can't map"; + } + } + else { + // mach-o does not support independently sliding segments + } + return slide; +} + + +void ImageLoader::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context) +{ + if ( context.verboseMapping ) + fprintf(stderr, "dyld: Mapping %s\n", this->getPath()); + // find address range for image + intptr_t slide = this->assignSegmentAddresses(context); + // map in all segments + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + seg->map(fd, offsetInFat, slide, context); + } + // update slide to reflect load location + this->setSlide(slide); + + // now that it is mapped and slide is set, mark that we should unmap it when done + for(unsigned int i=0; i < segmentCount; ++i){ + fSegments[i]->setUnMapWhenDestructed(true); + } +} + +void ImageLoader::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context) +{ + if ( context.verboseMapping ) + fprintf(stderr, "dyld: Mapping memory %p\n", memoryImage); + // find address range for image + intptr_t slide = this->assignSegmentAddresses(context); + // map in all segments + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + seg->map(memoryImage, slide, context); + } + // update slide to reflect load location + this->setSlide(slide); + // set R/W permissions on all segments at slide location + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + seg->setPermissions(); + } +} + +bool ImageLoader::allDependentLibrariesAsWhenPreBound() const +{ + return fAllLibraryChecksumsAndLoadAddressesMatch; +} + + +void ImageLoader::recursiveLoadLibraries(const LinkContext& context) +{ + if ( ! fLibrariesLoaded ) { + // break cycles + fLibrariesLoaded = true; + + // get list of libraries this image needs + fLibrariesCount = this->doGetDependentLibraryCount(); + fLibraries = new DependentLibrary[fLibrariesCount]; + this->doGetDependentLibraries(fLibraries); + + // try to load each + bool canUsePrelinkingInfo = true; + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& requiredLib = fLibraries[i]; + try { + requiredLib.image = context.loadLibrary(requiredLib.name, true, this->getPath(), NULL); + if ( requiredLib.image == this ) { + // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168 + requiredLib.image = context.loadLibrary(requiredLib.name, false, NULL, NULL); + if ( requiredLib.image != this ) + fprintf(stderr, "dyld: warning DYLD_ setting caused circular dependency in %s\n", this->getPath()); + } + LibraryInfo actualInfo = requiredLib.image->doGetLibraryInfo(); + requiredLib.checksumMatches = ( actualInfo.checksum == requiredLib.info.checksum ); + // check found library version is compatible + if ( actualInfo.minVersion < requiredLib.info.minVersion ) { + throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d", + this->getShortName(), requiredLib.info.minVersion >> 16, (requiredLib.info.minVersion >> 8) & 0xff, requiredLib.info.minVersion & 0xff, + requiredLib.image->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff); + } + // prebinding for this image disabled if any dependent library changed or slid + if ( !requiredLib.checksumMatches || (requiredLib.image->getSlide() != 0) ) + canUsePrelinkingInfo = false; + //if ( context.verbosePrebinding ) { + // if ( !requiredLib.checksumMatches ) + // fprintf(stderr, "dyld: checksum mismatch, (%lld v %lld) for %s referencing %s\n", requiredLib.info.checksum, actualInfo.checksum, this->getPath(), requiredLib.image->getPath()); + // if ( requiredLib.image->getSlide() != 0 ) + // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), requiredLib.image->getPath()); + //} + } + catch (const char* msg) { + //if ( context.verbosePrebinding ) + // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), requiredLib.image->getPath()); + if ( requiredLib.required ) { + const char* formatString = "Library not loaded: %s\n Referenced from: %s\n Reason: %s"; + const char* referencedFrom = this->getPath(); + char buf[strlen(requiredLib.name)+strlen(referencedFrom)+strlen(formatString)+strlen(msg)+2]; + sprintf(buf, formatString, requiredLib.name, referencedFrom, msg); + throw strdup(buf); // this is a leak if exception doesn't halt program + } + // ok if weak library not found + requiredLib.image = NULL; + canUsePrelinkingInfo = false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero + } + } + fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo; + + // tell each to load its dependents + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) { + libInfo.isSubFramework = libInfo.image->isSubframeworkOf(context, this); + libInfo.isReExported = libInfo.isSubFramework || this->hasSubLibrary(context, libInfo.image); + //if ( libInfo.isReExported ) + // fprintf(stderr, "%s re-exports %s\n", strrchr(this->getPath(), '/'), strrchr(libInfo.image->getPath(),'/')); + libInfo.image->recursiveLoadLibraries(context); + } + } + + // do deep prebind check + if ( fAllLibraryChecksumsAndLoadAddressesMatch ) { + for(unsigned int i=0; i < fLibrariesCount; ++i){ + const DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) { + if ( !libInfo.image->allDependentLibrariesAsWhenPreBound() ) + fAllLibraryChecksumsAndLoadAddressesMatch = false; + } + } + } + + } +} + +void ImageLoader::recursiveRebase(const LinkContext& context) +{ + if ( ! fBased ) { + // break cycles + fBased = true; + + try { + // rebase lower level libraries first + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) + libInfo.image->recursiveRebase(context); + } + + // rebase this image + doRebase(context); + } + catch (const char* msg) { + // this image is not rebased + fBased = false; + throw msg; + } + } +} + + + + +void ImageLoader::recursiveBind(const LinkContext& context, BindingLaziness bindness) +{ + // normally just non-lazy pointers are bound up front, + // but DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound up from + // and some dyld API's bind all lazys at runtime + bool nonLazy = false; + bool lazy = false; + switch( bindness ) { + case kNonLazyOnly: + nonLazy = true; + break; + case kLazyAndNonLazy: + nonLazy = true; + lazy = true; + break; + case kLazyOnly: + case kLazyOnlyNoDependents: + lazy = true; + break; + } + const bool doNonLazy = nonLazy && !fBoundAllNonLazy; + const bool doLazy = lazy && !fBoundAllLazy; + if ( doNonLazy || doLazy ) { + // break cycles + bool oldBoundAllNonLazy = fBoundAllNonLazy; + bool oldBoundAllLazy = fBoundAllLazy; + fBoundAllNonLazy = fBoundAllNonLazy || nonLazy; + fBoundAllLazy = fBoundAllLazy || lazy; + + try { + // bind lower level libraries first + if ( bindness != kLazyOnlyNoDependents ) { + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) + libInfo.image->recursiveBind(context, bindness); + } + } + // bind this image + if ( doLazy && !doNonLazy ) + doBind(context, kLazyOnly); + else if ( !doLazy && doNonLazy ) + doBind(context, kNonLazyOnly); + else + doBind(context, kLazyAndNonLazy); + } + catch (const char* msg) { + // restore state + fBoundAllNonLazy = oldBoundAllNonLazy; + fBoundAllLazy = oldBoundAllLazy; + throw msg; + } + } +} + +// +// This is complex because _dyld_register_func_for_add_image() is defined to not only +// notify you of future image loads, but also of all currently loaded images. Therefore +// each image needs to track that all add-image-funcs have been notified about it. +// Since add-image-funcs cannot be removed, each has a unique index and each image +// records the thru which index notificiation has already been done. +// +void ImageLoader::recursiveImageNotification(const LinkContext& context, uint32_t addImageCount) +{ + if ( fNextAddImageIndex < addImageCount ) { + // break cycles + const uint32_t initIndex = fNextAddImageIndex; + fNextAddImageIndex = addImageCount; + + // notify all requestors about this image + context.imageNotification(this, initIndex); + + // notify about lower level libraries first + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) + libInfo.image->recursiveImageNotification(context, addImageCount); + } + } +} + + +void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, std::vector& newImages) +{ + if ( ! fAnnounced ) { + // break cycles + fAnnounced = true; + + // announce lower level libraries first + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) + libInfo.image->recursiveImageAnnouncement(context, newImages); + } + + // add to list of images to notify gdb about + newImages.push_back(this); + //fprintf(stderr, "next size = %d\n", newImages.size()); + + // remember that this image wants to be notified about other images + if ( this->hasImageNotification() ) + context.addImageNeedingNotification(this); + } +} + + + +void ImageLoader::recursiveInitialization(const LinkContext& context) +{ + if ( ! fInitialized ) { + // break cycles + fInitialized = true; + + try { + // initialize lower level libraries first + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.image != NULL ) + libInfo.image->recursiveInitialization(context); + } + + // record termination order + if ( this->needsTermination() ) + context.terminationRecorder(this); + + // initialize this image + this->doInitialization(context); + } + catch (const char* msg) { + // this image is not initialized + fInitialized = false; + throw msg; + } + } +} + +void ImageLoader::reprebindCommit(const LinkContext& context, bool commit) +{ + // do nothing on unprebound images + if ( ! this->isPrebindable() ) + return; + + // do nothing if prebinding is up to date + if ( this->usablePrebinding(context) ) + return; + + // make sure we are not replacing a symlink with a file + char realFilePath[PATH_MAX]; + if ( realpath(this->getPath(), realFilePath) == NULL ) { + throwf("realpath() failed on %s, errno=%d", this->getPath(), errno); + } + // recreate temp file name + char tempFilePath[PATH_MAX]; + ImageLoader::addSuffix(realFilePath, "_redoprebinding", tempFilePath); + + if ( commit ) { + // all files successfully reprebound, so do swap + int result = rename(tempFilePath, realFilePath); + if ( result != 0 ) { + // if there are two dylibs with the same install path, the second will fail to prebind + // because the _redoprebinding temp file is gone. In that case, log and go on. + if ( errno == ENOENT ) + fprintf(stderr, "update_prebinding: temp file missing: %s\n", tempFilePath); + else + throwf("can't swap temporary re-prebound file: rename(%s,%s) returned errno=%d", tempFilePath, realFilePath, errno); + } + } + else { + // something went wrong during prebinding, delete the temp files + unlink(tempFilePath); + } +} + +void ImageLoader::reprebind(const LinkContext& context, time_t timestamp) +{ + // do nothing on unprebound images + if ( ! this->isPrebindable() ) + return; + + // do nothing if prebinding is up to date + if ( this->usablePrebinding(context) ) { + if ( context.verbosePrebinding ) + fprintf(stderr, "dyld: no need to re-prebind: %s\n", this->getPath()); + return; + } + // make copy of file and map it in + char tempFilePath[PATH_MAX]; + realpath(this->getPath(), tempFilePath); + ImageLoader::addSuffix(this->getPath(), "_redoprebinding", tempFilePath); + uint8_t* fileToPrebind; + uint64_t fileToPrebindSize; + this->copyAndMap(tempFilePath, &fileToPrebind, &fileToPrebindSize); + + // do format specific prebinding + this->doPrebinding(context, timestamp, fileToPrebind); + + // flush and swap files + int result = msync(fileToPrebind, fileToPrebindSize, MS_ASYNC); + if ( result != 0 ) + throw "error syncing re-prebound file"; + result = munmap(fileToPrebind, fileToPrebindSize); + if ( result != 0 ) + throw "error unmapping re-prebound file"; + + // log + if ( context.verbosePrebinding ) + fprintf(stderr, "dyld: re-prebound: %s\n", this->getPath()); +} + +void ImageLoader::copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize) +{ + // reopen dylib + int src = open(this->getPath(), O_RDONLY); + if ( src == -1 ) + throw "can't open image"; + struct stat stat_buf; + if ( fstat(src, &stat_buf) == -1) + throw "can't stat image"; + if ( stat_buf.st_mtime != fLastModified ) + throw "image file changed since it was loaded"; + + // create new file with all same permissions to hold copy of dylib + unlink(tempFile); + int dst = open(tempFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode); + if ( dst == -1 ) + throw "can't create temp image"; + + // mark source as "don't cache" + (void)fcntl(src, F_NOCACHE, 1); + // we want to cache the dst because we are about to map it in and modify it + + // copy permission bits + if ( chmod(tempFile, stat_buf.st_mode & 07777) == -1 ) + throw "can't chmod temp image"; + if ( chown(tempFile, stat_buf.st_uid, stat_buf.st_gid) == -1) + throw "can't chown temp image"; + + // copy contents + ssize_t len; + const uint32_t kBufferSize = 128*1024; + static uint8_t* buffer = NULL; + if ( buffer == NULL ) { + vm_address_t addr = 0; + if ( vm_allocate(mach_task_self(), &addr, kBufferSize, true /*find range*/) == KERN_SUCCESS ) + buffer = (uint8_t*)addr; + else + throw "can't allcoate copy buffer"; + } + while ( (len = read(src, buffer, kBufferSize)) > 0 ) { + write(dst, buffer, len); + } + + // map in dst file + *fileToPrebindSize = stat_buf.st_size - fOffsetInFatFile; // this may map in too much, but it does not matter + *fileToPrebind = (uint8_t*)mmap(NULL, *fileToPrebindSize, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, dst, fOffsetInFatFile); + if ( *fileToPrebind == (uint8_t*)(-1) ) + throw "can't mmap temp image"; + + // closing notes: + // ok to close file after mapped in + // ok to throw above without closing file because the throw will terminate update_prebinding + int result1 = close(dst); + int result2 = close(src); + if ( (result1 != 0) || (result2 != 0) ) + throw "can't close file"; +} + + +static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime) +{ + static uint64_t sUnitsPerSecond = 0; + if ( sUnitsPerSecond == 0 ) { + struct mach_timebase_info timeBaseInfo; + if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) { + sUnitsPerSecond = timeBaseInfo.denom; + } + } + if ( partTime < sUnitsPerSecond ) { + uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond; + uint32_t milliSeconds = milliSecondsTimeTen/10; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10); + } + else { + uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond; + uint32_t seconds = secondsTimeTen/100; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10); + } +} + +static char* commatize(uint64_t in, char* out) +{ + char* result = out; + char rawNum[30]; + sprintf(rawNum, "%llu", in); + const int rawNumLen = strlen(rawNum); + for(int i=0; i < rawNumLen-1; ++i) { + *out++ = rawNum[i]; + if ( ((rawNumLen-i) % 3) == 1 ) + *out++ = ','; + } + *out++ = rawNum[rawNumLen-1]; + *out = '\0'; + return result; +} + + +void ImageLoader::printStatistics(unsigned int imageCount) +{ + uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalNotifyTime + fgTotalInitTime; + char commaNum1[40]; + char commaNum2[40]; + + printTime("total time", totalTime, totalTime); + fprintf(stderr, "total images loaded: %d (%d used prebinding)\n", imageCount, fgImagesWithUsedPrebinding); + printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime); + fprintf(stderr, "total rebase fixups: %s\n", commatize(fgTotalRebaseFixups, commaNum1)); + printTime("total rebase fixups time", fgTotalRebaseFixups, totalTime); + fprintf(stderr, "total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1)); + printTime("total binding fixups time", fgTotalBindTime, totalTime); + fprintf(stderr, "total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2)); + printTime("total notify time time", fgTotalNotifyTime, totalTime); + printTime("total init time time", fgTotalInitTime, totalTime); +} + + +// +// copy path and add suffix to result +// +// /path/foo.dylib _debug => /path/foo_debug.dylib +// foo.dylib _debug => foo_debug.dylib +// foo _debug => foo_debug +// /path/bar _debug => /path/bar_debug +// /path/bar.A.dylib _debug => /path/bar.A_debug.dylib +// +void ImageLoader::addSuffix(const char* path, const char* suffix, char* result) +{ + strcpy(result, path); + + char* start = strrchr(result, '/'); + if ( start != NULL ) + start++; + else + start = result; + + char* dot = strrchr(start, '.'); + if ( dot != NULL ) { + strcpy(dot, suffix); + strcat(&dot[strlen(suffix)], &path[dot-result]); + } + else { + strcat(result, suffix); + } +} + + +void Segment::map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader::LinkContext& context) +{ + vm_offset_t fileOffset = this->getFileOffset() + offsetInFatWrapper; + vm_size_t size = this->getFileSize(); + void* requestedLoadAddress = (void*)(this->getPreferredLoadAddress() + slide); + int protection = 0; + if ( !this->unaccessible() ) { + if ( this->executable() ) + protection |= PROT_EXEC; + if ( this->readable() ) + protection |= PROT_READ; + if ( this->writeable() ) + protection |= PROT_WRITE; + } + void* loadAddress = mmap(requestedLoadAddress, size, protection, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, fileOffset); + if ( loadAddress == ((void*)(-1)) ) + throwf("mmap() error %d at address=0x%08lX, size=0x%08lX in Segment::map() mapping %s", errno, (uintptr_t)requestedLoadAddress, (uintptr_t)size, this->getImage()->getPath()); + + if ( context.verboseMapping ) + fprintf(stderr, "%18s at %p->%p\n", this->getName(), loadAddress, (char*)loadAddress+this->getFileSize()-1); +} + +void Segment::map(const void* memoryImage, intptr_t slide, const ImageLoader::LinkContext& context) +{ + vm_address_t loadAddress = this->getPreferredLoadAddress() + slide; + vm_address_t srcAddr = (uintptr_t)memoryImage + this->getFileOffset(); + vm_size_t size = this->getFileSize(); + kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress); + if ( r != KERN_SUCCESS ) + throw "can't map segment"; + + if ( context.verboseMapping ) + fprintf(stderr, "%18s at %p->%p\n", this->getName(), (char*)loadAddress, (char*)loadAddress+this->getFileSize()-1); +} + +void Segment::setPermissions() +{ + vm_prot_t protection = 0; + if ( !this->unaccessible() ) { + if ( this->executable() ) + protection |= VM_PROT_EXECUTE; + if ( this->readable() ) + protection |= VM_PROT_READ; + if ( this->writeable() ) + protection |= VM_PROT_WRITE; + } + vm_address_t addr = this->getActualLoadAddress(); + vm_size_t size = this->getSize(); + const bool setCurrentPermissions = false; + kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection); + if ( r != KERN_SUCCESS ) + throw "can't set vm permissions for mapped segment"; +} + +void Segment::tempWritable() +{ + vm_address_t addr = this->getActualLoadAddress(); + vm_size_t size = this->getSize(); + const bool setCurrentPermissions = false; + kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, VM_PROT_WRITE | VM_PROT_READ); + if ( r != KERN_SUCCESS ) + throw "can't set vm permissions for mapped segment"; +} + + +bool Segment::hasTrailingZeroFill() +{ + return ( this->writeable() && (this->getSize() > this->getFileSize()) ); +} + + +uintptr_t Segment::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context) +{ + vm_address_t addr = 0; + vm_size_t size = length; + if ( context.slideAndPackDylibs ) { + addr = (fgNextNonSplitSegAddress - length) & (-4096); // page align + kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*use this range*/); + if ( r != KERN_SUCCESS ) + throw "out of address space"; + fgNextNonSplitSegAddress = addr; + } + else { + kern_return_t r = vm_allocate(mach_task_self(), &addr, size, true /*find range*/); + if ( r != KERN_SUCCESS ) + throw "out of address space"; + } + return addr; +} + +bool Segment::reserveAddressRange(uintptr_t start, size_t length) +{ + vm_address_t addr = start; + vm_size_t size = length; + kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/); + if ( r != KERN_SUCCESS ) + return false; + return true; +} + + + diff --git a/src/ImageLoader.h b/src/ImageLoader.h new file mode 100644 index 0000000..609c222 --- /dev/null +++ b/src/ImageLoader.h @@ -0,0 +1,460 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef __IMAGELOADER__ +#define __IMAGELOADER__ + +#include +#include // struct mach_timebase_info +#include +#include + +#include "mach-o/dyld_gdb.h" + + +// utility +__attribute__((noreturn)) void throwf(const char* format, ...); + +// +// ImageLoader is an abstract base class. To support loading a particular executable +// file format, you make a concrete subclass of ImageLoader. +// +// For each executable file (dynamic shared object) in use, an ImageLoader is instantiated. +// +// The ImageLoader base class does the work of linking together images, but it knows nothing +// about any particular file format. +// +// +class ImageLoader { +public: + + typedef uint32_t DefinitionFlags; + static const DefinitionFlags kNoDefinitionOptions = 0; + static const DefinitionFlags kWeakDefinition = 1; + + typedef uint32_t ReferenceFlags; + static const ReferenceFlags kNoReferenceOptions = 0; + static const ReferenceFlags kWeakReference = 1; + static const ReferenceFlags kTentativeDefinition = 2; + + + enum BindingLaziness { kNonLazyOnly, kLazyAndNonLazy, kLazyOnly, kLazyOnlyNoDependents }; + enum InitializerRunning { kDontRunInitializers, kRunInitializers, kDontRunInitializersButTellObjc }; + enum PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding }; + enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers }; + enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion }; + + struct Symbol; // abstact symbol + + struct MappedRegion { + uintptr_t address; + size_t size; + }; + typedef std::vector RegionsVector; + + struct LinkContext { + ImageLoader* (*loadLibrary)(const char* libraryName, bool search, const char* origin, const char* rpath[]); + uint32_t (*imageNotification)(ImageLoader* image, uint32_t startIndex); + void (*terminationRecorder)(ImageLoader* image); + bool (*flatExportFinder)(const char* name, const Symbol** sym, ImageLoader** image); + bool (*coalescedExportFinder)(const char* name, const Symbol** sym, ImageLoader** image); + void (*undefinedHandler)(const char* name); + void (*addImageNeedingNotification)(ImageLoader* image); + void (*notifyAdding)(std::vector& images); + void (*getAllMappedRegions)(RegionsVector&); + void * (*bindingHandler)(const char *, const char *, void *); + BindingOptions bindingOptions; + int argc; + const char** argv; + const char** envp; + const char** apple; + ImageLoader* mainExecutable; + const char* imageSuffix; + PrebindMode prebindUsage; + SharedRegionMode sharedRegionMode; + bool bindFlat; + bool slideAndPackDylibs; + bool verboseOpts; + bool verboseEnv; + bool verboseMapping; + bool verboseRebase; + bool verboseBind; + bool verboseInit; + bool verbosePrebinding; + bool verboseWarnings; + }; + + // constructor is protected, but anyone can delete an image + virtual ~ImageLoader(); + + // link() takes a newly instantiated ImageLoader and does all + // fixups needed to make it usable by the process + void link(const LinkContext& context, BindingLaziness mode, InitializerRunning inits, uint32_t notifyCount); + + // runInitializers() is normally called in link() but the main executable must + // run crt code before initializers + void runInitializers(const LinkContext& context); + + // runNotification() is normally called in link() but the main executable must + // run crt code before initializers + void runNotification(const LinkContext& context, uint32_t notifyCount); + + // used by dyld to see if a requested library is already loaded (might be symlink) + bool statMatch(const struct stat& stat_buf) const; + + // get short name of this image + const char* getShortName() const; + + // get path used to load this image, not necessarily the "real" path + const char* getPath() const { return fPath; } + + uint32_t getPathHash() const { return fPathHash; } + + // get path used to load this image represents (ZeroLink only) which image this .o is part of + const char* getLogicalPath() const; + + // get path this image is intended to be placed on disk or NULL if no preferred install location + virtual const char* getInstallPath() const = 0; + + // image was loaded with NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME and all clients are looking for install path + bool matchInstallPath() const; + void setMatchInstallPath(bool); + + // if path was a fat file, offset of image loaded in that fat file + uint64_t getOffsetInFatFile() const; + + // mark that this image's exported symbols should be ignored when linking other images (e.g. RTLD_LOCAL) + void setHideExports(bool hide = true); + + // check if this image's exported symbols should be ignored when linking other images + bool hasHiddenExports() const; + + // checks if this image is already linked into the process + bool isLinked() const; + + // even if image is deleted, leave segments mapped in + void setLeaveMapped(); + + // checks if the specifed address is within one of this image's segments + virtual bool containsAddress(const void* addr) const; + + // adds to list of ranges of memory mapped in + void addMappedRegions(RegionsVector& regions) const; + + // st_mtime from stat() on file + time_t lastModified(); + + // image should create prebound version of itself + void reprebind(const LinkContext& context, time_t timestamp); + + // if 'commit', the prebound version should be swapped in, otherwise deleted + void reprebindCommit(const LinkContext& context, bool commit); + + // only valid for main executables, returns a pointer its entry point + virtual void* getMain() const = 0; + + // dyld API's require each image to have an associated mach_header + virtual const struct mach_header* machHeader() const = 0; + + // dyld API's require each image to have a slide (actual load address minus preferred load address) + virtual uintptr_t getSlide() const = 0; + + // dyld API's require each image to have a slide (actual load address minus preferred load address) + virtual const void* getBaseAddress() const = 0; + + // image has exports that participate in runtime coalescing + virtual bool hasCoalescedExports() const = 0; + + // search symbol table of definitions in this image for requested name + virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const = 0; + + // gets address of implementation (code) of the specified exported symbol + virtual uintptr_t getExportedSymbolAddress(const Symbol* sym) const = 0; + + // gets attributes of the specified exported symbol + virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const = 0; + + // gets name of the specified exported symbol + virtual const char* getExportedSymbolName(const Symbol* sym) const = 0; + + // gets how many symbols are exported by this image + virtual uint32_t getExportedSymbolCount() const = 0; + + // gets the i'th exported symbol + virtual const Symbol* getIndexedExportedSymbol(uint32_t index) const = 0; + + // find exported symbol as if imported by this image + // used by RTLD_NEXT and RTLD_SELF + virtual const Symbol* resolveSymbol(const char* name, bool searchSelf, ImageLoader** foundIn) const; + + // gets how many symbols are imported by this image + virtual uint32_t getImportedSymbolCount() const = 0; + + // gets the i'th imported symbol + virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const = 0; + + // gets attributes of the specified imported symbol + virtual ReferenceFlags geImportedSymbolInfo(const Symbol* sym) const = 0; + + // gets name of the specified imported symbol + virtual const char* getImportedSymbolName(const Symbol* sym) const = 0; + + // checks if this image is a bundle and can be loaded but not linked + virtual bool isBundle() const = 0; + + // checks if this image is a dylib + virtual bool isDylib() const = 0; + + // only for main executable + virtual bool forceFlat() const = 0; + + // called at runtime when a lazily bound function is first called + virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0; + + // calls termination routines (e.g. C++ static destructors for image) + virtual void doTermination(const LinkContext& context) = 0; + + // tell this image about other images + virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) = 0; + + // return if this image has initialization routines + virtual bool needsInitialization() = 0; + + // return if this image has a routine to be called when any image is loaded or unloaded + virtual bool hasImageNotification() = 0; + + // return if this image has specified section and set start and length + virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) = 0; + + // given a pointer into an image, find which segment and section it is in + virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) = 0; + + // the image supports being prebound + virtual bool isPrebindable() const = 0; + + // the image is prebindable and its prebinding is valid + virtual bool usablePrebinding(const LinkContext& context) const = 0; + + // used to implement refernce counting of images + void incrementReferenceCount(); + bool decrementReferenceCount(); + + // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast + static void printStatistics(unsigned int imageCount); + + // used with DYLD_IMAGE_SUFFIX + static void addSuffix(const char* path, const char* suffix, char* result); + + static uint32_t hash(const char*); + + + void setPath(const char* path); // only called for images created from memory + void setLogicalPath(const char* path); + + +protected: + // abstract base class so all constructors protected + ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info); + ImageLoader(const char* moduleName); + ImageLoader(const ImageLoader&); + void operator=(const ImageLoader&); + + + struct LibraryInfo { + uint64_t checksum; + uint32_t minVersion; + uint32_t maxVersion; + }; + + struct DependentLibrary { + const char* name; + ImageLoader* image; + LibraryInfo info; + bool required; + bool checksumMatches; + bool isReExported; + bool isSubFramework; + }; + + typedef void (*Initializer)(int argc, const char* argv[], const char* envp[],const char* apple[]); + typedef void (*Terminator)(void); + + // To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized. + // These methods do the above, exactly once, and it the right order + void recursiveLoadLibraries(const LinkContext& context); + void recursiveRebase(const LinkContext& context); + void recursiveBind(const LinkContext& context, BindingLaziness bindness); + void recursiveImageAnnouncement(const LinkContext& context, std::vector& newImages); + void recursiveImageNotification(const LinkContext& context, uint32_t addImageCount); + void recursiveInitialization(const LinkContext& context); + + // map any segments this image has into memory and build fSegments + // this is called before doGetDependentLibraryCount so if metadata is in segments it is mapped in + virtual void instantiateSegments(const uint8_t* fileData) = 0; + + // return how many libraries this image depends on + virtual uint32_t doGetDependentLibraryCount() = 0; + + // fill in information about dependent libraries (array length is doGetDependentLibraryCount()) + virtual void doGetDependentLibraries(DependentLibrary libs[]) = 0; + + // called on images that are libraries, returns info about itself + virtual LibraryInfo doGetLibraryInfo() = 0; + + // do any fix ups in this image that depend only on the load address of the image + virtual void doRebase(const LinkContext& context) = 0; + + // do any symbolic fix ups in this image + virtual void doBind(const LinkContext& context, BindingLaziness bindness) = 0; + + // run any initialization routines in this image + virtual void doInitialization(const LinkContext& context) = 0; + + // write prebinding updates to mapped file fileToPrebind + virtual void doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind) = 0; + + // return if this image has termination routines + virtual bool needsTermination() = 0; + + // support for runtimes in which segments don't have to maintain their relative positions + virtual bool segmentsMustSlideTogether() const = 0; + + // built with PIC code and can load at any address + virtual bool segmentsCanSlide() const = 0; + + // set how much all segments slide + virtual void setSlide(intptr_t slide) = 0; + + // utility routine to map in all segements in fSegments from a file + virtual void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); + + // utility routine to map in all segements in fSegments from a memory image + virtual void mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context); + + // returns if all dependent libraries checksum's were as expected and none slide + bool allDependentLibrariesAsWhenPreBound() const; + + // in mach-o a child tells it parent to re-export, instead of the other way around... + virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0; + + // in mach-o a parent library knows name of sub libraries it re-exports.. + virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0; + + static uint32_t fgImagesWithUsedPrebinding; + static uint32_t fgTotalRebaseFixups; + static uint32_t fgTotalBindFixups; + static uint32_t fgTotalLazyBindFixups; + static uint32_t fgTotalPossibleLazyBindFixups; + static uint64_t fgTotalLoadLibrariesTime; + static uint64_t fgTotalRebaseTime; + static uint64_t fgTotalBindTime; + static uint64_t fgTotalNotifyTime; + static uint64_t fgTotalInitTime; + static uintptr_t fgNextSplitSegAddress; + const char* fPath; + const char* fLogicalPath; // for ZeroLink - the image which this bundle is part of + dev_t fDevice; + ino_t fInode; + time_t fLastModified; + uint64_t fOffsetInFatFile; + std::vector fSegments; + DependentLibrary* fLibraries; + uint32_t fLibrariesCount; + uint32_t fPathHash; + uint32_t fReferenceCount; + bool fAllLibraryChecksumsAndLoadAddressesMatch; + bool fLeaveMapped; // when unloaded, leave image mapped in cause some other code may have pointers into it + + +private: + void init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate); + intptr_t assignSegmentAddresses(const LinkContext& context); + void copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize); + + + bool fHideSymbols; // ignore this image's exported symbols when linking other images + bool fMatchByInstallName;// look at image's install-path not its load path + bool fLibrariesLoaded; + bool fBased; + bool fBoundAllNonLazy; + bool fBoundAllLazy; + bool fAnnounced; + bool fInitialized; + uint16_t fNextAddImageIndex; +}; + + +// +// Segment is an abstract base class. A segment is a chunk of an executable +// file that is mapped into memory. Each subclass of ImageLoader typically +// implements its own concrete subclass of Segment. +// +// +class Segment { +public: + virtual ~Segment() {} + + virtual const ImageLoader* getImage() = 0; + virtual const char* getName() = 0; + virtual uintptr_t getSize() = 0; + virtual uintptr_t getFileSize() = 0; + virtual bool hasTrailingZeroFill(); + virtual uintptr_t getFileOffset() = 0; + virtual bool readable() = 0; + virtual bool writeable() = 0; + virtual bool executable() = 0; + virtual bool unaccessible() = 0; + virtual bool hasFixUps() = 0; + virtual uintptr_t getActualLoadAddress() = 0; + virtual uintptr_t getPreferredLoadAddress() = 0; + virtual void setUnMapWhenDestructed(bool unmap) = 0; + +protected: + // abstract base class so all constructors protected + Segment() {} + Segment(const Segment&); + void operator=(const Segment&); + + virtual bool hasPreferredLoadAddress() = 0; + //virtual void setActualLoadAddress(uint64_t addr) = 0; + + static bool reserveAddressRange(uintptr_t start, size_t length); + static uintptr_t reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context); + static uintptr_t fgNextNonSplitSegAddress; + +private: + void map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader::LinkContext& context); + void map(const void* memoryImage, intptr_t slide, const ImageLoader::LinkContext& context); + void setPermissions(); + void tempWritable(); + + friend class ImageLoader; + friend class ImageLoaderMachO; +}; + + + +#endif + diff --git a/src/ImageLoaderMachO.cpp b/src/ImageLoaderMachO.cpp new file mode 100644 index 0000000..84a3da6 --- /dev/null +++ b/src/ImageLoaderMachO.cpp @@ -0,0 +1,2463 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if __ppc__ || __ppc64__ + #include +#endif + +#include "ImageLoaderMachO.h" +#include "mach-o/dyld_gdb.h" + +// no header for this yet, rdar://problem/3850825 +extern "C" void sys_icache_invalidate(void *, size_t); + +// optimize strcmp for ppc +#if __ppc__ + #include +#else + #define astrcmp(a,b) strcmp(a,b) +#endif + +// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables +#if __LP64__ + #define RELOC_SIZE 3 + #define LC_SEGMENT_COMMAND LC_SEGMENT_64 + #define LC_ROUTINES_COMMAND LC_ROUTINES_64 + struct macho_header : public mach_header_64 {}; + struct macho_segment_command : public segment_command_64 {}; + struct macho_section : public section_64 {}; + struct macho_nlist : public nlist_64 {}; + struct macho_routines_command : public routines_command_64 {}; +#else + #define RELOC_SIZE 2 + #define LC_SEGMENT_COMMAND LC_SEGMENT + #define LC_ROUTINES_COMMAND LC_ROUTINES + struct macho_header : public mach_header {}; + struct macho_segment_command : public segment_command {}; + struct macho_section : public section {}; + struct macho_nlist : public nlist {}; + struct macho_routines_command : public routines_command {}; +#endif + + +uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs = 0; +uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs = 0; + + +//#define LINKEDIT_USAGE_DEBUG 1 + +#if LINKEDIT_USAGE_DEBUG + #include + static std::set sLinkEditPageBuckets; + + namespace dyld { + extern ImageLoader* findImageContainingAddress(const void* addr); + }; + + static void noteAccessedLinkEditAddress(const void* addr) + { + uintptr_t page = ((uintptr_t)addr) & (-4096); + sLinkEditPageBuckets.insert(page); + fprintf(stderr, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page, dyld::findImageContainingAddress(addr)->getPath()); + } +#endif + +// only way to share initialization in C++ +void ImageLoaderMachO::init() +{ + fMachOData = NULL; + fLinkEditBase = NULL; + fSymbolTable = NULL; + fStrings = NULL; + fDynamicInfo = NULL; + fSlide = 0; + fIsSplitSeg = false; + fHasSubLibraries= false; + fHasSubUmbrella = false; + fDashInit = NULL; + fModInitSection = NULL; + fModTermSection = NULL; + fDATAdyld = NULL; + fImageNotifySection = NULL; + fTwoLevelHints = NULL; + fDylibID = NULL; + fReExportThruFramework = NULL; + fTextSegmentWithFixups = NULL; +} + +// create image by copying an in-memory mach-o file +ImageLoaderMachO::ImageLoaderMachO(const char* moduleName, const struct mach_header* mh, uint64_t len, const LinkContext& context) + : ImageLoader(moduleName) +{ + // clean slate + this->init(); + + // temporary use this buffer until TEXT is mapped in + fMachOData = (const uint8_t*)mh; + + // create segments + this->instantiateSegments((const uint8_t*)mh); + + // map segments + if ( mh->filetype != MH_EXECUTE ) + ImageLoader::mapSegments((const void*)mh, len, context); + + // get pointers to interesting things + this->parseLoadCmds(); +} + + +// create image by mapping in a mach-o file +ImageLoaderMachO::ImageLoaderMachO(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, + uint64_t lenInFat, const struct stat& info, const LinkContext& context) + : ImageLoader(path, offsetInFat, info) +{ + // clean slate + this->init(); + + // read load commands + const unsigned int dataSize = sizeof(macho_header) + ((macho_header*)firstPage)->sizeofcmds; + uint8_t buffer[dataSize]; + const uint8_t* fileData = firstPage; + if ( dataSize > 4096 ) { + // only read more if cmds take up more space than first page + fileData = buffer; + memcpy(buffer, firstPage, 4096); + pread(fd, &buffer[4096], dataSize-4096, offsetInFat+4096); + } + + // temporary use this buffer until TEXT is mapped in + fMachOData = fileData; + + // the meaning of many fields changes in split seg mach-o files + fIsSplitSeg = ((((macho_header*)fileData)->flags & MH_SPLIT_SEGS) != 0) && (((macho_header*)fileData)->filetype == MH_DYLIB); + + // create segments + this->instantiateSegments(fileData); + + // map segments, except for main executable which is already mapped in by kernel + if ( ((macho_header*)fileData)->filetype != MH_EXECUTE ) + this->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context); + + // get pointers to interesting things + this->parseLoadCmds(); +} + + + + +void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData) +{ + const uint32_t cmd_count = ((macho_header*)fileData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fileData[sizeof(macho_header)]; + + // construct Segment object for each LC_SEGMENT cmd and add to list + const struct load_command* cmd = cmds; + for (unsigned long i = 0; i < cmd_count; ++i) { + if ( cmd->cmd == LC_SEGMENT_COMMAND ) { + fSegments.push_back(new SegmentMachO((struct macho_segment_command*)cmd, this, fileData)); + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + + + +bool ImageLoaderMachO::segmentsMustSlideTogether() const +{ + return true; +} + +bool ImageLoaderMachO::segmentsCanSlide() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->filetype == MH_DYLIB) || (mh->filetype == MH_BUNDLE) ); +} + +bool ImageLoaderMachO::isBundle() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( mh->filetype == MH_BUNDLE ); +} + +bool ImageLoaderMachO::isDylib() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( mh->filetype == MH_DYLIB ); +} + +bool ImageLoaderMachO::forceFlat() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->flags & MH_FORCE_FLAT) != 0 ); +} + +bool ImageLoaderMachO::usesTwoLevelNameSpace() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->flags & MH_TWOLEVEL) != 0 ); +} + +bool ImageLoaderMachO::isPrebindable() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->flags & MH_PREBOUND) != 0 ); +} + +bool ImageLoaderMachO::hasCoalescedExports() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->flags & MH_WEAK_DEFINES) != 0 ); +} + +bool ImageLoaderMachO::needsCoalescing() const +{ + const macho_header* mh = (macho_header*)fMachOData; + return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 ); +} + +#if !__LP64__ // split segs not supported for 64-bits + +#if 1 // hack until kernel headers and glue are in system +struct _shared_region_mapping_np { + mach_vm_address_t address; + mach_vm_size_t size; + mach_vm_offset_t file_offset; + vm_prot_t max_prot; /* read/write/execute/COW/ZF */ + vm_prot_t init_prot; /* read/write/execute/COW/ZF */ +}; +struct _shared_region_range_np { + mach_vm_address_t address; + mach_vm_size_t size; +}; + +// Called by dyld. +// Requests the kernel to map a number of regions from the fd into the +// shared sections address range (0x90000000-0xAFFFFFFF). +// If shared_region_make_private_np() has not been called by this process, +// the file mapped in is seen in the address space of all processes that +// participate in using the shared region. +// If shared_region_make_private_np() _has_ been called by this process, +// the file mapped in is only seen by this process. +// If the slide parameter is not NULL and then regions cannot be mapped +// as requested, the kernel will try to map the file in at a different +// address in the shared region and return the distance slid. +// If the mapping requesting cannot be fulfilled, returns non-zero. +static int +_shared_region_map_file_np( + int fd, // file descriptor to map into shared region + unsigned int regionCount, // number of entres in array of regions + const _shared_region_mapping_np regions[], // the array of regions to map + uint64_t* slide) // the amount all regions were slid, NULL means don't attempt to slide +{ + //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide); + //for ( unsigned int i=0; i < regionCount; ++i) { + // fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size); + //} + int r = syscall(299, fd, regionCount, regions, slide); +// if(0 != r) +// fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno)); + return r; +} +// Called by dyld if shared_region_map_file() fails. +// Requests the kernel to take this process out of using the shared region. +// The specified ranges are created as private copies from the shared region for this process. +static int +_shared_region_make_private_np( + unsigned int rangeCount, // number of entres in array of msrp_range + const _shared_region_range_np ranges[]) // the array of shared regions to make private +{ + //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges); + int r = syscall(300, rangeCount, ranges); +// if(0 != r) +// fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno)); + return r; +} +#define KERN_SHREG_PRIVATIZABLE 54 +#endif // hack until kernel headers and glue are in system + +static uintptr_t sNextAltLoadAddress +#if __ppc_ + = 0xC0000000; +#else + = 0; +#endif + + +static +bool +hasSharedRegionMapFile(void) +{ + int mib[CTL_MAXNAME]; + int value = 0; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_SHREG_PRIVATIZABLE; + size = sizeof (int); + if (sysctl(mib, 2, &value, &size, NULL, 0) != 0) { + value = 0; + } + + return 0 != value; +} + +int +ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd, + uint64_t offsetInFat, + uint64_t lenInFat, + uint64_t fileLen, + const LinkContext& context) +{ + const unsigned int segmentCount = fSegments.size(); + const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); + const unsigned int regionCount = segmentCount+extraZeroFillEntries; + _shared_region_mapping_np regions[regionCount]; + initMappingTable(offsetInFat, regions); + int r = -1; + // find space somewhere to allocate split seg + bool foundRoom = false; + vm_size_t biggestDiff = 0; + while ( ! foundRoom ) { + foundRoom = true; + for(unsigned int i=0; i < regionCount; ++i) { + vm_address_t addr = sNextAltLoadAddress + regions[i].address - regions[0].address; + vm_size_t size = regions[i].size ; + r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/); + if ( 0 != r ) { + // no room here, deallocate what has succeeded so far + for(unsigned int j=0; j < i; ++j) { + vm_address_t addr = sNextAltLoadAddress + regions[j].address - regions[0].address; + vm_size_t size = regions[j].size ; + (void)vm_deallocate(mach_task_self(), addr, size); + } + sNextAltLoadAddress += 0x00100000; // skip ahead 1MB and try again + if ( (sNextAltLoadAddress & 0xF0000000) == 0x90000000 ) + throw "can't map split seg anywhere"; + foundRoom = false; + break; + } + vm_size_t high = (regions[i].address + size - regions[0].address) & 0x0FFFFFFF; + if ( high > biggestDiff ) + biggestDiff = high; + } + } + + // map in each region + uintptr_t slide = sNextAltLoadAddress - regions[0].address; + this->setSlide(slide); + for(unsigned int i=0; i < regionCount; ++i) { + if ( (regions[i].init_prot & VM_PROT_ZF) != 0 ) { + // do nothing vm_allocate() zero-fills by default + } + else { + void* mmapAddress = (void*)(uintptr_t)(regions[i].address + slide); + size_t size = regions[i].size; + int protection = 0; + if ( regions[i].init_prot & VM_PROT_EXECUTE ) + protection |= PROT_EXEC; + if ( regions[i].init_prot & VM_PROT_READ ) + protection |= PROT_READ; + if ( regions[i].init_prot & VM_PROT_WRITE ) + protection |= PROT_WRITE; + off_t offset = regions[i].file_offset; + //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath); + mmapAddress = mmap(mmapAddress, size, protection, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, offset); + if ( mmapAddress == ((void*)(-1)) ) + throw "mmap error"; + } + } + // set so next maps right after this one + sNextAltLoadAddress += biggestDiff; + sNextAltLoadAddress = (sNextAltLoadAddress + 4095) & (-4096); + + // logging + if ( context.verboseMapping ) { + fprintf(stderr, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath()); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + const _shared_region_mapping_np* entry = ®ions[entryIndex]; + if ( (entry->init_prot & VM_PROT_ZF) == 0 ) + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1); + if ( entryIndex < (regionCount-1) ) { + const _shared_region_mapping_np* nextEntry = ®ions[entryIndex+1]; + if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) { + uint64_t segOffset = nextEntry->address - entry->address; + fprintf(stderr, "%18s at 0x%08lX->0x%08lX (zerofill)\n", + seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1)); + ++entryIndex; + } + } + } + } + + return r; +} + + +void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context) +{ + enum SharedRegionState + { + kSharedRegionStartState = 0, + kSharedRegionLoadFileState, + kSharedRegionMapFileState, + kSharedRegionMapFilePrivateState, + kSharedRegionMapFilePrivateOutsideState, + }; + static SharedRegionState sSharedRegionState = kSharedRegionStartState; + + // non-split segment libraries handled by super class + if ( !fIsSplitSeg ) + return ImageLoader::mapSegments(fd, offsetInFat, lenInFat, fileLen, context); + + if ( kSharedRegionStartState == sSharedRegionState ) { + if ( hasSharedRegionMapFile() ) { + if ( (context.sharedRegionMode == kUsePrivateSharedRegion) || context.slideAndPackDylibs ) { + sharedRegionMakePrivate(context); + sSharedRegionState = kSharedRegionMapFilePrivateState; + } + else if ( context.sharedRegionMode == kDontUseSharedRegion ) { + sSharedRegionState = kSharedRegionMapFilePrivateOutsideState; + } + else { + sSharedRegionState = kSharedRegionMapFileState; + } + } + else { + sSharedRegionState = kSharedRegionLoadFileState; + } + } + + if ( kSharedRegionLoadFileState == sSharedRegionState ) { + if ( 0 != sharedRegionLoadFile(fd, offsetInFat, lenInFat, fileLen, context) ) { + sSharedRegionState = kSharedRegionMapFilePrivateOutsideState; + } + } + else + if ( kSharedRegionMapFileState == sSharedRegionState ) { + if ( 0 != sharedRegionMapFile(fd, offsetInFat, lenInFat, fileLen, context) ) { + sharedRegionMakePrivate(context); + sSharedRegionState = kSharedRegionMapFilePrivateState; + } + } + + if ( kSharedRegionMapFilePrivateState == sSharedRegionState ) { + if ( 0 != sharedRegionMapFilePrivate(fd, offsetInFat, lenInFat, fileLen, context) ) { + sSharedRegionState = kSharedRegionMapFilePrivateOutsideState; + } + } + + if ( kSharedRegionMapFilePrivateOutsideState == sSharedRegionState ) { + if ( 0 != sharedRegionMapFilePrivateOutside(fd, offsetInFat, lenInFat, fileLen, context) ) { + throw "mapping error"; + } + } +} + +unsigned int +ImageLoaderMachO::getExtraZeroFillEntriesCount() +{ + // calculate mapping entries + const unsigned int segmentCount = fSegments.size(); + unsigned int extraZeroFillEntries = 0; + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + if ( seg->hasTrailingZeroFill() ) + ++extraZeroFillEntries; + } + + return extraZeroFillEntries; +} + +void +ImageLoaderMachO::initMappingTable(uint64_t offsetInFat, + _shared_region_mapping_np *mappingTable) +{ + unsigned int segmentCount = fSegments.size(); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + _shared_region_mapping_np* entry = &mappingTable[entryIndex]; + entry->address = seg->getActualLoadAddress(); + entry->size = seg->getFileSize(); + entry->file_offset = seg->getFileOffset() + offsetInFat; + entry->init_prot = VM_PROT_NONE; + if ( !seg->unaccessible() ) { + if ( seg->executable() ) + entry->init_prot |= VM_PROT_EXECUTE; + if ( seg->readable() ) + entry->init_prot |= VM_PROT_READ; + if ( seg->writeable() ) + entry->init_prot |= VM_PROT_WRITE | VM_PROT_COW; + } + entry->max_prot = entry->init_prot; + if ( seg->hasTrailingZeroFill() ) { + _shared_region_mapping_np* zfentry = &mappingTable[++entryIndex]; + zfentry->address = entry->address + seg->getFileSize(); + zfentry->size = seg->getSize() - seg->getFileSize(); + zfentry->file_offset = 0; + zfentry->init_prot = entry->init_prot | VM_PROT_COW | VM_PROT_ZF; + zfentry->max_prot = zfentry->init_prot; + } + } +} + +int +ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext& context) +{ + if ( context.verboseMapping ) + fprintf(stderr, "dyld: making shared regions private\n"); + + // shared mapping failed, so make private copy of shared region and try mapping private + RegionsVector allRegions; + context.getAllMappedRegions(allRegions); + std::vector<_shared_region_range_np> splitSegRegions; + const unsigned int allRegiontCount = allRegions.size(); + for(unsigned int i=0; i < allRegiontCount; ++i){ + MappedRegion region = allRegions[i]; + uint8_t highByte = region.address >> 28; + if ( (highByte == 9) || (highByte == 0xA) ) { + _shared_region_range_np splitRegion; + splitRegion.address = region.address; + splitRegion.size = region.size; + splitSegRegions.push_back(splitRegion); + } + } + int result = _shared_region_make_private_np(splitSegRegions.size(), &splitSegRegions[0]); + // notify gdb or other lurkers that this process is no longer using the shared region + dyld_all_image_infos.processDetachedFromSharedRegion = true; + return result; +} + +int +ImageLoaderMachO::sharedRegionMapFile(int fd, + uint64_t offsetInFat, + uint64_t lenInFat, + uint64_t fileLen, + const LinkContext& context) +{ + // build table of segments to map + const unsigned int segmentCount = fSegments.size(); + const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); + const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries; + _shared_region_mapping_np mappingTable[mappingTableCount]; + initMappingTable(offsetInFat, mappingTable); +// uint64_t slide; + uint64_t *slidep = NULL; + + // try to map it in shared + int r = _shared_region_map_file_np(fd, mappingTableCount, mappingTable, slidep); + if ( 0 == r ) { + if(NULL != slidep && 0 != *slidep) { + // update with actual load addresses + } + if ( context.verboseMapping ) { + fprintf(stderr, "dyld: Mapping split-seg shared %s\n", this->getPath()); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + const _shared_region_mapping_np* entry = &mappingTable[entryIndex]; + if ( (entry->init_prot & VM_PROT_ZF) == 0 ) + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1); + if ( entryIndex < (mappingTableCount-1) ) { + const _shared_region_mapping_np* nextEntry = &mappingTable[entryIndex+1]; + if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) { + uint64_t segOffset = nextEntry->address - entry->address; + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1)); + ++entryIndex; + } + } + } + } + } + return r; +} + +int +ImageLoaderMachO::sharedRegionMapFilePrivate(int fd, + uint64_t offsetInFat, + uint64_t lenInFat, + uint64_t fileLen, + const LinkContext& context) +{ + const unsigned int segmentCount = fSegments.size(); + + // adjust base address of segments to pack next to last dylib + if ( context.slideAndPackDylibs ) { + uintptr_t lowestReadOnly = (uintptr_t)(-1); + uintptr_t lowestWritable = (uintptr_t)(-1); + for(unsigned int segIndex=0; segIndex < segmentCount; ++segIndex){ + Segment* seg = fSegments[segIndex]; + uintptr_t segEnd = seg->getActualLoadAddress(); + if ( seg->writeable() ) { + if ( segEnd < lowestWritable ) + lowestWritable = segEnd; + } + else { + if ( segEnd < lowestReadOnly ) + lowestReadOnly = segEnd; + } + } + uintptr_t baseAddress; + if ( lowestWritable - 256*1024*1024 < lowestReadOnly ) + baseAddress = lowestWritable - 256*1024*1024; + else + baseAddress = lowestReadOnly; + // record that we want dylb slid to fgNextSplitSegAddress + this->setSlide(fgNextSplitSegAddress - baseAddress); + } + + // build table of segments to map + const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); + const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries; + _shared_region_mapping_np mappingTable[mappingTableCount]; + initMappingTable(offsetInFat, mappingTable); + uint64_t slide = 0; + + // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs) + int r = _shared_region_map_file_np(fd, mappingTableCount, mappingTable, context.slideAndPackDylibs ? NULL : &slide); + if ( 0 == r ) { + if ( 0 != slide ) { + slide = (slide) & (-4096); // round down to page boundary + this->setSlide(slide); + } + if ( context.verboseMapping ) { + if ( slide == 0 ) + fprintf(stderr, "dyld: Mapping split-seg un-shared %s\n", this->getPath()); + else + fprintf(stderr, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide, this->getPath()); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + const _shared_region_mapping_np* entry = &mappingTable[entryIndex]; + if ( (entry->init_prot & VM_PROT_ZF) == 0 ) + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1); + if ( entryIndex < (mappingTableCount-1) ) { + const _shared_region_mapping_np* nextEntry = &mappingTable[entryIndex+1]; + if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) { + uint64_t segOffset = nextEntry->address - entry->address; + fprintf(stderr, "%18s at 0x%08lX->0x%08lX (zerofill)\n", + seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1)); + ++entryIndex; + } + } + } + } + if ( context.slideAndPackDylibs ) { + // calculate where next split-seg dylib can load + uintptr_t largestReadOnly = 0; + uintptr_t largestWritable = 0; + for (unsigned int segIndex=0; segIndex < segmentCount; ++segIndex) { + Segment* seg = fSegments[segIndex]; + uintptr_t segEnd = seg->getActualLoadAddress()+seg->getSize(); + segEnd = (segEnd+4095) & (-4096); // page align + if ( seg->writeable() ) { + if ( segEnd > largestWritable ) + largestWritable = segEnd; + } + else { + if ( segEnd > largestReadOnly ) + largestReadOnly = segEnd; + } + } + if ( largestWritable - 256*1024*1024 > largestReadOnly ) + fgNextSplitSegAddress = largestWritable - 256*1024*1024; + else + fgNextSplitSegAddress = largestReadOnly; + } + } + if ( context.slideAndPackDylibs && (r != 0) ) + throw "can't rebase split-seg dylib"; + + return r; +} + + +int +ImageLoaderMachO::sharedRegionLoadFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context) +{ + + // map in split segment file at random address, then tell kernel to share it + void* loadAddress = 0; + loadAddress = mmap(NULL, fileLen, PROT_READ, MAP_FILE, fd, 0); + if ( loadAddress == ((void*)(-1)) ) + throw "mmap error"; + + // calculate mapping entries + const unsigned int segmentCount = fSegments.size(); + unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); + + // build table of segments to map + const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries; + const uintptr_t baseAddress = fSegments[0]->getPreferredLoadAddress(); + sf_mapping mappingTable[mappingTableCount]; + initMappingTable(offsetInFat, mappingTable, baseAddress); + + + // use load_shared_file() to map all segments at once + int flags = 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use + static bool firstTime = true; + if ( firstTime ) { + // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region + // this is used by Xcode to prevent development libraries from polluting the global shared segment + if ( context.sharedRegionMode == kUsePrivateSharedRegion ) + flags |= NEW_LOCAL_SHARED_REGIONS; + firstTime = false; + } + + caddr_t base_address = (caddr_t)baseAddress; + kern_return_t r; + r = load_shared_file( (char*)fPath, // path of file to map shared + (char*)loadAddress, // beginning of local copy of sharable pages in file + fileLen, // end of shareable pages in file + &base_address, // beginning of address range to map + mappingTableCount, // number of entres in array of sf_mapping + mappingTable, // the array of sf_mapping + &flags); // in/out flags + if ( 0 != r ) { + // try again but tell kernel it is ok to slide + flags |= ALTERNATE_LOAD_SITE; + r = load_shared_file((char*)fPath,(char*)loadAddress, fileLen, &base_address, + mappingTableCount, mappingTable, &flags); + } + + // unmap file from random address now that they are (hopefully) mapped into the shared region + munmap(loadAddress, fileLen); + + if ( 0 == r ) { + if ( base_address != (caddr_t)baseAddress ) + this->setSlide((uintptr_t)base_address - baseAddress); + if ( context.verboseMapping ) { + if ( base_address != (caddr_t)baseAddress ) + fprintf(stderr, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath()); + else + fprintf(stderr, "dyld: Mapping split-seg load_shared %s\n", this->getPath()); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + const sf_mapping* entry = &mappingTable[entryIndex]; + if ( (entry->protection & VM_PROT_ZF) == 0 ) + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1); + if ( entryIndex < (mappingTableCount-1) ) { + const sf_mapping* nextEntry = &mappingTable[entryIndex+1]; + if ( (nextEntry->protection & VM_PROT_ZF) != 0 ) { + fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n", + seg->getName(), (uintptr_t)(nextEntry->mapping_offset + base_address), (uintptr_t)(nextEntry->mapping_offset + base_address + nextEntry->size - 1)); + ++entryIndex; + } + } + } + } + } + return r; +} +void +ImageLoaderMachO::initMappingTable(uint64_t offsetInFat, + sf_mapping *mappingTable, + uintptr_t baseAddress) +{ + unsigned int segmentCount = fSegments.size(); + for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ + Segment* seg = fSegments[segIndex]; + sf_mapping* entry = &mappingTable[entryIndex]; + entry->mapping_offset = seg->getPreferredLoadAddress() - baseAddress; + entry->size = seg->getFileSize(); + entry->file_offset = seg->getFileOffset() + offsetInFat; + entry->protection = VM_PROT_NONE; + if ( !seg->unaccessible() ) { + if ( seg->executable() ) + entry->protection |= VM_PROT_EXECUTE; + if ( seg->readable() ) + entry->protection |= VM_PROT_READ; + if ( seg->writeable() ) + entry->protection |= VM_PROT_WRITE | VM_PROT_COW; + } + + entry->cksum = 0; + if ( seg->hasTrailingZeroFill() ) { + sf_mapping* zfentry = &mappingTable[++entryIndex]; + zfentry->mapping_offset = entry->mapping_offset + seg->getFileSize(); + zfentry->size = seg->getSize() - seg->getFileSize(); + zfentry->file_offset = 0; + zfentry->protection = entry->protection | VM_PROT_COW | VM_PROT_ZF; + zfentry->cksum = 0; + } + } +} + +#endif // !__LP64__ split segs not supported for 64-bits + + +void ImageLoaderMachO::setSlide(intptr_t slide) +{ + fSlide = slide; +} + +void ImageLoaderMachO::parseLoadCmds() +{ + // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + // set up pointer to __LINKEDIT segment + if ( strcmp(seg->getName(),"__LINKEDIT") == 0 ) + fLinkEditBase = (uint8_t*)(seg->getActualLoadAddress() - seg->getFileOffset()); + // __TEXT segment always starts at beginning of file and contains mach_header and load commands + if ( strcmp(seg->getName(),"__TEXT") == 0 ) { + if ( seg->hasFixUps() ) + fTextSegmentWithFixups = (SegmentMachO*)seg; + } + // some segment always starts at beginning of file and contains mach_header and load commands + if ( (seg->getFileOffset() == 0) && (seg->getFileSize() != 0) ) { + fMachOData = (uint8_t*)(seg->getActualLoadAddress()); + } + } + + // walk load commands (mapped in at start of __TEXT segment) + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SYMTAB: + { + const struct symtab_command* symtab = (struct symtab_command*)cmd; + fStrings = (const char*)&fLinkEditBase[symtab->stroff]; + fSymbolTable = (struct macho_nlist*)(&fLinkEditBase[symtab->symoff]); + } + break; + case LC_DYSYMTAB: + fDynamicInfo = (struct dysymtab_command*)cmd; + break; + case LC_SUB_UMBRELLA: + fHasSubUmbrella = true; + break; + case LC_SUB_FRAMEWORK: + { + const struct sub_framework_command* subf = (struct sub_framework_command*)cmd; + fReExportThruFramework = (char*)cmd + subf->umbrella.offset; + } + break; + case LC_SUB_LIBRARY: + fHasSubLibraries = true; + break; + case LC_ROUTINES_COMMAND: + fDashInit = (struct macho_routines_command*)cmd; + break; + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + const bool isDataSeg = (strcmp(seg->segname, "__DATA") == 0); + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + const uint8_t type = sect->flags & SECTION_TYPE; + if ( type == S_MOD_INIT_FUNC_POINTERS ) + fModInitSection = sect; + else if ( type == S_MOD_TERM_FUNC_POINTERS ) + fModTermSection = sect; + else if ( isDataSeg && (strcmp(sect->sectname, "__dyld") == 0) ) + fDATAdyld = sect; + else if ( isDataSeg && (strcmp(sect->sectname, "__image_notify") == 0) ) + fImageNotifySection = sect; + } + } + break; + case LC_TWOLEVEL_HINTS: + fTwoLevelHints = (struct twolevel_hints_command*)cmd; + break; + case LC_ID_DYLIB: + { + fDylibID = (struct dylib_command*)cmd; + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + + + + +const char* ImageLoaderMachO::getInstallPath() const +{ + if ( fDylibID != NULL ) { + return (char*)fDylibID + fDylibID->dylib.name.offset; + } + return NULL; +} + +// test if this image is re-exported through parent (the image that loaded this one) +bool ImageLoaderMachO::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const +{ + if ( fReExportThruFramework != NULL ) { + // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent... + const char* parentInstallPath = parent->getInstallPath(); + if ( parentInstallPath != NULL ) { + const char* lastSlash = strrchr(parentInstallPath, '/'); + if ( lastSlash != NULL ) { + if ( strcmp(&lastSlash[1], fReExportThruFramework) == 0 ) + return true; + if ( context.imageSuffix != NULL ) { + // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end + char reexportAndSuffix[strlen(context.imageSuffix)+strlen(fReExportThruFramework)+1]; + strcpy(reexportAndSuffix, fReExportThruFramework); + strcat(reexportAndSuffix, context.imageSuffix); + if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 ) + return true; + } + } + } + } + return false; +} + +// test if child is re-exported +bool ImageLoaderMachO::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const +{ + if ( fHasSubLibraries ) { + // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child... + const char* childInstallPath = child->getInstallPath(); + if ( childInstallPath != NULL ) { + const char* lastSlash = strrchr(childInstallPath, '/'); + if ( lastSlash != NULL ) { + const char* firstDot = strchr(lastSlash, '.'); + int len; + if ( firstDot == NULL ) + len = strlen(lastSlash); + else + len = firstDot-lastSlash-1; + char childLeafName[len+1]; + strncpy(childLeafName, &lastSlash[1], len); + childLeafName[len] = '\0'; + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SUB_LIBRARY: + { + const struct sub_library_command* lib = (struct sub_library_command*)cmd; + const char* aSubLibName = (char*)cmd + lib->sub_library.offset; + if ( strcmp(aSubLibName, childLeafName) == 0 ) + return true; + if ( context.imageSuffix != NULL ) { + // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end + char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1]; + strcpy(aSubLibNameAndSuffix, aSubLibName); + strcat(aSubLibNameAndSuffix, context.imageSuffix); + if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 ) + return true; + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + } + } + } + if ( fHasSubUmbrella ) { + // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child... + const char* childInstallPath = child->getInstallPath(); + if ( childInstallPath != NULL ) { + const char* lastSlash = strrchr(childInstallPath, '/'); + if ( lastSlash != NULL ) { + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SUB_UMBRELLA: + { + const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd; + const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset; + if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 ) + return true; + if ( context.imageSuffix != NULL ) { + // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end + char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1]; + strcpy(umbrellaAndSuffix, aSubUmbrellaName); + strcat(umbrellaAndSuffix, context.imageSuffix); + if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 ) + return true; + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + } + } + } + return false; +} + + +void* ImageLoaderMachO::getMain() const +{ + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (unsigned long i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_UNIXTHREAD: + { + #if __ppc__ + const ppc_thread_state_t* registers = (ppc_thread_state_t*)(((char*)cmd) + 16); + return (void*)registers->srr0; + #elif __ppc64__ + const ppc_thread_state64_t* registers = (ppc_thread_state64_t*)(((char*)cmd) + 16); + return (void*)registers->srr0; + #elif __i386__ + const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16); + return (void*)registers->eip; + #else + #warning need processor specific code + #endif + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + return NULL; +} + + +uint32_t ImageLoaderMachO::doGetDependentLibraryCount() +{ + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + uint32_t count = 0; + const struct load_command* cmd = cmds; + for (unsigned long i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + ++count; + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + return count; +} + +void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs[]) +{ + uint32_t index = 0; + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (unsigned long i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + { + const struct dylib_command* dylib = (struct dylib_command*)cmd; + DependentLibrary* lib = &libs[index++]; + lib->name = (char*)cmd + dylib->dylib.name.offset; + //lib->name = strdup((char*)cmd + dylib->dylib.name.offset); + lib->image = NULL; + lib->info.checksum = dylib->dylib.timestamp; + lib->info.minVersion = dylib->dylib.compatibility_version; + lib->info.maxVersion = dylib->dylib.current_version; + lib->required = (cmd->cmd == LC_LOAD_DYLIB); + lib->checksumMatches = false; + lib->isReExported = false; + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + +ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo() +{ + LibraryInfo info; + if ( fDylibID != NULL ) { + info.minVersion = fDylibID->dylib.compatibility_version; + info.maxVersion = fDylibID->dylib.current_version; + info.checksum = fDylibID->dylib.timestamp; + } + else { + info.minVersion = 0; + info.maxVersion = 0; + info.checksum = 0; + } + return info; +} + + +uintptr_t ImageLoaderMachO::getRelocBase() +{ + if ( fIsSplitSeg ) { + // in split segment libraries r_address is offset from first writable segment + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i){ + Segment* seg = fSegments[i]; + if ( seg->writeable() ) { + return seg->getActualLoadAddress(); + } + } + } + + // in non-split segment libraries r_address is offset from first segment + return fSegments[0]->getActualLoadAddress(); +} + +#if __ppc__ +static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationType, uint16_t otherHalf, uintptr_t slide) +{ + // low 16 bits of 32-bit ppc instructions need fixing + struct ppcInstruction { uint16_t opcode; int16_t immediateValue; }; + ppcInstruction* instruction = (ppcInstruction*)locationToFix; + //uint32_t before = *((uint32_t*)locationToFix); + switch ( relocationType ) + { + case PPC_RELOC_LO16: + instruction->immediateValue = ((otherHalf << 16) | instruction->immediateValue) + slide; + break; + case PPC_RELOC_HI16: + instruction->immediateValue = ((((instruction->immediateValue << 16) | otherHalf) + slide) >> 16); + break; + case PPC_RELOC_HA16: + int16_t signedOtherHalf = (int16_t)(otherHalf & 0xffff); + uint32_t temp = (instruction->immediateValue << 16) + signedOtherHalf + slide; + if ( (temp & 0x00008000) != 0 ) + temp += 0x00008000; + instruction->immediateValue = temp >> 16; + } + //uint32_t after = *((uint32_t*)locationToFix); + //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after); +} +#endif + +void ImageLoaderMachO::doRebase(const LinkContext& context) +{ + // if prebound and loaded at prebound address, then no need to rebase + // Note: you might think that the check for allDependentLibrariesAsWhenPreBound() is not needed + // but it is. If a dependent library changed, this image's lazy pointers into that library + // need to be updated (reset back to lazy binding handler). That work is done most easily + // here because there is a PPC_RELOC_PB_LA_PTR reloc record for each lazy pointer. + if ( this->usablePrebinding(context) && this->usesTwoLevelNameSpace() ) { + // skip rebasing cause prebound and prebinding not disabled + ++fgImagesWithUsedPrebinding; // bump totals for statistics + return; + } + + // print why prebinding was not used + if ( context.verbosePrebinding ) { + if ( !this->isPrebindable() ) { + fprintf(stderr, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath()); + } + else if ( fSlide != 0 ) { + fprintf(stderr, "dyld: image slid, so could not use prebinding in %s\n", this->getPath()); + } + else if ( !this->allDependentLibrariesAsWhenPreBound() ) { + fprintf(stderr, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath()); + } + else if ( !this->usesTwoLevelNameSpace() ){ + fprintf(stderr, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath()); + } + else { + fprintf(stderr, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath()); + } + } + + // if there are __TEXT fixups, temporarily make __TEXT writable + if ( fTextSegmentWithFixups != NULL ) + fTextSegmentWithFixups->tempWritable(); + + // cache this value that is used in the following loop + register const uintptr_t slide = this->fSlide; + + // loop through all local (internal) relocation records + const uintptr_t relocBase = this->getRelocBase(); + const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]); + const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel]; + for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + if ( (reloc->r_address & R_SCATTERED) == 0 ) { + if ( reloc->r_symbolnum == R_ABS ) { + // ignore absolute relocations + } + else if (reloc->r_length == RELOC_SIZE) { + switch(reloc->r_type) { + case GENERIC_RELOC_VANILLA: + *((uintptr_t*)(reloc->r_address + relocBase)) += slide; + break; + #if __ppc__ + case PPC_RELOC_HI16: + case PPC_RELOC_LO16: + case PPC_RELOC_HA16: + // some tools leave object file relocations in linked images + otherRelocsPPC((uintptr_t*)(reloc->r_address + relocBase), reloc->r_type, reloc[1].r_address, slide); + ++reloc; // these relocations come in pairs, skip next + break; + #endif + default: + throw "unknown local relocation type"; + } + } + else { + throw "bad local relocation length"; + } + } + else { + const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; + if (sreloc->r_length == RELOC_SIZE) { + uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase); + switch(sreloc->r_type) { + case GENERIC_RELOC_VANILLA: + *locationToFix += slide; + break; + #if __ppc__ || __ppc64__ + case PPC_RELOC_PB_LA_PTR: + // should only see these in prebound images, and we got here so prebinding is being ignored + *locationToFix = sreloc->r_value + slide; + break; + #endif + #if __ppc__ + case PPC_RELOC_HI16: + case PPC_RELOC_LO16: + case PPC_RELOC_HA16: + // Metrowerks compiler sometimes leaves object file relocations in linked images??? + ++reloc; // these relocations come in pairs, get next one + otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide); + break; + #endif + #if __i386__ + case GENERIC_RELOC_PB_LA_PTR: + // should only see these in prebound images, and we got here so prebinding is being ignored + *locationToFix = sreloc->r_value + slide; + break; + #endif + default: + throw "unknown local scattered relocation type"; + } + } + else { + throw "bad local scattered relocation length"; + } + } + } + + // if there were __TEXT fixups, restore write protection + if ( fTextSegmentWithFixups != NULL ) { + fTextSegmentWithFixups->setPermissions(); + sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(), fTextSegmentWithFixups->getSize()); + } + + // update stats + fgTotalRebaseFixups += fDynamicInfo->nlocrel; +} + + +const struct macho_nlist* ImageLoaderMachO::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], + const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) +{ + int32_t high = symbolCount-1; + int32_t mid = hintIndex; + + // handle out of range hint + if ( mid >= (int32_t)symbolCount ) { + mid = symbolCount/2; + ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs; + } + else { + ++ImageLoaderMachO::fgHintedBinaryTreeSearchs; + } + + for (int32_t low = 0; low <= high; mid = (low+high)/2) { + const uint32_t index = toc[mid].symbol_index; + const struct macho_nlist* pivot = &symbols[index]; + const char* pivotStr = &stringPool[pivot->n_un.n_strx]; +#if LINKEDIT_USAGE_DEBUG + noteAccessedLinkEditAddress(&toc[mid]); + noteAccessedLinkEditAddress(pivot); + noteAccessedLinkEditAddress(pivotStr); +#endif + int cmp = astrcmp(key, pivotStr); + if ( cmp == 0 ) + return pivot; + if ( cmp > 0 ) { + // key > pivot + low = mid + 1; + } + else { + // key < pivot + high = mid - 1; + } + } + return NULL; +} + +const struct macho_nlist* ImageLoaderMachO::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) +{ + ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs; + const struct macho_nlist* base = symbols; + for (uint32_t n = symbolCount; n > 0; n /= 2) { + const struct macho_nlist* pivot = &base[n/2]; + const char* pivotStr = &stringPool[pivot->n_un.n_strx]; +#if LINKEDIT_USAGE_DEBUG + noteAccessedLinkEditAddress(pivot); + noteAccessedLinkEditAddress(pivotStr); +#endif + int cmp = astrcmp(key, pivotStr); + if ( cmp == 0 ) + return pivot; + if ( cmp > 0 ) { + // key > pivot + // move base to symbol after pivot + base = &pivot[1]; + --n; + } + else { + // key < pivot + // keep same base + } + } + return NULL; +} + +const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const +{ + const struct macho_nlist* sym = NULL; + const struct twolevel_hint* theHint = (struct twolevel_hint*)hint; + if ( fDynamicInfo->tocoff == 0 ) + sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym); + else { + uint32_t start = fDynamicInfo->nextdefsym; + if ( theHint != NULL ) + start = theHint->itoc; + if ( (theHint == NULL) || (theHint->isub_image == 0) ) { + sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], + fDynamicInfo->ntoc, start); + } + } + if ( sym != NULL ) { + if ( foundIn != NULL ) + *foundIn = (ImageLoader*)this; + + return (const Symbol*)sym; + } + + if ( searchReExports ) { + // hint might tell us to try a particular subimage + if ( (theHint != NULL) && (theHint->isub_image > 0) && (theHint->isub_image <= fLibrariesCount) ) { + // isub_image is an index into a list that is sorted non-rexported images first + uint32_t index = 0; + ImageLoader* target = NULL; + // pass one, only look at sub-frameworks + for (uint32_t i=0; i < fLibrariesCount; ++i) { + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.isSubFramework && (libInfo.image != NULL)) { + if ( ++index == theHint->isub_image ) { + target = libInfo.image; + break; + } + } + } + if (target != NULL) { + // pass two, only look at non-sub-framework-reexports + for (uint32_t i=0; i < fLibrariesCount; ++i) { + DependentLibrary& libInfo = fLibraries[i]; + if ( libInfo.isReExported && !libInfo.isSubFramework && (libInfo.image != NULL) ) { + if ( ++index == theHint->isub_image ) { + target = libInfo.image; + break; + } + } + } + } + if (target != NULL) { + const Symbol* result = target->findExportedSymbol(name, NULL, searchReExports, foundIn); + if ( result != NULL ) + return result; + } + } + + // hint failed, try all sub images + // pass one, only look at sub-frameworks + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( (libInfo.image != NULL) && libInfo.isSubFramework ) { + const Symbol* result = libInfo.image->findExportedSymbol(name, NULL, searchReExports, foundIn); + if ( result != NULL ) + return result; + } + } + // pass two, only look at non-sub-framework-reexports + for(unsigned int i=0; i < fLibrariesCount; ++i){ + DependentLibrary& libInfo = fLibraries[i]; + if ( (libInfo.image != NULL) && libInfo.isReExported && !libInfo.isSubFramework ) { + const Symbol* result = libInfo.image->findExportedSymbol(name, NULL, searchReExports, foundIn); + if ( result != NULL ) + return result; + } + } + } + + // last change: the hint is wrong (non-zero but actually in this image) + if ( (theHint != NULL) && (theHint->isub_image != 0) ) { + sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], + fDynamicInfo->ntoc, fDynamicInfo->nextdefsym); + if ( sym != NULL ) { + if ( foundIn != NULL ) + *foundIn = (ImageLoader*)this; + return (const Symbol*)sym; + } + } + + return NULL; +} + + +uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym) const +{ + const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym; + return nlistSym->n_value + fSlide; +} + +ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const +{ + const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym; + if ( (nlistSym->n_desc & N_WEAK_DEF) != 0 ) + return kWeakDefinition; + return kNoDefinitionOptions; +} + +const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const +{ + const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym; + return &fStrings[nlistSym->n_un.n_strx]; +} + +uint32_t ImageLoaderMachO::getExportedSymbolCount() const +{ + return fDynamicInfo->nextdefsym; +} + + +const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const +{ + if ( index < fDynamicInfo->nextdefsym ) { + const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index]; + return (const ImageLoader::Symbol*)sym; + } + return NULL; +} + + +uint32_t ImageLoaderMachO::getImportedSymbolCount() const +{ + return fDynamicInfo->nundefsym; +} + + +const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const +{ + if ( index < fDynamicInfo->nundefsym ) { + const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index]; + return (const ImageLoader::Symbol*)sym; + } + return NULL; +} + + +ImageLoader::ReferenceFlags ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol* sym) const +{ + const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym; + ImageLoader::ReferenceFlags flags = kNoReferenceOptions; + if ( ((nlistSym->n_type & N_TYPE) == N_UNDF) && (nlistSym->n_value != 0) ) + flags |= ImageLoader::kTentativeDefinition; + if ( (nlistSym->n_desc & N_WEAK_REF) != 0 ) + flags |= ImageLoader::kWeakReference; + return flags; +} + + +const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const +{ + const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym; + return &fStrings[nlistSym->n_un.n_strx]; +} + + +bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) +{ + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) { + *start = (uintptr_t*)(sect->addr + fSlide); + *length = sect->size; + return true; + } + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + return false; +} + + +bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) +{ + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide(); + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) { + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ((sect->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) { + if ( segmentName != NULL ) + *segmentName = sect->segname; + if ( sectionName != NULL ) + *sectionName = sect->sectname; + if ( sectionOffset != NULL ) + *sectionOffset = unslidInteriorAddress - sect->addr; + return true; + } + } + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + return false; +} + + +bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist* symbol) +{ + // if a define and weak ==> coalesced + if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) ) + return true; + // if an undefine and not referencing a weak symbol ==> coalesced + if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) ) + return true; + + // regular symbol + return false; +} + + +static void __attribute__((noreturn)) throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn) +{ + const char* formatString = "Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n"; + char buf[strlen(symbol)+strlen(referencedFrom)+strlen(expectedIn)+strlen(formatString)]; + sprintf(buf, formatString, symbol, referencedFrom, expectedIn); + throw strdup(buf); // this is a leak if exception doesn't halt program +} + +uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, bool twoLevel, ImageLoader** foundIn) +{ + const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx]; + + if ( context.bindFlat || !twoLevel ) { + // flat lookup + const Symbol* sym; + if ( context.flatExportFinder(symbolName, &sym, foundIn) ) + return (*foundIn)->getExportedSymbolAddress(sym); + // if a bundle is loaded privately the above will not find its exports + if ( this->isBundle() && this->hasHiddenExports() ) { + // look in self for needed symbol + sym = this->findExportedSymbol(symbolName, NULL, false, foundIn); + if ( sym != NULL ) + return (*foundIn)->getExportedSymbolAddress(sym); + } + if ( ((undefinedSymbol->n_type & N_PEXT) != 0) || ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) { + // could be a multi-module private_extern internal reference + // the static linker squirrels away the target address in n_value + uintptr_t addr = undefinedSymbol->n_value + this->fSlide; + *foundIn = this; + return addr; + } + if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) { + // definition can't be found anywhere + // if reference is weak_import, then it is ok, just return 0 + return 0; + } + throwSymbolNotFound(symbolName, this->getPath(), "flat namespace"); + } + else { + // symbol requires searching images with coalesced symbols + if ( this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol) ) { + const Symbol* sym; + if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) + return (*foundIn)->getExportedSymbolAddress(sym); + //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace"); + //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName); + } + + // two level lookup + void* hint = NULL; + ImageLoader* target = NULL; + uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc); + if ( ord == EXECUTABLE_ORDINAL ) { + target = context.mainExecutable; + } + else if ( ord == SELF_LIBRARY_ORDINAL ) { + target = this; + } + else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) { + // rnielsen: HACKHACK + // flat lookup + const Symbol* sym; + if ( context.flatExportFinder(symbolName, &sym, foundIn) ) + return (*foundIn)->getExportedSymbolAddress(sym); + // no image has exports this symbol + // either report error or hope ZeroLink can just-in-time load an image + context.undefinedHandler(symbolName); + // try looking again + if ( context.flatExportFinder(symbolName, &sym, foundIn) ) + return (*foundIn)->getExportedSymbolAddress(sym); + + throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup"); + } + else if ( ord <= fLibrariesCount ) { + DependentLibrary& libInfo = fLibraries[ord-1]; + target = libInfo.image; + if ( (target == NULL) && (((undefinedSymbol->n_desc & N_WEAK_REF) != 0) || !libInfo.required) ) { + // if target library not loaded and reference is weak or library is weak return 0 + return 0; + } + } + else { + throw "corrupt binary, library ordinal too big"; + } + + if ( target == NULL ) { + fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath()); + throw "symbol not found"; + } + + // interpret hint + if ( fTwoLevelHints != NULL ) { + uint32_t symIndex = undefinedSymbol - fSymbolTable; + int32_t undefinedIndex = symIndex - fDynamicInfo->iundefsym; + if ( (undefinedIndex >= 0) && ((uint32_t)undefinedIndex < fDynamicInfo->nundefsym) ) { + const struct twolevel_hint* hints = (struct twolevel_hint*)(&fLinkEditBase[fTwoLevelHints->offset]); + const struct twolevel_hint* theHint = &hints[undefinedIndex]; + hint = (void*)theHint; + } + } + + const Symbol* sym = target->findExportedSymbol(symbolName, hint, true, foundIn); + if ( sym!= NULL ) { + return (*foundIn)->getExportedSymbolAddress(sym); + } + else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) { + // don't know why the static linker did not eliminate the internal reference to a private extern definition + *foundIn = this; + return undefinedSymbol->n_value + fSlide; + } + else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) { + // if definition not found and reference is weak return 0 + return 0; + } + + // nowhere to be found + throwSymbolNotFound(symbolName, this->getPath(), target->getPath()); + } +} + +void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, bool onlyCoalescedSymbols) +{ + const uintptr_t relocBase = this->getRelocBase(); + const bool twoLevel = this->usesTwoLevelNameSpace(); + const bool prebound = this->isPrebindable(); + + // if there are __TEXT fixups, temporarily make __TEXT writable + if ( fTextSegmentWithFixups != NULL ) + fTextSegmentWithFixups->tempWritable(); + + // cache last lookup + const struct macho_nlist* lastUndefinedSymbol = 0; + uintptr_t symbolAddr = 0; + ImageLoader* image = NULL; + + // loop through all external relocation records and bind each + const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]); + const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel]; + for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + if (reloc->r_length == RELOC_SIZE) { + switch(reloc->r_type) { + case GENERIC_RELOC_VANILLA: + { + const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum]; + // if only processing coalesced symbols and this one does not require coalesceing, skip to next + if ( onlyCoalescedSymbols && !symbolRequiresCoalescing(undefinedSymbol) ) + continue; + uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase)); + uintptr_t value = *location; + if ( prebound ) { + // we are doing relocations, so prebinding was not usable + // in a prebound executable, the n_value field is set to the address where the symbol was found when prebound + // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address + // if mach-o relocation structs had an "addend" field this would not be necessary. + value -= undefinedSymbol->n_value; + } + // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too + if ( undefinedSymbol != lastUndefinedSymbol ) { + symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, &image); + lastUndefinedSymbol = undefinedSymbol; + } + if ( context.verboseBind ) { + const char *path = NULL; + if(NULL != image) { + path = image->getShortName(); + } + if(0 == value) { + fprintf(stderr, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n", + this->getShortName(), (uintptr_t)location, + path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr); + } + else { + fprintf(stderr, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n", + this->getShortName(), (uintptr_t)location, + path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, value); + } + } + value += symbolAddr; + *location = value; + } + break; + default: + throw "unknown external relocation type"; + } + } + else { + throw "bad external relocation length"; + } + } + + // if there were __TEXT fixups, restore write protection + if ( fTextSegmentWithFixups != NULL ) { + fTextSegmentWithFixups->setPermissions(); + sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(), fTextSegmentWithFixups->getSize()); + } + + // update stats + fgTotalBindFixups += fDynamicInfo->nextrel; +} + +const mach_header* ImageLoaderMachO::machHeader() const +{ + return (mach_header*)fMachOData; +} + +uintptr_t ImageLoaderMachO::getSlide() const +{ + return fSlide; +} + +// hmm. maybe this should be up in ImageLoader?? +const void* ImageLoaderMachO::getBaseAddress() const +{ + Segment* seg = fSegments[0]; + return (const void*)seg->getActualLoadAddress(); +} + + +uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) +{ + // scan for all non-lazy-pointer sections + const bool twoLevel = this->usesTwoLevelNameSpace(); + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + const uint8_t type = sect->flags & SECTION_TYPE; + if ( type == S_LAZY_SYMBOL_POINTERS ) { + const uint32_t pointerCount = sect->size / sizeof(uintptr_t); + uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide); + if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) { + const uint32_t indirectTableOffset = sect->reserved1; + const uint32_t lazyIndex = lazyPointer - symbolPointers; + uint32_t symbolIndex = indirectTable[indirectTableOffset + lazyIndex]; + if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) { + ImageLoader *image = NULL; + const char *path = NULL; + uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, &image); + if ( context.verboseBind ) { + if(NULL == path && NULL != image) { + path = image->getShortName(); + } + fprintf(stderr, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", + this->getShortName(), &fStrings[fSymbolTable[symbolIndex].n_un.n_strx], "lazy_ptr", + path, &fStrings[fSymbolTable[symbolIndex].n_un.n_strx], (uintptr_t)&symbolPointers[lazyIndex], symbolAddr); + } + if ( NULL != context.bindingHandler ) { + if(NULL == path && NULL != image) { + path = image->getPath(); + } + symbolAddr = (uintptr_t)context.bindingHandler(path, &fStrings[fSymbolTable[symbolIndex].n_un.n_strx], (void *)symbolAddr); + } + symbolPointers[lazyIndex] = symbolAddr; + // update stats + fgTotalLazyBindFixups++; + return symbolPointers[lazyIndex]; + } + } + } + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + throw "lazy pointer not found"; +} + + + +void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context, BindingLaziness bindness, bool onlyCoalescedSymbols) +{ + // scan for all non-lazy-pointer sections + const bool twoLevel = this->usesTwoLevelNameSpace(); + const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; + const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + const uint8_t type = sect->flags & SECTION_TYPE; + const uint32_t pointerCount = sect->size / sizeof(uintptr_t); + if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { + if ( (bindness == kLazyOnly) || (bindness == kLazyOnlyNoDependents) ) + continue; + } + else if ( type == S_LAZY_SYMBOL_POINTERS ) { + // process each symbol pointer in this section + fgTotalPossibleLazyBindFixups += pointerCount; + if ( bindness == kNonLazyOnly ) + continue; + } + else { + continue; + } + const uint32_t indirectTableOffset = sect->reserved1; + uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide); + for (uint32_t j=0; j < pointerCount; ++j) { + uint32_t symbolIndex = indirectTable[indirectTableOffset + j]; + if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) { + symbolPointers[j] += this->fSlide; + } + else if ( symbolIndex == INDIRECT_SYMBOL_ABS) { + // do nothing since already has absolute address + } + else { + const struct macho_nlist* sym = &fSymbolTable[symbolIndex]; + if ( symbolIndex == 0 ) { + // This could be rdar://problem/3534709 + if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) { + static bool alreadyWarned = false; + if ( (sym->n_type & N_TYPE) != N_UNDF ) { + // The indirect table parallels the (non)lazy pointer sections. For + // instance, to find info about the fifth lazy pointer you look at the + // fifth entry in the indirect table. (try otool -Iv on a file). + // The entry in the indirect table contains an index into the symbol table. + + // The bug in ld caused the entry in the indirect table to be zero + // (instead of a magic value that means a local symbol). So, if the + // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid + // symbol table index. The check I put in place is to see if the zero'th + // symbol table entry is an import entry (usually it is a local symbol + // definition). + if ( context.verboseWarnings && !alreadyWarned ) { + fprintf(stderr, "dyld: malformed executable '%s', skipping indirect symbol to %s\n", + this->getPath(), &fStrings[sym->n_un.n_strx]); + alreadyWarned = true; + } + continue; + } + } + } + ImageLoader *image = NULL; + // if only processing coalesced symbols and this one does not require coalesceing, skip to next + if ( onlyCoalescedSymbols && !symbolRequiresCoalescing(sym) ) + continue; + uintptr_t symbolAddr; + symbolAddr = resolveUndefined(context, sym, twoLevel, &image); + if ( context.verboseBind ) { + const char *path = NULL; + if(NULL != image) { + path = image->getShortName(); + } + const char *typeName; + if ( type == S_LAZY_SYMBOL_POINTERS ) { + typeName = "lazy_ptr"; + } + else { + typeName = "non_lazy_ptr"; + } + fprintf(stderr, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", + this->getShortName(), &fStrings[sym->n_un.n_strx], typeName, + path, &fStrings[sym->n_un.n_strx], (uintptr_t)&symbolPointers[j], symbolAddr); + } + symbolPointers[j] = symbolAddr; + } + } + // update stats + fgTotalBindFixups += pointerCount; + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + +/* + * The address of these symbols are written in to the (__DATA,__dyld) section + * at the following offsets: + * at offset 0 stub_binding_helper_interface + * at offset 4 _dyld_func_lookup + * at offset 8 start_debug_thread + * The 'C' types (if any) for these symbols are ignored here and all are + * declared as longs so the assignment of their address in to the section will + * not require a cast. stub_binding_helper_interface is really a label in the + * assembly code interface for the stub binding. It does not have a meaningful + * 'C' type. _dyld_func_lookup is the routine in dyld_libfuncs.c. + * start_debug_thread is the routine in debug.c. + * + * For ppc the image's stub_binding_binding_helper is read from: + * at offset 20 the image's stub_binding_binding_helper address + * and saved into to the image structure. + */ +struct DATAdyld { + void* dyldLazyBinder; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface + void* dyldFuncLookup; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup + void* startDebugThread; // debugger interface ??? + void* debugPort; // debugger interface ??? + void* debugThread; // debugger interface ??? + void* stubBindHelper; // filled in at static link time to point to stub helper in image + void* coreDebug; // ??? +}; + +// These are defined in dyldStartup.s +extern "C" void stub_binding_helper(); +extern "C" bool dyld_func_lookup(const char* name, uintptr_t* address); + + +void ImageLoaderMachO::setupLazyPointerHandler() +{ + if ( fDATAdyld != NULL ) { + struct DATAdyld* dd = (struct DATAdyld*)(fDATAdyld->addr + fSlide); + if ( fDATAdyld->size > offsetof(DATAdyld, dyldLazyBinder) ) { + if ( dd->dyldLazyBinder != (void*)&stub_binding_helper ) + dd->dyldLazyBinder = (void*)&stub_binding_helper; + } + if ( fDATAdyld->size > offsetof(DATAdyld, dyldFuncLookup) ) { + if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup ) + dd->dyldFuncLookup = (void*)&dyld_func_lookup; + } + //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) ) + // dd->startDebugThread = &start_debug_thread; +#ifdef __ppc__ + //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) ) + // save = dd->stubBindHelper; +#endif + } +} + +bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const +{ + // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind + if ( this->isPrebindable() && this->allDependentLibrariesAsWhenPreBound() && (this->getSlide() == 0) ) { + // allow environment variables to disable prebinding + if ( context.bindFlat ) + return false; + switch ( context.prebindUsage ) { + case kUseAllPrebinding: + return true; + case kUseSplitSegPrebinding: + return this->fIsSplitSeg; + case kUseAllButAppPredbinding: + return (this != context.mainExecutable); + case kUseNoPrebinding: + return false; + } + } + return false; +} + +void ImageLoaderMachO::doBind(const LinkContext& context, BindingLaziness bindness) +{ + // set dyld entry points in image + this->setupLazyPointerHandler(); + + // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind + // note: flat-namespace binaries need to be imports rebound (even if correctly prebound) + if ( this->usablePrebinding(context) && this->usesTwoLevelNameSpace() ) { + // if image has coalesced symbols, then these need to be rebound + if ( this->needsCoalescing() ) { + this->doBindExternalRelocations(context, true); + this->doBindIndirectSymbolPointers(context, kLazyAndNonLazy, true); + } + // skip binding because prebound and prebinding not disabled + return; + } + + // values bound by name are stored two different ways in mach-o + switch (bindness) { + case kNonLazyOnly: + case kLazyAndNonLazy: + // external relocations are used for data initialized to external symbols + this->doBindExternalRelocations(context, false); + break; + case kLazyOnly: + case kLazyOnlyNoDependents: + break; + } + // "indirect symbols" are used for code references to external symbols + this->doBindIndirectSymbolPointers(context, bindness, false); +} + + + +void ImageLoaderMachO::doImageInit(const LinkContext& context) +{ + if ( fDashInit != NULL ) { + Initializer func = (Initializer)(fDashInit->init_address + fSlide); + if ( context.verboseInit ) + fprintf(stderr, "dyld: calling -init function 0x%p in %s\n", func, this->getPath()); + func(context.argc, context.argv, context.envp, context.apple); + } +} + +void ImageLoaderMachO::doModInitFunctions(const LinkContext& context) +{ + if ( fModInitSection != NULL ) { + Initializer* inits = (Initializer*)(fModInitSection->addr + fSlide); + const uint32_t count = fModInitSection->size / sizeof(uintptr_t); + for (uint32_t i=0; i < count; ++i) { + Initializer func = inits[i]; + if ( context.verboseInit ) + fprintf(stderr, "dyld: calling initializer function %p in %s\n", func, this->getPath()); + func(context.argc, context.argv, context.envp, context.apple); + } + } +} + + +void ImageLoaderMachO::doInitialization(const LinkContext& context) +{ + // mach-o has -init and static initializers + doImageInit(context); + doModInitFunctions(context); +} + +bool ImageLoaderMachO::needsInitialization() +{ + return ( (fDashInit != NULL) || (fModInitSection != NULL) ); +} + + +bool ImageLoaderMachO::needsTermination() +{ + return ( fModTermSection != NULL ); +} + +bool ImageLoaderMachO::hasImageNotification() +{ + return ( fImageNotifySection != NULL ); +} + + +void ImageLoaderMachO::doTermination(const LinkContext& context) +{ + if ( fModTermSection != NULL ) { + Terminator* terms = (Terminator*)(fModTermSection->addr + fSlide); + const uint32_t count = fModTermSection->size / sizeof(uintptr_t); + for (uint32_t i=count; i > 0; --i) { + Terminator func = terms[i-1]; + if ( context.verboseInit ) + fprintf(stderr, "dyld: calling terminaton function %p in %s\n", func, this->getPath()); + func(); + } + } +} + +void ImageLoaderMachO::doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) +{ + if ( fImageNotifySection != NULL ) { + dyld_image_notifier* notes = (dyld_image_notifier*)(fImageNotifySection->addr + fSlide); + const uint32_t count = fImageNotifySection->size / sizeof(uintptr_t); + for (uint32_t i=count; i > 0; --i) { + dyld_image_notifier func = notes[i-1]; + func(mode, infoCount, info); + } + } +} + +void ImageLoaderMachO::printStatistics(unsigned int imageCount) +{ + ImageLoader::printStatistics(imageCount); + fprintf(stderr, "total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs); + fprintf(stderr, "total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs); + +#if LINKEDIT_USAGE_DEBUG + fprintf(stderr, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets.size()); +#endif +} + +void ImageLoaderMachO::doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind) +{ + // update __DATA segment + this->applyPrebindingToDATA(fileToPrebind); + + // update load commands + this->applyPrebindingToLoadCommands(context, fileToPrebind, timestamp); + + // update symbol table + this->applyPrebindingToLinkEdit(context, fileToPrebind); +} + +void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind) +{ + const unsigned int segmentCount = fSegments.size(); + for(unsigned int i=0; i < segmentCount; ++i) { + SegmentMachO* seg = (SegmentMachO*)fSegments[i]; + if ( seg->writeable() ) { + memcpy(&fileToPrebind[seg->fFileOffset], (void*)seg->getActualLoadAddress(), seg->fFileSize); + } + } +} + +void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext& context, uint8_t* fileToPrebind, time_t timestamp) +{ + macho_header* mh = (macho_header*)fileToPrebind; + const uint32_t cmd_count = mh->ncmds; + const struct load_command* const cmds = (struct load_command*)&fileToPrebind[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + { + // update each dylib load command with the timestamp of the target dylib + struct dylib_command* dylib = (struct dylib_command*)cmd; + const char* name = (char*)cmd + dylib->dylib.name.offset; + for (const DependentLibrary* dl=fLibraries; dl < &fLibraries[fLibrariesCount]; dl++) { + if (strcmp(dl->name, name) == 0 ) { + // found matching DependentLibrary for this load command + ImageLoaderMachO* targetImage = (ImageLoaderMachO*)(dl->image); // !!! assume only mach-o images are prebound + if ( ! targetImage->isPrebindable() ) + throw "dependent dylib is not prebound"; + // if the target is currently being re-prebound then its timestamp will be the same as this one + if ( ! targetImage->usablePrebinding(context) ) { + dylib->dylib.timestamp = timestamp; + } + else { + // otherwise dependent library is already correctly prebound, so use its checksum + dylib->dylib.timestamp = targetImage->doGetLibraryInfo().checksum; + } + break; + } + } + } + break; + case LC_ID_DYLIB: + { + // update the ID of this library with the new timestamp + struct dylib_command* dylib = (struct dylib_command*)cmd; + dylib->dylib.timestamp = timestamp; + } + break; + case LC_SEGMENT_COMMAND: + // if dylib was rebased, update segment commands + if ( fSlide != 0 ) { + struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + seg->vmaddr += fSlide; + struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + sect->addr += fSlide; + } + } + break; + case LC_ROUTINES_COMMAND: + // if dylib was rebased, update -init command + if ( fSlide != 0 ) { + struct macho_routines_command* routines = (struct macho_routines_command*)cmd; + routines->init_address += fSlide; + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + +void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext& context, uint8_t* fileToPrebind) +{ + // In prebound images, the n_value of the symbol table entry for is the prebound address + // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers + const char* stringPool = NULL; + struct macho_nlist* symbolTable = NULL; + const struct dysymtab_command* dysymtab = NULL; + + // get symbol table info + macho_header* mh = (macho_header*)fileToPrebind; + const uint32_t cmd_count = mh->ncmds; + const struct load_command* const cmds = (struct load_command*)&fileToPrebind[sizeof(macho_header)]; + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SYMTAB: + { + const struct symtab_command* symtab = (struct symtab_command*)cmd; + stringPool = (const char*)&fileToPrebind[symtab->stroff]; + symbolTable = (struct macho_nlist*)(&fileToPrebind[symtab->symoff]); + } + break; + case LC_DYSYMTAB: + dysymtab = (struct dysymtab_command*)cmd; + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + + // walk all imports and re-resolve their n_value (needed incase prebinding is invalid) + struct macho_nlist* lastImport = &symbolTable[dysymtab->iundefsym+dysymtab->nundefsym]; + for (struct macho_nlist* entry = &symbolTable[dysymtab->iundefsym]; entry < lastImport; ++entry) { + ImageLoader* dummy; + entry->n_value = this->resolveUndefined(context, entry, this->usesTwoLevelNameSpace(), &dummy); + } + + // walk all exports and slide their n_value + struct macho_nlist* lastExport = &symbolTable[dysymtab->iextdefsym+dysymtab->nextdefsym]; + for (struct macho_nlist* entry = &symbolTable[dysymtab->iextdefsym]; entry < lastExport; ++entry) { + entry->n_value += fSlide; + } + + // walk all local symbols and slide their n_value + struct macho_nlist* lastLocal = &symbolTable[dysymtab->ilocalsym+dysymtab->nlocalsym]; + for (struct macho_nlist* entry = &symbolTable[dysymtab->ilocalsym]; entry < lastLocal; ++entry) { + if ( (entry->n_type & N_TYPE) == N_SECT ) + entry->n_value += fSlide; + } + + // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value + relocation_info* const relocsStart = (struct relocation_info*)(&fileToPrebind[dysymtab->locreloff]); + relocation_info* const relocsEnd = &relocsStart[dysymtab->nlocrel]; + for (relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + if ( (reloc->r_address & R_SCATTERED) != 0 ) { + struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; + if (sreloc->r_length == RELOC_SIZE) { + switch(sreloc->r_type) { + #if __ppc__ || __ppc64__ + case PPC_RELOC_PB_LA_PTR: + #elif __i386__ + case GENERIC_RELOC_PB_LA_PTR: + #else + #error unknown architecture + #endif + sreloc->r_value += fSlide; + break; + } + } + } + } + +} + + +SegmentMachO::SegmentMachO(const struct macho_segment_command* cmd, ImageLoaderMachO* image, const uint8_t* fileData) + : fImage(image), fSize(cmd->vmsize), fFileSize(cmd->filesize), fFileOffset(cmd->fileoff), fPreferredLoadAddress(cmd->vmaddr), + fVMProtection(cmd->initprot), fHasFixUps(false), fUnMapOnDestruction(false) +{ + strncpy(fName, cmd->segname, 16); + fName[16] = '\0'; + // scan sections for fix-up bit + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)cmd + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[cmd->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( (sect->flags & (S_ATTR_EXT_RELOC | S_ATTR_LOC_RELOC)) != 0 ) + fHasFixUps = true; + } +} + +SegmentMachO::~SegmentMachO() +{ + if ( fUnMapOnDestruction ) { + //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress()); + munmap((void*)(this->getActualLoadAddress()), this->getSize()); + } +} + +const ImageLoader* SegmentMachO::getImage() +{ + return fImage; +} + +const char* SegmentMachO::getName() +{ + return fName; +} + +uintptr_t SegmentMachO::getSize() +{ + return fSize; +} + +uintptr_t SegmentMachO::getFileSize() +{ + return fFileSize; +} + +uintptr_t SegmentMachO::getFileOffset() +{ + return fFileOffset; +} + +bool SegmentMachO::readable() +{ + return ( (fVMProtection & VM_PROT_READ) != 0); +} + +bool SegmentMachO::writeable() +{ + return ((fVMProtection & VM_PROT_WRITE) != 0); +} + +bool SegmentMachO::executable() +{ + return ((fVMProtection & VM_PROT_EXECUTE) != 0); +} + +bool SegmentMachO::unaccessible() +{ + return (fVMProtection == 0); +} + +bool SegmentMachO::hasFixUps() +{ + return fHasFixUps; +} + +uintptr_t SegmentMachO::getActualLoadAddress() +{ + return fPreferredLoadAddress + fImage->fSlide; +} + +uintptr_t SegmentMachO::getPreferredLoadAddress() +{ + return fPreferredLoadAddress; +} + +bool SegmentMachO::hasPreferredLoadAddress() +{ + return (fPreferredLoadAddress != 0); +} + +void SegmentMachO::setUnMapWhenDestructed(bool unmap) +{ + fUnMapOnDestruction = unmap; +} + +static uint32_t *buildCRCTable(void) +{ + uint32_t *table = new uint32_t[256]; + uint32_t p = 0xedb88320UL; // standard CRC-32 polynomial + + for (unsigned int i = 0; i < 256; i++) { + uint32_t c = i; + for (unsigned int j = 0; j < 8; j++) { + if ( c & 1 ) c = p ^ (c >> 1); + else c = c >> 1; + } + table[i] = c; + } + + return table; +} + +uint32_t SegmentMachO::crc32() +{ + if ( !readable() ) return 0; + + static uint32_t *crcTable = NULL; + if ( !crcTable ) crcTable = buildCRCTable(); + + uint32_t crc = ~(uint32_t)0; + uint8_t *p = (uint8_t *)getActualLoadAddress(); + uint8_t *end = p + getSize(); + while ( p < end ) { + crc = crcTable[(crc & 0xff) ^ (*p++)] ^ (crc >> 8); + } + return crc ^ ~(uint32_t)0; +} + + + + + diff --git a/src/ImageLoaderMachO.h b/src/ImageLoaderMachO.h new file mode 100644 index 0000000..acafd58 --- /dev/null +++ b/src/ImageLoaderMachO.h @@ -0,0 +1,209 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef __IMAGELOADERMACHO__ +#define __IMAGELOADERMACHO__ + +#include + +#include "ImageLoader.h" + +struct sf_mapping; +struct _shared_region_mapping_np; + +// +// ImageLoaderMachO is the concrete subclass of ImageLoader which loads mach-o format files. +// The class is written to be 64-bit clean and support both 32-bit and 64-bit executables in +// mach-o. +// +// +class ImageLoaderMachO : public ImageLoader { +public: + ImageLoaderMachO(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offset, uint64_t len, const struct stat& info, const LinkContext& context); + ImageLoaderMachO(const char* moduleName, const struct mach_header* mh, uint64_t len, const LinkContext& context); + virtual ~ImageLoaderMachO() {} + + const char* getInstallPath() const; + virtual void* getMain() const; + virtual const struct mach_header* machHeader() const; + virtual uintptr_t getSlide() const; + virtual const void* getBaseAddress() const; + virtual bool hasCoalescedExports() const; + virtual const Symbol* findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const; + virtual uintptr_t getExportedSymbolAddress(const Symbol* sym) const; + virtual DefinitionFlags getExportedSymbolInfo(const Symbol* sym) const; + virtual const char* getExportedSymbolName(const Symbol* sym) const; + virtual uint32_t getExportedSymbolCount() const; + virtual const Symbol* getIndexedExportedSymbol(uint32_t index) const; + virtual uint32_t getImportedSymbolCount() const; + virtual const Symbol* getIndexedImportedSymbol(uint32_t index) const; + virtual ReferenceFlags geImportedSymbolInfo(const Symbol* sym) const; + virtual const char* getImportedSymbolName(const Symbol* sym) const; + virtual bool isBundle() const; + virtual bool isDylib() const; + virtual bool forceFlat() const; + virtual uintptr_t doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context); + virtual void doTermination(const LinkContext& context); + virtual void doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]); + virtual bool needsInitialization(); + virtual bool hasImageNotification(); + virtual bool getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length); + virtual bool findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset); + virtual bool usablePrebinding(const LinkContext& context) const; + + + static void printStatistics(unsigned int imageCount); + +protected: + ImageLoaderMachO(const ImageLoaderMachO&); + void operator=(const ImageLoaderMachO&); + + virtual uint32_t doGetDependentLibraryCount(); + virtual void doGetDependentLibraries(DependentLibrary libs[]); + virtual LibraryInfo doGetLibraryInfo(); + virtual void doRebase(const LinkContext& context); + virtual void doBind(const LinkContext& context, BindingLaziness bindness); + virtual void doInitialization(const LinkContext& context); + virtual void doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind); + virtual bool needsTermination(); + virtual void instantiateSegments(const uint8_t* fileData); + virtual bool segmentsMustSlideTogether() const; + virtual bool segmentsCanSlide() const; + virtual void setSlide(intptr_t slide); + virtual bool usesTwoLevelNameSpace() const; + virtual bool isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const; + virtual bool hasSubLibrary(const LinkContext& context, const ImageLoader* child) const; + virtual bool isPrebindable() const; + +#if !__LP64__ // split segs not supported for 64-bits + virtual void mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); +#endif + +private: + friend class SegmentMachO; + + void init(); + void parseLoadCmds(); + void doBindIndirectSymbolPointers(const LinkContext& context, BindingLaziness bindness, bool onlyCoalescedSymbols); + void doBindExternalRelocations(const LinkContext& context, bool onlyCoalescedSymbols); + uintptr_t resolveUndefined(const LinkContext& context, const struct macho_nlist* symbol, bool twoLevel, ImageLoader **foundIn); + uintptr_t getRelocBase(); + void doImageInit(const LinkContext& context); + void doModInitFunctions(const LinkContext& context); + void setupLazyPointerHandler(); + void applyPrebindingToDATA(uint8_t* fileToPrebind); + void applyPrebindingToLoadCommands(const LinkContext& context, uint8_t* fileToPrebind, time_t timestamp); + void applyPrebindingToLinkEdit(const LinkContext& context, uint8_t* fileToPrebind); +#if !__LP64__ // split segs not supported for 64-bits + unsigned int getExtraZeroFillEntriesCount(); + int sharedRegionLoadFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); + int sharedRegionMapFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); + int sharedRegionMakePrivate(const LinkContext& context); + int sharedRegionMapFilePrivate(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); + int sharedRegionMapFilePrivateOutside(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context); + void initMappingTable(uint64_t offsetInFat, sf_mapping *mappingTable, uintptr_t baseAddress); + void initMappingTable(uint64_t offsetInFat, _shared_region_mapping_np *mappingTable); +#endif + bool needsCoalescing() const; + + static bool symbolRequiresCoalescing(const struct macho_nlist* symbol); + static uintptr_t bindLazySymbol(const mach_header*, uintptr_t* lazyPointer); + static const struct macho_nlist* binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount); + static const struct macho_nlist* binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], + const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex); + + const uint8_t* fMachOData; + const uint8_t* fLinkEditBase; // add any internal "offset" to this to get actual address + const struct macho_nlist* fSymbolTable; + const char* fStrings; + const struct dysymtab_command* fDynamicInfo; + uintptr_t fSlide; + bool fIsSplitSeg; + bool fHasSubLibraries; + bool fHasSubUmbrella; + bool fTextSegmentHasFixups; + const struct macho_routines_command* fDashInit; + const struct macho_section* fModInitSection; + const struct macho_section* fModTermSection; + const struct macho_section* fDATAdyld; + const struct macho_section* fImageNotifySection; + const struct twolevel_hints_command* fTwoLevelHints; + const struct dylib_command* fDylibID; + const char* fReExportThruFramework; + SegmentMachO* fTextSegmentWithFixups; // NULL unless __TEXT segment has fixups + + static uint32_t fgHintedBinaryTreeSearchs; + static uint32_t fgUnhintedBinaryTreeSearchs; +}; + + +class SegmentMachO : public Segment +{ +public: + SegmentMachO(const struct macho_segment_command* cmd, ImageLoaderMachO*, const uint8_t* fileData); + virtual ~SegmentMachO(); + + virtual const ImageLoader* getImage(); + virtual const char* getName(); + virtual uintptr_t getSize(); + virtual uintptr_t getFileSize(); + virtual uintptr_t getFileOffset(); + virtual bool readable(); + virtual bool writeable(); + virtual bool executable(); + virtual bool unaccessible(); + virtual bool hasFixUps(); + virtual uintptr_t getActualLoadAddress(); + virtual uintptr_t getPreferredLoadAddress(); + virtual void setUnMapWhenDestructed(bool unmap); + virtual uint32_t crc32(); + +protected: + virtual bool hasPreferredLoadAddress(); + +private: + SegmentMachO(const SegmentMachO&); + void operator=(const SegmentMachO&); + + friend class ImageLoaderMachO; + + + ImageLoaderMachO* const fImage; + char fName[18]; + const uintptr_t fSize; + const uintptr_t fFileSize; + const uintptr_t fFileOffset; + const uintptr_t fPreferredLoadAddress; + const uint16_t fVMProtection; + bool fHasFixUps; + bool fUnMapOnDestruction; +}; + + +#endif // __IMAGELOADERMACHO__ + + + + diff --git a/src/dyld.cpp b/src/dyld.cpp new file mode 100644 index 0000000..1be0973 --- /dev/null +++ b/src/dyld.cpp @@ -0,0 +1,1965 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include // mach_absolute_time() +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mach-o/dyld_gdb.h" + +#include "dyld.h" +#include "ImageLoader.h" +#include "ImageLoaderMachO.h" +#include "dyldLibSystemThreadHelpers.h" + + +#define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */ + + +/* implemented in dyld_gdb.cpp */ +void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]); +void removeImageFromAllImages(const mach_header* mh); +#if OLD_GDB_DYLD_INTERFACE +void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath); +void removeImageForgdb(const struct mach_header* mh); +#endif + +// magic so CrashReporter logs message +extern "C" { + char error_string[1024]; +} + + +// +// The file contains the core of dyld used to get a process to main(). +// The API's that dyld supports are implemented in dyldAPIs.cpp. +// +// +// +// +// + + +namespace dyld { + + +// +// state of all environment variables dyld uses +// +struct EnvironmentVariables { + const char* const * DYLD_FRAMEWORK_PATH; + const char* const * DYLD_FALLBACK_FRAMEWORK_PATH; + const char* const * DYLD_LIBRARY_PATH; + const char* const * DYLD_FALLBACK_LIBRARY_PATH; + const char* const * DYLD_ROOT_PATH; + const char* const * DYLD_INSERT_LIBRARIES; + const char* const * LD_LIBRARY_PATH; // for unix conformance + bool DYLD_PRINT_LIBRARIES; + bool DYLD_PRINT_LIBRARIES_POST_LAUNCH; + bool DYLD_BIND_AT_LAUNCH; + bool DYLD_PRINT_STATISTICS; + bool DYLD_PRINT_OPTS; + bool DYLD_PRINT_ENV; + // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix + // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts + // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv + // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat + // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit + // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping + // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind + // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase + // DYLD_PRINT_APIS ==> gLogAPIs + // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage + // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding + // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode + // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode + // DYLD_SLIDE_AND_PACK_DYLIBS ==> gLinkContext.slideAndPackDylibs + // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings +}; + +// all global state +static const char* sExecPath = NULL; +static const struct mach_header* sMainExecutableMachHeader = NULL; +static cpu_type_t sHostCPU; +static cpu_subtype_t sHostCPUsubtype; +static ImageLoader* sMainExecutable = NULL; +static std::vector sAllImages; +static std::vector sImageRoots; +static std::vector sImageFilesNeedingTermination; +static std::vector sImagesToNotifyAboutOtherImages; +static std::vector sAddImageCallbacks; +static std::vector sRemoveImageCallbacks; +static ImageLoader* sLastImageByAddressCache; +static EnvironmentVariables sEnv; +static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL }; +static const char* sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL }; +static BundleNotificationCallBack sBundleNotifier = NULL; +static BundleLocatorCallBack sBundleLocation = NULL; +static UndefinedHandler sUndefinedHandler = NULL; +ImageLoader::LinkContext gLinkContext; +bool gLogAPIs = false; +const struct ThreadingHelpers* gThreadHelpers = NULL; + + + +// utility class to assure files are closed when an exception is thrown +class FileOpener { +public: + FileOpener(const char* path); + ~FileOpener(); + int getFileDescriptor() { return fd; } +private: + int fd; +}; + +FileOpener::FileOpener(const char* path) +{ + fd = open(path, O_RDONLY, 0); +} + +FileOpener::~FileOpener() +{ + close(fd); +} + + + +// Objective-C installs an addImage hook to dyld to get notified about new images +// The callback needs to be run after the image is rebased and bound, but before its initializers are called +static uint32_t imageNotification(ImageLoader* image, uint32_t startIndex) +{ + // tell all register add image handlers about this + const uint32_t callbackCount = sAddImageCallbacks.size(); + for (uint32_t i=startIndex; i < callbackCount; ++i) { + ImageCallback cb = sAddImageCallbacks[i]; + //fprintf(stderr, "dyld: calling add-image-callback[%d]=%p for %s\n", i, cb, image->getPath()); + (cb)(image->machHeader(), image->getSlide()); + } + return callbackCount; +} + + + +// notify gdb et al about these new images +static void notifyAdding(std::vector& images) +{ + // build array + unsigned int len = images.size(); + if ( len != 0 ) { + dyld_image_info infos[len]; + for (unsigned int i=0; i < len; ++i) { + dyld_image_info* p = &infos[i]; + ImageLoader* image = images[i]; + p->imageLoadAddress = image->machHeader(); + p->imageFilePath = image->getPath(); + p->imageFileModDate = image->lastModified(); + //fprintf(stderr, "notifying objc about %s\n", image->getPath()); + } + + // tell gdb + addImagesToAllImages(len, infos); + + // tell all interested images (after gdb, so you can debug anything the notification does) + for (std::vector::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) { + (*it)->doNotification(dyld_image_adding, len, infos); + } + } +} + + + +// In order for register_func_for_add_image() callbacks to to be called bottom up, +// we need to maintain a list of root images. The main executable is usally the +// first root. Any images dynamically added are also roots (unless already loaded). +// If DYLD_INSERT_LIBRARIES is used, those libraries are first. +static void addRootImage(ImageLoader* image) +{ + //fprintf(stderr, "addRootImage(%p, %s)\n", image, image->getPath()); + // add to list of roots + sImageRoots.push_back(image); +} + +// Objective-C will contain a __DATA/__image_notify section which contains pointers to a function to call +// whenever any new image is loaded. +static void addImageNeedingNotification(ImageLoader* image) +{ + sImagesToNotifyAboutOtherImages.push_back(image); +} + +static void addImage(ImageLoader* image) +{ + // add to master list + sAllImages.push_back(image); + + if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) { + uint64_t offset = image->getOffsetInFatFile(); + if ( offset == 0 ) + fprintf(stderr, "dyld: loaded: %s\n", image->getPath()); + else + fprintf(stderr, "dyld: loaded: %s, cpu-sub-type: %d\n", image->getPath(), image->machHeader()->cpusubtype); + } + +#if OLD_GDB_DYLD_INTERFACE + // let gdb find out about this + addImageForgdb(image->machHeader(), image->getSlide(), image->getPath(), image->getLogicalPath()); +#endif +} + +void removeImage(ImageLoader* image) +{ + // flush find-by-address cache + if ( sLastImageByAddressCache == image ) + sLastImageByAddressCache = NULL; + + // if in termination list, pull it out and run terminator + for (std::vector::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) { + if ( *it == image ) { + sImageFilesNeedingTermination.erase(it); + image->doTermination(gLinkContext); + break; + } + } + + // tell all register add image handlers about this + // do this before removing image from internal data structures so that the callback can querey dyld about the image + for (std::vector::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) { + (*it)(image->machHeader(), image->getSlide()); + } + + // remove from master list + for (std::vector::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) { + if ( *it == image ) { + sAllImages.erase(it); + break; + } + } + + // if in announcement list, pull it out + for (std::vector::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) { + if ( *it == image ) { + sImagesToNotifyAboutOtherImages.erase(it); + break; + } + } + + // if in root list, pull it out + for (std::vector::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) { + if ( *it == image ) { + sImageRoots.erase(it); + break; + } + } + + // tell gdb, new way + removeImageFromAllImages(image->machHeader()); + +#if OLD_GDB_DYLD_INTERFACE + // tell gdb, old way + removeImageForgdb(image->machHeader()); + gdb_dyld_state_changed(); +#endif +} + + +static void terminationRecorder(ImageLoader* image) +{ + sImageFilesNeedingTermination.push_back(image); +} + +const char* getExecutablePath() +{ + return sExecPath; +} + + +void initializeMainExecutable() +{ + const int rootCount = sImageRoots.size(); + for(int i=0; i < rootCount; ++i) { + ImageLoader* image = sImageRoots[i]; + //fprintf(stderr, "initializeMainExecutable: image = %p\n", image); + image->runInitializers(gLinkContext); + } +/* + // this does not work??? + for (std::vector::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) { + ImageLoader* image = *it; + fprintf(stderr, "initializeMainExecutable: image = %p\n", image); + // don't know why vector sometimes starts with NULL element??? + if ( image != NULL ) + image->runInitializers(gLinkContext); + } +*/ + if ( sEnv.DYLD_PRINT_STATISTICS ) + ImageLoaderMachO::printStatistics(sAllImages.size()); +} + +bool mainExecutablePrebound() +{ + return sMainExecutable->usablePrebinding(gLinkContext); +} + +ImageLoader* mainExecutable() +{ + return sMainExecutable; +} + + +void runTerminators() +{ + const unsigned int imageCount = sImageFilesNeedingTermination.size(); + for(unsigned int i=imageCount; i > 0; --i){ + ImageLoader* image = sImageFilesNeedingTermination[i-1]; + image->doTermination(gLinkContext); + } + sImageFilesNeedingTermination.clear(); +} + + +// +// Turns a colon separated list of strings +// into a NULL terminated array of string +// pointers. +// +static const char** parseColonList(const char* list) +{ + if ( list[0] == '\0' ) + return NULL; + + int colonCount = 0; + for(const char* s=list; *s != '\0'; ++s) { + if (*s == ':') + ++colonCount; + } + + int index = 0; + const char* start = list; + char** result = new char*[colonCount+2]; + for(const char* s=list; *s != '\0'; ++s) { + if (*s == ':') { + int len = s-start; + char* str = new char[len+1]; + strncpy(str, start, len); + str[len] = '\0'; + start = &s[1]; + result[index++] = str; + } + } + int len = strlen(start); + char* str = new char[len+1]; + strcpy(str, start); + result[index++] = str; + result[index] = NULL; + + return (const char**)result; +} + +/* + * Library path searching is not done for setuid programs + * which are not run by the real user. Futher the + * evironment varaible for the library path is cleared so + * that if this program executes a non-set uid program this + * part of the evironment will not be passed along so that + * that program also will not have it's libraries searched + * for. + */ + static bool riskyUser() + { + static bool checked = false; + static bool risky = false; + if ( !checked ) { + risky = ( getuid() != 0 && (getuid() != geteuid() || getgid() != getegid()) ); + checked = true; + } + return risky; + } + + +static bool disableIfBadUser(char* rhs) +{ + bool didDisable = false; + if ( riskyUser() ) { + *rhs ='\0'; + didDisable = true; + } + return didDisable; +} + +static void paths_expand_roots(const char **paths, const char *key, const char *val) +{ +// assert(val != NULL); +// assert(paths != NULL); + if(NULL != key) { + size_t keyLen = strlen(key); + for(int i=0; paths[i] != NULL; ++i) { + if ( strncmp(paths[i], key, keyLen) == 0 ) { + char* newPath = new char[strlen(val) + (strlen(paths[i]) - keyLen) + 1]; + strcpy(newPath, val); + strcat(newPath, &paths[i][keyLen]); + paths[i] = newPath; + } + } + } + return; +} + +static void removePathWithPrefix(const char* paths[], const char* prefix) +{ + size_t prefixLen = strlen(prefix); + for(int s=0,d=0; (paths[d] != NULL) && (paths[s] != NULL); ++s, ++d) { + if ( strncmp(paths[s], prefix, prefixLen) == 0 ) + ++s; + paths[d] = paths[s]; + } +} + +#if 0 +static void paths_dump(const char **paths) +{ +// assert(paths != NULL); + const char **strs = paths; + while(*strs != NULL) + { + fprintf(stderr, "\"%s\"\n", *strs); + strs++; + } + return; +} +#endif + +static void printOptions(const char* argv[]) +{ + uint32_t i = 0; + while ( NULL != argv[i] ) { + fprintf(stderr, "opt[%i] = \"%s\"\n", i, argv[i]); + i++; + } +} + +static void printEnvironmentVariables(const char* envp[]) +{ + while ( NULL != *envp ) { + fprintf(stderr, "%s\n", *envp); + envp++; + } +} + + + +void processDyldEnvironmentVarible(const char* key, const char* value) +{ + if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + sEnv.DYLD_FRAMEWORK_PATH = parseColonList(value); + } + else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = parseColonList(value); + } + else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + sEnv.DYLD_LIBRARY_PATH = parseColonList(value); + } + else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + sEnv.DYLD_FALLBACK_LIBRARY_PATH = parseColonList(value); + } + else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) { + if ( !disableIfBadUser((char*)value) ) { + if ( strcmp(value, "/") != 0 ) { + sEnv.DYLD_ROOT_PATH = parseColonList(value); + for (int i=0; sEnv.DYLD_ROOT_PATH[i] != NULL; ++i) { + if ( sEnv.DYLD_ROOT_PATH[i][0] != '/' ) { + fprintf(stderr, "dyld: warning DYLD_ROOT_PATH not used because it contains a non-absolute path"); + sEnv.DYLD_ROOT_PATH = NULL; + } + } + } + } + } + else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + gLinkContext.imageSuffix = value; + } + else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) { + if ( !disableIfBadUser((char*)value) ) + sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value); + } + else if ( strcmp(key, "DYLD_DEBUG_TRACE") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_DEBUG_TRACE not supported\n"); + } + else if ( strcmp(key, "DYLD_ERROR_PRINT") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_ERROR_PRINT not supported\n"); + } + else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) { + sEnv.DYLD_PRINT_OPTS = true; + } + else if ( strcmp(key, "DYLD_PRINT_ENV") == 0 ) { + sEnv.DYLD_PRINT_ENV = true; + } + else if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) { + sEnv.DYLD_PRINT_LIBRARIES = true; + } + else if ( strcmp(key, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) { + sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH = true; + } + else if ( strcmp(key, "DYLD_TRACE") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_TRACE not supported\n"); + } + else if ( strcmp(key, "DYLD_EBADEXEC_ONLY") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_EBADEXEC_ONLY not supported\n"); + } + else if ( strcmp(key, "DYLD_BIND_AT_LAUNCH") == 0 ) { + sEnv.DYLD_BIND_AT_LAUNCH = true; + } + else if ( strcmp(key, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) { + gLinkContext.bindFlat = true; + } + else if ( strcmp(key, "DYLD_DEAD_LOCK_HANG") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_DEAD_LOCK_HANG not supported\n"); + } + else if ( strcmp(key, "DYLD_ABORT_MULTIPLE_INITS") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_ABORT_MULTIPLE_INITS not supported\n"); + } + else if ( strcmp(key, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) { + gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion; + } + else if ( strcmp(key, "DYLD_SLIDE_AND_PACK_DYLIBS") == 0 ) { + gLinkContext.slideAndPackDylibs = true; + } + else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) { + // since the new dyld never runs fix_prebinding, no need to warn if someone does not want it run + //fprintf(stderr, "dyld: warning DYLD_NO_FIX_PREBINDING not supported\n"); + } + else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) { + gLinkContext.verbosePrebinding = true; + } + else if ( strcmp(key, "DYLD_HINTS_DEBUG") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_HINTS_DEBUG not supported\n"); + } + else if ( strcmp(key, "DYLD_SAMPLE_DEBUG") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_SAMPLE_DEBUG not supported\n"); + } + else if ( strcmp(key, "DYLD_EXECUTABLE_PATH_DEBUG") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_EXECUTABLE_PATH_DEBUG not supported\n"); + } + else if ( strcmp(key, "DYLD_TWO_LEVEL_DEBUG") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_TWO_LEVEL_DEBUG not supported\n"); + } + else if ( strcmp(key, "DYLD_LAZY_INITIALIZERS") == 0 ) { + fprintf(stderr, "dyld: warning DYLD_LAZY_INITIALIZERS not supported\n"); + } + else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) { + gLinkContext.verboseInit = true; + } + else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) { + sEnv.DYLD_PRINT_STATISTICS = true; + } + else if ( strcmp(key, "DYLD_PRINT_SEGMENTS") == 0 ) { + gLinkContext.verboseMapping = true; + } + else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) { + gLinkContext.verboseBind = true; + } + else if ( strcmp(key, "DYLD_PRINT_REBASINGS") == 0 ) { + gLinkContext.verboseRebase = true; + } + else if ( strcmp(key, "DYLD_PRINT_APIS") == 0 ) { + gLogAPIs = true; + } + else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) { + gLinkContext.verboseWarnings = true; + } + else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) { + if ( strcmp(value, "private") == 0 ) { + gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion; + } + else if ( strcmp(value, "avoid") == 0 ) { + gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion; + } + else if ( strcmp(value, "use") == 0 ) { + gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion; + } + else if ( value[0] == '\0' ) { + gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion; + } + else { + fprintf(stderr, "dyld: warning unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n"); + } + } + else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) { + if ( strcmp(value, "all") == 0 ) { + gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding; + } + else if ( strcmp(value, "app") == 0 ) { + gLinkContext.prebindUsage = ImageLoader::kUseAllButAppPredbinding; + } + else if ( strcmp(value, "nonsplit") == 0 ) { + gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding; + } + else if ( value[0] == '\0' ) { + gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding; + } + else { + fprintf(stderr, "dyld: warning unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n"); + } + } + else { + fprintf(stderr, "dyld: warning, unknown environment variable: %s\n", key); + } +} + +static void checkEnvironmentVariables(const char* envp[]) +{ + const char* home = NULL; + const char** p; + for(p = envp; *p != NULL; p++) { + const char* keyEqualsValue = *p; + if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) { + const char* equals = strchr(keyEqualsValue, '='); + if ( equals != NULL ) { + const char* value = &equals[1]; + const int keyLen = equals-keyEqualsValue; + char key[keyLen]; + strncpy(key, keyEqualsValue, keyLen); + key[keyLen] = '\0'; + processDyldEnvironmentVarible(key, value); + } + } + else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) { + home = &keyEqualsValue[5]; + } + else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) { + const char* path = &keyEqualsValue[16]; + if ( !disableIfBadUser((char*)path) ) + sEnv.LD_LIBRARY_PATH = parseColonList(path); + } + } + + // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment + if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) { + const char** paths = sFrameworkFallbackPaths; + if ( home != NULL ) { + if ( riskyUser() ) + removePathWithPrefix(paths, "$HOME"); + else + paths_expand_roots(paths, "$HOME", home); + } + sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths; + } + + // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment + if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) { + const char** paths = sLibraryFallbackPaths; + if ( home != NULL ) { + if ( riskyUser() ) + removePathWithPrefix(paths, "$HOME"); + else + paths_expand_roots(paths, "$HOME", home); + } + sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths; + } +} + + +static void getHostInfo() +{ +#if 0 + struct host_basic_info info; + mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; + mach_port_t hostPort = mach_host_self(); + kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count); + mach_port_deallocate(mach_task_self(), hostPort); + if ( result != KERN_SUCCESS ) + throw "host_info() failed"; + + sHostCPU = info.cpu_type; + sHostCPUsubtype = info.cpu_subtype; +#endif + + size_t valSize = sizeof(sHostCPU); + if (sysctlbyname ("hw.cputype", &sHostCPU, &valSize, NULL, 0) != 0) + throw "sysctlbyname(hw.cputype) failed"; + valSize = sizeof(sHostCPUsubtype); + if (sysctlbyname ("hw.cpusubtype", &sHostCPUsubtype, &valSize, NULL, 0) != 0) + throw "sysctlbyname(hw.cpusubtype) failed"; +} + +bool validImage(ImageLoader* possibleImage) +{ + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i) { + if ( possibleImage == sAllImages[i] ) { + return true; + } + } + return false; +} + +uint32_t getImageCount() +{ + return sAllImages.size(); +} + +ImageLoader* getIndexedImage(unsigned int index) +{ + if ( index < sAllImages.size() ) + return sAllImages[index]; + else + return NULL; +} + +ImageLoader* findImageByMachHeader(const struct mach_header* target) +{ + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i) { + ImageLoader* anImage = sAllImages[i]; + if ( anImage->machHeader() == target ) + return anImage; + } + return NULL; +} + + +ImageLoader* findImageContainingAddress(const void* addr) +{ +#if FIND_STATS + static int cacheHit = 0; + static int cacheMiss = 0; + static int cacheNotMacho = 0; + if ( ((cacheHit+cacheMiss+cacheNotMacho) % 100) == 0 ) + fprintf(stderr, "findImageContainingAddress(): cache hit = %d, miss = %d, unknown = %d\n", cacheHit, cacheMiss, cacheNotMacho); +#endif + // first look in image where last address was found rdar://problem/3685517 + if ( (sLastImageByAddressCache != NULL) && sLastImageByAddressCache->containsAddress(addr) ) { +#if FIND_STATS + ++cacheHit; +#endif + return sLastImageByAddressCache; + } + // do exhastive search + // todo: consider maintaining a list sorted by address ranges and do a binary search on that + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i) { + ImageLoader* anImage = sAllImages[i]; + if ( anImage->containsAddress(addr) ) { + sLastImageByAddressCache = anImage; +#if FIND_STATS + ++cacheMiss; +#endif + return anImage; + } + } +#if FIND_STATS + ++cacheNotMacho; +#endif + return NULL; +} + + +void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData) +{ + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i) { + ImageLoader* anImage = sAllImages[i]; + (*callback)(anImage, userData); + } +} + +ImageLoader* findLoadedImage(const struct stat& stat_buf) +{ + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i){ + ImageLoader* anImage = sAllImages[i]; + if ( anImage->statMatch(stat_buf) ) + return anImage; + } + return NULL; +} + +// based on ANSI-C strstr() +static const char* strrstr(const char* str, const char* sub) +{ + const int sublen = strlen(sub); + for(const char* p = &str[strlen(str)]; p != str; --p) { + if ( strncmp(p, sub, sublen) == 0 ) + return p; + } + return NULL; +} + + +// +// Find framework path +// +// /path/foo.framework/foo => foo.framework/foo +// /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo +// /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar +// /path/foo.framework/Libraries/bar.dylb => NULL +// /path/foo.framework/bar => NULL +// +// Returns NULL if not a framework path +// +static const char* getFrameworkPartialPath(const char* path) +{ + const char* dirDot = strrstr(path, ".framework/"); + if ( dirDot != NULL ) { + const char* dirStart = dirDot; + for ( ; dirStart >= path; --dirStart) { + if ( (*dirStart == '/') || (dirStart == path) ) { + const char* frameworkStart = &dirStart[1]; + if ( dirStart == path ) + --frameworkStart; + int len = dirDot - frameworkStart; + char framework[len+1]; + strncpy(framework, frameworkStart, len); + framework[len] = '\0'; + const char* leaf = strrchr(path, '/'); + if ( leaf != NULL ) { + if ( strcmp(framework, &leaf[1]) == 0 ) { + return frameworkStart; + } + if ( gLinkContext.imageSuffix != NULL ) { + // some debug frameworks have install names that end in _debug + if ( strncmp(framework, &leaf[1], len) == 0 ) { + if ( strcmp( gLinkContext.imageSuffix, &leaf[len+1]) == 0 ) + return frameworkStart; + } + } + } + } + } + } + return NULL; +} + + +static const char* getLibraryLeafName(const char* path) +{ + const char* start = strrchr(path, '/'); + if ( start != NULL ) + return &start[1]; + else + return path; +} + + + +const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1; + + +// +// A fat file may contain multiple sub-images for the same CPU type. +// In that case, dyld picks which sub-image to use by scanning a table +// of preferred cpu-sub-types for the running cpu. +// +// There is one row in the table for each cpu-sub-type on which dyld might run. +// The first entry in a row is that cpu-sub-type. It is followed by all +// cpu-sub-types that can run on that cpu, if preferred order. Each row ends with +// a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable), +// followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row. +// + + +// +// 32-bit PowerPC sub-type lists +// +const int kPPC_RowCount = 4; +static const cpu_subtype_t kPPC32[kPPC_RowCount][6] = { + // G5 can run any code + { 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 }, + + // G4 can run all but G5 code + { 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 }, + { 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 }, + + // G3 cannot run G4 or G5 code + { 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 } +}; + + +// +// 64-bit PowerPC sub-type lists +// +const int kPPC64_RowCount = 1; +static const cpu_subtype_t kPPC64[kPPC64_RowCount][3] = { + // G5 can run any 64-bit code + { CPU_SUBTYPE_POWERPC_970, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST }, +}; + + + +// +// 32-bit x86 sub-type lists +// +// TO-DO + + + +// scan the tables above to find the cpu-sub-type-list for this machine +static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype) +{ + switch (cpu) { + case CPU_TYPE_POWERPC: + for (int i=0; i < kPPC_RowCount ; ++i) { + if ( kPPC32[i][0] == subtype ) + return kPPC32[i]; + } + break; + case CPU_TYPE_POWERPC64: + for (int i=0; i < kPPC64_RowCount ; ++i) { + if ( kPPC64[i][0] == subtype ) + return kPPC64[i]; + } + break; + case CPU_TYPE_I386: + // To do + break; + } + return NULL; +} + + + + +// scan fat table-of-contents for best most preferred subtype +static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, uint64_t* offset, uint64_t* len) +{ + const fat_arch* const archs = (fat_arch*)(((char*)fh)+sizeof(fat_header)); + for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) { + for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) { + if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu) + && (list[subTypeIndex] == archs[fatIndex].cpusubtype) ) { + *offset = OSSwapBigToHostInt32(archs[fatIndex].offset); + *len = OSSwapBigToHostInt32(archs[fatIndex].size); + return true; + } + } + } + return false; +} + +// scan fat table-of-contents for exact match of cpu and cpu-sub-type +static bool fatFindExactMatch(cpu_type_t cpu, cpu_subtype_t subtype, const fat_header* fh, uint64_t* offset, uint64_t* len) +{ + const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header)); + for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) + && ((cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == subtype) ) { + *offset = OSSwapBigToHostInt32(archs[i].offset); + *len = OSSwapBigToHostInt32(archs[i].size); + return true; + } + } + return false; +} + +// scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types +static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t* offset, uint64_t* len) +{ + const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header)); + for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) { + switch (cpu) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: + if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_POWERPC_ALL ) { + *offset = OSSwapBigToHostInt32(archs[i].offset); + *len = OSSwapBigToHostInt32(archs[i].size); + return true; + } + break; + case CPU_TYPE_I386: + if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_I386_ALL ) { + *offset = OSSwapBigToHostInt32(archs[i].offset); + *len = OSSwapBigToHostInt32(archs[i].size); + return true; + } + break; + } + } + } + return false; +} + + +// +// A fat file may contain multiple sub-images for the same cpu-type, +// each optimized for a different cpu-sub-type (e.g G3 or G5). +// This routine picks the optimal sub-image. +// +static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len) +{ + // assume all dylibs loaded must have same cpu type as main executable + const cpu_type_t cpu = sMainExecutableMachHeader->cputype; + + // We only know the subtype to use if the main executable cpu type matches the host + if ( (cpu & CPU_TYPE_MASK) == sHostCPU ) { + // get preference ordered list of subtypes + const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(cpu, sHostCPUsubtype); + + // use ordered list to find best sub-image in fat file + if ( subTypePreferenceList != NULL ) + return fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, offset, len); + + // if running cpu is not in list, try for an exact match + if ( fatFindExactMatch(cpu, sHostCPUsubtype, fh, offset, len) ) + return true; + } + + // running on an uknown cpu, can only load generic code + return fatFindRunsOnAllCPUs(cpu, fh, offset, len); +} + + + +// +// This is used to validate if a non-fat (aka thin or raw) mach-o file can be used +// on the current processor. It is deemed compatible if any of the following are true: +// 1) mach_header subtype is in list of compatible subtypes for running processor +// 2) mach_header subtype is same as running processor subtype +// 3) mach_header subtype runs on all processor variants +// +// +bool isCompatibleMachO(const uint8_t* firstPage) +{ + const mach_header* mh = (mach_header*)firstPage; + if ( mh->magic == sMainExecutableMachHeader->magic ) { + if ( mh->cputype == sMainExecutableMachHeader->cputype ) { + if ( (mh->cputype & CPU_TYPE_MASK) == sHostCPU ) { + // get preference ordered list of subtypes that this machine can use + const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(mh->cputype, sHostCPUsubtype); + if ( subTypePreferenceList != NULL ) { + // if image's subtype is in the list, it is compatible + for (const cpu_subtype_t* p = subTypePreferenceList; *p != CPU_SUBTYPE_END_OF_LIST; ++p) { + if ( *p == mh->cpusubtype ) + return true; + } + // have list and not in list, so not compatible + throw "incompatible cpu-subtype"; + } + // unknown cpu sub-type, but if exact match for current subtype then ok to use + if ( mh->cpusubtype == sHostCPUsubtype ) + return true; + } + + // cpu unknown, so don't know if subtype is compatible + // only load _ALL variant + switch (mh->cputype) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: + if ( mh->cpusubtype == CPU_SUBTYPE_POWERPC_ALL ) + return true; + break; + case CPU_TYPE_I386: + if ( mh->cpusubtype == CPU_SUBTYPE_I386_ALL ) + return true; + break; + } + } + } + return false; +} + + +// The kernel maps in main executable before dyld gets control. We need to +// make an ImageLoader* for the already mapped in main executable. +static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, const char* path) +{ + // try mach-o loader + if ( isCompatibleMachO((const uint8_t*)mh) ) { + ImageLoader* image = new ImageLoaderMachO(path, mh, 0, gLinkContext); + addImage(image); + return image; + } + + return NULL; +} + + + + +// map in file and instantiate an ImageLoader +static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path, const LoadContext& context) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + uint64_t fileOffset = 0; + uint64_t fileLength = stat_buf.st_size; +#if __ppc64__ + if ( *((uint32_t*)((char*)(&stat_buf)+0x60)) == 0xFEFEFEFE ) + fileLength = *((uint64_t*)((char*)(&stat_buf)+0x30)); // HACK work around for kernel stat bug rdar://problem/3845883 +#endif + + // validate it is a file (not directory) + if ( (stat_buf.st_mode & S_IFMT) != S_IFREG ) + throw "not a file"; + + // min file is 4K + if ( fileLength < 4096 ) { + throw "file to short"; + } + + uint8_t firstPage[4096]; + pread(fd, firstPage, 4096,0); + + // if fat wrapper, find usable sub-file + const fat_header* fileStartAsFat = (fat_header*)firstPage; + if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { + if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) { + pread(fd, firstPage, 4096, fileOffset); + } + else { + throw "no matching architecture in fat wrapper"; + } + } + + // try mach-o loader + if ( isCompatibleMachO(firstPage) ) { + char realFilePath[PATH_MAX]; + if ( gLinkContext.slideAndPackDylibs ) { + // when prebinding, we always want to track the real path of images + if ( realpath(path, realFilePath) != NULL ) + path = realFilePath; + } + + // instantiate an image + ImageLoader* image = new ImageLoaderMachO(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext); + + // now sanity check that this loaded image does not have the same install path as any existing image + const char* loadedImageInstallPath = image->getInstallPath(); + if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) { + for (std::vector::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) { + ImageLoader* anImage = *it; + const char* installPath = anImage->getInstallPath(); + if ( installPath != NULL) { + if ( strcmp(loadedImageInstallPath, installPath) == 0 ) { + //fprintf(stderr, "duplicate(%s) => %p\n", installPath, anImage); + delete image; + return anImage; + } + } + } + } + + // some API's restrict what they can load + if ( context.mustBeBundle && !image->isBundle() ) + throw "not a bundle"; + if ( context.mustBeDylib && !image->isDylib() ) + throw "not a dylib"; + + // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list + if ( ! image->isBundle() ) + addImage(image); + + return image; + } + + // try other file formats... + + throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", + firstPage[0], firstPage[1], firstPage[2], firstPage[3], firstPage[4], firstPage[5], firstPage[6],firstPage[7]); +} + + +// try to open file +static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stdout, "%s(%s)\n", __func__, path); + ImageLoader* image = NULL; + + // open file (automagically closed when this function exits) + FileOpener file(path); + + //fprintf(stderr, "open(%s) => %d\n", path, file.getFileDescriptor() ); + + if ( file.getFileDescriptor() == -1 ) + return NULL; + + struct stat stat_buf; +#if __ppc64__ + memset(&stat_buf, 254, sizeof(struct stat)); // hack until rdar://problem/3845883 is fixed +#endif + if ( fstat(file.getFileDescriptor(), &stat_buf) == -1) + throw "stat error"; + + // in case image was renamed or found via symlinks, check for inode match + image = findLoadedImage(stat_buf); + if ( image != NULL ) + return image; + + // needed to implement NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + if ( context.dontLoad ) + return NULL; + + try { + return loadPhase6(file.getFileDescriptor(), stat_buf, path, context); + } + catch (const char* msg) { + char* newMsg = new char[strlen(msg) + strlen(path) + 8]; + sprintf(newMsg, "%s: %s", path, msg); + exceptions->push_back(newMsg); + return NULL; + } +} + +// look for path match with existing loaded images +static ImageLoader* loadPhase5check(const char* path, const LoadContext& context) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + // search path against load-path and install-path of all already loaded images + uint32_t hash = ImageLoader::hash(path); + for (std::vector::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) { + ImageLoader* anImage = *it; + // check has first to cut down on strcmp calls + if ( anImage->getPathHash() == hash ) + if ( strcmp(path, anImage->getPath()) == 0 ) { + // if we are looking for a dylib don't return something else + if ( !context.mustBeDylib || anImage->isDylib() ) + return anImage; + } + if ( context.matchByInstallName || anImage->matchInstallPath() ) { + const char* installPath = anImage->getInstallPath(); + if ( installPath != NULL) { + if ( strcmp(path, installPath) == 0 ) { + // if we are looking for a dylib don't return something else + if ( !context.mustBeDylib || anImage->isDylib() ) + return anImage; + } + } + } + } + + //fprintf(stderr, "check(%s) => NULL\n", path); + return NULL; +} + + +// open or check existing +static ImageLoader* loadPhase5(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + if ( exceptions != NULL ) + return loadPhase5open(path, context, exceptions); + else + return loadPhase5check(path, context); +} + +// try with and without image suffix +static ImageLoader* loadPhase4(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + ImageLoader* image = NULL; + if ( gLinkContext.imageSuffix != NULL ) { + char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2]; + ImageLoader::addSuffix(path, gLinkContext.imageSuffix, pathWithSuffix); + image = loadPhase5(pathWithSuffix, context, exceptions); + } + if ( image == NULL ) + image = loadPhase5(path, context, exceptions); + return image; +} + + +// expand @ variables +static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + ImageLoader* image = NULL; + if ( strncmp(path, "@executable_path/", 17) == 0 ) { + // handle @executable_path path prefix + const char* executablePath = sExecPath; + char newPath[strlen(executablePath) + strlen(path)]; + strcpy(newPath, executablePath); + char* addPoint = strrchr(newPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &path[17]); + else + strcpy(newPath, &path[17]); + image = loadPhase4(newPath, context, exceptions); + if ( image != NULL ) + return image; + + // perhaps main executable path is a sym link, find realpath and retry + char resolvedPath[PATH_MAX]; + if ( realpath(sExecPath, resolvedPath) != NULL ) { + char newRealPath[strlen(resolvedPath) + strlen(path)]; + strcpy(newRealPath, resolvedPath); + char* addPoint = strrchr(newRealPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &path[17]); + else + strcpy(newRealPath, &path[17]); + image = loadPhase4(newRealPath, context, exceptions); + if ( image != NULL ) + return image; + } + } + else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) { + // handle @loader_path path prefix + char newPath[strlen(context.origin) + strlen(path)]; + strcpy(newPath, context.origin); + char* addPoint = strrchr(newPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &path[13]); + else + strcpy(newPath, &path[13]); + image = loadPhase4(newPath, context, exceptions); + if ( image != NULL ) + return image; + + // perhaps loader path is a sym link, find realpath and retry + char resolvedPath[PATH_MAX]; + if ( realpath(context.origin, resolvedPath) != NULL ) { + char newRealPath[strlen(resolvedPath) + strlen(path)]; + strcpy(newRealPath, resolvedPath); + char* addPoint = strrchr(newRealPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &path[13]); + else + strcpy(newRealPath, &path[13]); + image = loadPhase4(newRealPath, context, exceptions); + if ( image != NULL ) + return image; + } + } + + return loadPhase4(path, context, exceptions); +} + + +// try search paths +static ImageLoader* loadPhase2(const char* path, const LoadContext& context, + const char* const frameworkPaths[], const char* const libraryPaths[], + std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + ImageLoader* image = NULL; + const char* frameworkPartialPath = getFrameworkPartialPath(path); + if ( frameworkPaths != NULL ) { + if ( frameworkPartialPath != NULL ) { + const int frameworkPartialPathLen = strlen(frameworkPartialPath); + for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) { + char npath[strlen(*fp)+frameworkPartialPathLen+8]; + strcpy(npath, *fp); + strcat(npath, "/"); + strcat(npath, frameworkPartialPath); + //fprintf(stderr, "dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath); + image = loadPhase4(npath, context, exceptions); + if ( image != NULL ) + return image; + } + } + } + if ( libraryPaths != NULL ) { + const char* libraryLeafName = getLibraryLeafName(path); + const int libraryLeafNameLen = strlen(libraryLeafName); + for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) { + char libpath[strlen(*lp)+libraryLeafNameLen+8]; + strcpy(libpath, *lp); + strcat(libpath, "/"); + strcat(libpath, libraryLeafName); + //fprintf(stderr, "dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath); + image = loadPhase4(libpath, context, exceptions); + if ( image != NULL ) + return image; + } + } + return NULL; +} + +// try search overrides and fallbacks +static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + ImageLoader* image = NULL; + + // handle LD_LIBRARY_PATH environment variables that force searching + if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) { + image = loadPhase2(path, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions); + if ( image != NULL ) + return image; + } + + // handle DYLD_ environment variables that force searching + if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) { + image = loadPhase2(path, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, exceptions); + if ( image != NULL ) + return image; + } + + // try raw path + image = loadPhase3(path, context, exceptions); + if ( image != NULL ) + return image; + + // try fallback paths + if ( (sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_FALLBACK_LIBRARY_PATH != NULL) ) { + image = loadPhase2(path, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, sEnv.DYLD_FALLBACK_LIBRARY_PATH, exceptions); + if ( image != NULL ) + return image; + } + + return NULL; +} + +// try root substitutions +static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std::vector* exceptions) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + + // handle DYLD_ROOT_PATH which forces absolute paths to use a new root + if ( (sEnv.DYLD_ROOT_PATH != NULL) && (path[0] == '/') ) { + for(const char* const* rootPath = sEnv.DYLD_ROOT_PATH ; *rootPath != NULL; ++rootPath) { + char newPath[strlen(*rootPath) + strlen(path)+2]; + strcpy(newPath, *rootPath); + strcat(newPath, path); + ImageLoader* image = loadPhase1(newPath, context, exceptions); + if ( image != NULL ) + return image; + } + } + + // try raw path + return loadPhase1(path, context, exceptions); +} + +// +// Given all the DYLD_ environment variables, the general case for loading libraries +// is that any given path expands into a list of possible locations to load. We +// also must take care to ensure two copies of the "same" library are never loaded. +// +// The algorithm used here is that there is a separate function for each "phase" of the +// path expansion. Each phase function calls the next phase with each possible expansion +// of that phase. The result is the last phase is called with all possible paths. +// +// To catch duplicates the algorithm is run twice. The first time, the last phase checks +// the path against all loaded images. The second time, the last phase calls open() on +// the path. Either time, if an image is found, the phases all unwind without checking +// for other paths. +// +ImageLoader* load(const char* path, const LoadContext& context) +{ + //fprintf(stderr, "%s(%s)\n", __func__ , path); + char realPath[PATH_MAX]; + // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match + if ( context.useSearchPaths && ( gLinkContext.imageSuffix != NULL) ) { + if ( realpath(path, realPath) != NULL ) + path = realPath; + } + + // try all path permutations and check against existing loaded images + ImageLoader* image = loadPhase0(path, context, NULL); + if ( image != NULL ) + return image; + + // try all path permutations and try open() until first sucesss + std::vector exceptions; + image = loadPhase0(path, context, &exceptions); + if ( image != NULL ) + return image; + else if ( context.dontLoad ) + return NULL; + else if ( exceptions.size() == 0 ) + throw "image not found"; + else { + const char* msgStart = "no suitable image found. Did find:"; + const char* delim = "\n\t"; + size_t allsizes = strlen(msgStart)+8; + for (unsigned int i=0; i < exceptions.size(); ++i) + allsizes += (strlen(exceptions[i]) + strlen(delim)); + char* fullMsg = new char[allsizes]; + strcpy(fullMsg, msgStart); + for (unsigned int i=0; i < exceptions.size(); ++i) { + strcat(fullMsg, delim); + strcat(fullMsg, exceptions[i]); + } + throw (const char*)fullMsg; + } +} + + + + +// create when NSLinkModule is called for a second time on a bundle +ImageLoader* cloneImage(ImageLoader* image) +{ + const uint64_t offsetInFat = image->getOffsetInFatFile(); + + // open file (automagically closed when this function exits) + FileOpener file(image->getPath()); + + struct stat stat_buf; +#if __ppc64__ + memset(&stat_buf, 254, sizeof(struct stat)); // hack until rdar://problem/3845883 is fixed +#endif + if ( fstat(file.getFileDescriptor(), &stat_buf) == -1) + throw "stat error"; + + // read first page of file + uint8_t firstPage[4096]; + pread(file.getFileDescriptor(), firstPage, 4096, offsetInFat); + + // fat length is only used for sanity checking, since this image was already loaded once, just use upper bound + uint64_t lenInFat = stat_buf.st_size - offsetInFat; + + // try mach-o loader + if ( isCompatibleMachO(firstPage) ) { + ImageLoader* clone = new ImageLoaderMachO(image->getPath(), file.getFileDescriptor(), firstPage, offsetInFat, lenInFat, stat_buf, gLinkContext); + // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list + if ( ! image->isBundle() ) + addImage(clone); + return clone; + } + + // try other file formats... + throw "can't clone image"; +} + + +ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName) +{ + // try mach-o each loader + if ( isCompatibleMachO(mem) ) { + ImageLoader* image = new ImageLoaderMachO(moduleName, (mach_header*)mem, len, gLinkContext); + // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list + if ( ! image->isBundle() ) + addImage(image); + return image; + } + + // try other file formats... + + throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", + mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6],mem[7]); +} + + +void registerAddCallback(ImageCallback func) +{ + // now add to list to get notified when any more images are added + sAddImageCallbacks.push_back(func); + + // call callback with all existing images, starting at roots + const int rootCount = sImageRoots.size(); + for(int i=0; i < rootCount; ++i) { + ImageLoader* image = sImageRoots[i]; + image->runNotification(gLinkContext, sAddImageCallbacks.size()); + } + +// for (std::vector::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) { +// ImageLoader* image = *it; +// image->runNotification(gLinkContext, sAddImageCallbacks.size()); +// } +} + +void registerRemoveCallback(ImageCallback func) +{ + sRemoveImageCallbacks.push_back(func); +} + +void clearErrorMessage() +{ + error_string[0] = '\0'; +} + +void setErrorMessage(const char* message) +{ + // save off error message in global buffer for CrashReporter to find + strncpy(error_string, message, sizeof(error_string)-1); + error_string[sizeof(error_string)-1] = '\0'; +} + +const char* getErrorMessage() +{ + return error_string; +} + +void halt(const char* message) +{ + fprintf(stderr, "dyld: %s\n", message); + setErrorMessage(message); + strncpy(error_string, message, sizeof(error_string)-1); + error_string[sizeof(error_string)-1] = '\0'; + +#if __ppc__ || __ppc64__ + __asm__ ("trap"); +#elif __i386__ + __asm__ ("int3"); +#else + #error unknown architecture +#endif + abort(); // needed to suppress warning that noreturn function returns +} + + +uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer) +{ + uintptr_t result = 0; + // acquire read-lock on dyld's data structures +#if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved + if ( gThreadHelpers != NULL ) + (*gThreadHelpers->lockForReading)(); +#endif + // lookup and bind lazy pointer and get target address + try { + // note, target should always be mach-o, because only mach-o lazy handler wired up to this + ImageLoader* target = dyld::findImageByMachHeader(mh); + if ( target == NULL ) + throw "image not found for lazy pointer"; + result = target->doBindLazySymbol(lazyPointer, gLinkContext); + } + catch (const char* message) { + fprintf(stderr, "dyld: lazy symbol binding failed: %s\n", message); + halt(message); + } + // release read-lock on dyld's data structures +#if 0 + if ( gThreadHelpers != NULL ) + (*gThreadHelpers->unlockForReading)(); +#endif + // return target address to glue which jumps to it with real parameters restored + return result; +} + + +// SPI used by ZeroLink to lazy load bundles +void registerZeroLinkHandlers(BundleNotificationCallBack notify, BundleLocatorCallBack locate) +{ + sBundleNotifier = notify; + sBundleLocation = locate; +} + +void registerUndefinedHandler(UndefinedHandler handler) +{ + sUndefinedHandler = handler; +} + +static void undefinedHandler(const char* symboName) +{ + if ( sUndefinedHandler != NULL ) { + (*sUndefinedHandler)(symboName); + } +} + +static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, ImageLoader** image) +{ + // try ZeroLink short cut to finding bundle which exports this symbol + if ( sBundleLocation != NULL ) { + ImageLoader* zlImage = (*sBundleLocation)(name); + if ( zlImage == ((ImageLoader*)(-1)) ) { + // -1 is magic value that request symbol is in a bundle not yet linked into process + // try calling handler to link in that symbol + undefinedHandler(name); + // call locator again + zlImage = (*sBundleLocation)(name); + } + // if still not found, then ZeroLink has no idea where to find it + if ( zlImage == ((ImageLoader*)(-1)) ) + return false; + if ( zlImage != NULL ) { + // ZeroLink cache knows where the symbol is + *sym = zlImage->findExportedSymbol(name, NULL, false, image); + if ( *sym != NULL ) { + *image = zlImage; + return true; + } + } + else { + // ZeroLink says it is in some bundle already loaded, but not linked, walk them all + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i){ + ImageLoader* anImage = sAllImages[i]; + if ( anImage->isBundle() && !anImage->hasHiddenExports() ) { + //fprintf(stderr, "dyld: search for %s in %s\n", name, anImage->getPath()); + *sym = anImage->findExportedSymbol(name, NULL, false, image); + if ( *sym != NULL ) { + return true; + } + } + } + } + } + + // search all images in order + ImageLoader* firstWeakImage = NULL; + const ImageLoader::Symbol* firstWeakSym = NULL; + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i){ + ImageLoader* anImage = sAllImages[i]; + if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) { + *sym = anImage->findExportedSymbol(name, NULL, false, image); + if ( *sym != NULL ) { + // if weak definition found, record first one found + if ( ((*image)->getExportedSymbolInfo(*sym) & ImageLoader::kWeakDefinition) != 0 ) { + if ( firstWeakImage == NULL ) { + firstWeakImage = *image; + firstWeakSym = *sym; + } + } + else { + // found non-weak, so immediately return with it + return true; + } + } + } + } + if ( firstWeakSym != NULL ) { + // found a weak definition, but no non-weak, so return first weak found + *sym = firstWeakSym; + *image = firstWeakImage; + return true; + } + + return false; +} + +bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image) +{ + return findExportedSymbol(name, false, sym, image); +} + +bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image) +{ + return findExportedSymbol(name, true, sym, image); +} + + +bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, ImageLoader** image) +{ + // search all images in order + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i){ + ImageLoader* anImage = sAllImages[i]; + // only look at images whose paths contain the hint string (NULL hint string is wildcard) + if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) { + *sym = anImage->findExportedSymbol(name, NULL, false, image); + if ( *sym != NULL ) { + return true; + } + } + } + return false; +} + +static void getMappedRegions(ImageLoader::RegionsVector& regions) +{ + const unsigned int imageCount = sAllImages.size(); + for(unsigned int i=0; i < imageCount; ++i){ + ImageLoader* anImage = sAllImages[i]; + anImage->addMappedRegions(regions); + } +} + + +static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const char* rpath[]) +{ + dyld::LoadContext context; + context.useSearchPaths = search; + context.useLdLibraryPath = false; + context.dontLoad = false; + context.mustBeBundle = false; + context.mustBeDylib = true; + context.matchByInstallName = false; + context.origin = origin; + context.rpath = rpath; + return load(libraryName, context); +} + + +static void setContext(int argc, const char* argv[], const char* envp[], const char* apple[]) +{ + gLinkContext.loadLibrary = &libraryLocator; + gLinkContext.imageNotification = &imageNotification; + gLinkContext.terminationRecorder = &terminationRecorder; + gLinkContext.flatExportFinder = &flatFindExportedSymbol; + gLinkContext.coalescedExportFinder = &findCoalescedExportedSymbol; + gLinkContext.undefinedHandler = &undefinedHandler; + gLinkContext.addImageNeedingNotification = &addImageNeedingNotification; + gLinkContext.notifyAdding = ¬ifyAdding; + gLinkContext.getAllMappedRegions = &getMappedRegions; + gLinkContext.bindingHandler = NULL; + gLinkContext.bindingOptions = ImageLoader::kBindingNone; + gLinkContext.mainExecutable = sMainExecutable; + gLinkContext.argc = argc; + gLinkContext.argv = argv; + gLinkContext.envp = envp; + gLinkContext.apple = apple; +} + + + +void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader::InitializerRunning runInitializers) +{ + // add to list of known images. This did not happen at creation time for bundles + if ( image->isBundle() ) + addImage(image); + + // we detect root images as those not linked in yet + if ( !image->isLinked() ) + addRootImage(image); + + // notify ZeroLink of new image with concat of logical and physical name + if ( sBundleNotifier != NULL && image->isBundle() ) { + const int logicalLen = strlen(image->getLogicalPath()); + char logAndPhys[strlen(image->getPath())+logicalLen+2]; + strcpy(logAndPhys, image->getLogicalPath()); + strcpy(&logAndPhys[logicalLen+1], image->getPath()); + (*sBundleNotifier)(logAndPhys, image); + } + + // process images + image->link(gLinkContext, bindness, runInitializers, sAddImageCallbacks.size()); + +#if OLD_GDB_DYLD_INTERFACE + // notify gdb that loaded libraries have changed + gdb_dyld_state_changed(); +#endif +} + + +// +// Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which +// sets up some registers and call this function. +// +// Returns address of main() in target program which __dyld_start jumps to +// +uintptr_t +_main(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[]) +{ + // Pickup the pointer to the exec path. + const char* executable = apple[0]; + if ( executable[0] == '/' ) { + // have full path, use it + sExecPath = executable; + } + else { + // have relative path, use cwd to make absolute + char cwdbuff[MAXPATHLEN]; + if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) { + // maybe use static buffer to avoid calling malloc so early... + char* s = new char[strlen(cwdbuff) + strlen(executable) + 2]; + strcpy(s, cwdbuff); + strcat(s, "/"); + strcat(s, executable); + sExecPath = s; + } + } + uintptr_t result = 0; + sMainExecutableMachHeader = mainExecutableMH; + checkEnvironmentVariables(envp); + if ( sEnv.DYLD_PRINT_OPTS ) + printOptions(argv); + if ( sEnv.DYLD_PRINT_ENV ) + printEnvironmentVariables(envp); + getHostInfo(); + setContext(argc, argv, envp, apple); + ImageLoader::BindingLaziness bindness = sEnv.DYLD_BIND_AT_LAUNCH ? ImageLoader::kLazyAndNonLazy : ImageLoader::kNonLazyOnly; + + // load any inserted libraries before loading the main executable so that they are first in flat namespace + int insertLibrariesCount = 0; + if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) { + for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) { + insertLibrariesCount++; + } + } + ImageLoader* insertedImages[insertLibrariesCount]; + if ( insertLibrariesCount > 0 ) { + for (int i=0; i < insertLibrariesCount; ++i) { + try { + LoadContext context; + context.useSearchPaths = false; + context.useLdLibraryPath = false; + context.dontLoad = false; + context.mustBeBundle = false; + context.mustBeDylib = true; + context.matchByInstallName = false; + context.origin = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES + context.rpath = NULL; + insertedImages[i] = load(sEnv.DYLD_INSERT_LIBRARIES[i], context); + } + catch (...) { + char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50]; + sprintf(buf, "could not load inserted library: %s\n", sEnv.DYLD_INSERT_LIBRARIES[i]); + insertedImages[i] = NULL; + halt(buf); + } + } + } + + // load and link main executable + try { + sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, sExecPath); + gLinkContext.mainExecutable = sMainExecutable; + if ( sMainExecutable->forceFlat() ) { + gLinkContext.bindFlat = true; + gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding; + } + link(sMainExecutable, bindness, ImageLoader::kDontRunInitializers); + result = (uintptr_t)sMainExecutable->getMain(); + } + catch(const char* message) { + halt(message); + } + catch(...) { + fprintf(stderr, "dyld: launch failed\n"); + } + + // Link in any inserted libraries. + // Do this after link main executable so any extra libraries pulled in by inserted libraries are at end of flat namespace + if ( insertLibrariesCount > 0 ) { + for (int i=0; i < insertLibrariesCount; ++i) { + try { + if ( insertedImages[i] != NULL ) + link(insertedImages[i], bindness, ImageLoader::kDontRunInitializers); + } + catch (const char* message) { + char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50+strlen(message)]; + sprintf(buf, "could not link inserted library: %s\n%s\n", sEnv.DYLD_INSERT_LIBRARIES[i], message); + halt(buf); + } + } + } + + return result; +} + + + + +}; // namespace + + + diff --git a/src/dyld.exp b/src/dyld.exp new file mode 100644 index 0000000..ee6ad95 --- /dev/null +++ b/src/dyld.exp @@ -0,0 +1,52 @@ +# +# Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +# + +# +# Only the following symbols should be "global". +# gdb and vmutils lookup these symbols in dyld in order to determine what images the process is using +# + +# Mac OS X 10.4 way to discover a process's images +_dyld_all_image_infos + +# CrashReporter uses this to get message as to why dyld terminated the process +_error_string + +# Used by various tools to see build number of dyld +_dyldVersionString +_dyldVersionNumber + +# Entry points into dyld needed by loaded every image +_stub_binding_helper +_dyld_func_lookup + +# Old symbols left for compatibility +_gdb_dyld_version +_gdb_dyld_state_changed +_gdb_nobject_images +_gdb_object_image_size +_gdb_nlibrary_images +_gdb_library_image_size +_object_images +_library_images +_send_event diff --git a/src/dyld.h b/src/dyld.h new file mode 100644 index 0000000..72e0e2a --- /dev/null +++ b/src/dyld.h @@ -0,0 +1,94 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#include "ImageLoader.h" + + + +// +// dyld functions available when implementing dyld API's +// +// +namespace dyld { + + struct LoadContext + { + bool useSearchPaths; + bool useLdLibraryPath; + bool matchByInstallName; + bool dontLoad; + bool mustBeBundle; + bool mustBeDylib; + const char* origin; // path for expanding @loader_path + const char** rpath; // future support of -rpath + }; + + + + typedef void (*ImageCallback)(const struct mach_header* mh, intptr_t slide); + typedef void (*BundleNotificationCallBack)(const char* imageName, ImageLoader* image); + typedef ImageLoader* (*BundleLocatorCallBack)(const char* symbolName); + typedef void (*UndefinedHandler)(const char* symbolName); + + + extern ImageLoader::LinkContext gLinkContext; + extern bool gLogAPIs; + extern const struct ThreadingHelpers* gThreadHelpers; + + + extern void registerAddCallback(ImageCallback func); + extern void registerRemoveCallback(ImageCallback func); + extern void registerZeroLinkHandlers(BundleNotificationCallBack, BundleLocatorCallBack); + extern void registerUndefinedHandler(UndefinedHandler); + extern void initializeMainExecutable(); + extern void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader::InitializerRunning runInitializers); + extern void runTerminators(); + extern const char* getExecutablePath(); + extern bool validImage(ImageLoader*); + extern ImageLoader* getIndexedImage(uint32_t index); + extern uint32_t getImageCount(); + extern ImageLoader* findImageByMachHeader(const struct mach_header* target); + extern ImageLoader* findImageContainingAddress(const void* addr); + extern ImageLoader* findImageByName(const char* path); + extern ImageLoader* findLoadedImageByInstallPath(const char* path); + extern bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image); + extern bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, ImageLoader** image); + extern ImageLoader* load(const char* path, const LoadContext& context); + extern ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName); + extern void removeImage(ImageLoader* image); + extern ImageLoader* cloneImage(ImageLoader* image); + extern void forEachImageDo( void (*)(ImageLoader*, void*), void*); + extern uintptr_t _main(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[]); + extern void halt(const char* message) __attribute__((noreturn)); + extern void setErrorMessage(const char* msg); + extern const char* getErrorMessage(); + extern void clearErrorMessage(); + extern bool mainExecutablePrebound(); + extern ImageLoader* mainExecutable(); + extern void processDyldEnvironmentVarible(const char* key, const char* value); + +}; + diff --git a/src/dyldAPIs.cpp b/src/dyldAPIs.cpp new file mode 100644 index 0000000..fb9f89c --- /dev/null +++ b/src/dyldAPIs.cpp @@ -0,0 +1,1608 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// This file implements that API's in +// +// + + +#include +#include +#include +#include +#include + +extern "C" mach_port_name_t task_self_trap(void); // can't include because it is missing extern C + +#include "mach-o/dyld_gdb.h" +#include "mach-o/dyld.h" +#include "mach-o/dyld_priv.h" +#include "dlfcn.h" + +#include "ImageLoader.h" +#include "dyld.h" +#include "dyldLibSystemThreadHelpers.h" + +static char sLastErrorFilePath[1024]; +static NSLinkEditErrors sLastErrorFileCode; +static int sLastErrorNo; + + +// In 10.3.x and earlier all the NSObjectFileImage API's were implemeneted in libSystem.dylib +// Beginning in 10.4 the NSObjectFileImage API's are implemented in dyld and libSystem just forwards +// This conditional keeps support for old libSystem's which needed some help implementing the API's +#define OLD_LIBSYSTEM_SUPPORT 1 + + +// The following functions have no prototype in any header. They are special cases +// where _dyld_func_lookup() is used directly. +static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit); +static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options); +static void _dyld_register_binding_handler(void * (*)(const char *, const char *, void *), ImageLoader::BindingOptions); +static void _dyld_fork_prepare(); +static void _dyld_fork_parent(); +static void _dyld_fork_child(); +static void _dyld_fork_child_final(); +static void _dyld_make_delayed_module_initializer_calls(); +static void _dyld_mod_term_funcs(); +static bool NSMakePrivateModulePublic(NSModule module); +static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header); +static void registerThreadHelpers(const dyld::ThreadingHelpers*); +static void _dyld_update_prebinding(int pathCount, const char* paths[], uint32_t flags); +static const struct dyld_all_image_infos* _dyld_get_all_image_infos(); + +// The following functions are dyld API's, but since dyld links with a static copy of libc.a +// the public name cannot be used. +static void client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module); +static bool client_NSIsSymbolNameDefined(const char* symbolName); + + +static void unimplemented() +{ + dyld::halt("unimplemented dyld function\n"); +} + +struct dyld_func { + const char* name; + void* implementation; +}; + +static struct dyld_func dyld_funcs[] = { + {"__dyld_image_count", (void*)_dyld_image_count }, + {"__dyld_get_image_header", (void*)_dyld_get_image_header }, + {"__dyld_get_image_vmaddr_slide", (void*)_dyld_get_image_vmaddr_slide }, + {"__dyld_get_image_name", (void*)_dyld_get_image_name }, + {"__dyld_lookup_and_bind", (void*)client_dyld_lookup_and_bind }, + {"__dyld_lookup_and_bind_with_hint", (void*)_dyld_lookup_and_bind_with_hint }, + {"__dyld_lookup_and_bind_objc", (void*)unimplemented }, + {"__dyld_lookup_and_bind_fully", (void*)_dyld_lookup_and_bind_fully }, + {"__dyld_install_handlers", (void*)_dyld_install_handlers }, + {"__dyld_link_edit_error", (void*)NSLinkEditError }, +#if OLD_LIBSYSTEM_SUPPORT + {"__dyld_link_module", (void*)_dyld_link_module }, +#endif + {"__dyld_unlink_module", (void*)NSUnLinkModule }, + {"__dyld_register_func_for_add_image", (void*)_dyld_register_func_for_add_image }, + {"__dyld_register_func_for_remove_image", (void*)_dyld_register_func_for_remove_image }, + {"__dyld_register_func_for_link_module", (void*)unimplemented }, + {"__dyld_register_func_for_unlink_module", (void*)unimplemented }, + {"__dyld_register_func_for_replace_module", (void*)unimplemented }, + {"__dyld_get_objc_module_sect_for_module", (void*)unimplemented }, + {"__dyld_bind_objc_module", (void*)_dyld_bind_objc_module }, + {"__dyld_bind_fully_image_containing_address", (void*)_dyld_bind_fully_image_containing_address }, + {"__dyld_image_containing_address", (void*)_dyld_image_containing_address }, + {"__dyld_get_image_header_containing_address", (void*)_dyld_get_image_header_containing_address }, + {"__dyld_moninit", (void*)_dyld_moninit }, + {"__dyld_register_binding_handler", (void*)_dyld_register_binding_handler }, + {"__dyld_fork_prepare", (void*)_dyld_fork_prepare }, + {"__dyld_fork_parent", (void*)_dyld_fork_parent }, + {"__dyld_fork_child", (void*)_dyld_fork_child }, + {"__dyld_fork_child_final", (void*)_dyld_fork_child_final }, + {"__dyld_fork_mach_init", (void*)unimplemented }, + {"__dyld_make_delayed_module_initializer_calls",(void*)_dyld_make_delayed_module_initializer_calls }, + {"__dyld_NSNameOfSymbol", (void*)NSNameOfSymbol }, + {"__dyld_NSAddressOfSymbol", (void*)NSAddressOfSymbol }, + {"__dyld_NSModuleForSymbol", (void*)NSModuleForSymbol }, + {"__dyld_NSLookupAndBindSymbol", (void*)NSLookupAndBindSymbol }, + {"__dyld_NSLookupAndBindSymbolWithHint", (void*)NSLookupAndBindSymbolWithHint }, + {"__dyld_NSLookupSymbolInModule", (void*)NSLookupSymbolInModule}, + {"__dyld_NSLookupSymbolInImage", (void*)NSLookupSymbolInImage}, + {"__dyld_NSMakePrivateModulePublic", (void*)NSMakePrivateModulePublic}, + {"__dyld_NSIsSymbolNameDefined", (void*)client_NSIsSymbolNameDefined}, + {"__dyld_NSIsSymbolNameDefinedWithHint", (void*)NSIsSymbolNameDefinedWithHint }, + {"__dyld_NSIsSymbolNameDefinedInImage", (void*)NSIsSymbolNameDefinedInImage}, + {"__dyld_NSNameOfModule", (void*)NSNameOfModule }, + {"__dyld_NSLibraryNameForModule", (void*)NSLibraryNameForModule }, + {"__dyld_NSAddLibrary", (void*)NSAddLibrary }, + {"__dyld_NSAddLibraryWithSearching", (void*)NSAddLibraryWithSearching }, + {"__dyld_NSAddImage", (void*)NSAddImage }, + {"__dyld__NSGetExecutablePath", (void*)_NSGetExecutablePath }, + {"__dyld_launched_prebound", (void*)_dyld_launched_prebound }, + {"__dyld_all_twolevel_modules_prebound", (void*)_dyld_all_twolevel_modules_prebound }, + {"__dyld_call_module_initializers_for_dylib", (void*)_dyld_call_module_initializers_for_dylib }, + {"__dyld_mod_term_funcs", (void*)_dyld_mod_term_funcs }, + {"__dyld_install_link_edit_symbol_handlers", (void*)dyld::registerZeroLinkHandlers }, + {"__dyld_NSCreateObjectFileImageFromFile", (void*)NSCreateObjectFileImageFromFile }, + {"__dyld_NSCreateObjectFileImageFromMemory", (void*)NSCreateObjectFileImageFromMemory }, + {"__dyld_NSCreateCoreFileImageFromFile", (void*)unimplemented }, + {"__dyld_NSDestroyObjectFileImage", (void*)NSDestroyObjectFileImage }, + {"__dyld_NSLinkModule", (void*)NSLinkModule }, + {"__dyld_NSHasModInitObjectFileImage", (void*)NSHasModInitObjectFileImage }, + {"__dyld_NSSymbolDefinitionCountInObjectFileImage", (void*)NSSymbolDefinitionCountInObjectFileImage }, + {"__dyld_NSSymbolDefinitionNameInObjectFileImage", (void*)NSSymbolDefinitionNameInObjectFileImage }, + {"__dyld_NSIsSymbolDefinedInObjectFileImage", (void*)NSIsSymbolDefinedInObjectFileImage }, + {"__dyld_NSSymbolReferenceNameInObjectFileImage", (void*)NSSymbolReferenceNameInObjectFileImage }, + {"__dyld_NSSymbolReferenceCountInObjectFileImage", (void*)NSSymbolReferenceCountInObjectFileImage }, + {"__dyld_NSGetSectionDataInObjectFileImage", (void*)NSGetSectionDataInObjectFileImage }, + {"__dyld_NSFindSectionAndOffsetInObjectFileImage", (void*)NSFindSectionAndOffsetInObjectFileImage }, + {"__dyld_register_thread_helpers", (void*)registerThreadHelpers }, + {"__dyld_dladdr", (void*)dladdr }, + {"__dyld_dlclose", (void*)dlclose }, + {"__dyld_dlerror", (void*)dlerror }, + {"__dyld_dlopen", (void*)dlopen }, + {"__dyld_dlsym", (void*)dlsym }, + {"__dyld_update_prebinding", (void*)_dyld_update_prebinding }, + {"__dyld_get_all_image_infos", (void*)_dyld_get_all_image_infos }, + {NULL, 0} +}; + + + +// dyld's abstract type NSSymbol is implemented as const ImageLoader::Symbol* +inline NSSymbol SymbolToNSSymbol(const ImageLoader::Symbol* sym) +{ + return (NSSymbol)sym; +} +inline const ImageLoader::Symbol* NSSymbolToSymbol(NSSymbol sym) +{ + return (const ImageLoader::Symbol*)sym; +} + +// dyld's abstract type NSModule is implemented as ImageLoader* +inline NSModule ImageLoaderToNSModule(ImageLoader* image) +{ + return (NSModule)image; +} +inline ImageLoader* NSModuleToImageLoader(NSModule module) +{ + ImageLoader* image = (ImageLoader*)module; + if ( dyld::validImage(image) ) + return image; + return NULL; +} + +// actual definition for opaque type +struct __NSObjectFileImage +{ + ImageLoader* image; + const void* imageBaseAddress; // not used with OFI created from files + size_t imageLength; // not used with OFI created from files +}; +static std::vector sObjectFileImages; + + + +// +// __NSObjectFileImage are deleted in NSDestroyObjectFileImage() +// The contained image is delete in one of two places: +// NSUnLinkModule deletes the image if there is no __NSObjectFileImage with a reference to it +// NSDestroyObjectFileImage deletes the image if image is not in list of valid images +// + + +static void dyldAPIhalt(const char* apiName, const char* errorMsg) +{ + fprintf(stderr, "dyld: %s() error\n", apiName); + dyld::halt(errorMsg); +} + + + +static void setLastError(NSLinkEditErrors code, int errnum, const char* file, const char* message) +{ + dyld::setErrorMessage(message); + strncpy(sLastErrorFilePath, file, 1024); + sLastErrorFilePath[1023] = '\0'; + sLastErrorFileCode = code; + sLastErrorNo = errnum; +} + + +/* + *_dyld_NSGetExecutablePath is the dyld side of _NSGetExecutablePath which + * copies the path of the executable into the buffer and returns 0 if the path + * was successfully copied in the provided buffer. If the buffer is not large + * enough, -1 is returned and the expected buffer size is copied in *bufsize. + * Note that _NSGetExecutablePath will return "a path" to the executable not a + * "real path" to the executable. That is the path may be a symbolic link and + * not the real file. And with deep directories the total bufsize needed could + * be more than MAXPATHLEN. + */ +int _NSGetExecutablePath(char* buf, uint32_t *bufsize) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(...)\n", __func__); + const char* exePath = dyld::getExecutablePath(); + if(*bufsize < strlen(exePath) + 1){ + *bufsize = strlen(exePath) + 1; + return -1; + } + strcpy(buf, exePath); + return 0; +} + + +// +// _dyld_call_module_initializers_for_dylib() is the dyld side of +// __initialize_Cplusplus() which is in dylib1.o. +// It is intended to only be called inside -init rouintes. +// -init routines are called before module initializers (what C++ +// initializers use). Calling __initialize_Cplusplus() in a -init +// routine causes the module initializers for an image to be called +// which then allows C++ to be used inside a -init routine +// +static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "__initialize_Cplusplus()\n"); + + // for now, do nothing... +} + + +void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", %p, %p)\n", __func__, symbolName, address, module); + ImageLoader* image; + const ImageLoader::Symbol* sym; + dyld::clearErrorMessage(); + if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) { + try { + dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers); + if ( address != NULL) + *address = (void*)image->getExportedSymbolAddress(sym); + if ( module != NULL) + *module = ImageLoaderToNSModule(image); + } + catch (const char* msg) { + dyldAPIhalt(__func__, msg); + } + } + else { + // on failure to find symbol return NULLs + if ( address != NULL) + *address = NULL; + if ( module != NULL) + *module = NULL; + } +} + +// Note: This cannot have public name because dyld is built with a static copy of libc.a +// which calls dyld_lookup_and_bind() and expects to find dyld's symbols not host process +static void client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "_dyld_lookup_and_bind(\"%s\", %p, %p)\n", symbolName, address, module); + ImageLoader* image; + const ImageLoader::Symbol* sym; + if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) { + if ( address != NULL) + *address = (void*)image->getExportedSymbolAddress(sym); + if ( module != NULL) + *module = ImageLoaderToNSModule(image); + } + else { + // on failure to find symbol return NULLs + if ( address != NULL) + *address = NULL; + if ( module != NULL) + *module = NULL; + } +} + +void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* library_name_hint, void** address, NSModule* module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", \"%s\", %p, %p)\n", __func__, symbolName, library_name_hint, address, module); + ImageLoader* image; + const ImageLoader::Symbol* sym; + // Look for library whose path contains the hint. If that fails search everywhere + if ( dyld::flatFindExportedSymbolWithHint(symbolName, library_name_hint, &sym, &image) + || dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) { + if ( address != NULL) + *address = (void*)image->getExportedSymbolAddress(sym); + if ( module != NULL) + *module = ImageLoaderToNSModule(image); + } + else { + // on failure to find symbol return NULLs + if ( address != NULL) + *address = NULL; + if ( module != NULL) + *module = NULL; + } +} + + +NSSymbol NSLookupAndBindSymbol(const char *symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\")\n", __func__, symbolName); + ImageLoader* image; + const ImageLoader::Symbol* sym; + if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) { + return SymbolToNSSymbol(sym); + } + // return NULL on failure + return NULL; +} + +NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint); + ImageLoader* image; + const ImageLoader::Symbol* sym; + bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image); + if ( ! found ) { + // hint failed, do slow search of all images + found = dyld::flatFindExportedSymbol(symbolName, &sym, &image); + } + if ( found ) + return SymbolToNSSymbol(sym); + + // return NULL on failure and log + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", \"%s\") => NULL \n", __func__, symbolName, libraryNameHint); + return NULL; +} + +uint32_t _dyld_image_count(void) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + return dyld::getImageCount(); +} + +const struct mach_header* _dyld_get_image_header(uint32_t image_index) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%u)\n", __func__, image_index); + ImageLoader* image = dyld::getIndexedImage(image_index); + if ( image != NULL ) + return (struct mach_header*)image->machHeader(); + else + return NULL; +} + + +static __attribute__((noinline)) +const struct mach_header* addImage(const char* path, bool search, bool dontLoad, bool matchInstallName, bool abortOnError) +{ + ImageLoader* image = NULL; + try { + dyld::clearErrorMessage(); + void* callerAddress = __builtin_return_address(2); // note layers: 2: real client, 1: libSystem glue, 0: dyld API + ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress); + dyld::LoadContext context; + context.useSearchPaths = search; + context.useLdLibraryPath = false; + context.matchByInstallName = matchInstallName; + context.dontLoad = dontLoad; + context.mustBeBundle = false; + context.mustBeDylib = true; + context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path + context.rpath = NULL; // support not yet implemented + + image = load(path, context); + if ( image != NULL ) { + if ( context.matchByInstallName ) + image->setMatchInstallPath(true); + dyld::link(image, ImageLoader::kNonLazyOnly, ImageLoader::kRunInitializers); + return image->machHeader(); + } + } + catch (const char* msg) { + if ( abortOnError) { + char pathMsg[strlen(msg)+strlen(path)+4]; + strcpy(pathMsg, msg); + strcat(pathMsg, " "); + strcat(pathMsg, path); + dyldAPIhalt("NSAddImage", pathMsg); + } + // not halting, so set error state for NSLinkEditError to find + setLastError(NSLinkEditOtherError, 0, path, msg); + } + return NULL; +} + +const struct mach_header* NSAddImage(const char* path, uint32_t options) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", 0x%08X)\n", __func__, path, options); + const bool dontLoad = ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 ); + const bool search = ( (options & NSADDIMAGE_OPTION_WITH_SEARCHING) != 0 ); + const bool matchInstallName = ( (options & NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME) != 0 ); + const bool abortOnError = ( (options & NSADDIMAGE_OPTION_RETURN_ON_ERROR) == 0 ); + return addImage(path, search, dontLoad, matchInstallName, abortOnError); +} + +bool NSAddLibrary(const char* path) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\")\n", __func__, path); + return (addImage(path, false, false, false, false) != NULL); +} + +bool NSAddLibraryWithSearching(const char* path) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\")\n", __func__, path); + return (addImage(path, true, false, false, false) != NULL); +} + + + +//#define NSADDIMAGE_OPTION_NONE 0x0 +//#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 +//#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 + +bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, \"%s\")\n", __func__, (void *)mh, symbolName); + ImageLoader* image = dyld::findImageByMachHeader(mh); + if ( image != NULL ) { + if ( image->findExportedSymbol(symbolName, NULL, true, NULL) != NULL) + return true; + } + return false; +} + +NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", __func__, mh, symbolName, options); + const ImageLoader::Symbol* symbol = NULL; + dyld::clearErrorMessage(); + ImageLoader* image = dyld::findImageByMachHeader(mh); + if ( image != NULL ) { + try { + if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY ) { + dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers); + } + else if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW ) { + dyld::link(image, ImageLoader::kLazyOnlyNoDependents, ImageLoader::kDontRunInitializers); + } + } + catch (const char* msg) { + if ( (options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR) == 0 ) { + dyldAPIhalt(__func__, msg); + } + } + symbol = image->findExportedSymbol(symbolName, NULL, true, NULL); + } + if ( dyld::gLogAPIs && (symbol == NULL) ) + fprintf(stderr, "%s(%p, \"%s\", 0x%08X) ==> NULL\n", __func__, mh, symbolName, options); + return SymbolToNSSymbol(symbol); +} + + +// Note: This cannot have public name because dyld is built with a static copy of libc.a +// which calls NSIsSymbolNameDefined() and expects to find dyld's symbols not host process +static bool client_NSIsSymbolNameDefined(const char* symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "NSIsSymbolNameDefined(\"%s\")\n", symbolName); + ImageLoader* image; + const ImageLoader::Symbol* sym; + return dyld::flatFindExportedSymbol(symbolName, &sym, &image); +} + +bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint); + ImageLoader* image; + const ImageLoader::Symbol* sym; + bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image); + if ( ! found ) { + // hint failed, do slow search of all images + found = dyld::flatFindExportedSymbol(symbolName, &sym, &image); + } + if ( !found && dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", \"%s\") => false \n", __func__, symbolName, libraryNameHint); + return found; +} + +const char* NSNameOfSymbol(NSSymbol symbol) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol); + const char* result = NULL; + ImageLoader* image = dyld::findImageContainingAddress(symbol); + if ( image != NULL ) + result = image->getExportedSymbolName(NSSymbolToSymbol(symbol)); + return result; +} + +void* NSAddressOfSymbol(NSSymbol symbol) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol); + void* result = NULL; + ImageLoader* image = dyld::findImageContainingAddress(symbol); + if ( image != NULL ) + result = (void*)image->getExportedSymbolAddress(NSSymbolToSymbol(symbol)); + return result; +} + +NSModule NSModuleForSymbol(NSSymbol symbol) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol); + NSModule result = NULL; + ImageLoader* image = dyld::findImageContainingAddress(symbol); + if ( image != NULL ) + result = ImageLoaderToNSModule(image); + return result; +} + + +intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%u)\n", __func__, image_index); + ImageLoader* image = dyld::getIndexedImage(image_index); + if ( image != NULL ) + return image->getSlide(); + else + return 0; +} + +const char* _dyld_get_image_name(uint32_t image_index) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%u)\n", __func__, image_index); + ImageLoader* image = dyld::getIndexedImage(image_index); + if ( image != NULL ) + return image->getLogicalPath(); + else + return NULL; +} + + + +bool _dyld_all_twolevel_modules_prebound(void) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + return FALSE; // fixme +} + +void _dyld_bind_objc_module(const void *objc_module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objc_module); + // do nothing, with new dyld everything already bound +} + + +bool _dyld_bind_fully_image_containing_address(const void* address) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, address); + dyld::clearErrorMessage(); + ImageLoader* image = dyld::findImageContainingAddress(address); + if ( image != NULL ) { + try { + dyld::link(image, ImageLoader::kLazyAndNonLazy, ImageLoader::kDontRunInitializers); + return true; + } + catch (const char* msg) { + dyldAPIhalt(__func__, msg); + } + } + return false; +} + +bool _dyld_image_containing_address(const void* address) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, address); + ImageLoader *imageLoader = dyld::findImageContainingAddress(address); + return (NULL != imageLoader); +} + +static NSObjectFileImage createObjectImageFile(ImageLoader* image, const void* address = NULL, size_t len=0) +{ + NSObjectFileImage result = new __NSObjectFileImage(); + result->image = image; + result->imageBaseAddress = address; + result->imageLength = len; + sObjectFileImages.push_back(result); + return result; +} + +NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(\"%s\", ...)\n", __func__, pathName); + try { + void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue + ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress); + + dyld::LoadContext context; + context.useSearchPaths = false; + context.useLdLibraryPath = false; + context.matchByInstallName = false; + context.dontLoad = false; + context.mustBeBundle = true; + context.mustBeDylib = false; + context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path + context.rpath = NULL; // support not yet implemented + + ImageLoader* image = dyld::load(pathName, context); + // Note: We DO NOT link the image! NSLinkModule will do that + if ( image != NULL ) { + if ( !image->isBundle() ) { + // the image must have been already loaded (since context.mustBeBundle will prevent it from being loaded) + return NSObjectFileImageInappropriateFile; + } + *objectFileImage = createObjectImageFile(image); + return NSObjectFileImageSuccess; + } + } + catch (const char* msg) { + //fprintf(stderr, "dyld: NSCreateObjectFileImageFromFile() error: %s\n", msg); + return NSObjectFileImageInappropriateFile; + } + return NSObjectFileImageFailure; +} + + +NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* address, size_t size, NSObjectFileImage *objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, %lu, %p)\n", __func__, address, size, objectFileImage); + + try { + ImageLoader* image = dyld::loadFromMemory((const uint8_t*)address, size, NULL); + if ( ! image->isBundle() ) { + // this API can only be used with bundles... + delete image; + return NSObjectFileImageInappropriateFile; + } + // Note: We DO NOT link the image! NSLinkModule will do that + if ( image != NULL ) { + *objectFileImage = createObjectImageFile(image, address, size); + return NSObjectFileImageSuccess; + } + } + catch (const char* msg) { + fprintf(stderr, "dyld: NSCreateObjectFileImageFromMemory() error: %s\n", msg); + } + return NSObjectFileImageFailure; +} + +static bool validOFI(NSObjectFileImage objectFileImage) +{ + const int ofiCount = sObjectFileImages.size(); + for (int i=0; i < ofiCount; ++i) { + if ( sObjectFileImages[i] == objectFileImage ) + return true; + } + return false; +} + +bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objectFileImage); + + if ( validOFI(objectFileImage) ) { + // if the image has never been linked or has been unlinked, the image is not in the list of valid images + // and we should delete it + bool linkedImage = dyld::validImage(objectFileImage->image); + if ( ! linkedImage ) + delete objectFileImage->image; + + // remove from list of ofi's + for (std::vector::iterator it=sObjectFileImages.begin(); it != sObjectFileImages.end(); it++) { + if ( *it == objectFileImage ) { + sObjectFileImages.erase(it); + break; + } + } + + // if object was created from a memory, release that memory + // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands over ownership of the memory to dyld + if ( objectFileImage->imageBaseAddress != NULL ) { + vm_deallocate(mach_task_self(), (vm_address_t)objectFileImage->imageBaseAddress, objectFileImage->imageLength); + } + + // free ofi object + delete objectFileImage; + + return true; + } + return false; +} + +bool NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objectFileImage); + return objectFileImage->image->needsInitialization(); +} + +uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objectFileImage); + return objectFileImage->image->getExportedSymbolCount(); +} + +const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p,%d)\n", __func__, objectFileImage, ordinal); + const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedExportedSymbol(ordinal); + return objectFileImage->image->getExportedSymbolName(sym); +} + +uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objectFileImage); + return objectFileImage->image->getImportedSymbolCount(); +} + +const char * NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, + bool* tentative_definition) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p,%d)\n", __func__, objectFileImage, ordinal); + const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedImportedSymbol(ordinal); + if ( tentative_definition != NULL ) { + ImageLoader::ReferenceFlags flags = objectFileImage->image->geImportedSymbolInfo(sym); + if ( (flags & ImageLoader::kTentativeDefinition) != 0 ) + *tentative_definition = true; + else + *tentative_definition = false; + } + return objectFileImage->image->getImportedSymbolName(sym); +} + +void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, + const char* segmentName, const char* sectionName, unsigned long* size) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p,%s, %s)\n", __func__, objectFileImage, segmentName, sectionName); + + void* start; + size_t length; + if ( objectFileImage->image->getSectionContent(segmentName, sectionName, &start, &length) ) { + if ( size != NULL ) + *size = length; + return start; + } + return NULL; +} + + + +bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p,%s)\n", __func__, objectFileImage, symbolName); + const ImageLoader::Symbol* sym = objectFileImage->image->findExportedSymbol(symbolName, NULL, true, NULL); + return ( sym != NULL ); +} + +/* + * Given an imageOffset into an ObjectFileImage, returns + * the segment/section name and offset into that section of + * that imageOffset. Returns FALSE if the imageOffset is not + * in any section. You can used the resulting sectionOffset to + * index into the data returned by NSGetSectionDataInObjectFileImage. + * + * First appeared in Mac OS X 10.3 + * + * SPI: currently only used by ZeroLink to detect +load methods + */ +bool +NSFindSectionAndOffsetInObjectFileImage(NSObjectFileImage objectFileImage, + unsigned long imageOffset, + const char** segmentName, /* can be NULL */ + const char** sectionName, /* can be NULL */ + unsigned long* sectionOffset) /* can be NULL */ +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, objectFileImage); + + return objectFileImage->image->findSection((char*)(objectFileImage->image->getBaseAddress())+imageOffset, segmentName, sectionName, sectionOffset); +} + + + +NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", __func__, objectFileImage, moduleName, options); + + dyld::clearErrorMessage(); + try { + // NSLinkModule allows a bundle to be link multpile times + // each link causes the bundle to be copied to a new address + if ( objectFileImage->image->isLinked() ) { + // already linked, so clone a new one and link it +#if 0 + fprintf(stderr, "dyld: warning: %s(0x%08X, \"%s\", 0x%08X) called more than once for 0x%08X\n", + __func__, objectFileImage, moduleName, options, objectFileImage); +#endif + objectFileImage->image = dyld::cloneImage(objectFileImage->image); + } + + // if this ofi was made with NSCreateObjectFileImageFromFile() then physical path is already set + // if this ofi was create with NSCreateObjectFileImageFromMemory() then the phyiscal path should be set if supplied + if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 ) { + if ( objectFileImage->imageBaseAddress != NULL ) { + const char* physEnd = &moduleName[strlen(moduleName)+1]; + objectFileImage->image->setPath(physEnd); + } + } + + // set moduleName as the name anyone calling _dyld_get_image_name() will see + objectFileImage->image->setLogicalPath(moduleName); + + // support private bundles + if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 ) + objectFileImage->image->setHideExports(); + + // set up linking options + ImageLoader::BindingLaziness bindness = ImageLoader::kNonLazyOnly; + if ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 ) + bindness = ImageLoader::kLazyAndNonLazy; + ImageLoader::InitializerRunning runInitializers = ImageLoader::kRunInitializers; + if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) != 0 ) + runInitializers = ImageLoader::kDontRunInitializersButTellObjc; + + // load libraries, rebase, bind, to make this image usable + dyld::link(objectFileImage->image, bindness, runInitializers); + + return ImageLoaderToNSModule(objectFileImage->image); + } + catch (const char* msg) { + if ( (options & NSLINKMODULE_OPTION_RETURN_ON_ERROR) == 0 ) + dyldAPIhalt(__func__, msg); + // not halting, so set error state for NSLinkEditError to find + dyld::removeImage(objectFileImage->image); + setLastError(NSLinkEditOtherError, 0, moduleName, msg); + return NULL; + } +} + +#if OLD_LIBSYSTEM_SUPPORT +// This is for compatibility with old libSystems (libdyld.a) which process ObjectFileImages outside dyld +static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", "NSLinkModule", object_addr, moduleName, options); // note name/args translation + ImageLoader* image = NULL; + dyld::clearErrorMessage(); + try { + const char* imageName = moduleName; + if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 ) + imageName = &moduleName[strlen(moduleName)+1]; + + image = dyld::loadFromMemory((const uint8_t*)object_addr, object_size, imageName); + + if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 ) + image->setLogicalPath(moduleName); + + if ( image != NULL ) { + // support private bundles + if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 ) + image->setHideExports(); + + // set up linking options + ImageLoader::BindingLaziness bindness = ImageLoader::kNonLazyOnly; + if ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 ) + bindness = ImageLoader::kLazyAndNonLazy; + ImageLoader::InitializerRunning runInitializers = ImageLoader::kRunInitializers; + if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) != 0 ) + runInitializers = ImageLoader::kDontRunInitializersButTellObjc; + + // load libraries, rebase, bind, to make this image usable + dyld::link(image, bindness, runInitializers); + } + } + catch (const char* msg) { + if ( (options & NSLINKMODULE_OPTION_RETURN_ON_ERROR) == 0 ) + dyldAPIhalt("NSLinkModule", msg); + // not halting, so set error state for NSLinkEditError to find + setLastError(NSLinkEditOtherError, 0, moduleName, msg); + // if image was created for this bundle, destroy it + if ( image != NULL ) { + dyld::removeImage(image); + delete image; + } + image = NULL; + } + return ImageLoaderToNSModule(image); +} +#endif + +NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, \"%s\")\n", __func__, (void *)module, symbolName); + ImageLoader* image = NSModuleToImageLoader(module); + if ( image == NULL ) + return NULL; + return SymbolToNSSymbol(image->findExportedSymbol(symbolName, NULL, false, NULL)); +} + +const char* NSNameOfModule(NSModule module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, module); + ImageLoader* image = NSModuleToImageLoader(module); + if ( image == NULL ) + return NULL; + return image->getPath(); +} + +const char* NSLibraryNameForModule(NSModule module) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, module); + ImageLoader* image = NSModuleToImageLoader(module); + if ( image == NULL ) + return NULL; + return image->getPath(); +} + +bool NSUnLinkModule(NSModule module, uint32_t options) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, 0x%08X)\n", __func__, module, options); + if ( module == NULL ) + return false; + ImageLoader* image = NSModuleToImageLoader(module); + if ( image == NULL ) + return false; + dyld::removeImage(image); + + if ( (options & NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) != 0 ) + image->setLeaveMapped(); + + // TODO: NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES + + // Only delete image if there is no ofi referencing it + // That means the ofi was destroyed after linking, so no one is left to delete this image + const int ofiCount = sObjectFileImages.size(); + bool found = false; + for (int i=0; i < ofiCount; ++i) { + NSObjectFileImage ofi = sObjectFileImages[i]; + if ( ofi->image == image ) + found = true; + } + if ( !found ) + delete image; + + return true; +} + +// internal name and parameters do not match public name and parameters... +static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "NSLinkEditErrorHandlers()\n"); + + dyld::registerUndefinedHandler((dyld::UndefinedHandler)undefined); + // no support for multiple or linkedit handlers +} + +const struct mach_header * _dyld_get_image_header_containing_address(const void* address) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, address); + ImageLoader* image = dyld::findImageContainingAddress(address); + if ( image != NULL ) + return image->machHeader(); + return NULL; +} + + +void _dyld_register_func_for_add_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, (void *)func); + dyld::registerAddCallback(func); +} + +void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, (void *)func); + dyld::registerRemoveCallback(func); +} + +// called by atexit() function installed by crt +static void _dyld_mod_term_funcs() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + dyld::runTerminators(); +} + +// called by crt before main +static void _dyld_make_delayed_module_initializer_calls() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + dyld::initializeMainExecutable(); +} + + +void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileName, const char** errorString) +{ + // FIXME FIXME + *c = sLastErrorFileCode; + *errorNumber = sLastErrorNo; + *fileName = sLastErrorFilePath; + *errorString = dyld::getErrorMessage(); +} + +static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *, const char *, void *), ImageLoader::BindingOptions bindingOptions) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + dyld::gLinkContext.bindingHandler = bindingHandler; + dyld::gLinkContext.bindingOptions = bindingOptions; +} + +// Call by fork() in libSystem before the kernel trap is done +static void _dyld_fork_prepare() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); +} + +// Call by fork() in libSystem after the kernel trap is done on the parent side +static void _dyld_fork_parent() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); +} + +// Call by fork() in libSystem after the kernel trap is done on the child side +static void _dyld_fork_child() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + // The implementation of fork() in libSystem knows to reset the variable mach_task_self_ + // in libSystem for the child of a fork. But dyld is built with a static copy + // of libc.a and has its own copy of mach_task_self_ which we reset here. + // + // In mach_init.h mach_task_self() is #defined to mach_task_self_ and + // in mach_init() mach_task_self_ is initialized to task_self_trap(). + // + extern mach_port_t mach_task_self_; + mach_task_self_ = task_self_trap(); +} + +// Call by fork() in libSystem after the kernel trap is done on the child side after +// other libSystem child side fixups are done +static void _dyld_fork_child_final() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); +} + + +typedef void (*MonitorProc)(char *lowpc, char *highpc); + +static void monInitCallback(ImageLoader* image, void* userData) +{ + MonitorProc proc = (MonitorProc)userData; + void* start; + size_t length; + if ( image->getSectionContent("__TEXT", "__text", &start, &length) ) { + proc((char*)start, (char*)start+length); + } +} + +// +// _dyld_moninit is called from profiling runtime routine moninit(). +// dyld calls back with the range of each __TEXT/__text section in every +// linked image. +// +void _dyld_moninit(MonitorProc proc) +{ + dyld::forEachImageDo(&monInitCallback, (void*)proc); +} + +// returns true if prebinding was used in main executable +bool _dyld_launched_prebound() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + + // ¥¥¥Êif we deprecate prebinding, we may want to consider always returning true or false here + return dyld::mainExecutablePrebound(); +} + + +// +// _dyld_NSMakePrivateModulePublic() is the dyld side of the hack +// NSMakePrivateModulePublic() needed for the dlopen() to turn it's +// RTLD_LOCAL handles into RTLD_GLOBAL. It just simply turns off the private +// flag on the image for this module. If the module was found and it was +// private then everything worked and TRUE is returned else FALSE is returned. +// +static bool NSMakePrivateModulePublic(NSModule module) +{ + ImageLoader* image = NSModuleToImageLoader(module); + if ( image != NULL ) { + if ( image->hasHiddenExports() ) { + image->setHideExports(false); + return true; + } + } + return false; +} + + + +bool lookupDyldFunction(const char* name, uintptr_t* address) +{ + for (const dyld_func* p = dyld_funcs; p->name != NULL; ++p) { + if ( strcmp(p->name, name) == 0 ) { + if( p->implementation == unimplemented ) + fprintf(stderr, "unimplemented dyld function: %s\n", p->name); + *address = (uintptr_t)p->implementation; + return true; + } + } + *address = 0; + return false; +} + + +static void registerThreadHelpers(const dyld::ThreadingHelpers* helpers) +{ + // We need to make sure libSystem's lazy pointer's are bound + // before installing thred helpers. + // The reason for this is that if accessing the lock requires + // a lazy pointer to be bound (and it does when multi-module + // libSystem) is not prebound, the lazy handler will be + // invoked which tries to acquire the lock again...an infinite + // loop. + ImageLoader* image = dyld::findImageContainingAddress(helpers); + dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers); + + dyld::gThreadHelpers = helpers; +} + + +static void dlerrorClear() +{ + if ( dyld::gThreadHelpers != NULL ) { + char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(1); + buffer[0] = '\0'; + } +} + +static void dlerrorSet(const char* msg) +{ + if ( dyld::gThreadHelpers != NULL ) { + char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(strlen(msg)+1); + strcpy(buffer, msg); + } +} + + + +void* dlopen(const char* path, int mode) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%s, 0x%08X)\n", __func__, path, mode); + + dlerrorClear(); + + // passing NULL for path means return magic object + if ( path == NULL ) { + return RTLD_DEFAULT; + } + + try { + void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue + ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress); + + ImageLoader* image = NULL; + dyld::LoadContext context; + context.useSearchPaths = true; + context.useLdLibraryPath= (strchr(path, '/') == NULL); // a leafname implies should search + context.matchByInstallName = true; + context.dontLoad = ( (mode & RTLD_NOLOAD) != 0 ); + context.mustBeBundle = false; + context.mustBeDylib = false; + context.origin = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path + context.rpath = NULL; // support not yet implemented + + image = load(path, context); + if ( image != NULL ) { + image->incrementReferenceCount(); + if ( ! image->isLinked() ) { + ImageLoader::BindingLaziness bindiness = ImageLoader::kNonLazyOnly; + if ( (mode & RTLD_NOW) != 0 ) + bindiness = ImageLoader::kLazyAndNonLazy; + dyld::link(image, bindiness, ImageLoader::kRunInitializers); + // only hide exports if image is not already in use + if ( (mode & RTLD_LOCAL) != 0 ) + image->setHideExports(true); + } + // RTLD_NODELETE means don't unmap image even after dlclosed. This is what dlcompat did on Mac OS X 10.3 + // On other *nix OS's, it means dlclose() should do nothing, but the handle should be invalidated. + // The subtle differences are: + // 1) if the image has any termination routines, whether they are run during dlclose or when the process terminates + // 2) If someone does a supsequent dlopen() on the same image, whether the same address should be used. + if ( (mode & RTLD_NODELETE) != 0 ) + image->setLeaveMapped(); + return image; + } + } + catch (const char* msg) { + const char* format = "dlopen(%s, %d): %s"; + char temp[strlen(format)+strlen(path)+strlen(msg)+10]; + sprintf(temp, format, path, mode, msg); + dlerrorSet(temp); + } + return NULL; +} + +int dlclose(void* handle) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p)\n", __func__, handle); + + ImageLoader* image = (ImageLoader*)handle; + if ( dyld::validImage(image) ) { + if ( image->decrementReferenceCount() ) { + // for now, only bundles can be unloaded + // to unload dylibs we would need to track all direct and indirect uses + if ( image->isBundle() ) { + dyld::removeImage(image); + delete image; + } + } + dlerrorClear(); + return 0; + } + else { + dlerrorSet("invalid handle passed to dlclose()"); + return -1; + } +} + + + +int dladdr(const void* address, Dl_info* info) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, %p)\n", __func__, address, info); + + ImageLoader* image = dyld::findImageContainingAddress(address); + if ( image != NULL ) { + info->dli_fname = image->getLogicalPath(); + info->dli_fbase = (void*)image->machHeader(); + // find closest exported symbol in the image + const uint32_t exportCount = image->getExportedSymbolCount(); + const ImageLoader::Symbol* bestSym = NULL; + const void* bestAddr = 0; + for(uint32_t i=0; i < exportCount; ++i) { + const ImageLoader::Symbol* sym = image->getIndexedExportedSymbol(i); + const void* symAddr = (void*)image->getExportedSymbolAddress(sym); + if ( (symAddr <= address) && (bestAddr < symAddr) ) { + bestSym = sym; + bestAddr = symAddr; + } + } + if ( bestSym != NULL ) { + info->dli_sname = image->getExportedSymbolName(bestSym) + 1; // strip off leading underscore + info->dli_saddr = (void*)bestAddr; + } + else { + info->dli_sname = NULL; + info->dli_saddr = NULL; + } + return 1; // success + } + return 0; // failure +} + + +char* dlerror() +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + + if ( dyld::gThreadHelpers != NULL ) { + char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(1); + // if no error set, return NULL + if ( buffer[0] != '\0' ) + return buffer; + } + return NULL; +} + +void* dlsym(void* handle, const char* symbolName) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s(%p, %s)\n", __func__, handle, symbolName); + + dlerrorClear(); + + ImageLoader* image; + const ImageLoader::Symbol* sym; + + // dlsym() assumes symbolName passed in is same as in C source code + // dyld assumes all symbol names have an underscore prefix + char underscoredName[strlen(symbolName)+2]; + underscoredName[0] = '_'; + strcpy(&underscoredName[1], symbolName); + + // magic "search all" handle + if ( handle == RTLD_DEFAULT ) { + if ( dyld::flatFindExportedSymbol(underscoredName, &sym, &image) ) { + return (void*)image->getExportedSymbolAddress(sym); + } + const char* format = "dlsym(RTLD_DEFAULT, %s): symbol not found"; + char temp[strlen(format)+strlen(symbolName)+2]; + sprintf(temp, format, symbolName); + dlerrorSet(temp); + return NULL; + } + + // magic "search what I would see" handle + if ( handle == RTLD_NEXT ) { + void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue + ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress); + sym = callerImage->resolveSymbol(underscoredName, false, &image); + if ( sym != NULL ) { + return (void*)image->getExportedSymbolAddress(sym); + } + const char* format = "dlsym(RTLD_NEXT, %s): symbol not found"; + char temp[strlen(format)+strlen(symbolName)+2]; + sprintf(temp, format, symbolName); + dlerrorSet(temp); + return NULL; + } +#ifdef RTLD_SELF + // magic "search me, then what I would see" handle + if ( handle == RTLD_SELF ) { + void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue + ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress); + sym = callerImage->findExportedSymbol(underscoredName, NULL, false, &image); // search first in calling image + if ( sym != NULL ) { + return (void*)image->getExportedSymbolAddress(sym); + } + sym = callerImage->resolveSymbol(underscoredName, false, &image); // search what calling image links against + if ( sym != NULL ) { + return (void*)image->getExportedSymbolAddress(sym); + } + const char* format = "dlsym(RTLD_SELF, %s): symbol not found"; + char temp[strlen(format)+strlen(symbolName)+2]; + sprintf(temp, format, symbolName); + dlerrorSet(temp); + return NULL; + } +#endif + // real handle + image = (ImageLoader*)handle; + if ( dyld::validImage(image) ) { + ImageLoader* foundIn; + sym = image->findExportedSymbol(underscoredName, NULL, true, &foundIn); + if ( sym != NULL ) { + return (void*)(foundIn->getExportedSymbolAddress(sym)); + } + sym = image->resolveSymbol(underscoredName, false, &image);// search what image links against + if ( sym != NULL ) { + return (void*)image->getExportedSymbolAddress(sym); + } + const char* format = "dlsym(%p, %s): symbol not found"; + char temp[strlen(format)+strlen(symbolName)+20]; + sprintf(temp, format, handle, symbolName); + dlerrorSet(temp); + } + else { + dlerrorSet("invalid handle passed to dlsym()"); + } + return NULL; +} + + +#define UPDATE_PREBINDING_DRY_RUN 0x00000001 +#define UPDATE_PREBINDING_PROGRESS 0x00000002 + +// +// SPI called only by update_prebinding tool to redo prebinding in all prebound files specified +// There must be no dylibs loaded when this fnction is called. +// +__attribute__((noreturn)) +static void _dyld_update_prebinding(int pathCount, const char* paths[], uint32_t flags) +{ + if ( dyld::gLogAPIs ) + fprintf(stderr, "%s()\n", __func__); + + // list of requested dylibs actually loaded + std::vector preboundImages; + + try { + // verify no dylibs loaded + if ( dyld::getImageCount() != 1 ) + throw "_dyld_update_prebinding cannot be called with dylib already loaded"; + + const uint32_t max_allowed_link_errors = 10; + uint32_t link_error_count = 0; + + // load and link each dylib + for (int i=0; i < pathCount; ++i) { + dyld::LoadContext context; + context.useSearchPaths = false; + context.matchByInstallName = true; + context.dontLoad = false; + context.mustBeBundle = false; + context.mustBeDylib = true; + context.origin = NULL; // @loader_path not allowed in prebinding list + context.rpath = NULL; // support not yet implemented + + ImageLoader* image = NULL; + try { + image = dyld::load(paths[i], context); + // bind lazy and non-lazy symbols, but don't run initializers + // this may bring in other dylibs later in the list or missing from list, but that is ok + dyld::link(image, ImageLoader::kLazyAndNonLazy, ImageLoader::kDontRunInitializers); + // recored images we successfully loaded + preboundImages.push_back(image); + } + catch (const char* msg) { + if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) { + const char *stage; + if ( image == NULL ) // load exception + stage = "load"; + else // link exception + stage = "link"; + fprintf(stderr, "update_prebinding: warning: could not %s %s: %s\n", stage, paths[i], msg); + } + if ( image != NULL ) + link_error_count++; + if ( link_error_count > max_allowed_link_errors ) + throw; + } + } + + // find missing images + uint32_t loadedImageCount = dyld::getImageCount(); + if ( loadedImageCount > (preboundImages.size()+1) ) { + if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) + fprintf(stderr, "update_prebinding: warning: the following dylibs were loaded but will not have their prebinding updated because they are not in the list of paths to reprebind\n"); + for (uint32_t i=1; i < loadedImageCount; ++i) { + ImageLoader* target = dyld::getIndexedImage(i); + bool found = false; + for (std::vector::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) { + if ( *it == target ) { + found = true; + break; + } + } + if ( !found ) + if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) + fprintf(stderr, " %s\n", target->getPath()); + } + } + + // warn about unprebound files in the list + bool unpreboundWarned = false; + for (std::vector::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) { + if ( ! (*it)->isPrebindable() && (*it != dyld::mainExecutable()) ) { + if ( ! unpreboundWarned ) { + if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) + fprintf(stderr, "update_prebinding: warning: the following dylibs were specified but were not built prebound\n"); + unpreboundWarned = true; + } + if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) + fprintf(stderr, " %s\n", (*it)->getPath()); + } + } + + if(UPDATE_PREBINDING_DRY_RUN & flags) { + fprintf(stderr, "update_prebinding: dry-run: no changes were made to the filesystem.\n"); + } + else { + uint32_t imageCount = preboundImages.size(); + uint32_t imageNumber = 1; + // tell each image to write itself out re-prebound + struct timeval currentTime = { 0 , 0 }; + gettimeofday(¤tTime, NULL); + time_t timestamp = currentTime.tv_sec; + for (std::vector::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) { + (*it)->reprebind(dyld::gLinkContext, timestamp); + if(UPDATE_PREBINDING_PROGRESS & flags) { + fprintf(stdout, "update_prebinding: progress: %3u/%u\n", imageNumber, imageCount); + fflush(stdout); + imageNumber++; + } + } + + // tell file system to flush all dirty buffers to disk + // after this sync, all the _redoprebinding files will be on disk + sync(); + + // now commit (swap file) for each re-prebound image + // this only updates directories, since the files have already been flushed by previous sync() + for (std::vector::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) { + (*it)->reprebindCommit(dyld::gLinkContext, true); + } + + // tell file system to flush all dirty buffers to disk + // this should flush out all directory changes caused by the file swapping + sync(); + } + } + catch (const char* msg) { + // delete temp files + try { + for (std::vector::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) { + (*it)->reprebindCommit(dyld::gLinkContext, false); + } + } + catch (const char* commitMsg) { + fprintf(stderr, "update_prebinding: error: %s\n", commitMsg); + } + fprintf(stderr, "update_prebinding: error: %s\n", msg); + exit(1); + } + exit(0); +} + + + +static const struct dyld_all_image_infos* _dyld_get_all_image_infos() +{ + return &dyld_all_image_infos; +} + + + + + + + + diff --git a/src/dyldAPIsInLibSystem.cpp b/src/dyldAPIsInLibSystem.cpp new file mode 100644 index 0000000..67f4eb7 --- /dev/null +++ b/src/dyldAPIsInLibSystem.cpp @@ -0,0 +1,1133 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include + +#include "mach-o/dyld.h" +#include "mach-o/dyld_priv.h" + +#include "dyldLock.h" + +/* + * names_match() takes an install_name from an LC_LOAD_DYLIB command and a + * libraryName (which is -lx or -framework Foo argument passed to the static + * link editor for the same library) and determines if they match. This depends + * on conventional use of names including major versioning. + */ +static +bool +names_match( +char *install_name, +const char* libraryName) +{ + char *basename; + unsigned long n; + + /* + * Conventional install names have these forms: + * /System/Library/Frameworks/AppKit.framework/Versions/A/Appkit + * /Local/Library/Frameworks/AppKit.framework/Appkit + * /lib/libsys_s.A.dylib + * /usr/lib/libsys_s.dylib + */ + basename = strrchr(install_name, '/'); + if(basename == NULL) + basename = install_name; + else + basename++; + + /* + * By checking the base name matching the library name we take care + * of the -framework cases. + */ + if(strcmp(basename, libraryName) == 0) + return(TRUE); + + /* + * Now check the base name for "lib" if so proceed to check for the + * -lx case dealing with a possible .X.dylib and a .dylib extension. + */ + if(strncmp(basename, "lib", 3) ==0){ + n = strlen(libraryName); + if(strncmp(basename+3, libraryName, n) == 0){ + if(strncmp(basename+3+n, ".dylib", 6) == 0) + return(TRUE); + if(basename[3+n] == '.' && + basename[3+n+1] != '\0' && + strncmp(basename+3+n+2, ".dylib", 6) == 0) + return(TRUE); + } + } + return(FALSE); +} + +void NSInstallLinkEditErrorHandlers( +const NSLinkEditErrorHandlers* handlers) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)( + void (*undefined)(const char* symbol_name), + NSModule (*multiple)(NSSymbol s, NSModule old, NSModule newhandler), + void (*linkEdit)(NSLinkEditErrors c, int errorNumber, + const char* fileName, const char* errorString)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_install_handlers", (void**)&p); + p(handlers->undefined, handlers->multiple, handlers->linkEdit); +} + +const char* +NSNameOfModule( +NSModule module) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static const char* (*p)(NSModule module) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSNameOfModule", (void**)&p); + return(p(module)); +} + +const char* +NSLibraryNameForModule( +NSModule module) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static const char* (*p)(NSModule module) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLibraryNameForModule", (void**)&p); + return(p(module)); +} + +bool +NSIsSymbolNameDefined( +const char* symbolName) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(const char* symbolName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSIsSymbolNameDefined", (void**)&p); + return(p(symbolName)); +} + +bool +NSIsSymbolNameDefinedWithHint( +const char* symbolName, +const char* libraryNameHint) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(const char* symbolName, + const char* libraryNameHint) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedWithHint", (void**)&p); + return(p(symbolName, libraryNameHint)); +} + +bool +NSIsSymbolNameDefinedInImage( +const struct mach_header *image, +const char* symbolName) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(const struct mach_header *image, + const char* symbolName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", (void**)&p); + return(p(image, symbolName)); +} + +NSSymbol +NSLookupAndBindSymbol( +const char* symbolName) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSSymbol (*p)(const char* symbolName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLookupAndBindSymbol", (void**)&p); + return(p(symbolName)); +} + +NSSymbol +NSLookupAndBindSymbolWithHint( +const char* symbolName, +const char* libraryNameHint) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSSymbol (*p)(const char* symbolName, + const char* libraryNameHint) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLookupAndBindSymbolWithHint", (void**)&p); + return(p(symbolName, libraryNameHint)); +} + +NSSymbol +NSLookupSymbolInModule( +NSModule module, +const char* symbolName) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static NSSymbol (*p)(NSModule module, const char* symbolName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLookupSymbolInModule", (void**)&p); + return(p(module, symbolName)); +} + +NSSymbol +NSLookupSymbolInImage( +const struct mach_header *image, +const char* symbolName, +uint32_t options) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static NSSymbol (*p)(const struct mach_header *image, + const char* symbolName, + uint32_t options) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void**)&p); + return(p(image, symbolName, options)); +} + +const char* +NSNameOfSymbol( +NSSymbol symbol) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static char * (*p)(NSSymbol symbol) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSNameOfSymbol",(void**)&p); + return(p(symbol)); +} + +void * +NSAddressOfSymbol( +NSSymbol symbol) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void * (*p)(NSSymbol symbol) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSAddressOfSymbol", (void**)&p); + return(p(symbol)); +} + +NSModule +NSModuleForSymbol( +NSSymbol symbol) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static NSModule (*p)(NSSymbol symbol) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSModuleForSymbol", (void**)&p); + return(p(symbol)); +} + +bool +NSAddLibrary( +const char* pathName) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static bool (*p)(const char* pathName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSAddLibrary", (void**)&p); + return(p(pathName)); +} + +bool +NSAddLibraryWithSearching( +const char* pathName) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static bool (*p)(const char* pathName) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSAddLibraryWithSearching", (void**)&p); + return(p(pathName)); +} + +const struct mach_header * +NSAddImage( +const char* image_name, +uint32_t options) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static const struct mach_header * (*p)(const char* image_name, + uint32_t options) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSAddImage", (void**)&p); + return(p(image_name, options)); +} + +/* + * This routine returns the current version of the named shared library the + * executable it was built with. The libraryName parameter is the same as the + * -lx or -framework Foo argument passed to the static link editor when building + * the executable (with -lx it would be "x" and with -framework Foo it would be + * "Foo"). If this the executable was not built against the specified library + * it returns -1. It should be noted that if this only returns the value the + * current version of the named shared library the executable was built with + * and not a list of current versions that dependent libraries and bundles the + * program is using were built with. + */ +int32_t +NSVersionOfLinkTimeLibrary( +const char* libraryName) +{ + unsigned long i; + struct load_command *load_commands, *lc; + struct dylib_command *dl; + char *install_name; +#ifndef __OPENSTEP__ + static struct mach_header *mh = NULL; + if(mh == NULL) + mh = _NSGetMachExecuteHeader(); +#else /* defined(__OPENSTEP__) */ +#ifdef __DYNAMIC__ + static struct mach_header *mh = NULL; + if(mh == NULL) + _dyld_lookup_and_bind("__mh_execute_header", &mh, NULL); +#else + struct mach_header *mh; + mh = (struct mach_header *)&_mh_execute_header; +#endif +#endif /* __OPENSTEP__ */ + load_commands = (struct load_command *) + ((char *)mh + sizeof(struct mach_header)); + lc = load_commands; + for(i = 0; i < mh->ncmds; i++){ + if(lc->cmd == LC_LOAD_DYLIB){ + dl = (struct dylib_command *)lc; + install_name = (char *)dl + dl->dylib.name.offset; + if(names_match(install_name, libraryName) == TRUE) + return(dl->dylib.current_version); + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + return(-1); +} + +/* + * This routine returns the current version of the named shared library the + * program it is running against. The libraryName parameter is the same as + * would be static link editor using the -lx or -framework Foo flags (with -lx + * it would be "x" and with -framework Foo it would be "Foo"). If the program + * is not using the specified library it returns -1. + */ +int32_t +NSVersionOfRunTimeLibrary( +const char* libraryName) +{ + unsigned long i, j, n; + char *install_name; + struct load_command *load_commands, *lc; + struct dylib_command *dl; + const struct mach_header *mh; + + n = _dyld_image_count(); + for(i = 0; i < n; i++){ + mh = _dyld_get_image_header(i); + if(mh->filetype != MH_DYLIB) + continue; + load_commands = (struct load_command *) + ((char *)mh + sizeof(struct mach_header)); + lc = load_commands; + for(j = 0; j < mh->ncmds; j++){ + if(lc->cmd == LC_ID_DYLIB){ + dl = (struct dylib_command *)lc; + install_name = (char *)dl + dl->dylib.name.offset; + if(names_match(install_name, libraryName) == TRUE) + return(dl->dylib.current_version); + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + } + return(-1); +} + +/* + * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the + * specified file name if the file is a correct Mach-O file that can be loaded + * with NSloadModule(). For return codes of NSObjectFileImageFailure and + * NSObjectFileImageFormat an error message is printed to stderr. All + * other codes cause no printing. + */ +NSObjectFileImageReturnCode +NSCreateObjectFileImageFromFile( +const char* pathName, +NSObjectFileImage *objectFileImage) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromFile", (void**)&p); + return p(pathName, objectFileImage); +} + + +/* + * NSCreateObjectFileImageFromMemory() creates an NSObjectFileImage for the + * object file mapped into memory at address of size length if the object file + * is a correct Mach-O file that can be loaded with NSloadModule(). For return + * codes of NSObjectFileImageFailure and NSObjectFileImageFormat an error + * message is printed to stderr. All other codes cause no printing. + */ +NSObjectFileImageReturnCode +NSCreateObjectFileImageFromMemory( +const void* address, +size_t size, +NSObjectFileImage *objectFileImage) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSObjectFileImageReturnCode (*p)(const void*, size_t, NSObjectFileImage*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSCreateObjectFileImageFromMemory", (void**)&p); + return p(address, size, objectFileImage); +} + +/* + * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the + * specified core file name if the file is a correct Mach-O core file. + * For return codes of NSObjectFileImageFailure and NSObjectFileImageFormat + * an error message is printed to stderr. All other codes cause no printing. + */ +NSObjectFileImageReturnCode +NSCreateCoreFileImageFromFile( +const char* pathName, +NSObjectFileImage *objectFileImage) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSCreateCoreFileImageFromFile", (void**)&p); + return p(pathName, objectFileImage); +} + +bool +NSDestroyObjectFileImage( +NSObjectFileImage objectFileImage) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static bool (*p)(NSObjectFileImage) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSDestroyObjectFileImage", (void**)&p); + return p(objectFileImage); +} + + +NSModule +NSLinkModule( +NSObjectFileImage objectFileImage, +const char* moduleName, +uint32_t options) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static NSModule (*p)(NSObjectFileImage, const char*, unsigned long) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSLinkModule", (void**)&p); + + return p(objectFileImage, moduleName, options); +} + + +/* + * NSFindSectionAndOffsetInObjectFileImage() takes the specified imageOffset + * into the specified ObjectFileImage and returns the segment/section name and + * offset into that section of that imageOffset. Returns FALSE if the + * imageOffset is not in any section. You can used the resulting sectionOffset + * to index into the data returned by NSGetSectionDataInObjectFileImage. + * + * SPI: currently only used by ZeroLink to detect +load methods + */ +bool +NSFindSectionAndOffsetInObjectFileImage( +NSObjectFileImage objectFileImage, +unsigned long imageOffset, +const char** segmentName, /* can be NULL */ +const char** sectionName, /* can be NULL */ +unsigned long* sectionOffset) /* can be NULL */ +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(NSObjectFileImage, unsigned long, const char**, const char**, unsigned long*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSFindSectionAndOffsetInObjectFileImage", (void**)&p); + + return p(objectFileImage, imageOffset, segmentName, sectionName, sectionOffset); +} + + +/* + * NSSymbolDefinitionCountInObjectFileImage() returns the number of symbol + * definitions in the NSObjectFileImage. + */ +uint32_t +NSSymbolDefinitionCountInObjectFileImage( +NSObjectFileImage objectFileImage) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static unsigned long (*p)(NSObjectFileImage) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSSymbolDefinitionCountInObjectFileImage", (void**)&p); + + return p(objectFileImage); +} + +/* + * NSSymbolDefinitionNameInObjectFileImage() returns the name of the i'th + * symbol definitions in the NSObjectFileImage. If the ordinal specified is + * outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will + * be returned. + */ +const char* +NSSymbolDefinitionNameInObjectFileImage( +NSObjectFileImage objectFileImage, +uint32_t ordinal) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static const char* (*p)(NSObjectFileImage, uint32_t) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSSymbolDefinitionNameInObjectFileImage", (void**)&p); + + return p(objectFileImage, ordinal); +} + +/* + * NSSymbolReferenceCountInObjectFileImage() returns the number of references + * to undefined symbols the NSObjectFileImage. + */ +uint32_t +NSSymbolReferenceCountInObjectFileImage( +NSObjectFileImage objectFileImage) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static unsigned long (*p)(NSObjectFileImage) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSSymbolReferenceCountInObjectFileImage", (void**)&p); + + return p(objectFileImage); +} + +/* + * NSSymbolReferenceNameInObjectFileImage() returns the name of the i'th + * undefined symbol in the NSObjectFileImage. If the ordinal specified is + * outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be + * returned. + */ +const char* +NSSymbolReferenceNameInObjectFileImage( +NSObjectFileImage objectFileImage, +uint32_t ordinal, +bool *tentative_definition) /* can be NULL */ +{ + DYLD_READER_LOCK_THIS_BLOCK; + static const char* (*p)(NSObjectFileImage, uint32_t, bool*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSSymbolReferenceNameInObjectFileImage", (void**)&p); + + return p(objectFileImage, ordinal, tentative_definition); +} + +/* + * NSIsSymbolDefinedInObjectFileImage() returns TRUE if the specified symbol + * name has a definition in the NSObjectFileImage and FALSE otherwise. + */ +bool +NSIsSymbolDefinedInObjectFileImage( +NSObjectFileImage objectFileImage, +const char* symbolName) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(NSObjectFileImage, const char*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSIsSymbolDefinedInObjectFileImage", (void**)&p); + + return p(objectFileImage, symbolName); +} + +/* + * NSGetSectionDataInObjectFileImage() returns a pointer to the section contents + * in the NSObjectFileImage for the specified segmentName and sectionName if + * it exists and it is not a zerofill section. If not it returns NULL. If + * the parameter size is not NULL the size of the section is also returned + * indirectly through that pointer. + */ +void * +NSGetSectionDataInObjectFileImage( +NSObjectFileImage objectFileImage, +const char* segmentName, +const char* sectionName, +unsigned long *size) /* can be NULL */ +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void* (*p)(NSObjectFileImage, const char*, const char*, unsigned long*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSGetSectionDataInObjectFileImage", (void**)&p); + + return p(objectFileImage, segmentName, sectionName, size); +} + +/* + * NSHasModInitObjectFileImage() returns TRUE if the NSObjectFileImage has any + * module initialization sections and FALSE it it does not. + * + * SPI: currently only used by ZeroLink to detect C++ initializers + */ +bool +NSHasModInitObjectFileImage( +NSObjectFileImage objectFileImage) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(NSObjectFileImage) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_NSHasModInitObjectFileImage", (void**)&p); + + return p(objectFileImage); +} + +void +NSLinkEditError( +NSLinkEditErrors *c, +int *errorNumber, +const char* *fileName, +const char* *errorString) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(NSLinkEditErrors *c, + int *errorNumber, + const char* *fileName, + const char* *errorString) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_link_edit_error", (void**)&p); + if(p != NULL) + p(c, errorNumber, fileName, errorString); +} + +bool +NSUnLinkModule( +NSModule module, +uint32_t options) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static bool (*p)(NSModule module, uint32_t options) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_unlink_module", (void**)&p); + + return p(module, options); +} + +NSModule +NSReplaceModule( +NSModule moduleToReplace, +NSObjectFileImage newObjectFileImage, +uint32_t options) +{ + return(NULL); +} + +/* + *_NSGetExecutablePath copies the path of the executable into the buffer and + * returns 0 if the path was successfully copied in the provided buffer. If the + * buffer is not large enough, -1 is returned and the expected buffer size is + * copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to + * the executable not a "real path" to the executable. That is the path may be + * a symbolic link and not the real file. And with deep directories the total + * bufsize needed could be more than MAXPATHLEN. + */ +int +_NSGetExecutablePath( +char *buf, +uint32_t *bufsize) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static int (*p)(char *buf, uint32_t *bufsize) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld__NSGetExecutablePath", (void**)&p); + return(p(buf, bufsize)); +} + +void +_dyld_lookup_and_bind( +const char* symbol_name, +void** address, +NSModule* module) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(const char*, void** , NSModule*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_lookup_and_bind", (void**)&p); + p(symbol_name, address, module); +} + +void +_dyld_lookup_and_bind_with_hint( +const char* symbol_name, +const char* library_name_hint, +void** address, +NSModule* module) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(const char*, const char*, void**, NSModule*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_lookup_and_bind_with_hint", (void**)&p); + p(symbol_name, library_name_hint, address, module); +} + +void +_dyld_lookup_and_bind_objc( +const char* symbol_name, +void** address, +NSModule* module) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(const char* , void**, NSModule*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_lookup_and_bind_objc", (void**)&p); + p(symbol_name, address, module); +} + +void +_dyld_lookup_and_bind_fully( +const char* symbol_name, +void** address, +NSModule* module) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(const char*, void**, NSModule*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_lookup_and_bind_fully", (void**)&p); + p(symbol_name, address, module); +} + +bool +_dyld_bind_fully_image_containing_address( +const void* address) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static bool (*p)(const void*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_bind_fully_image_containing_address", (void**)&p); + return p(address); +} + + +/* + * _dyld_register_func_for_add_image registers the specified function to be + * called when a new image is added (a bundle or a dynamic shared library) to + * the program. When this function is first registered it is called for once + * for each image that is currently part of the program. + */ +void +_dyld_register_func_for_add_image( +void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p); + p(func); +} + +/* + * _dyld_register_func_for_remove_image registers the specified function to be + * called when an image is removed (a bundle or a dynamic shared library) from + * the program. + */ +void +_dyld_register_func_for_remove_image( +void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_register_func_for_remove_image", (void**)&p); + p(func); +} + +/* + * _dyld_register_func_for_link_module registers the specified function to be + * called when a module is bound into the program. When this function is first + * registered it is called for once for each module that is currently bound into + * the program. + */ +void +_dyld_register_func_for_link_module( +void (*func)(NSModule module)) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(void (*func)(NSModule module)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_register_func_for_link_module", (void**)&p); + p(func); +} + +/* + * _dyld_register_func_for_unlink_module registers the specified function to be + * called when a module is unbound from the program. + */ +void +_dyld_register_func_for_unlink_module( +void (*func)(NSModule module)) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(void (*func)(NSModule module)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_register_func_for_unlink_module", (void**)&p); + p(func); +} + +/* + * _dyld_register_func_for_replace_module registers the specified function to be + * called when a module is to be replace with another module in the program. + */ +void +_dyld_register_func_for_replace_module( +void (*func)(NSModule oldmodule, NSModule newmodule)) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void (*p)(void (*func)(NSModule oldmodule, + NSModule newmodule)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_register_func_for_replace_module", (void**)&p); + p(func); +} + + +/* + * _dyld_get_objc_module_sect_for_module is passed a module and sets a + * pointer to the (__OBJC,__module) section and its size for the specified + * module. + */ +void +_dyld_get_objc_module_sect_for_module( +NSModule module, +void **objc_module, +unsigned long *size) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void (*p)(NSModule module, + void **objc_module, + unsigned long *size) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_objc_module_sect_for_module", (void**)&p); + p(module, objc_module, size); +} + +/* + * _dyld_bind_objc_module() is passed a pointer to something in an (__OBJC, + * __module) section and causes the module that is associated with that address + * to be bound. + */ +void +_dyld_bind_objc_module( +const void* objc_module) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void (*p)(const void *objc_module) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_bind_objc_module", (void**)&p); + p(objc_module); +} + + +#if __DYNAMIC__ +bool +_dyld_present( +void) +{ + // hmmm, this code is in libSystem.dylib, which is loaded by dyld... + return true; +} +#endif + +uint32_t +_dyld_image_count( +void) +{ + DYLD_NO_LOCK_THIS_BLOCK; + static unsigned long (*p)(void) = NULL; + + if(_dyld_present() == 0) + return(0); + if(p == NULL) + _dyld_func_lookup("__dyld_image_count", (void**)&p); + return(p()); +} + +const struct mach_header * +_dyld_get_image_header( +uint32_t image_index) +{ + DYLD_NO_LOCK_THIS_BLOCK; + static struct mach_header * (*p)(uint32_t image_index) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_image_header", (void**)&p); + return(p(image_index)); +} + +intptr_t +_dyld_get_image_vmaddr_slide( +uint32_t image_index) +{ + DYLD_NO_LOCK_THIS_BLOCK; + static unsigned long (*p)(uint32_t image_index) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_image_vmaddr_slide", (void**)&p); + return(p(image_index)); +} + +const char* +_dyld_get_image_name( +uint32_t image_index) +{ + DYLD_NO_LOCK_THIS_BLOCK; + static const char* (*p)(uint32_t image_index) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_image_name", (void**)&p); + return(p(image_index)); +} + +bool +_dyld_image_containing_address( +const void* address) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(const void*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_image_containing_address", (void**)&p); + return(p(address)); +} + +const struct mach_header * +_dyld_get_image_header_containing_address( +const void* address) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static const struct mach_header * (*p)(const void*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_image_header_containing_address", (void**)&p); + return p(address); +} + +void _dyld_moninit( +void (*monaddition)(char *lowpc, char *highpc)) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void (*p)(void (*monaddition)(char *lowpc, char *highpc)) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_moninit", (void**)&p); + p(monaddition); +} + +bool _dyld_launched_prebound( +void) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(void) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_launched_prebound", (void**)&p); + return(p()); +} + +bool _dyld_all_twolevel_modules_prebound( +void) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static bool (*p)(void) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_all_twolevel_modules_prebound", (void**)&p); + return(p()); +} + + +#include +#include +#include +#include +#include +#include "dyldLock.h" +#include "dyldLibSystemThreadHelpers.h" + +// pthread key used to access per-thread dlerror message +static pthread_key_t dlerrorPerThreadKey; + +// data kept per-thread +struct dlerrorPerThreadData +{ + uint32_t sizeAllocated; + char message[1]; +}; + +// function called by dyld to get buffer to store dlerror message +static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired) +{ + const int size = (sizeRequired < 256) ? 256 : sizeRequired; + dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey); + if ( data == NULL ) { + //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); + const int mallocSize = sizeof(dlerrorPerThreadData)+size; + data = (dlerrorPerThreadData*)malloc(mallocSize); + data->sizeAllocated = size; + pthread_setspecific(dlerrorPerThreadKey, data); + } + else if ( data->sizeAllocated < sizeRequired ) { + free(data); + //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); + const int mallocSize = sizeof(dlerrorPerThreadData)+size; + data = (dlerrorPerThreadData*)malloc(mallocSize); + data->sizeAllocated = size; + pthread_setspecific(dlerrorPerThreadKey, data); + } + return data->message; +} + +// that table passed to dyld containing thread helpers +static dyld::ThreadingHelpers sThreadHelpers = { 1, &lockForLazyBinding, &unlockForLazyBinding, &getPerThreadBufferFor_dlerror }; + +// +// during initialization of libSystem this routine will run +// and call dyld, registering the threading helpers. +// +// +static int registerWithDyld() +{ + static void (*p)(dyld::ThreadingHelpers*) = NULL; + + // create key and tell pthread package to call free() on any data associated with key if thread dies + pthread_key_create(&dlerrorPerThreadKey, &free); + + if(p == NULL) + _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p); + if(p != NULL) + p(&sThreadHelpers); + + return 0; +} + +// should be able to use __attribute__((constructor)) on registerWithDyld, but compiler has bug (3679135) +// instead use initialization of global to force it to run. +static int hack = registerWithDyld(); + + +char* dlerror() +{ + DYLD_READER_LOCK_THIS_BLOCK; + static char* (*p)() = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_dlerror", (void**)&p); + return(p()); +} + +int dladdr(const void* addr, Dl_info* info) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static int (*p)(const void* , Dl_info*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_dladdr", (void**)&p); + return(p(addr, info)); +} + +int dlclose(void* handle) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static int (*p)(void* handle) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_dlclose", (void**)&p); + return(p(handle)); +} + +void* dlopen(const char* path, int mode) +{ + DYLD_WRITER_LOCK_THIS_BLOCK; + static void* (*p)(const char* path, int) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_dlopen", (void**)&p); + return(p(path, mode)); +} + +void* dlsym(void* handle, const char* symbol) +{ + DYLD_READER_LOCK_THIS_BLOCK; + static void* (*p)(void* handle, const char* symbol) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_dlsym", (void**)&p); + return(p(handle, symbol)); +} + + + + + diff --git a/src/dyldExceptions.c b/src/dyldExceptions.c new file mode 100644 index 0000000..39b0606 --- /dev/null +++ b/src/dyldExceptions.c @@ -0,0 +1,212 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include + +// +// BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c +// +#define KEYMGR_API_MAJOR_GCC3 3 +/* ... with these keys. */ +#define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */ +#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */ +#define KEYMGR_EH_GLOBALS_KEY 13 + +/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */ +struct live_images { + unsigned long this_size; /* sizeof (live_images) */ + struct mach_header *mh; /* the image info */ + unsigned long vm_slide; + void (*destructor)(struct live_images *); /* destructor for this */ + struct live_images *next; + unsigned int examined_p; + void *fde; + void *object_info; + unsigned long info[2]; /* Future use. */ +}; +// +// END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c +// + + +// +// dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc. +// +// In order for C++ exceptions to work within dyld, the C++ exception handling code +// must be able to find the exception handling frame data inside dyld. The standard +// exception handling code uses crt and keymgr to keep track of all images and calls +// getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement +// our own copy of those functions below to enable exceptions within dyld. +// +// Note: This exception handling is completely separate from any user code exception . +// handling which has its own keymgr (in libSystem). +// + + +static struct live_images sDyldImage; // zero filled +static void* sObjectList = NULL; +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) +static void* sEHGlobals = NULL; +#endif + + +// called by dyldStartup.s very early +void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide) +{ + sDyldImage.this_size = sizeof(struct live_images); + sDyldImage.mh = mh; + sDyldImage.vm_slide = slide; +} + + + +// Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) +typedef struct Sinfo_Node { + uint32_t size; /* Size of this node. */ + uint16_t major_version; /* API major version. */ + uint16_t minor_version; /* API minor version. */ +} Tinfo_Node; +static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 }; +const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info }; +#endif + +static __attribute__((noreturn)) +void dyld_abort() +{ + fprintf(stderr, "internal dyld error\n"); + abort(); +} + +void* _keymgr_get_and_lock_processwide_ptr(unsigned int key) +{ + // The C++ exception handling code uses two keys. No other keys should be seen + if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) { + return &sDyldImage; + } + else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) { + return sObjectList; + } + dyld_abort(); +} + +void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value) +{ + // The C++ exception handling code uses just this key. No other keys should be seen + if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) { + sObjectList = value; + return; + } + dyld_abort(); +} + +void _keymgr_unlock_processwide_ptr(unsigned int key) +{ + // The C++ exception handling code uses just this key. No other keys should be seen + if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) { + return; + } + dyld_abort(); +} + +void* _keymgr_get_per_thread_data(unsigned int key) +{ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) + // gcc 3.5 and later use this key + if ( key == KEYMGR_EH_GLOBALS_KEY ) + return sEHGlobals; +#endif + + // used by std::termination which dyld does not use + dyld_abort(); +} + +void _keymgr_set_per_thread_data(unsigned int key, void *keydata) +{ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) + // gcc 3.5 and later use this key + if ( key == KEYMGR_EH_GLOBALS_KEY ) { + sEHGlobals = keydata; + return; + } +#endif + // used by std::termination which dyld does not use + dyld_abort(); +} + +#if __LP64__ + #define LC_SEGMENT_COMMAND LC_SEGMENT_64 + #define macho_header mach_header_64 + #define macho_segment_command segment_command_64 + #define macho_section section_64 + #define getsectdatafromheader getsectdatafromheader_64 +#else + #define LC_SEGMENT_COMMAND LC_SEGMENT + #define macho_header mach_header + #define macho_segment_command segment_command + #define macho_section section +#endif + +// needed by C++ exception handling code to find __eh_frame section +const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size) +{ + const struct load_command* cmd; + unsigned long i; + + cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header)); + for(i = 0; i < mh->ncmds; i++) { + if ( cmd->cmd == LC_SEGMENT_COMMAND ) { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + if ( strcmp(seg->segname, segname) == 0 ) { + const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) ); + unsigned long j; + for (j = 0; j < seg->nsects; j++) { + if ( strcmp(sect[j].sectname, sectname) == 0 ) { + *size = sect[j].size; + return (void*)(sect[j].addr); + } + } + } + } + cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize ); + } + return NULL; +} + + +// Hack for transition of rdar://problem/3933738 +// Can be removed later. +// Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64 +#if __ppc64__ + #undef getsectdatafromheader + const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size) + { + return getsectdatafromheader_64(mh, segname, sectname, size); + } +#endif + + diff --git a/src/dyldInitialization.cpp b/src/dyldInitialization.cpp new file mode 100644 index 0000000..8491e7e --- /dev/null +++ b/src/dyldInitialization.cpp @@ -0,0 +1,256 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#if __ppc__ || __ppc64__ + #include +#endif +#include "dyld.h" + +#if __LP64__ + #define macho_header mach_header_64 + #define LC_SEGMENT_COMMAND LC_SEGMENT_64 + #define macho_segment_command segment_command_64 + #define macho_section section_64 + #define RELOC_SIZE 3 +#else + #define macho_header mach_header + #define LC_SEGMENT_COMMAND LC_SEGMENT + #define macho_segment_command segment_command + #define macho_section section + #define RELOC_SIZE 2 +#endif + + +// +// Code to bootstrap dyld into a runnable state +// +// + +namespace dyldbootstrap { + + +typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]); + +// +// For a regular executable, the crt code calls dyld to run the executables initializers. +// For a static executable, crt directly runs the initializers. +// dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers. +// We pass argc, argv, etc in case libc.a uses those arguments +// +static void runDyldInitializers(const struct macho_header* mh, intptr_t slide, int argc, const char* argv[], const char* envp[], const char* apple[]) +{ + const uint32_t cmd_count = mh->ncmds; + const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + const uint8_t type = sect->flags & SECTION_TYPE; + if ( type == S_MOD_INIT_FUNC_POINTERS ){ + Initializer* inits = (Initializer*)(sect->addr + slide); + const uint32_t count = sect->size / sizeof(uintptr_t); + for (uint32_t i=0; i < count; ++i) { + Initializer func = inits[i]; + func(argc, argv, envp, apple); + } + } + } + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } +} + + +// +// If the kernel does not load dyld at its preferred address, we need to apply +// fixups to various initialized parts of the __DATA segment +// +static void rebaseDyld(const struct macho_header* mh, intptr_t slide) +{ + // get interesting pointers into dyld + const uint32_t cmd_count = mh->ncmds; + const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); + const struct load_command* cmd = cmds; + const struct macho_segment_command* linkEditSeg = NULL; + const struct dysymtab_command* dynamicSymbolTable = NULL; + const struct macho_section* nonLazySection = NULL; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) + linkEditSeg = seg; + const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); + const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; + for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { + const uint8_t type = sect->flags & SECTION_TYPE; + if ( type == S_NON_LAZY_SYMBOL_POINTERS ) + nonLazySection = sect; + } + } + break; + case LC_DYSYMTAB: + dynamicSymbolTable = (struct dysymtab_command *)cmd; + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + + // use reloc's to rebase all random data pointers + const uintptr_t relocBase = (uintptr_t)mh; + const relocation_info* const relocsStart = (struct relocation_info*)(linkEditSeg->vmaddr + slide + dynamicSymbolTable->locreloff - linkEditSeg->fileoff); + const relocation_info* const relocsEnd = &relocsStart[dynamicSymbolTable->nlocrel]; + for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + if ( (reloc->r_address & R_SCATTERED) == 0 ) { + if (reloc->r_length == RELOC_SIZE) { + switch(reloc->r_type) { + case GENERIC_RELOC_VANILLA: + *((uintptr_t*)(reloc->r_address + relocBase)) += slide; + break; + } + } + } + else { + const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; + if (sreloc->r_length == RELOC_SIZE) { + uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase); + switch(sreloc->r_type) { + case GENERIC_RELOC_VANILLA: + #if __ppc__ || __ppc64__ + case PPC_RELOC_PB_LA_PTR: + #elif __i386__ + case GENERIC_RELOC_PB_LA_PTR: + #endif + // Note the use of PB_LA_PTR is unique here. Seems like ld should strip out all lazy pointers + // but it does not. But, since all lazy-pointers point within dyld, they can be slid too + *locationToFix += slide; + break; + } + } + } + } + + // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) + if ( nonLazySection != NULL ) { + const uint32_t pointerCount = nonLazySection->size / sizeof(uintptr_t); + uintptr_t* const symbolPointers = (uintptr_t*)(nonLazySection->addr + slide); + for (uint32_t j=0; j < pointerCount; ++j) { + symbolPointers[j] += slide; + } + } + + +} + +// +// For some reason the kernel loads dyld with __TEXT and __LINKEDIT writable +// rdar://problem/3702311 +// +static void segmentProtectDyld(const struct macho_header* mh, intptr_t slide) +{ + const uint32_t cmd_count = mh->ncmds; + const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); + const struct load_command* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd) { + case LC_SEGMENT_COMMAND: + { + const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; + vm_address_t addr = seg->vmaddr + slide; + vm_size_t size = seg->vmsize; + const bool setCurrentPermissions = false; + vm_protect(mach_task_self(), addr, size, setCurrentPermissions, seg->initprot); + //fprintf(stderr, "dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot); + } + break; + } + cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); + } + +} + +extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp +extern "C" void mach_init(); + +// +// This is code to bootstrap dyld. This work in normally done for a program by dyld and crt. +// In dyld we have to do this manually. +// +uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char* argv[], intptr_t slide) +{ + // _mh_dylinker_header is magic symbol defined by static linker (ld), see + const struct macho_header* dyldsMachHeader = (const struct macho_header*)(((char*)&_mh_dylinker_header)+slide); + + // if kernel had to slide dyld, we need to fix up load sensitive locations + // we have to do this before using any global variables + if ( slide != 0 ) { + rebaseDyld(dyldsMachHeader, slide); + } + + // enable C++ exceptions to work inside dyld + dyld_exceptions_init(dyldsMachHeader, slide); + + // allow dyld to use mach messaging + mach_init(); + + // set protection on segments (has to be done after mach_init) + segmentProtectDyld(dyldsMachHeader, slide); + + // kernel sets up env pointer to be just past end of agv array + const char** envp = &argv[argc+1]; + + // kernel sets up apple pointer to be just past end of envp array + const char** apple = envp; + while(*apple != NULL) { ++apple; } + ++apple; + + // run all C++ initializers inside dyld + runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple); + + // now that we are done bootstrapping dyld, call dyld's main + return dyld::_main(appsMachHeader, argc, argv, envp, apple); +} + + + + +} // end of namespace + + + + diff --git a/src/dyldLibSystemThreadHelpers.h b/src/dyldLibSystemThreadHelpers.h new file mode 100644 index 0000000..ac5e3dc --- /dev/null +++ b/src/dyldLibSystemThreadHelpers.h @@ -0,0 +1,52 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef __DYLDLIBSYSTEMHELPERS__ +#define __DYLDLIBSYSTEMHELPERS__ + +#include + + +namespace dyld { + // + // This file contains the synchronization utilities used by dyld to be thread safe. + // This struct is implemented in in libSystem (where pthreads is available) + // and passed to dyld to use. + // + struct ThreadingHelpers + { + uintptr_t version; + void (*lockForReading)(); + void (*unlockForReading)(); + char* (*getThreadBufferFor_dlerror)(uint32_t sizeRequired); + }; +}; + + + + + +#endif // __DYLDLIBSYSTEMHELPERS__ + diff --git a/src/dyldLock.cpp b/src/dyldLock.cpp new file mode 100644 index 0000000..496ed92 --- /dev/null +++ b/src/dyldLock.cpp @@ -0,0 +1,287 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#include "dyldLock.h" + +// until the reader/writer locks are fully tested, we just use a simple recursive mutex +#define REAL_READER_WRITER_LOCK 0 + + + +// +// This class implements a recursive reader/writer lock. +// Recursive means a thread that has already aquired the lock can re-acquire it. +// The lock allows either: +// a) one "writer" thread to hold lock +// b) multiple "reader" threads to hold +// +// A thread with the writer can acquire a reader lock. +// A thread with a reader lock can acquire a writer lock iff it is the only thread with a reader lock +// +class RecursiveReaderWriterLock +{ +public: + RecursiveReaderWriterLock() __attribute__((visibility("hidden"))); + void initIfNeeded(); + + + void lockForSingleWritingThread() __attribute__((visibility("hidden"))); + void unlockForSingleWritingThread() __attribute__((visibility("hidden"))); + + void lockForMultipleReadingThreads() __attribute__((visibility("hidden"))); + void unlockForMultipleReadingThreads() __attribute__((visibility("hidden"))); + +private: +#if REAL_READER_WRITER_LOCK + struct ThreadRecursionCount { + pthread_t fThread; + uint32_t fCount; + }; + bool writerThreadIsAnyThreadBut(pthread_t thread); + void writerThreadRetain(pthread_t thread); + bool writerThreadRelease(pthread_t thread); + + enum { kMaxReaderThreads = 4 }; + bool readerThreadSetRetain(pthread_t thread); + bool readerThreadSetRelease(pthread_t thread); + bool readerThreadSetContainsAnotherThread(pthread_t thread); + + ThreadRecursionCount fWriterThread; + ThreadRecursionCount fReaderThreads[kMaxReaderThreads]; + pthread_cond_t fLockFree; + pthread_mutex_t fMutex; +#else + pthread_mutex_t fMutex; +#endif + bool fInitialized; // assumes this is statically initialized to false because sLock is static +}; + + +// +// initIfNeeded() is a hack so that when libSystem_debug.dylb is useable. +// The problem is that Objective-C +load methods are called before C++ initialziers are run +// If +load method makes a call into dyld, sLock is not initialized. +// +// The long term solution is for objc and dyld to work more closely together so that instead +// of running all +load methods before all initializers, we run each image's +load then its +// initializers all in bottom up order. +// +// This lazy initialization is not thread safe, but as long as someone does not create a +// new thread in a +load method, the C++ constructor for sLock will be called before main() +// so there will only be one thead. +// +void RecursiveReaderWriterLock::initIfNeeded() +{ + if ( ! fInitialized ) { + pthread_mutexattr_t recursiveMutexAttr; + pthread_mutexattr_init(&recursiveMutexAttr); + pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&fMutex, &recursiveMutexAttr); + #if REAL_READER_WRITER_LOCK + pthread_cond_init(&fLockFree, NULL); + fWriterThread.fThread = NULL; + fWriterThread.fCount = 0; + for (int i=0; i < kMaxReaderThreads; ++i) { + fReaderThreads[i].fThread = NULL; + fReaderThreads[i].fCount = 0; + } + #endif + fInitialized = true; + } +} + +RecursiveReaderWriterLock::RecursiveReaderWriterLock() +{ + initIfNeeded(); +} + +void RecursiveReaderWriterLock::lockForSingleWritingThread() +{ + this->initIfNeeded(); +#if REAL_READER_WRITER_LOCK + pthread_mutex_lock(&fMutex); + pthread_t thisThread = pthread_self(); + // wait as long as there is another writer or any readers on a different thread + while ( writerThreadIsAnyThreadBut(thisThread) || readerThreadSetContainsAnotherThread(thisThread) ) { + pthread_cond_wait(&fLockFree, &fMutex); + } + writerThreadRetain(thisThread); + pthread_mutex_unlock(&fMutex); +#else + pthread_mutex_lock(&fMutex); +#endif +} + +void RecursiveReaderWriterLock::unlockForSingleWritingThread() +{ + this->initIfNeeded(); +#if REAL_READER_WRITER_LOCK + pthread_mutex_lock(&fMutex); + if ( writerThreadRelease(pthread_self()) ) { + pthread_cond_broadcast(&fLockFree); + } + pthread_mutex_unlock(&fMutex); +#else + pthread_mutex_unlock(&fMutex); +#endif +} + + +void RecursiveReaderWriterLock::lockForMultipleReadingThreads() +{ + this->initIfNeeded(); +#if REAL_READER_WRITER_LOCK + pthread_mutex_lock(&fMutex); + pthread_t thisThread = pthread_self(); + // wait as long as there is a writer on another thread or too many readers already + while ( writerThreadIsAnyThreadBut(thisThread) || !readerThreadSetRetain(thisThread) ) { + pthread_cond_wait(&fLockFree, &fMutex); + } + pthread_mutex_unlock(&fMutex); +#else + pthread_mutex_lock(&fMutex); +#endif +} + + +void RecursiveReaderWriterLock::unlockForMultipleReadingThreads() +{ + this->initIfNeeded(); +#if REAL_READER_WRITER_LOCK + pthread_mutex_lock(&fMutex); + if ( readerThreadSetRelease(pthread_self()) ) { + pthread_cond_broadcast(&fLockFree); + } + pthread_mutex_unlock(&fMutex); +#else + pthread_mutex_unlock(&fMutex); +#endif +} + +#if REAL_READER_WRITER_LOCK +bool RecursiveReaderWriterLock::writerThreadIsAnyThreadBut(pthread_t thread) +{ + return ( (fWriterThread.fThread != NULL) && (fWriterThread.fThread != thread) ); +} + +void RecursiveReaderWriterLock::writerThreadRetain(pthread_t thread) +{ + ++fWriterThread.fCount; +} + +bool RecursiveReaderWriterLock::writerThreadRelease(pthread_t thread) +{ + return ( --fWriterThread.fCount == 0 ); +} + + +bool RecursiveReaderWriterLock::readerThreadSetRetain(pthread_t thread) +{ + // if thread is already in set, bump its count + for (int i=0; i < kMaxReaderThreads; ++i) { + if ( fReaderThreads[i].fThread == thread ) { + ++fReaderThreads[i].fCount; + return true; + } + } + // find empty slot in set + for (int i=0; i < kMaxReaderThreads; ++i) { + if ( fReaderThreads[i].fThread == NULL ) { + fReaderThreads[i].fThread = thread; + fReaderThreads[i].fCount = 1; + return true; + } + } + + // all reader slots full + return false; +} + +bool RecursiveReaderWriterLock::readerThreadSetRelease(pthread_t thread) +{ + for (int i=0; i < kMaxReaderThreads; ++i) { + if ( fReaderThreads[i].fThread == thread ) { + if ( --fReaderThreads[i].fCount == 0 ) { + fReaderThreads[i].fThread = NULL; + return true; + } + return false; + } + } + // should never get here + return false; +} + +bool RecursiveReaderWriterLock::readerThreadSetContainsAnotherThread(pthread_t thread) +{ + for (int i=0; i < kMaxReaderThreads; ++i) { + if ( (fReaderThreads[i].fThread != NULL) && (fReaderThreads[i].fThread != thread) ) + return true; + } + return false; +} +#endif + + +// dyld's global reader/writer lock +static RecursiveReaderWriterLock sLock; + + +LockReaderHelper::LockReaderHelper() +{ + sLock.lockForMultipleReadingThreads(); +} + +LockReaderHelper::~LockReaderHelper() +{ + sLock.unlockForMultipleReadingThreads(); +} + + +LockWriterHelper::LockWriterHelper() +{ + sLock.lockForSingleWritingThread(); +} + +LockWriterHelper::~LockWriterHelper() +{ + sLock.unlockForSingleWritingThread(); +} + + +// needed by lazy binding +void lockForLazyBinding() +{ + sLock.lockForMultipleReadingThreads(); +} + +void unlockForLazyBinding() +{ + sLock.unlockForMultipleReadingThreads(); +} + + + diff --git a/src/dyldLock.h b/src/dyldLock.h new file mode 100644 index 0000000..d6291fb --- /dev/null +++ b/src/dyldLock.h @@ -0,0 +1,87 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef __DYLDLOCK__ +#define __DYLDLOCK__ + +// +// This file contains the syncronization utilities used by dyld to be thread safe. +// Access to all dyld data structures is protected by a reader-writer lock. +// This lock allows multiple "reader" threads to access dyld data structures at +// the same time. If there is a "writer" thread, it is the only thread allowed +// access to dyld data structures. +// +// The implementation of all dyld API's must acquire the global lock around accesses +// to dyld's data structures. This is done using the macros DYLD_*_LOCK_THIS_BLOCK. +// Example: +// +// void dyld_api_modifying_dyld() { +// DYLD_WRITER_LOCK_THIS_BLOCK; +// // free to do stuff here +// // that modifies dyld data structures +// } +// +// void dyld_api_examinging_dyld() { +// DYLD_READER_LOCK_THIS_BLOCK +// // can only do stuff here +// // that examines but does not modify dyld data structures +// } +// +// void dyld_api_state_free() { +// DYLD_NO_LOCK_THIS_BLOCK +// // can only do stuff here +// // that does not require locking +// } +// + + +#define DYLD_READER_LOCK_THIS_BLOCK LockReaderHelper _dyld_lock; +#define DYLD_WRITER_LOCK_THIS_BLOCK LockWriterHelper _dyld_lock; +#define DYLD_NO_LOCK_THIS_BLOCK + +// used by dyld wrapper functions in libSystem +class LockReaderHelper +{ +public: + LockReaderHelper() __attribute__((visibility("hidden"))); + ~LockReaderHelper() __attribute__((visibility("hidden"))); +}; + +// used by dyld wrapper functions in libSystem +class LockWriterHelper +{ +public: + LockWriterHelper() __attribute__((visibility("hidden"))); + ~LockWriterHelper() __attribute__((visibility("hidden"))); +}; + +// used by lazy binding +extern void lockForLazyBinding() __attribute__((visibility("hidden"))); +extern void unlockForLazyBinding() __attribute__((visibility("hidden"))); + + + +#endif // __DYLDLOCK__ + diff --git a/src/dyldNew.cpp b/src/dyldNew.cpp new file mode 100644 index 0000000..a74d858 --- /dev/null +++ b/src/dyldNew.cpp @@ -0,0 +1,74 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +//#include + + +// +// dyld does not use malloc anywhere, instead C++ new is used. +// All dyld allocations go in dyld-only zone so as to be not co-mingled with target proccess's allocations +// +// +// + +static malloc_zone_t* sZone = NULL; // could be initialized to malloc_create_zone, but that would require careful ordering of initializers + + +void* operator new(std::size_t len) throw (std::bad_alloc) +{ + if ( sZone == NULL ) { + sZone = malloc_create_zone(40960, 0); + malloc_set_zone_name(sZone, "dyld heap"); + } + //fprintf(stderr, "new(%d)\n", len); + return malloc_zone_malloc(sZone, len); +} + +void* operator new[](std::size_t len) throw (std::bad_alloc) +{ + if ( sZone == NULL ) { + sZone = malloc_create_zone(40960, 0); + malloc_set_zone_name(sZone, "dyld heap"); + } + //fprintf(stderr, "new[](%d)\n", len); + return malloc_zone_malloc(sZone, len); +} + + +void operator delete(void* obj) throw() +{ + //fprintf(stderr, "delete(%p)\n", obj); + malloc_zone_free(sZone, obj); +} + + +void operator delete[](void* obj) throw() +{ + //fprintf(stderr, "delete[](%p)\n", obj); + malloc_zone_free(sZone, obj); +} + + diff --git a/src/dyldStartup.s b/src/dyldStartup.s new file mode 100644 index 0000000..e69b9c9 --- /dev/null +++ b/src/dyldStartup.s @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * C runtime startup for i386 and ppc interface to the dynamic linker. + * This is the same as the entry point in crt0.o with the addition of the + * address of the mach header passed as the an extra first argument. + * + * Kernel sets up stack frame to look like: + * + * | STRING AREA | + * +-------------+ + * | 0 | +* +-------------+ + * | apple[n] | + * +-------------+ + * : + * +-------------+ + * | apple[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | env[n] | + * +-------------+ + * : + * : + * +-------------+ + * | env[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | arg[argc-1] | + * +-------------+ + * : + * : + * +-------------+ + * | arg[0] | + * +-------------+ + * | argc | + * +-------------+ + * sp-> | mh | address of where the a.out's file offset 0 is in memory + * +-------------+ + * + * Where arg[i] and env[i] point into the STRING AREA + */ + + .globl __dyld_start + + +#ifdef __i386__ + .data +__dyld_start_static_picbase: + .long L__dyld_start_picbase + + + .text + .align 2 +# stable entry points into dyld + .globl _stub_binding_helper +_stub_binding_helper: + jmp _stub_binding_helper_interface + nop + nop + nop + .globl _dyld_func_lookup +_dyld_func_lookup: + jmp __Z18lookupDyldFunctionPKcPm + + .text + .align 4, 0x90 + .globl __dyld_start +__dyld_start: + pushl $0 # push a zero for debugger end of frames marker + movl %esp,%ebp # pointer to base of kernel frame + andl $-16,%esp # force SSE alignment + + # call dyldbootstrap::start(app_mh, argc, argv, slide) + call L__dyld_start_picbase +L__dyld_start_picbase: + popl %ebx # set %ebx to runtime value of picbase + movl __dyld_start_static_picbase-L__dyld_start_picbase(%ebx), %eax + subl %eax, %ebx # slide = L__dyld_start_picbase - [__dyld_start_static_picbase] + pushl %ebx # param4 = slide + lea 12(%ebp),%ebx + pushl %ebx # param3 = argv + movl 8(%ebp),%ebx + pushl %ebx # param2 = argc + movl 4(%ebp),%ebx + pushl %ebx # param1 = mh + call __ZN13dyldbootstrap5startEPK11mach_headeriPPKcl + + # clean up stack and jump to result + movl %ebp,%esp # restore the unaligned stack pointer + addl $8,%esp # remove the mh argument, and debugger end + # frame marker + movl $0,%ebp # restore ebp back to zero + jmp %eax # jump to the entry point + + + .globl dyld_stub_binding_helper +dyld_stub_binding_helper: + hlt +L_end: +#endif /* __i386__ */ + +#if __ppc__ || __ppc64__ +#include + + .data + .align 2 +__dyld_start_static_picbase: + .g_long L__dyld_start_picbase + +#if __ppc__ + .set L_mh_offset,0 + .set L_argc_offset,4 + .set L_argv_offset,8 +#else + .set L_mh_offset,0 + .set L_argc_offset,8 ; stack is 8-byte aligned and there is a 4-byte hole between argc and argv + .set L_argv_offset,16 +#endif + + .text + .align 2 +; stable entry points into dyld + .globl _stub_binding_helper +_stub_binding_helper: + b _stub_binding_helper_interface + nop + .globl _dyld_func_lookup +_dyld_func_lookup: + b __Z18lookupDyldFunctionPKcPm + + + + .text + .align 2 +__dyld_start: + mr r26,r1 ; save original stack pointer into r26 + subi r1,r1,GPR_BYTES ; make space for linkage + clrrgi r1,r1,5 ; align to 32 bytes + addi r0,0,0 ; load 0 into r0 + stg r0,0(r1) ; terminate initial stack frame + stgu r1,-SF_MINSIZE(r1); allocate minimal stack frame + + ; call dyldbootstrap::start(app_mh, argc, argv, slide) + lg r3,L_mh_offset(r26) ; r3 = mach_header + lwz r4,L_argc_offset(r26) ; r4 = argc (int == 4 bytes) + addi r5,r26,L_argv_offset ; r5 = argv + bcl 20,31,L__dyld_start_picbase +L__dyld_start_picbase: + mflr r31 ; put address of L__dyld_start_picbase in r31 + addis r6,r31,ha16(__dyld_start_static_picbase-L__dyld_start_picbase) + lg r6,lo16(__dyld_start_static_picbase-L__dyld_start_picbase)(r6) + subf r6,r6,r31 ; r6 = slide + bl __ZN13dyldbootstrap5startEPK11mach_headeriPPKcl + + ; clean up stack and jump to result + mtctr r3 ; Put entry point in count register + mr r12,r3 ; also put in r12 for ABI convention. + addi r1,r26,GPR_BYTES; Restore the stack pointer and remove the + ; mach_header argument. + bctr ; jump to the program's entry point + + .globl dyld_stub_binding_helper +dyld_stub_binding_helper: + trap +L_end: +#endif /* __ppc__ */ + + diff --git a/src/dyld_debug.c b/src/dyld_debug.c new file mode 100644 index 0000000..56c4cec --- /dev/null +++ b/src/dyld_debug.c @@ -0,0 +1,249 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +int dummy_dyld_symbol = 1; + +#include +#include + +// The following API's are deprecated. +// In Mac OS X 10.4 we only do a minimal implementation of these API's +// to keep from breaking existing clients (Omni and MS Crash Reporters). +// +// This minmal implementation only allows inspection of one process and +// only reveals the current images in that process (no notification of +// later image changes). It assumes both processes use the same dyld +// and dyld has not slid in either process. +// +#if __ppc__ + +#include "mach-o/dyld_debug.h" +#include "mach-o/dyld_gdb.h" + +// global state set up by _dyld_debug_subscribe_to_events() and accessed by _dyld_debug_module_name() +static const struct dyld_image_info* sImages = NULL; +static uint32_t sImagesCount = 0; +static task_port_t sImagesTaskPort = 0; + + +// reads an address range out of another process +// returns a malloc'ed block that caller should free +static void* xprocess_read(task_port_t target_task, const void* address, size_t len) +{ + void* result = NULL; + mach_vm_address_t page_address = (uint32_t)address & (-4096); + mach_vm_address_t last_page_address = ((uint32_t)address + len + 4095) & (-4096); + mach_vm_size_t page_size = last_page_address - page_address; + uint8_t* local_start; + uint32_t local_len; + kern_return_t r = vm_read( + target_task, + page_address, + page_size, + (vm_offset_t*)&local_start, + &local_len); + if ( r == KERN_SUCCESS ) { + result = malloc(len); + if ( result != NULL ) + memcpy(result, &local_start[(uint32_t)address - page_address], len); + vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_len); + } + return result; +} + +// reads a c-string out of another process. The returned string should be vm_deallocated. +// All strings must be less than 1 to 2 pages long +static const char* xprocess_read_string(task_port_t target_task, const void* address) +{ + char* result = NULL; + mach_vm_address_t page_address = (uint32_t)address & (-4096); + mach_vm_size_t page_size = 0x2000; // always read two pages + uint8_t* local_start; + uint32_t local_len; + kern_return_t r = vm_read( + target_task, + page_address, + page_size, + (vm_offset_t*)&local_start, + &local_len); + if ( r == KERN_SUCCESS ) { + const char* str = (char*)&local_start[(uint32_t)address - page_address]; + return str; + } + return result; +} + + +// SPI into dyld to get address of _dyld_get_all_image_infos data structure +static const struct dyld_all_image_infos* dyld_get_all_image_infos() +{ + static const struct dyld_all_image_infos* (*p)() = NULL; + + if ( p == NULL ) + _dyld_func_lookup("__dyld_get_all_image_infos", (void**)&p); + + if ( p != NULL ) + return p(); + else + return NULL; +} + + + +/* + * _dyld_debug_module_name() is passed a dyld_debug_module struct and + * sets image_name and module_name as well as the nameCnts. If the module + * does not refer to a valid module DYLD_INVALID_ARGUMENTS is returned. + */ +enum dyld_debug_return +_dyld_debug_module_name( +task_port_t target_task, +unsigned long send_timeout, +unsigned long rcv_timeout, +boolean_t inconsistent_data_ok, +struct dyld_debug_module module, +char **image_name, +unsigned long *image_nameCnt, +char **module_name, +unsigned long *module_nameCnt) +{ + // examine sImage* info set up by _dyld_debug_subscribe_to_events() + if ( sImagesTaskPort == target_task ) { + unsigned int i; + for (i=0; i < sImagesCount; ++i) { + if ( module.header == sImages[i].imageLoadAddress ) { + // copy requested string + const char* path = xprocess_read_string(sImagesTaskPort, sImages[i].imageFilePath); + if ( path != NULL ) { + *image_name = (char*)path; + *image_nameCnt = strlen(path); + *module_name = NULL; + *module_nameCnt = 0; + return DYLD_SUCCESS; + } + } + } + } + + // not supported + return DYLD_INVALID_ARGUMENTS; +} + + +/* + * set_dyld_debug_error_func() is called to register a function to be called + * when error occurs in the dyld debug API's. + */ +void +_dyld_debug_set_error_func( +void (*func)(struct dyld_debug_error_data *e)) +{ + // do nothing +} + + + +// Examine a mach_header in another process and determine its slid +static ptrdiff_t slideForHeader(task_port_t target_task, const struct mach_header* otherAddressHeader) +{ + const struct mach_header* mh = xprocess_read(target_task, otherAddressHeader, 0x2000); + if ( mh != NULL ) { + int i; + const struct segment_command *sgp = + (const struct segment_command *)((char*)mh + sizeof(mh)); + + for (i = 0; i < mh->ncmds; i++){ + if (sgp->cmd == LC_SEGMENT) { + if (sgp->fileoff == 0 && sgp->filesize != 0) { + return (uintptr_t)mh - (uintptr_t)sgp->vmaddr; + } + } + sgp = (const struct segment_command *)((char *)sgp + sgp->cmdsize); + } + free((void*)mh); + } + return 0; +} + + +/* + * _dyld_debug_subscribe_to_events creates a new thread that is will call the + * specified dyld_event_routine when dynamic link events occur in the target + * task. This uses _dyld_debug_add_event_subscriber() and is just a different + * interface to get events. + */ +enum dyld_debug_return +_dyld_debug_subscribe_to_events( +task_port_t target_task, +unsigned long send_timeout, +unsigned long rcv_timeout, +boolean_t inconsistent_data_ok, +void (*dyld_event_routine)(struct dyld_event event)) +{ + sImages = NULL; + sImagesCount = 0; + sImagesTaskPort = 0; + // get location of dyld_get_all_image_infos in this process + // It is possible that dyld slid in one of the processes, in which case this fails + const struct dyld_all_image_infos* infoOtherAddressSpace = dyld_get_all_image_infos(); + if ( infoOtherAddressSpace != NULL ) { + const struct dyld_all_image_infos* infos; + infos = (const struct dyld_all_image_infos*)xprocess_read(target_task, infoOtherAddressSpace, sizeof(struct dyld_all_image_infos)); + if ( infos != NULL ) { + // sanity check version + if ( infos->version == 1 ) { + sImages = xprocess_read(target_task, infos->infoArray, infos->infoArrayCount * sizeof(struct dyld_image_info)); + if ( sImages != NULL ) { + int i; + // save info info into sImage* globals for use by later calls to _dyld_debug_module_name() + sImagesCount = infos->infoArrayCount; + sImagesTaskPort = target_task; + // tell caller about every image + for (i=0; i < infos->infoArrayCount; ++i) { + struct dyld_event addEvent; + bzero(&addEvent, sizeof(struct dyld_event)); + const struct mach_header* mh = sImages[i].imageLoadAddress; + addEvent.type = DYLD_IMAGE_ADDED; + addEvent.arg[0].header = (struct mach_header*)mh; + addEvent.arg[0].vmaddr_slide = slideForHeader(target_task, mh); + addEvent.arg[0].module_index = 0; + (*dyld_event_routine)(addEvent); + } + } + } + // we free the dyld_all_image_infos struct, but not the array we copied + // The array is left in sImage* for use by later calls to _dyld_debug_module_name() + free((void*)infos); + } + } + + // tell client event handler no more images + struct dyld_event event; + event.type = DYLD_PAST_EVENTS_END; + (*dyld_event_routine)(event); + + return DYLD_SUCCESS; +} + +#endif diff --git a/src/dyld_gdb.cpp b/src/dyld_gdb.cpp new file mode 100644 index 0000000..89a1cd7 --- /dev/null +++ b/src/dyld_gdb.cpp @@ -0,0 +1,227 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include + +#include + +#include "mach-o/dyld_gdb.h" + + +// old gdb interface to dyld only supported on 32-bit ppc and i386 (not ppc64_ +#if OLD_GDB_DYLD_INTERFACE + +unsigned int gdb_dyld_version = 2; + + +/* + * gdb_dyld_state_changed() is a dummy routine called by dyld after images get + * added or removed/ Gdb is expected to set a break point at + * gdb_dyld_state_changed() then re-read dyld internal data as specified in + * the header file dyld_gdb.h + */ +void gdb_dyld_state_changed() +{ + // do nothing +} + +#define NLIBRARY_IMAGES 200 +#define NOBJECT_IMAGES 1 + + +struct image { + const char* physical_name; // physical image name (file name) + uint32_t vmaddr_slide; // the slide from the staticly linked address + const mach_header* mh; // address of the mach header of the image + uint32_t valid; // TRUE if this is struct is valid + const char* name; // image name for reporting errors +}; + + +struct library_images { + struct image images[NLIBRARY_IMAGES]; + uint32_t nimages; + struct library_images* next_images; +}; +struct object_images { + struct image images[NOBJECT_IMAGES]; + uint32_t nimages; + struct library_images* next_images; +}; + +unsigned int gdb_nobject_images = NOBJECT_IMAGES; +unsigned int gdb_object_image_size = sizeof(image); +unsigned int gdb_nlibrary_images = NLIBRARY_IMAGES; +unsigned int gdb_library_image_size = sizeof(image); + +extern "C" { +object_images object_images = { {}, 0 , NULL }; +library_images library_images = { {}, 0 , NULL }; +void send_event(const struct dyld_event* event); +} + + +enum dyld_event_type { + DYLD_IMAGE_ADDED = 0, + DYLD_IMAGE_REMOVED = 5 +}; + +struct dyld_event { + enum dyld_event_type type; + const struct mach_header* header; + uintptr_t slide; +}; + + +// gdb only notices changes bundles/dylibs loaded at runtime +// if the "send_event()" function in dyld is called... +void send_event(const struct dyld_event* event); +void (*send_event_ptr)(const struct dyld_event* event) = &send_event; + +void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath) +{ + struct library_images* li = &library_images; + while ( li->nimages >= NLIBRARY_IMAGES ) { + if ( li->next_images == NULL ) { + struct library_images* li2 = new struct library_images(); + li2->nimages = 0; + li2->next_images = NULL; + li->next_images = li2; + li = li2; + } + else { + li = li->next_images; + } + } + image* info = &li->images[li->nimages++]; + info->physical_name = physicalPath; + info->vmaddr_slide = slide; + info->mh = mh; + info->valid = 1; + info->name = logicalPath; + + // ping gdb about change + dyld_event event; + event.type = DYLD_IMAGE_ADDED; + event.header = mh; + event.slide = slide; + + // we have to indirect through a function pointer to keep gcc-3.5 from inlining away the function call + // rdar://problem/3830560 + (*send_event_ptr)(&event); +} + +// move this to after use, otherwise gcc will see it has an empty implementation and +// optimize away the call site +void send_event(const struct dyld_event* event) +{ + // This function exists to let gdb set a break point + // and catch libraries being added... +} + + +void removeImageForgdb(const mach_header* mh) +{ + for (struct library_images* li = &library_images; li != NULL; li = li->next_images) { + for( uint32_t n=0; n < li->nimages; ++n) { + struct image* image = &li->images[n]; + if ( image->mh == mh ) { + image->physical_name = NULL; + image->vmaddr_slide = 0; + image->mh = 0; + image->valid = 0; + image->name = NULL; + return; + } + } + } +} + +#endif + +static std::vector sImageInfos; + + + +void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]) +{ + // set infoArray to NULL to denote it is in-use + dyld_all_image_infos.infoArray = NULL; + + // append all new images + for (uint32_t i=0; i < infoCount; ++i) + sImageInfos.push_back(info[i]); + dyld_all_image_infos.infoArrayCount = sImageInfos.size(); + + // set infoArray back to base address of vector + dyld_all_image_infos.infoArray = &sImageInfos[0]; + + // tell gdb that about the new images + dyld_all_image_infos.notification(dyld_image_adding, infoCount, info); +} + +void removeImageFromAllImages(const struct mach_header* loadAddress) +{ + dyld_image_info goingAway; + + // set infoArray to NULL to denote it is in-use + dyld_all_image_infos.infoArray = NULL; + + // remove image from infoArray + for (std::vector::iterator it=sImageInfos.begin(); it != sImageInfos.end(); it++) { + if ( it->imageLoadAddress == loadAddress ) { + goingAway = *it; + sImageInfos.erase(it); + break; + } + } + dyld_all_image_infos.infoArrayCount = sImageInfos.size(); + + // set infoArray back to base address of vector + dyld_all_image_infos.infoArray = &sImageInfos[0]; + + // tell gdb that about the new images + dyld_all_image_infos.notification(dyld_image_removing, 1, &goingAway); +} + + +static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]) +{ + // do nothing + // gdb sets a break point here to catch notifications + //fprintf(stderr, "dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount); + //for (uint32_t i=0; i < dyld_all_image_infos.infoArrayCount; ++i) + // fprintf(stderr, "dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath); +} + + + +struct dyld_all_image_infos dyld_all_image_infos = { 1, 0, NULL, &gdb_image_notifier, false }; + + + diff --git a/src/glue.c b/src/glue.c new file mode 100644 index 0000000..eac9512 --- /dev/null +++ b/src/glue.c @@ -0,0 +1,129 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include + +// +// Stub functions needed for dyld to link with libc.a instead of libSystem.dylib +// +// +static char* dyld_progname = "dyld"; + +// +// libc has calls to _dyld_lookup_and_bind to find args and environment. Since +// dyld links with a staic copy of libc, those calls need to find dyld's args and env +// not the host process. We implement a special _dyld_lookup_and_bind() that +// just knows how to bind the few symbols needed by dyld. +// +void _dyld_lookup_and_bind(const char* symbolName, void** address, void* module) +{ + if ( strcmp(symbolName, "_environ") == 0 ) { + // dummy up empty environment list + static char *p = NULL; + static char **pp = &p; + *address = &pp; + return; + } + else if ( strcmp(symbolName, "___progname") == 0 ) { + *address = &dyld_progname; + return; + } + + fprintf(stderr, "dyld: internal error: unknown symbol '%s'\n", symbolName); +} + + +int NSIsSymbolNameDefined(const char* symbolName) +{ + if ( strcmp(symbolName, "___progname") == 0 ) { + return 1; + } + fprintf(stderr, "dyld: internal error: unknown symbol '%s'\n", symbolName); + return 0; +} + + +/* + * To avoid linking in libm. These variables are defined as they are used in + * pthread_init() to put in place a fast sqrt(). + */ +size_t hw_sqrt_len = 0; + +double +sqrt(double x) +{ + return(0.0); +} +double +hw_sqrt(double x) +{ + return(0.0); +} + +/* + * More stubs to avoid linking in libm. This works as along as we don't use + * long doubles. + */ +long +__fpclassifyd(double x) +{ + return(0); +} + +long +__fpclassify(long double x) +{ + return(0); +} + + +char* __hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve) +{ + return NULL; +} + +char* __hldtoa(/*long*/ double e, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve) +{ + return NULL; +} + +int __fegetfltrounds(void) +{ + return 1; /* FE_NEAREST */ +} + +/* + * We have our own localtime() to avoid needing the notify API which is used + * by the code in libc.a for localtime() but is in libnotify. + */ +struct tm* localtime(const time_t* t) +{ + return (struct tm*)NULL; +} + diff --git a/src/stub_binding_helper.s b/src/stub_binding_helper.s new file mode 100644 index 0000000..e2a6d87 --- /dev/null +++ b/src/stub_binding_helper.s @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#ifdef __i386__ +/* + * This is the interface for the stub_binding_helper for i386: + * The caller has pushed the address of the a lazy pointer to be filled in with + * the value for the defined symbol and pushed the address of the the mach + * header this pointer comes from. + * + * sp+4 address of lazy pointer + * sp+0 address of mach header + * + * After the symbol has been resolved and the pointer filled in this is to pop + * these arguments off the stack and jump to the address of the defined symbol. + */ + .text + .align 4,0x90 + .globl _stub_binding_helper_interface +_stub_binding_helper_interface: + call __ZN4dyld14bindLazySymbolEPK11mach_headerPm + addl $8,%esp + jmpl %eax +#endif /* __i386__ */ + + +#if __ppc__ || __ppc64__ +#include +/* + * This is the interface for the stub_binding_helper for the ppc: + * The caller has placed in r11 the address of the a lazy pointer to be filled + * in with the value for the defined symbol and placed in r12 the address of + * the the mach header this pointer comes from. + * + * r11 address of lazy pointer + * r12 address of mach header + */ +#define LRSAVE MODE_CHOICE(8,16) +#define STACK_SIZE MODE_CHOICE(144,288) +#define R3SAVE MODE_CHOICE(56,112) +#define R4SAVE MODE_CHOICE(60,120) +#define R5SAVE MODE_CHOICE(64,128) +#define R6SAVE MODE_CHOICE(68,136) +#define R7SAVE MODE_CHOICE(72,144) +#define R8SAVE MODE_CHOICE(76,152) +#define R9SAVE MODE_CHOICE(80,160) +#define R10SAVE MODE_CHOICE(84,168) + + + .text + .align 2 + .globl _stub_binding_helper_interface +_stub_binding_helper_interface: + mflr r0 ; get link register value + stg r0,LRSAVE(r1) ; save link register value in the linkage area + stgu r1,-STACK_SIZE(r1) ; save stack pointer and update it + + stg r3,R3SAVE(r1) ; save all registers that could contain + stg r4,R4SAVE(r1) ; parameters to the routine that is being + stg r5,R5SAVE(r1) ; bound. + stg r6,R6SAVE(r1) + stg r7,R7SAVE(r1) + stg r8,R8SAVE(r1) + stg r9,R9SAVE(r1) + stg r10,R10SAVE(r1) + + mr r3,r12 ; move address of mach header to 1st parameter + mr r4,r11 ; move address of lazy pointer to 2nd parameter + ; call dyld::bindLazySymbol(mh, lazy_symbol_pointer_address) + bl __ZN4dyld14bindLazySymbolEPK11mach_headerPm + mr r12,r3 ; move the symbol`s address into r12 + mtctr r12 ; move the symbol`s address into count register + + lg r0,STACK_SIZE+LRSAVE(r1) ; get old link register value + + lg r3,R3SAVE(r1) ; restore all registers that could contain + lg r4,R4SAVE(r1) ; parameters to the routine that was bound. + lg r5,R5SAVE(r1) + lg r6,R6SAVE(r1) + lg r7,R7SAVE(r1) + lg r8,R8SAVE(r1) + lg r9,R9SAVE(r1) + lg r10,R10SAVE(r1) + + addi r1,r1,STACK_SIZE; restore old stack pointer + mtlr r0 ; restore link register + + bctr ; jump to the symbol`s address that was bound + +#endif /* __ppc__ */ + + + + + + + + + + + diff --git a/unit-tests/bin/exit-non-zero-pass.pl b/unit-tests/bin/exit-non-zero-pass.pl new file mode 100755 index 0000000..149724f --- /dev/null +++ b/unit-tests/bin/exit-non-zero-pass.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl -w + +use strict; + +sub PASS +{ + my ($format, $args) = @_; + if(!defined $args) + { $args = []; } + printf("PASS \"$format\"\n", @$args); +} + +sub FAIL +{ + my ($format, $args) = @_; + if(!defined $args) + { $args = []; } + printf("FAIL \"$format\"\n", @$args); +} + +my $pass_string = shift @ARGV; +my $fail_string = shift @ARGV; + +if(0 != system(@ARGV)) +{ + PASS($pass_string); +} +else +{ + FAIL($fail_string); +} +exit 0; + diff --git a/unit-tests/bin/exit-zero-pass.pl b/unit-tests/bin/exit-zero-pass.pl new file mode 100755 index 0000000..54f4b32 --- /dev/null +++ b/unit-tests/bin/exit-zero-pass.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl -w + +use strict; + +sub PASS +{ + my ($format, $args) = @_; + if(!defined $args) + { $args = []; } + printf("PASS \"$format\"\n", @$args); +} + +sub FAIL +{ + my ($format, $args) = @_; + if(!defined $args) + { $args = []; } + printf("FAIL \"$format\"\n", @$args); +} + +my $pass_string = shift @ARGV; +my $fail_string = shift @ARGV; + +if(0 == system(@ARGV)) +{ + PASS($pass_string); +} +else +{ + FAIL($fail_string); +} +exit 0; + diff --git a/unit-tests/bin/make-recursive.pl b/unit-tests/bin/make-recursive.pl new file mode 100755 index 0000000..c980711 --- /dev/null +++ b/unit-tests/bin/make-recursive.pl @@ -0,0 +1,119 @@ +#!/usr/bin/perl + +use strict; +use Data::Dumper; +use File::Find; +use Cwd qw(realpath); + +my @args = @ARGV; + +my $makefiles = +{ + 'makefile' => undef, + 'Makefile' => undef, +}; + +my $find_opts = +{ + 'wanted' => \&find_callback, +}; + +my $keywords = +{ + 'root' => '', + 'cwd' => '', + 'cmd' => '', + 'exit' => '', + 'stdout' => [], + 'stderr' => [], +}; + +my $keyword; +my $max_keyword_len = 0; +foreach $keyword (keys %$keywords) +{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } } +my $delim = ':'; +$max_keyword_len += length($delim) + length(' '); + +my $last_keyword = ''; + +sub print_line +{ + my ($keyword, $val) = @_; + + if(!exists($$keywords{$keyword})) + { + print STDERR "error: keyword $keyword not in \$keywords set\n"; + exit(1); + } + + my $keyword_len = 0; + + if($keyword ne $last_keyword) + { + print("$keyword"); print($delim); + $keyword_len = length($keyword) + length($delim); + } + if($max_keyword_len > $keyword_len) + { + my $num_spaces = $max_keyword_len - $keyword_len; + print(' ' x $num_spaces); + } + print("$val"); + if(0) + { + $last_keyword = $keyword; + } +} + +my $root = '.'; +$root = &realpath($root); +print_line("root", "$root\n"); + +find($find_opts, $root); + +sub find_callback +{ + if(exists($$makefiles{$_})) + { + my $makefile = $_; + my $reldir = $File::Find::dir; + $reldir =~ s|^$root/||; + + &print_line("cwd", "\$root/$reldir\n"); + my $cmd = [ "make" ]; + + my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this? + &print_line("cmd", "@$cmd\n"); + + open(SAVEOUT, ">&STDOUT") || die("$!"); + open(SAVEERR, ">&STDERR") || die("$!"); + open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!"); + open(STDERR, ">/tmp/unit-tests-stderr") || die("$!"); + + my $exit = system(@$cmd); + + close(STDOUT) || die("$!"); + close(STDERR) || die("$!"); + open(STDOUT, ">&SAVEOUT") || die("$!"); + open(STDERR, ">&SAVEERR") || die("$!"); + + &print_line("exit", "$exit\n"); + + open(OUT, ") + { + &print_line("stdout", "$_"); + } + close(OUT) || die("$!"); + unlink("/tmp/unit-tests-stdout"); + + open(ERR, ") + { + &print_line("stderr", "$_"); + } + close(ERR) || die("$!"); + } + unlink("/tmp/unit-tests-stderr"); +} diff --git a/unit-tests/bin/result-filter.pl b/unit-tests/bin/result-filter.pl new file mode 100755 index 0000000..db07357 --- /dev/null +++ b/unit-tests/bin/result-filter.pl @@ -0,0 +1,120 @@ +#!/usr/bin/perl -w + +use strict; +use Data::Dumper; +use File::Find; +use Cwd; + +$Data::Dumper::Terse = 1; + +my $root = undef; +my $entry = ''; +my $pass_count = 0; +my $total_count = 0; + +# first match "root: " + +# a line starting with "cwd:" marks the beginning of a new test case +# call process_entry() on each test case +while(<>) +{ + if(m/^root:\s+(.*?)$/) + { + $root = $1; + } + elsif(m/^cwd:\s+(.*?)$/) + { + if(length($entry)) + { + &process_entry($root, $entry); + $entry = ''; + } + $entry .= $_; + } + else + { + $entry .= $_; + } +} +# don't forget last test case (no cwd: to mark end) +if(length($entry)) +{ + &process_entry($root, $entry); +} + +# show totals +my $percentage = $pass_count * 100 / $total_count; +print "\n"; +printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage; + + +sub process_entry +{ + my ($root, $lines) = @_; + + # build an associative array of keys to value(s) + my $lines_seq = [split /\n/, $lines]; + #print Dumper($lines_seq); + my $tbl = { 'root' => $root, 'stdout' => [], 'stderr' => [] }; + my $line; + foreach $line (@$lines_seq) + { + if($line =~ m/^(\w+):\s+(.*)$/) + { + my $key = $1; + my $val = $2; + if(!exists($$tbl{$key})) + { $$tbl{$key} = ''; } + + if($key eq 'stdout' || $key eq 'stderr') # if type is @array + { + push @{$$tbl{$key}}, $val; + } + else + { + $$tbl{$key} .= $val; + } + } + else + { + print "ERROR: $line"; + } + } + #print Dumper($tbl); + #return; + + my $test_name = $$tbl{cwd}; + if ($test_name =~ m|.*/([a-zA-Z0-9-+_]+)$|) + { + $test_name = $1; + } + + #if make failed (exit was non-zero), mark this as a failure + if(0 ne $$tbl{exit}) + { + printf "%-40s FAIL Makefile failure\n", $test_name; + $total_count++; + return; + } + my $seen_result = 0; + + # scan all stdout looking for lines that start with PASS or FAIL + foreach $line (@{$$tbl{stdout}}) + { + if($line =~ m/^(PASS|XPASS|FAIL|XFAIL).+/) + { + printf "%-40s %s\n", $test_name, $line; + $total_count++; + if($line =~ m/^PASS.+/) + { + $pass_count++; + } + $seen_result = 1; + } + } + if(!$seen_result) + { + printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name; + $total_count++; + } +} diff --git a/unit-tests/include/common.makefile b/unit-tests/include/common.makefile new file mode 100644 index 0000000..9cd0899 --- /dev/null +++ b/unit-tests/include/common.makefile @@ -0,0 +1,12 @@ +# stuff to include in every test Makefile + +SHELL = /bin/sh + +CC = gcc-4.0 ${ARCH} +CCFLAGS = -Wall -g -std=c99 + +CXX = g++-4.0 ${ARCH} +CXXFLAGS = -Wall -g + +RM = rm +RMFLAGS = -rf diff --git a/unit-tests/include/test.h b/unit-tests/include/test.h new file mode 100644 index 0000000..faca714 --- /dev/null +++ b/unit-tests/include/test.h @@ -0,0 +1,35 @@ +#include +#include + +#define DEFINE_TEST_FUNC(name) \ + static \ + inline \ + void \ + name(const char *format, ...) \ + { \ + va_list args; \ + va_start(args, format); \ + common(stdout, #name, format, args); \ + va_end(args); \ + return; \ + } + +static +inline +void +common(FILE *file, const char *prefix, const char *format, va_list args) +{ + fprintf(file, "%s \"", prefix); + vfprintf(file, format, args); + fprintf(file, "\"\n"); // should check for trailing newline + return; +} + +DEFINE_TEST_FUNC(PASS); +DEFINE_TEST_FUNC(XPASS); +DEFINE_TEST_FUNC(FAIL); +DEFINE_TEST_FUNC(XFAIL); + +DEFINE_TEST_FUNC(UNTESTED); +DEFINE_TEST_FUNC(UNSUPPORTED); +DEFINE_TEST_FUNC(UNRESOLVED); diff --git a/unit-tests/run-all-unit-tests b/unit-tests/run-all-unit-tests new file mode 100755 index 0000000..4a1d1c6 --- /dev/null +++ b/unit-tests/run-all-unit-tests @@ -0,0 +1,28 @@ +#!/bin/sh + +# cd into test-cases directory +cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'` + +echo "" +echo " * * * Running all unit tests for 32-bits * * *" + +# make clean +../bin/make-recursive.pl clean > /dev/null + +# build default architecture +../bin/make-recursive.pl | ../bin/result-filter.pl + +# if G5, then also run all test cases built for ppc64 +if [ `machine` = "ppc970" ] +then + echo "" + echo " * * * Running all unit tests for 64-bits * * *" + + # make clean + ../bin/make-recursive.pl clean > /dev/null + + # build 64-bit architecture + ../bin/make-recursive.pl ARCH="-arch ppc64" | ../bin/result-filter.pl +fi + + diff --git a/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/Makefile b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/Makefile new file mode 100644 index 0000000..3aeab86 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c libbar.dylib libfoo.dylib + ${CC} -I${TESTROOT}/include main.c -o main + +libfoo.dylib : foo.c libbar.dylib + ${CC} -I${TESTROOT}/include -dynamiclib foo.c -o libfoo.dylib libbar.dylib + +libbar.dylib : bar.c + ${CC} -I${TESTROOT}/include -dynamiclib bar.c -o libbar.dylib -install_name /usr/local/hide/libbar.dylib + +clean: + ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib diff --git a/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/bar.c b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/bar.c new file mode 100644 index 0000000..fa1d6fe --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/bar.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + diff --git a/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/foo.c b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/foo.c new file mode 100644 index 0000000..fa1d6fe --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/foo.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + diff --git a/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/main.c b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/main.c new file mode 100644 index 0000000..9442bf1 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/main.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" + +/// rdar://problem/4058724 + +int main() +{ + // test that image can be found via install path + const struct mach_header * mh1 = NSAddImage("libbar.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME); + const struct mach_header * mh2 = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME); + if ( mh2 != NULL ) + PASS("NSAddImage-MATCH_BY_INSTALLNAME"); + else + FAIL("NSAddImage-MATCH_BY_INSTALLNAME"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/Makefile b/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/Makefile new file mode 100644 index 0000000..e02d140 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/Makefile @@ -0,0 +1,35 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c + ${CC} -I${TESTROOT}/include main.c -o main + +clean: + ${RM} ${RMFLAGS} *~ main diff --git a/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/main.c b/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/main.c new file mode 100644 index 0000000..e8a3320 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" + +/// rdar://problem/3748251 + +int main() +{ + // test that NSAddImage() does not crash if image is not loaded + const struct mach_header * mh = NSAddImage("/System/Library/Frameworks/Cocoa.framework/Cocoa", NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED); + if ( mh == NULL ) + PASS("NSAddImage-RETURN_ONLY_IF_LOADED"); + else + FAIL("NSAddImage-RETURN_ONLY_IF_LOADED"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/NSAddImage-leafname/Makefile b/unit-tests/test-cases/NSAddImage-leafname/Makefile new file mode 100644 index 0000000..38794a0 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-leafname/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export DYLD_FALLBACK_LIBRARY_PATH="hide" && ./main + +all: main hide/libzzz.dylib + +main : main.c + ${CC} -I${TESTROOT}/include main.c -o main + +hide/libzzz.dylib: zzz.c + mkdir -p hide + ${CC} zzz.c -dynamiclib -o hide/libzzz.dylib + + +clean: + ${RM} ${RMFLAGS} *~ main hide diff --git a/unit-tests/test-cases/NSAddImage-leafname/main.c b/unit-tests/test-cases/NSAddImage-leafname/main.c new file mode 100644 index 0000000..28922af --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-leafname/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" + +/// rdar://problem/3751226 + +int main() +{ + // test that NSAddImage() uses fallback path when given a leaf name + const struct mach_header * mh = NSAddImage("libzzz.dylib", NSADDIMAGE_OPTION_WITH_SEARCHING); + if ( mh != NULL ) + PASS("NSAddImage-leafname"); + else + FAIL("NSAddImage-leafname"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/NSAddImage-leafname/zzz.c b/unit-tests/test-cases/NSAddImage-leafname/zzz.c new file mode 100644 index 0000000..80420c7 --- /dev/null +++ b/unit-tests/test-cases/NSAddImage-leafname/zzz.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +void zzz() {} diff --git a/unit-tests/test-cases/bundle-basic/Makefile b/unit-tests/test-cases/bundle-basic/Makefile new file mode 100644 index 0000000..2c905f2 --- /dev/null +++ b/unit-tests/test-cases/bundle-basic/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + diff --git a/unit-tests/test-cases/bundle-basic/bundle.c b/unit-tests/test-cases/bundle-basic/bundle.c new file mode 100644 index 0000000..64232df --- /dev/null +++ b/unit-tests/test-cases/bundle-basic/bundle.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +// test to see if bss section is properly expanded + +static int mydata[1000000]; + +bool checkdata() +{ + return ( mydata[500000] == 0 ); +} diff --git a/unit-tests/test-cases/bundle-basic/main.c b/unit-tests/test-cases/bundle-basic/main.c new file mode 100644 index 0000000..27f7635 --- /dev/null +++ b/unit-tests/test-cases/bundle-basic/main.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + +typedef bool (*CheckFunc)(); + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 1; + } + + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod == NULL ) { + FAIL("NSLinkModule failed"); + return 1; + } + + NSSymbol sym = NSLookupSymbolInModule(mod, "_checkdata"); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 1; + } + + CheckFunc func = NSAddressOfSymbol(sym); + if ( !func() ) { + FAIL("NSAddressOfSymbol failed"); + return 1; + } + + if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 1; + } + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("NSDestroyObjectFileImage failed"); + return 1; + } + + PASS("bundle-basic"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-memory-load/Makefile b/unit-tests/test-cases/bundle-memory-load/Makefile new file mode 100644 index 0000000..2c905f2 --- /dev/null +++ b/unit-tests/test-cases/bundle-memory-load/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + diff --git a/unit-tests/test-cases/bundle-memory-load/bundle.c b/unit-tests/test-cases/bundle-memory-load/bundle.c new file mode 100644 index 0000000..64232df --- /dev/null +++ b/unit-tests/test-cases/bundle-memory-load/bundle.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +// test to see if bss section is properly expanded + +static int mydata[1000000]; + +bool checkdata() +{ + return ( mydata[500000] == 0 ); +} diff --git a/unit-tests/test-cases/bundle-memory-load/main.c b/unit-tests/test-cases/bundle-memory-load/main.c new file mode 100644 index 0000000..8f212f1 --- /dev/null +++ b/unit-tests/test-cases/bundle-memory-load/main.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + +typedef bool (*CheckFunc)(); + +int main() +{ + int fd = open("test.bundle", O_RDONLY, 0); + if ( fd == -1 ) { + FAIL("open() failed"); + return 1; + } + + struct stat stat_buf; + if ( fstat(fd, &stat_buf) == -1) { + FAIL("fstat() failed"); + return 1; + } + + void* loadAddress = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if ( loadAddress == ((void*)(-1)) ) { + FAIL("mmap() failed"); + return 1; + } + + close(fd); + + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromMemory failed"); + return 1; + } + + NSModule mod = NSLinkModule(ofi, "he_he", NSLINKMODULE_OPTION_NONE); + if ( mod == NULL ) { + FAIL("NSLinkModule failed"); + return 1; + } + + NSSymbol sym = NSLookupSymbolInModule(mod, "_checkdata"); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 1; + } + + CheckFunc func = NSAddressOfSymbol(sym); + if ( !func() ) { + FAIL("NSAddressOfSymbol failed"); + return 1; + } + + if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 1; + } + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("NSDestroyObjectFileImage failed"); + return 1; + } + + // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage) + + PASS("bundle-memory-load"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-multi-link/Makefile b/unit-tests/test-cases/bundle-multi-link/Makefile new file mode 100644 index 0000000..ce5b2d4 --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-link/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + + diff --git a/unit-tests/test-cases/bundle-multi-link/bundle.c b/unit-tests/test-cases/bundle-multi-link/bundle.c new file mode 100644 index 0000000..9871eea --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-link/bundle.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +static int value = 0; + +int getValue() +{ + return value; +} + +void setValue(int v) +{ + value = v; +} + diff --git a/unit-tests/test-cases/bundle-multi-link/main.c b/unit-tests/test-cases/bundle-multi-link/main.c new file mode 100644 index 0000000..267d540 --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-link/main.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" // PASS(), FAIL() + + +/// +/// The point of this test case is to "load" a bundle once, but link it multiple times. +/// Each link creats a new instantiation of the bundle (e.g. new base address and new globals). +/// +/// + +typedef void (*setter)(int); +typedef int (*getter)(void); + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 0; + } + + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod == NULL ) { + FAIL("NSLinkModule failed"); + return 0; + } + + NSSymbol sym = NSLookupSymbolInModule(mod, "_setValue"); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 0; + } + + setter func = NSAddressOfSymbol(sym); + (*func)(1); + //fprintf(stderr, "address of foo() = %p in bundle first load %p\n", func, mod); + + + NSModule mod2 = NSLinkModule(ofi, "test2.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod2 == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed"); + return 0; + } + if ( mod == mod2 ) { + FAIL("2nd NSLinkModule return same function address as first"); + return 0; + } + + NSSymbol sym2getter = NSLookupSymbolInModule(mod2, "_getValue"); + if ( sym2getter == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed"); + return 0; + } + getter func2getter = NSAddressOfSymbol(sym2getter); + if ( (*func2getter)() != 0 ) { + FAIL("_getValue() on second link returned non-zero"); + return 0; + } + + NSSymbol sym2 = NSLookupSymbolInModule(mod2, "_setValue"); + if ( sym2 == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed"); + return 0; + } + setter func2 = NSAddressOfSymbol(sym2); + (*func2)(2); + + //fprintf(stderr, "address of foo() = %p in bundle second load %p\n", func2, mod2); + if ( func == func2 ) { + FAIL("2nd NSAddressOfSymbol return same function address as 1st"); + return 0; + } + + + NSModule mod3 = NSLinkModule(ofi, "test3.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod3 == NULL ) { + FAIL("3rd NSLinkModule failed"); + return 0; + } + if ( mod3 == mod ) { + FAIL("3rd NSLinkModule return same function address as 1st"); + return 0; + } + if ( mod3 == mod2 ) { + FAIL("3rd NSLinkModule return same function address as 2nd"); + return 0; + } + + NSSymbol sym3 = NSLookupSymbolInModule(mod3, "_setValue"); + if ( sym3 == NULL ) { + FAIL("3rd NSLookupSymbolInModule failed"); + return 0; + } + setter func3 = NSAddressOfSymbol(sym3); + (*func3)(3); + //fprintf(stderr, "address of foo() = %p in bundle third load %p\n", func3, mod3); + if ( func3 == func ) { + FAIL("3rd NSAddressOfSymbol return same function address as 1st"); + return 0; + } + if ( func3 == func2 ) { + FAIL("3rd NSAddressOfSymbol return same function address as 2nd"); + return 0; + } + + if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 0; + } + + if ( !NSUnLinkModule(mod3, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("3rd NSUnLinkModule failed"); + return 0; + } + + if ( !NSUnLinkModule(mod2, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("2nd NSUnLinkModule failed"); + return 0; + } + + // now link again after unlinking everything + NSModule mod4 = NSLinkModule(ofi, "test4.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod4 == NULL ) { + FAIL("4th NSLinkModule failed"); + return 0; + } + + // check that this is really a new copy by verifying the getValue() returns zero + NSSymbol sym4getter = NSLookupSymbolInModule(mod2, "_getValue"); + if ( sym4getter == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed"); + return 0; + } + getter func4getter = NSAddressOfSymbol(sym4getter); + if ( (*func4getter)() != 0 ) { + FAIL("_getValue() on fourth link returned non-zero"); + return 0; + } + + if ( !NSUnLinkModule(mod4, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("4th NSUnLinkModule failed"); + return 0; + } + + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("NSDestroyObjectFileImage failed"); + return 0; + } + + PASS("bundle-multi-link"); + return 0; +} + diff --git a/unit-tests/test-cases/bundle-multi-load/Makefile b/unit-tests/test-cases/bundle-multi-load/Makefile new file mode 100644 index 0000000..ce5b2d4 --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-load/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + + diff --git a/unit-tests/test-cases/bundle-multi-load/bundle.c b/unit-tests/test-cases/bundle-multi-load/bundle.c new file mode 100644 index 0000000..84955c4 --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-load/bundle.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +int foo() +{ + return 4; +} + diff --git a/unit-tests/test-cases/bundle-multi-load/main.c b/unit-tests/test-cases/bundle-multi-load/main.c new file mode 100644 index 0000000..5d4d052 --- /dev/null +++ b/unit-tests/test-cases/bundle-multi-load/main.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" // PASS(), FAIL() + +/// +/// The point of this test is to load the same bundle file multiple times and +/// verify each time it is linked is a new instantiations (new globals, etc) +/// + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 0; + } + + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod == NULL ) { + FAIL("NSLinkModule failed"); + return 0; + } + + NSSymbol sym = NSLookupSymbolInModule(mod, "_foo"); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 0; + } + + void* func = NSAddressOfSymbol(sym); + fprintf(stderr, "1st address of foo() = %p in module %p in OFI %p\n", func, mod, ofi); + + + NSObjectFileImage ofi2; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi2) != NSObjectFileImageSuccess ) { + FAIL("2nd NSCreateObjectFileImageFromFile failed"); + return 0; + } + + NSModule mod2 = NSLinkModule(ofi2, "test2.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod2 == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed"); + return 0; + } + if ( mod == mod2 ) { + FAIL("2nd NSLinkModule return same function address as first\n"); + return 0; + } + + NSSymbol sym2 = NSLookupSymbolInModule(mod2, "_foo"); + if ( sym2 == NULL ) { + FAIL("2nd NSLookupSymbolInModule failed\n"); + return 0; + } + + void* func2 = NSAddressOfSymbol(sym2); + fprintf(stderr, "2nd address of foo() = %p in module %p in OFI %p\n", func2, mod2, ofi2); + if ( func == func2 ) { + FAIL("2nd NSAddressOfSymbol return same function address as 1st\n"); + return 0; + } + + + NSObjectFileImage ofi3; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi3) != NSObjectFileImageSuccess ) { + FAIL("3rd NSCreateObjectFileImageFromFile failed"); + return 0; + } + NSModule mod3 = NSLinkModule(ofi3, "test3.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod3 == NULL ) { + FAIL("3rd NSLinkModule failed\n"); + return 0; + } + if ( mod3 == mod ) { + FAIL("3rd NSLinkModule return same function address as 1st\n"); + return 0; + } + if ( mod3 == mod2 ) { + FAIL("3rd NSLinkModule return same function address as 2nd\n"); + return 0; + } + + NSSymbol sym3 = NSLookupSymbolInModule(mod3, "_foo"); + if ( sym3 == NULL ) { + FAIL("3rd NSLookupSymbolInModule failed\n"); + return 0; + } + void* func3 = NSAddressOfSymbol(sym3); + fprintf(stderr, "3rd address of foo() = %p in module %p in OFI %p\n", func3, mod3, ofi3); + if ( func3 == func ) { + FAIL("3rd NSAddressOfSymbol return same function address as 1st\n"); + return 0; + } + if ( func3 == func2 ) { + FAIL("3rd NSAddressOfSymbol return same function address as 2nd\n"); + return 0; + } + + if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 0; + } + + if ( !NSUnLinkModule(mod3, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("3rd NSUnLinkModule failed"); + return 0; + } + + // note, we are calling NSDestroyObjectFileImage() before NSUnLinkModule() + if ( !NSDestroyObjectFileImage(ofi2) ) { + FAIL("2nd NSDestroyObjectFileImage failed"); + return 0; + } + if ( !NSUnLinkModule(mod2, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("2nd NSUnLinkModule failed"); + return 0; + } + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("1st NSDestroyObjectFileImage failed"); + return 0; + } + if ( !NSDestroyObjectFileImage(ofi3) ) { + FAIL("3rd NSDestroyObjectFileImage failed"); + return 0; + } + + PASS("bundle-multi-load"); + return 0; +} + diff --git a/unit-tests/test-cases/bundle-private/Makefile b/unit-tests/test-cases/bundle-private/Makefile new file mode 100644 index 0000000..2c905f2 --- /dev/null +++ b/unit-tests/test-cases/bundle-private/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + diff --git a/unit-tests/test-cases/bundle-private/bundle.c b/unit-tests/test-cases/bundle-private/bundle.c new file mode 100644 index 0000000..b7cdc4f --- /dev/null +++ b/unit-tests/test-cases/bundle-private/bundle.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// test to see if NSLINKMODULE_OPTION_PRIVATE works + +void findme() +{ +} diff --git a/unit-tests/test-cases/bundle-private/main.c b/unit-tests/test-cases/bundle-private/main.c new file mode 100644 index 0000000..86eac29 --- /dev/null +++ b/unit-tests/test-cases/bundle-private/main.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + +typedef bool (*CheckFunc)(); + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 1; + } + + NSModule modPriv = NSLinkModule(ofi, "test.bundle-private", NSLINKMODULE_OPTION_PRIVATE); + if ( modPriv == NULL ) { + FAIL("NSLinkModule failed"); + return 1; + } + + NSSymbol symPriv = NSLookupSymbolInModule(modPriv, "_findme"); + if ( symPriv == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 1; + } + + if ( NSIsSymbolNameDefined("_findme") ) { + FAIL("NSIsSymbolNameDefined (incorrectly) found symbol in private bundle"); + return 1; + } + + NSModule modPublic = NSLinkModule(ofi, "test.bundle-public", NSLINKMODULE_OPTION_NONE); + if ( modPublic == NULL ) { + FAIL("NSLinkModule failed"); + return 1; + } + + NSSymbol symPublic = NSLookupSymbolInModule(modPublic, "_findme"); + if ( symPublic == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 1; + } + + if ( !NSIsSymbolNameDefined("_findme") ) { + FAIL("NSIsSymbolNameDefined did not found symbol in public bundle"); + return 1; + } + + if ( !NSUnLinkModule(modPriv, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 1; + } + + if ( !NSUnLinkModule(modPublic, NSUNLINKMODULE_OPTION_NONE) ) { + FAIL("NSUnLinkModule failed"); + return 1; + } + + if ( NSIsSymbolNameDefined("_findme") ) { + FAIL("NSIsSymbolNameDefined found unlinked symbol in public bundle"); + return 1; + } + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("NSDestroyObjectFileImage failed"); + return 1; + } + + PASS("bundle-private"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-unlinkable/Makefile b/unit-tests/test-cases/bundle-unlinkable/Makefile new file mode 100644 index 0000000..e7f9fd2 --- /dev/null +++ b/unit-tests/test-cases/bundle-unlinkable/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c libstuff.dylib + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c libstuff.dylib + +libstuff.dylib : lib.c + ${CC} ${CCFLAGS} lib.c -dynamiclib -o libstuff.dylib -install_name libcantfind.dylib + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle libstuff.dylib + diff --git a/unit-tests/test-cases/bundle-unlinkable/bundle.c b/unit-tests/test-cases/bundle-unlinkable/bundle.c new file mode 100644 index 0000000..8f91e11 --- /dev/null +++ b/unit-tests/test-cases/bundle-unlinkable/bundle.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +extern int bar(); + + +int foo() +{ + return bar(); +} + diff --git a/unit-tests/test-cases/bundle-unlinkable/lib.c b/unit-tests/test-cases/bundle-unlinkable/lib.c new file mode 100644 index 0000000..541b964 --- /dev/null +++ b/unit-tests/test-cases/bundle-unlinkable/lib.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +int bar() +{ + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-unlinkable/main.c b/unit-tests/test-cases/bundle-unlinkable/main.c new file mode 100644 index 0000000..93af268 --- /dev/null +++ b/unit-tests/test-cases/bundle-unlinkable/main.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + +typedef bool (*CheckFunc)(); + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 1; + } + + // make sure not-yet-linked-ofi is not visible through _dyld_get_image_name + int count = _dyld_image_count(); + for(int i=0; i < count; ++i) { + const char* name = _dyld_get_image_name(i); + if ( strcmp(name, "test.bundle") == 0 ) { + FAIL("unlinked test.bundle found via _dyld_get_image_name()"); + return 1; + } + } + + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_RETURN_ON_ERROR); + if ( mod != NULL ) { + FAIL("NSLinkModule succeeded but should have failed"); + return 1; + } + + // make sure link-failed-ofi is not visible through _dyld_get_image_name + count = _dyld_image_count(); + for(int i=0; i < count; ++i) { + const char* name = _dyld_get_image_name(i); + if ( strcmp(name, "test.bundle") == 0 ) { + FAIL("failed linked test.bundle found via _dyld_get_image_name()"); + return 1; + } + } + + PASS("bundle-unlinkable"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-unload-keep-mapped/Makefile b/unit-tests/test-cases/bundle-unload-keep-mapped/Makefile new file mode 100644 index 0000000..2c905f2 --- /dev/null +++ b/unit-tests/test-cases/bundle-unload-keep-mapped/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + diff --git a/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c b/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c new file mode 100644 index 0000000..938ea75 --- /dev/null +++ b/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +// test to see if bss section is properly expanded + +static int mydata[10]; + +bool checkdata() +{ + return ( mydata[10] == 0 ); +} diff --git a/unit-tests/test-cases/bundle-unload-keep-mapped/main.c b/unit-tests/test-cases/bundle-unload-keep-mapped/main.c new file mode 100644 index 0000000..c79b0fd --- /dev/null +++ b/unit-tests/test-cases/bundle-unload-keep-mapped/main.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + +typedef bool (*CheckFunc)(); + +int main() +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 1; + } + + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_NONE); + if ( mod == NULL ) { + FAIL("NSLinkModule failed"); + return 1; + } + + NSSymbol sym = NSLookupSymbolInModule(mod, "_checkdata"); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInModule failed"); + return 1; + } + + CheckFunc func = NSAddressOfSymbol(sym); + if ( !func() ) { + FAIL("NSAddressOfSymbol failed"); + return 1; + } + + if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) ) { + FAIL("NSUnLinkModule failed"); + return 1; + } + + if ( !NSDestroyObjectFileImage(ofi) ) { + FAIL("NSDestroyObjectFileImage failed"); + return 1; + } + + // call function again, even though bundle is unloaded + func(); + + + PASS("bundle-basic"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/bundle-v-dylib/Makefile b/unit-tests/test-cases/bundle-v-dylib/Makefile new file mode 100644 index 0000000..e2df5ed --- /dev/null +++ b/unit-tests/test-cases/bundle-v-dylib/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c bar.dylib foo.bundle foo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c bar.dylib + +foo.bundle : foo.c + ${CC} ${CCFLAGS} -bundle -o foo.bundle foo.c + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib -o foo.dylib foo.c + +bar.dylib : bar.c + ${CC} ${CCFLAGS} -dynamiclib -o bar.dylib bar.c + +clean: + ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib bar.dylib + diff --git a/unit-tests/test-cases/bundle-v-dylib/bar.c b/unit-tests/test-cases/bundle-v-dylib/bar.c new file mode 100644 index 0000000..65f9d64 --- /dev/null +++ b/unit-tests/test-cases/bundle-v-dylib/bar.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + + +void bar() +{ + +} diff --git a/unit-tests/test-cases/bundle-v-dylib/foo.c b/unit-tests/test-cases/bundle-v-dylib/foo.c new file mode 100644 index 0000000..91fbe46 --- /dev/null +++ b/unit-tests/test-cases/bundle-v-dylib/foo.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + + +void foo() +{ + +} diff --git a/unit-tests/test-cases/bundle-v-dylib/main.c b/unit-tests/test-cases/bundle-v-dylib/main.c new file mode 100644 index 0000000..4f0e3a9 --- /dev/null +++ b/unit-tests/test-cases/bundle-v-dylib/main.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + + +void loadAsBundle(const char* path) +{ + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile(path, &ofi) == NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile() incorrectly allowed %s to be loaded", path); + exit(1); + } +} + +void loadAsDylib(const char* path) +{ + if ( NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR) != NULL ) { + FAIL("NSAddImage() incorrectly allowed %s to be loaded", path); + exit(1); + } +} + + +extern void bar(); + +int main() +{ + // verify that NSAddImage fails to load MH_BUNDLE + loadAsDylib("foo.bundle"); + + // verify that NSCreateObjectFileImageFromFile fails to load MH_DYLIB + loadAsBundle("foo.dylib"); + + // verify that NSCreateObjectFileImageFromFile fails to load MH_DYLIB already linked against main + loadAsBundle("bar.dylib"); + // verify that bar.dylib was not unloaded when above failed + bar(); + + PASS("bundle-v-dylib"); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/deadlock/Makefile b/unit-tests/test-cases/deadlock/Makefile new file mode 100644 index 0000000..76d4808 --- /dev/null +++ b/unit-tests/test-cases/deadlock/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c bar.dylib foo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.dylib + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib -o foo.dylib foo.c + +bar.dylib : bar.c + ${CC} ${CCFLAGS} -dynamiclib -o bar.dylib bar.c + +clean: + ${RM} ${RMFLAGS} *~ main foo.dylib bar.dylib + diff --git a/unit-tests/test-cases/deadlock/bar.c b/unit-tests/test-cases/deadlock/bar.c new file mode 100644 index 0000000..ea63b5f --- /dev/null +++ b/unit-tests/test-cases/deadlock/bar.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +void bar() +{ + +} diff --git a/unit-tests/test-cases/deadlock/foo.c b/unit-tests/test-cases/deadlock/foo.c new file mode 100644 index 0000000..8b9c637 --- /dev/null +++ b/unit-tests/test-cases/deadlock/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +void foo() +{ + +} diff --git a/unit-tests/test-cases/deadlock/main.c b/unit-tests/test-cases/deadlock/main.c new file mode 100644 index 0000000..07ad467 --- /dev/null +++ b/unit-tests/test-cases/deadlock/main.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include + +#include "test.h" + +/// rdar://problem/3811777 + +// barrier thread 1 thread 2 +// add image +// 1 +// acquire sMyLock +// 2 +// in callback acquire sMyLock call lazy pointer +// release sMyLock release sMyLock + +extern void foo(); + + +static volatile int sBarrier = 0; +static pthread_mutex_t sBarrierMutex; +static pthread_cond_t sBarrierFree; + +static void blockUntilBarrier(int n) +{ + pthread_mutex_lock(&sBarrierMutex); + while ( sBarrier < n ) + pthread_cond_wait(&sBarrierFree, &sBarrierMutex); + pthread_mutex_unlock(&sBarrierMutex); +} + +static void advanceToBarrier(int n) +{ + pthread_mutex_lock(&sBarrierMutex); + sBarrier = n; + pthread_cond_broadcast(&sBarrierFree); + pthread_mutex_unlock(&sBarrierMutex); +} + + + + + +static pthread_mutex_t sMyLock; + +static void* thread2(void* arg) +{ + // thread 2 + blockUntilBarrier(1); + pthread_mutex_lock(&sMyLock); + advanceToBarrier(2); + foo(); + pthread_mutex_unlock(&sMyLock); + return NULL; +} + + + +static void myImageHandler(const struct mach_header *mh, intptr_t vmaddr_slide) +{ + // thread 1 + if ( NSLookupSymbolInImage(mh, "_bar", 0) != NULL ) { + advanceToBarrier(1); + blockUntilBarrier(2); + pthread_mutex_lock(&sMyLock); + pthread_mutex_unlock(&sMyLock); + } +} + +int main() +{ + pthread_mutex_init(&sBarrierMutex, NULL); + pthread_cond_init(&sBarrierFree, NULL); + pthread_mutex_init(&sMyLock, NULL); + + // self-terminate this process if it locks up for two seconds + alarm(2); + + advanceToBarrier(0); + + pthread_t pthread2; + if ( pthread_create(&pthread2, NULL, thread2, NULL) != 0 ) { + FAIL("pthread_create failed"); + exit(0); + } + + // thread 1 + _dyld_register_func_for_add_image(&myImageHandler); + NSAddImage("bar.dylib", 0); + + PASS("deadlock"); +} diff --git a/unit-tests/test-cases/dladdr/Makefile b/unit-tests/test-cases/dladdr/Makefile new file mode 100644 index 0000000..b0ee016 --- /dev/null +++ b/unit-tests/test-cases/dladdr/Makefile @@ -0,0 +1,34 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/dladdr/main.c b/unit-tests/test-cases/dladdr/main.c new file mode 100644 index 0000000..a57e708 --- /dev/null +++ b/unit-tests/test-cases/dladdr/main.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +int bar() +{ + return 2; +} + +static int foo() +{ + return 3; +} + +int bar2() +{ + return 4; +} + +// checks global symbol +static void verifybar() +{ + Dl_info info; + if ( dladdr(&bar, &info) == 0 ) { + FAIL("dladdr(&bar, xx) failed"); + exit(0); + } + if ( strcmp(info.dli_sname, "bar") != 0 ) { + if ( strcmp(info.dli_sname, "_bar") == 0 ) { + XFAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname); + } + else { + FAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname); + exit(0); + } + } + if ( info.dli_saddr != &bar) { + FAIL("dladdr()->dli_saddr is not &bar"); + exit(0); + } + if ( info.dli_fbase != _dyld_get_image_header_containing_address(&bar) ) { + FAIL("dladdr()->dli_fbase is not image that contains &bar"); + exit(0); + } +} + +// checks local symbol (should resolve to previoius global symbol bar) +static void verifyfoo() +{ + Dl_info info; + if ( dladdr(&foo, &info) == 0 ) { + FAIL("dladdr(&foo, xx) failed"); + exit(0); + } + if ( strcmp(info.dli_sname, "bar") != 0 ) { + if ( strcmp(info.dli_sname, "_bar") == 0 ) { + XFAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname); + } + else { + FAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname); + exit(0); + } + } + if ( info.dli_saddr != &bar) { + FAIL("dladdr()->dli_saddr is not &bar"); + exit(0); + } + if ( info.dli_fbase != _dyld_get_image_header_containing_address(&bar) ) { + FAIL("dladdr()->dli_fbase is not image that contains &bar"); + exit(0); + } +} + + +int main() +{ + verifybar(); + verifyfoo(); + + + PASS("dladdr"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlclose-basic/Makefile b/unit-tests/test-cases/dlclose-basic/Makefile new file mode 100644 index 0000000..73451f0 --- /dev/null +++ b/unit-tests/test-cases/dlclose-basic/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +test.bundle : foo.c + ${CC} ${CCFLAGS} -bundle -o test.bundle foo.c + +main : main.c test.bundle + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + + diff --git a/unit-tests/test-cases/dlclose-basic/foo.c b/unit-tests/test-cases/dlclose-basic/foo.c new file mode 100644 index 0000000..39ab8be --- /dev/null +++ b/unit-tests/test-cases/dlclose-basic/foo.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +int foo() +{ + return 1; +} diff --git a/unit-tests/test-cases/dlclose-basic/main.c b/unit-tests/test-cases/dlclose-basic/main.c new file mode 100644 index 0000000..ee7c122 --- /dev/null +++ b/unit-tests/test-cases/dlclose-basic/main.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +int main() +{ + // regular open + void* handle = dlopen("test.bundle", RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"test.bundle\", RTLD_LAZY) failed"); + exit(1); + } + + // regular close + int result = dlclose(handle); + if ( result != 0 ) { + FAIL("dlclose() failed"); + exit(1); + } + + // now try to close again (expect to fail) + result = dlclose(handle); + if ( result != -1 ) { + FAIL("dlclose() on released handle should have returned -1, but returned %d", result); + exit(1); + } + + // now try to close a bad handle value (expect to fail) + result = dlclose((void*)0x12345); + if ( result != -1 ) { + FAIL("dlclose() on bogus handle should have returned -1, but returned %d", result); + exit(1); + } + + PASS("dlclose-basic"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlclose-bundle-unload/Makefile b/unit-tests/test-cases/dlclose-bundle-unload/Makefile new file mode 100644 index 0000000..84fc5b4 --- /dev/null +++ b/unit-tests/test-cases/dlclose-bundle-unload/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle + diff --git a/unit-tests/test-cases/dlclose-bundle-unload/foo.c b/unit-tests/test-cases/dlclose-bundle-unload/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlclose-bundle-unload/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlclose-bundle-unload/main.c b/unit-tests/test-cases/dlclose-bundle-unload/main.c new file mode 100644 index 0000000..3e0798a --- /dev/null +++ b/unit-tests/test-cases/dlclose-bundle-unload/main.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int main() +{ + // open same bundle three times + void* handle1 = dlopen("test.bundle", RTLD_LAZY); + if ( handle1 == NULL ) { + FAIL("dlclose-bundle-unload: dlopen(\"test.bundle\", RTLD_LAZY) failed with dlerror()=%s", dlerror()); + exit(0); + } + + void* handle2 = dlopen("test.bundle", RTLD_LAZY); + if ( handle2 == NULL ) { + FAIL("dlclose-bundle-unload: dlopen(\"test.bundle\", RTLD_LAZY) failed with dlerror()=%s", dlerror()); + exit(0); + } + + void* handle3 = dlopen("test.bundle", RTLD_LAZY); + if ( handle3 == NULL ) { + FAIL("dlclose-bundle-unload: dlopen(\"test.bundle\", RTLD_LAZY) failed with dlerror()=%s", dlerror()); + exit(0); + } + + // get symbol + void* sym = dlsym(handle1, "foo"); + if ( sym == NULL ) { + FAIL("dlclose-bundle-unload: dlsym(handle1, \"foo\") failed"); + exit(0); + } + + // close same bundle three times + if ( dlclose(handle3) != 0 ) { + FAIL("dlclose-bundle-unload: dlclose(handle3) != 0, dlerrr()=%s", dlerror()); + exit(0); + } + + if ( dlclose(handle2) != 0 ) { + FAIL("dlclose-bundle-unload: dlclose(handle2) != 0, dlerrr()=%s", dlerror()); + exit(0); + } + + if ( dlclose(handle1) != 0 ) { + FAIL("dlclose-bundle-unload: dlclose(handle1) != 0, dlerrr()=%s", dlerror()); + exit(0); + } + + + // extra close should fail + if ( dlclose(handle1) == 0 ) { + FAIL("dlclose-bundle-unload: dlclose(handle4) == 0, but should have failed"); + exit(0); + } + + + + PASS("dlclose-bundle-unload"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlerror/Makefile b/unit-tests/test-cases/dlerror/Makefile new file mode 100644 index 0000000..7337131 --- /dev/null +++ b/unit-tests/test-cases/dlerror/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/dlerror/main.c b/unit-tests/test-cases/dlerror/main.c new file mode 100644 index 0000000..808dc56 --- /dev/null +++ b/unit-tests/test-cases/dlerror/main.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This tests that the dlerror message is kept per thread +/// + +static void* work(void* arg) +{ + const char* str = (char*)arg; + for(int i=0; i < 1000; ++i) { + //fprintf(stderr, "dlopen(%s)\n", str); + void* handle = dlopen(str, RTLD_LAZY); + if ( handle != NULL ) { + FAIL("dlopen(%s) unexpectedly succeeded", str); + exit(0); + } + char* msg = dlerror(); + //fprintf(stderr, "dlopen(%s) => %s\n", str, msg); + if ( (msg == NULL) || (strstr(msg, str) == NULL) ) { + FAIL("dlerror() did not contain library name that could not be loaded", str); + exit(0); + } + + + } + return 0; +} + + + +int main() +{ + dlsym(RTLD_DEFAULT, "foobar"); + fprintf(stderr, "%s\n", dlerror()); + + pthread_t worker1; + if ( pthread_create(&worker1, NULL, work, "/frazzle/bar") != 0 ) { + FAIL("pthread_create failed"); + exit(0); + } + + pthread_t worker2; + if ( pthread_create(&worker2, NULL, work, "/frazzle/foo") != 0 ) { + FAIL("pthread_create failed"); + exit(0); + } + + pthread_t worker3; + if ( pthread_create(&worker3, NULL, work, "/frazzle/dazzle") != 0 ) { + FAIL("pthread_create failed"); + exit(0); + } + + void* result; + fprintf(stderr, "waiting for worker 1\n"); + pthread_join(worker1, &result); + fprintf(stderr, "waiting for worker 2\n"); + pthread_join(worker2, &result); + fprintf(stderr, "waiting for worker 3\n"); + pthread_join(worker3, &result); + + PASS("dlerror-thread-test"); + return 0; +} diff --git a/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/Makefile b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/Makefile new file mode 100644 index 0000000..b20f99c --- /dev/null +++ b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main "`pwd`/libfoo.dylib" + export DYLD_LIBRARY_PATH="`pwd`/alt" && ./main "`pwd`/libfoo.dylib" + +all: main alt/libfoo.dylib + +main : main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib + + +alt/libfoo.dylib : foo.c + mkdir -p alt + ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt/libfoo.dylib" -DALT + +libfoo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/libfoo.dylib" + + + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib alt/libfoo.dylib alt + diff --git a/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/foo.c b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/foo.c new file mode 100644 index 0000000..0502e90 --- /dev/null +++ b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/foo.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ +#ifdef ALT + return 1; +#else + return 0; +#endif +} diff --git a/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/main.c b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/main.c new file mode 100644 index 0000000..8067d7c --- /dev/null +++ b/unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/main.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include // for getenv() + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +typedef int (*fooproc)(); + +int main(int argc, const char* argv[]) +{ + void* handle = dlopen(argv[1], RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", argv[1]); + exit(0); + } + + fooproc sym = (fooproc)dlsym(handle, "foo"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"foo\") failed"); + exit(0); + } + + int expectedResult = 0; + if ( getenv("DYLD_LIBRARY_PATH") != NULL ) + expectedResult = 1; + + int actualResult = (*sym)(); + + if ( actualResult != expectedResult ) + FAIL("dlopen-DYLD_LIBRARY_PATH using wrong dylib"); + else + PASS("dlopen-DYLD_LIBRARY_PATH"); + + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/Makefile b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/Makefile new file mode 100644 index 0000000..6a3e391 --- /dev/null +++ b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/Makefile @@ -0,0 +1,70 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# tests combinations of dlopen() and LD_LIBRARY_PATH +# +# if dlopen() path contains a slash, LD_LIBRARY_PATH is ignored +# +# 1) leaf name found in current directory (On linux this fails because . is usually not in default LD_LIBRARY_PATH path) +# 2) cwd relative path +# 3) full path +# 4) leaf name and LD_LIBRARY_PATH overrides cwd (On 10.3, this fails because cwd was always searched before LD_LIBRARY_PATH??) +# 5) leaf name and LD_LIBRARY_PATH set to alternate directory +# 6) fullpath and LD_LIBRARY_PATH set to alt +# + +run: all + cd alt1 && ../main "libfoo.dylib" 1 "leafname found in cwd" + ./main "./alt1/libfoo.dylib" 1 "relative path" + ./main "`pwd`/alt2/libfoo.dylib" 2 "fullpath" + export LD_LIBRARY_PATH="`pwd`/alt1" && ./main "libfoo.dylib" 1 "leafname and LD_LIBRARY_PATH overrides cwd" + export LD_LIBRARY_PATH="`pwd`/alt1" && cd alt3 && ../main "libfoo.dylib" 1 "leafname and alt LD_LIBRARY_PATH" + export LD_LIBRARY_PATH="`pwd`/alt1" && ./main "`pwd`/alt2/libfoo.dylib" 2 "fullpath and LD_LIBRARY_PATH" + +all: main alt1/libfoo.dylib alt2/libfoo.dylib alt3 + +main : main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib + + +alt1/libfoo.dylib : foo.c + mkdir -p alt1 + ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt1/libfoo.dylib" -DVALUE=1 + +alt2/libfoo.dylib : foo.c + mkdir -p alt2 + ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt2/libfoo.dylib" -DVALUE=2 + +libfoo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/libfoo.dylib" -DVALUE=0 + +alt3 : + mkdir -p alt3 + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib alt1 alt2 alt3 + diff --git a/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/foo.c b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/foo.c new file mode 100644 index 0000000..de65df5 --- /dev/null +++ b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return VALUE; +} diff --git a/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/main.c b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/main.c new file mode 100644 index 0000000..70f18bb --- /dev/null +++ b/unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/main.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include // for getenv() + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +typedef int (*fooproc)(); + +// +// argv[1] is path to dlopen() +// argv[2] is exepect result from foo() +// argv[3] is message +// +int main(int argc, const char* argv[]) +{ + void* handle = dlopen(argv[1], RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen-LD_LIBRARY_PATH %s, dlopen(\"%s\") failed", argv[3], argv[1]); + exit(0); + } + + fooproc sym = (fooproc)dlsym(handle, "foo"); + if ( sym == NULL ) { + FAIL("dlopen-LD_LIBRARY_PATH %s, dlsym(handle, \"foo\") failed", argv[3]); + exit(0); + } + + int expectedResult = atoi(argv[2]); + + int actualResult = (*sym)(); + + if ( actualResult != expectedResult ) + FAIL("dlopen-LD_LIBRARY_PATH %s", argv[3]); + else + PASS("dlopen-LD_LIBRARY_PATH %s", argv[3]); + + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_GLOBAL/Makefile b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/Makefile new file mode 100644 index 0000000..260c1e0 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main foo.bundle bar.bundle + ./main foo.dylib bar.bundle + +all: main foo.bundle foo.dylib bar.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +foo.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o foo.bundle + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib + +bar.bundle : bar.c + ${CC} ${CCFLAGS} -flat_namespace -bundle bar.c -o bar.bundle -undefined suppress + +clean: + ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib bar.bundle + diff --git a/unit-tests/test-cases/dlopen-RTLD_GLOBAL/bar.c b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/bar.c new file mode 100644 index 0000000..e8e0806 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/bar.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int foo; + +int bar() +{ + return foo; +} + + diff --git a/unit-tests/test-cases/dlopen-RTLD_GLOBAL/foo.c b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/foo.c new file mode 100644 index 0000000..8689597 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo = 0; diff --git a/unit-tests/test-cases/dlopen-RTLD_GLOBAL/main.c b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/main.c new file mode 100644 index 0000000..a25854b --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_GLOBAL/main.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + + + +int main(int argc, const char* argv[]) +{ + // open first object which defines foo + void* handle = dlopen(argv[1], RTLD_GLOBAL); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", argv[1]); + exit(1); + } + + // open second object which uses foo + void* handle2 = dlopen(argv[2], RTLD_NOW); + if ( handle2 == NULL ) { + FAIL("dlopen(\"%s\") failed", argv[2]); + exit(1); + } + + PASS("dlopen-RTLD_GLOBAL"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/Makefile b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/Makefile new file mode 100644 index 0000000..d7b6978 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/Makefile @@ -0,0 +1,44 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c foo.dylib bar.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.dylib + + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib + +bar.dylib : bar.c + ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.dylib + + +clean: + ${RM} ${RMFLAGS} *~ main foo.dylib bar.dylib + diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/bar.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/bar.c new file mode 100644 index 0000000..73b29f2 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/bar.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int bar() +{ + return 2; +} + + diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/foo.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/foo.c new file mode 100644 index 0000000..d040e48 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 1; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/main.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/main.c new file mode 100644 index 0000000..b2862c5 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/main.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +int main(int argc, const char* argv[]) +{ + // main alreadly links with foo.dylib + // now dynamically link with bar.dylib + void* handle = dlopen("./bar.dylib", RTLD_GLOBAL); + if ( handle == NULL ) { + const char* msg = dlerror(); + FAIL("dlopen(\"%s\", RTLD_GLOBAL) failed: %s", argv[1], msg); + return EXIT_SUCCESS; + } + + // verify we can find _foo + void* fooSym = dlsym(RTLD_DEFAULT, "foo"); + if ( fooSym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(RTLD_DEFAULT, \"foo\") failed: %s", msg); + return EXIT_SUCCESS; + } + + // verify we can find _bar + void* barSym = dlsym(RTLD_DEFAULT, "bar"); + if ( barSym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(RTLD_DEFAULT, \"bar\") failed: %s", msg); + return EXIT_SUCCESS; + } + + // open foo privately (since it was already opened global, RTLD_LOCAL should have no effect + void* handleFoo = dlopen("./foo.dylib", RTLD_LOCAL); + if ( handleFoo == NULL ) { + const char* msg = dlerror(); + FAIL("dlopen(\"%s\", RTLD_LOCAL) failed: %s", "./foo.dylib", msg); + return EXIT_SUCCESS; + } + + // open foo privately (since it was already opened global, RTLD_LOCAL should have no effect + void* handleBar = dlopen("./bar.dylib", RTLD_LOCAL); + if ( handleBar == NULL ) { + const char* msg = dlerror(); + FAIL("dlopen(\"%s\", RTLD_LOCAL) failed: %s", "./bar.dylib", msg); + return EXIT_SUCCESS; + } + + // verify we can still find _foo + fooSym = dlsym(RTLD_DEFAULT, "foo"); + if ( fooSym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(RTLD_DEFAULT, \"foo\") failed: %s", msg); + return EXIT_SUCCESS; + } + + // verify we can still find _bar + barSym = dlsym(RTLD_DEFAULT, "bar"); + if ( barSym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(RTLD_DEFAULT, \"bar\") failed: %s", msg); + return EXIT_SUCCESS; + } + + PASS("dlopen-RTLD_LOCAL-ignore"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL/Makefile b/unit-tests/test-cases/dlopen-RTLD_LOCAL/Makefile new file mode 100644 index 0000000..260c1e0 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main foo.bundle bar.bundle + ./main foo.dylib bar.bundle + +all: main foo.bundle foo.dylib bar.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +foo.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o foo.bundle + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib + +bar.bundle : bar.c + ${CC} ${CCFLAGS} -flat_namespace -bundle bar.c -o bar.bundle -undefined suppress + +clean: + ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib bar.bundle + diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL/bar.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL/bar.c new file mode 100644 index 0000000..e8e0806 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL/bar.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int foo; + +int bar() +{ + return foo; +} + + diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL/foo.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL/foo.c new file mode 100644 index 0000000..8689597 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo = 0; diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL/main.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL/main.c new file mode 100644 index 0000000..b8a30bc --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_LOCAL/main.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + +int main(int argc, const char* argv[]) +{ + // open first object which defines foo + void* handle = dlopen(argv[1], RTLD_LOCAL); + if ( handle == NULL ) { + const char* msg = dlerror(); + // Panther dlopen() fails on RTLD_LOCAL of a dylib + if ( strstr(msg, "RTLD_LOCAL") != NULL ) + XFAIL("dlopen(\"%s\", RTLD_LOCAL) failed: %s", argv[1], msg); + else + FAIL("dlopen(\"%s\", RTLD_LOCAL) failed: %s", argv[1], msg); + return EXIT_SUCCESS; + } + + // open second object which uses foo + void* handle2 = dlopen(argv[2], RTLD_NOW); + if ( handle2 != NULL ) { + FAIL("dlopen(\"%s\") succeeded but foo should have been not found", argv[2]); + return EXIT_SUCCESS; + } + const char* msg = dlerror(); + if ( strstr(msg, "foo") == NULL ) { + FAIL("dlopen(\"%s\") correctly failed, but foo was not in error mesage: %s", argv[2], msg); + return EXIT_SUCCESS; + } + + + PASS("dlopen-RTLD_LOCAL"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_NODELETE/Makefile b/unit-tests/test-cases/dlopen-RTLD_NODELETE/Makefile new file mode 100644 index 0000000..776d676 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NODELETE/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle test.dylib + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle + +test.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib + diff --git a/unit-tests/test-cases/dlopen-RTLD_NODELETE/foo.c b/unit-tests/test-cases/dlopen-RTLD_NODELETE/foo.c new file mode 100644 index 0000000..5cc9791 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NODELETE/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo = 10; \ No newline at end of file diff --git a/unit-tests/test-cases/dlopen-RTLD_NODELETE/main.c b/unit-tests/test-cases/dlopen-RTLD_NODELETE/main.c new file mode 100644 index 0000000..296479e --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NODELETE/main.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This tests that RTLD_NODELETE prevents an image from being unloaded +/// + +static int trySO(const char* path) +{ // main links against libfoo.dylib so it should already be loaded + void* handle = dlopen(path, RTLD_NODELETE); + if ( handle == NULL ) { + const char* msg = dlerror(); + FAIL("dlopen(\"%s\" RTLD_NODELETE) failed but it should have worked: %s", path, msg); + exit(0); + } + void* sym = dlsym(handle, "foo"); + if ( sym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(handle, \"foo\") failed but it should have worked: %s", msg); + exit(0); + } + + int result = dlclose(handle); + if ( result != 0 ) { + if ( result == 1 ) { + // panther dyld returns 1 if you try to dlclose() a dylib + XFAIL("dlclose(handle[%s]) returned %d", path, result); + } + else { + FAIL("dlclose(handle) returned %d", result); + exit(0); + } + } + + // now try to access foo. If .so was unmapped, this will bus error + return *((int*)sym); +} + + +int main() +{ + trySO("test.bundle"); + trySO("test.dylib"); + + PASS("dlopen-RTLD_NODELETE"); + return 0; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD/Makefile b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/Makefile new file mode 100644 index 0000000..624f4f1 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main libfoo.dylib + +main : main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main + +libfoo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib + + + + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib + diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD/foo.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD/main.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/main.c new file mode 100644 index 0000000..7383a8c --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOLOAD/main.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This tests that RTLD_NOLOAD binds finds existing images +/// + + +int main() +{ + // main links against libfoo.dylib so it should already be loaded + void* handle = dlopen("libfoo.dylib", RTLD_NOLOAD); + if ( handle == NULL ) { + const char* msg = dlerror(); + // Panther dlcompat does not check existing loaded images (only those opened with dlopen) + if ( strstr(msg, "RTLD_NOLOAD") != NULL ) + XFAIL("dlopen(libfoo.dylib, RTLD_NOLOAD) failed but it should have worked: %s", msg); + else + FAIL("dlopen(libfoo.dylib, RTLD_NOLOAD) failed but it should have worked: %s", msg); + return 0; + } + void* sym = dlsym(handle, "foo"); + if ( sym == NULL ) { + const char* msg = dlerror(); + FAIL("dlsym(handle, \"foo\") failed but it should have worked: %s", msg); + return 0; + } + + // libfobbulate.dylib does not exist, so load should return NULL + void* handle2 = dlopen("libfobbulate.dylib", RTLD_NOLOAD); + if ( handle2 != NULL ) { + FAIL("dlopen(libfobbulate.dylib, RTLD_NOLOAD) succeeded but it should have failed"); + return 0; + } + + + + PASS("dlopen-RTLD_NOLOAD"); + return 0; +} diff --git a/unit-tests/test-cases/dlopen-RTLD_NOW/Makefile b/unit-tests/test-cases/dlopen-RTLD_NOW/Makefile new file mode 100644 index 0000000..0d2ffe2 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOW/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle foo.dylib foo_foo2.dylib + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c foo_foo2.dylib + ${CC} ${CCFLAGS} -bundle bundle.c foo_foo2.dylib -o test.bundle + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib + +foo_foo2.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -DFOO2 -o foo_foo2.dylib -install_name foo.dylib + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle foo.dylib foo_foo2.dylib + diff --git a/unit-tests/test-cases/dlopen-RTLD_NOW/bundle.c b/unit-tests/test-cases/dlopen-RTLD_NOW/bundle.c new file mode 100644 index 0000000..5772ff4 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOW/bundle.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +extern int foo(); +extern int foo2(); + +void doit() +{ + foo(); + foo2(); +} diff --git a/unit-tests/test-cases/dlopen-RTLD_NOW/foo.c b/unit-tests/test-cases/dlopen-RTLD_NOW/foo.c new file mode 100644 index 0000000..e937770 --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOW/foo.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} + +#if FOO2 +int foo2() +{ + return 10; +} +#endif diff --git a/unit-tests/test-cases/dlopen-RTLD_NOW/main.c b/unit-tests/test-cases/dlopen-RTLD_NOW/main.c new file mode 100644 index 0000000..2ebb4ad --- /dev/null +++ b/unit-tests/test-cases/dlopen-RTLD_NOW/main.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This tests that TLD_NOW binds all lazy symbols. +/// We do this by making sure a lazy symbol does not exist +/// and dlopen() errors out with a message string +/// that contains the missing symbol name. +/// + + +int main() +{ + void* handle = dlopen("test.bundle", RTLD_NOW); + if ( handle == NULL ) { + const char* msg = dlerror(); + if ( strstr(msg, "foo2") != NULL ) { + PASS("dlopen-RTLD_NOW"); + exit(0); + } + FAIL("dlopen(test.bundle, RTLD_NOW) failed but error message did not contain foo2: %s", msg); + exit(0); + } + FAIL("dlopen(test.bundle, RTLD_NOW) succeed but should have failed because foo2 does not exist"); + exit(0); +} diff --git a/unit-tests/test-cases/dlopen-basic/Makefile b/unit-tests/test-cases/dlopen-basic/Makefile new file mode 100644 index 0000000..776d676 --- /dev/null +++ b/unit-tests/test-cases/dlopen-basic/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle test.dylib + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle + +test.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib + diff --git a/unit-tests/test-cases/dlopen-basic/foo.c b/unit-tests/test-cases/dlopen-basic/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlopen-basic/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlopen-basic/main.c b/unit-tests/test-cases/dlopen-basic/main.c new file mode 100644 index 0000000..7ce2f89 --- /dev/null +++ b/unit-tests/test-cases/dlopen-basic/main.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +static void trySO(const char* path) +{ + void* handle = dlopen(path, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", path); + exit(0); + } + + void* sym = dlsym(handle, "foo"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"foo\") failed"); + exit(0); + } + + int result = dlclose(handle); + if ( result != 0 ) { + if ( result == 1 ) { + // panther dyld returns 1 if you try to dlclose() a dylib + XFAIL("dlclose(handle) returned %d", result); + } + else { + FAIL("dlclose(handle) returned %d", result); + exit(0); + } + } + +} + + + +int main() +{ + trySO("test.bundle"); + trySO("test.dylib"); + + PASS("dlopen-basic bundle and dylib"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-initializer/Makefile b/unit-tests/test-cases/dlopen-initializer/Makefile new file mode 100644 index 0000000..e307053 --- /dev/null +++ b/unit-tests/test-cases/dlopen-initializer/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test1.dylib test2.dylib + +main : main.c test1.dylib test2.dylib test3.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test1.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -DINIT_NAME=myinit -o test1.dylib + +test2.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -DINIT_NAME=_init -o test2.dylib + +test3.dylib : bar.c + ${CC} ${CCFLAGS} -dynamiclib bar.c -o test3.dylib + +clean: + ${RM} ${RMFLAGS} *~ main test1.dylib test2.dylib test3.dylib + diff --git a/unit-tests/test-cases/dlopen-initializer/bar.c b/unit-tests/test-cases/dlopen-initializer/bar.c new file mode 100644 index 0000000..e055874 --- /dev/null +++ b/unit-tests/test-cases/dlopen-initializer/bar.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +static int initCount = 0; + + +void _init() +{ + initCount++; +} + +int getInitCount() +{ + return initCount; +} + diff --git a/unit-tests/test-cases/dlopen-initializer/foo.c b/unit-tests/test-cases/dlopen-initializer/foo.c new file mode 100644 index 0000000..9ffde51 --- /dev/null +++ b/unit-tests/test-cases/dlopen-initializer/foo.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +static int initCount = 0; + +void INIT_NAME() __attribute__((constructor)); + +void INIT_NAME() +{ + initCount++; +} + +int getInitCount() +{ + return initCount; +} + diff --git a/unit-tests/test-cases/dlopen-initializer/main.c b/unit-tests/test-cases/dlopen-initializer/main.c new file mode 100644 index 0000000..5dc4f2e --- /dev/null +++ b/unit-tests/test-cases/dlopen-initializer/main.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +typedef int (*getInitCountProc)(void); + + +static void trySO(const char* path) +{ + void* handle = dlopen(path, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", path); + exit(0); + } + + getInitCountProc sym = (getInitCountProc)dlsym(handle, "getInitCount"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"getInitCount\") failed"); + exit(0); + } + + int count = (*sym)(); + if ( count != 1 ) { + FAIL("initializer in %s called %d times", path, count); + exit(0); + } + +} + + + +int main() +{ + trySO("test1.dylib"); + trySO("test2.dylib"); + //trySO("test3.dylib"); // Mac OS X 10.4 does not automatically run _init functions + PASS("dlopen-initializer"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-local-and-global/Makefile b/unit-tests/test-cases/dlopen-local-and-global/Makefile new file mode 100644 index 0000000..90f8872 --- /dev/null +++ b/unit-tests/test-cases/dlopen-local-and-global/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main-local-first + ./main-global-first + +all: main-local-first main-global-first foo.bundle foo.dylib + +main-local-first : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -DLOCAL_FIRST -o main-local-first + +main-global-first : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main-global-first + +foo.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o foo.bundle + +foo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib + +clean: + ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib main-global-first main-local-first + diff --git a/unit-tests/test-cases/dlopen-local-and-global/bar.c b/unit-tests/test-cases/dlopen-local-and-global/bar.c new file mode 100644 index 0000000..e8e0806 --- /dev/null +++ b/unit-tests/test-cases/dlopen-local-and-global/bar.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int foo; + +int bar() +{ + return foo; +} + + diff --git a/unit-tests/test-cases/dlopen-local-and-global/foo.c b/unit-tests/test-cases/dlopen-local-and-global/foo.c new file mode 100644 index 0000000..8689597 --- /dev/null +++ b/unit-tests/test-cases/dlopen-local-and-global/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo = 0; diff --git a/unit-tests/test-cases/dlopen-local-and-global/main.c b/unit-tests/test-cases/dlopen-local-and-global/main.c new file mode 100644 index 0000000..5c3b97e --- /dev/null +++ b/unit-tests/test-cases/dlopen-local-and-global/main.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + + + +static void* openWithModeGetSymbol(const char* path, int mode, const char* symbol) +{ + void* handle = dlopen(path, mode); + if ( handle == NULL ) { + const char* msg = dlerror(); + if ( ((mode & RTLD_LOCAL) != 0) && (strstr(msg, "RTLD_LOCAL") != NULL) ) + XFAIL("dlopen(\"%s\") failed: %s", path, msg); + else + FAIL("dlopen(\"%s\") failed: %s", path, msg); + exit(0); + } + + void* sym = dlsym(handle, symbol); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"%s\") failed", symbol); + exit(0); + } + return sym; +} + +static void trySO(const char* path) +{ +#if LOCAL_FIRST + void* symLocal = openWithModeGetSymbol(path, RTLD_LOCAL, "foo"); + void* symGlobal = openWithModeGetSymbol(path, RTLD_GLOBAL, "foo"); +#else + void* symGlobal = openWithModeGetSymbol(path, RTLD_GLOBAL, "foo"); + void* symLocal = openWithModeGetSymbol(path, RTLD_LOCAL, "foo"); +#endif + if ( symLocal != symGlobal ) { + FAIL("global load after local load failed"); + exit(0); + } +} + + +int main(int argc, const char* argv[]) +{ + trySO("foo.bundle"); + trySO("foo.dylib"); + + PASS("dlopen-local-and-global"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-multi/Makefile b/unit-tests/test-cases/dlopen-multi/Makefile new file mode 100644 index 0000000..776d676 --- /dev/null +++ b/unit-tests/test-cases/dlopen-multi/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle test.dylib + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : foo.c + ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle + +test.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib + diff --git a/unit-tests/test-cases/dlopen-multi/foo.c b/unit-tests/test-cases/dlopen-multi/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlopen-multi/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlopen-multi/main.c b/unit-tests/test-cases/dlopen-multi/main.c new file mode 100644 index 0000000..180e91e --- /dev/null +++ b/unit-tests/test-cases/dlopen-multi/main.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int main() +{ + void* handle1 = dlopen("test.bundle", RTLD_LAZY); + void* handle2 = dlopen("test.bundle", RTLD_LAZY); + void* handle3 = dlopen("test.dylib", RTLD_LAZY); + void* handle4 = dlopen("test.dylib", RTLD_LAZY); + if ((NULL == handle1)||(NULL == handle2)) { + FAIL("dlopen(\"test.bundle\") failed"); + } + if ((NULL == handle3)||(NULL == handle4)) { + FAIL("dlopen(\"test.dylib\") failed"); + } + if (handle1 != handle2) { + FAIL("dlopen handle1 and handle2 are not equal %p != %p",handle1,handle2); + } + if (handle3 != handle4) { + FAIL("dlopen handle3 and handle4 are not equal %p != %p",handle3,handle4); + } + if (dlclose(handle4)) { + XFAIL("Could not close handle4"); + } + if (dlclose(handle2)) { + FAIL("Could not close handle2"); + } + void* sym = dlsym(handle1, "foo"); + if ( sym == NULL ) { + FAIL("dlsym(handle1, \"foo\") failed"); + exit(0); + } + sym = dlsym(handle3, "foo"); + if ( sym == NULL ) { + FAIL("dlsym(handle3, \"foo\") failed"); + exit(0); + } + if (dlclose(handle1)) { + XFAIL("Could not close handle1"); + } + if (dlclose(handle3)) { + XFAIL("Could not close handle3"); + } + + PASS("dlopen-multi"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlopen-zero/Makefile b/unit-tests/test-cases/dlopen-zero/Makefile new file mode 100644 index 0000000..92ea1b0 --- /dev/null +++ b/unit-tests/test-cases/dlopen-zero/Makefile @@ -0,0 +1,37 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/dlopen-zero/main.c b/unit-tests/test-cases/dlopen-zero/main.c new file mode 100644 index 0000000..7240521 --- /dev/null +++ b/unit-tests/test-cases/dlopen-zero/main.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +int foo() +{ + return 42; +} + + +int main() +{ + // passing NULL as path to dlopen() has the special meaning of + // "get handle to main executable" + void* handle = dlopen(NULL, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(NULL, RTLD_LAZY) failed"); + exit(1); + } + + // make sure we find "foo" in this main executable + void* sym = dlsym(handle, "foo"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"foo\") failed"); + exit(1); + } + if ( sym != &foo ) { + FAIL("dlsym(handle, \"foo\") returned wrong address"); + exit(1); + } + + PASS("dlopen-zero"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_DEFAULT/Makefile b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/Makefile new file mode 100644 index 0000000..d029efe --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main test.bundle test.dylib + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : foo.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -bundle foo.c -o test.bundle + +test.dylib : foo.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo.c -o test.dylib + + + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib + diff --git a/unit-tests/test-cases/dlsym-RTLD_DEFAULT/foo.c b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/foo.c new file mode 100644 index 0000000..675f4df --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/foo.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +char* strdup(const char* str) +{ + return "from foo"; +} + +typedef char* (*strdupProc)(const char* str); + + +void myinit() __attribute__((constructor)); +void myinit() +{ + strdupProc sym = (strdupProc)dlsym(RTLD_DEFAULT, "strdup"); + if ( sym == NULL ) { + FAIL("dlsym(RTLD_DEFAULT, \"strdup\") failed"); + exit(0); + } + + const char* result = (*sym)("hello"); + if ( strcmp(result, "from main") != 0 ) { + FAIL("dlsym(RTLD_DEFAULT, \"strdup\") returned wrong strdup: %s", result); + exit(0); + } + +} diff --git a/unit-tests/test-cases/dlsym-RTLD_DEFAULT/main.c b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/main.c new file mode 100644 index 0000000..ed3d884 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_DEFAULT/main.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +typedef char* (*strdupProc)(const char* str); + + +char* strdup(const char* str) +{ + return "from main"; +} + + +static void trySO(const char* path) +{ + void* handle = dlopen(path, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", path); + exit(0); + } + + strdupProc sym = (strdupProc)dlsym(RTLD_DEFAULT, "strdup"); + if ( sym == NULL ) { + FAIL("dlsym(RTLD_DEFAULT, \"strdup\") failed"); + exit(0); + } + + const char* result = (*sym)("hello"); + if ( strcmp(result, "from main") != 0 ) { + FAIL("dlsym(RTLD_DEFAULT, \"strdup\") returned wrong strdup: %s", result); + exit(0); + } + +} + + + +int main() +{ + trySO("test.bundle"); + trySO("test.dylib"); + + PASS("dlsym-RTLD_DEFAULT bundle and dylib"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_NEXT/Makefile b/unit-tests/test-cases/dlsym-RTLD_NEXT/Makefile new file mode 100644 index 0000000..af0dec0 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_NEXT/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c test.bundle test.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : test.c foo1.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -bundle test.c foo1.dylib -o test.bundle + +test.dylib : test.c foo2.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c foo2.dylib -o test.dylib + +foo1.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo1.dylib + +foo2.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo2.dylib + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib foo1.dylib foo2.dylib + diff --git a/unit-tests/test-cases/dlsym-RTLD_NEXT/foo.c b/unit-tests/test-cases/dlsym-RTLD_NEXT/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_NEXT/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_NEXT/main.c b/unit-tests/test-cases/dlsym-RTLD_NEXT/main.c new file mode 100644 index 0000000..5c1064b --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_NEXT/main.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This process has five foo functions. They are in: +/// main, test.bundle, test.dylib, foo1.dylib, foo2.dylib +/// +/// Both test.bundle and test.dylib call dlsym(RTLD_NEXT, "foo"); +/// They should find the ones in foo1.dylib and foo2.dylib respectively. +/// We test this be looking up those symbols explictly. +/// + + +int foo() +{ + return 0; +} + +typedef void* (*TestProc)(void); + +static void trySO(const char* pathToLoad, const char* indirectLibrary) +{ + void* indirectHandle = dlopen(indirectLibrary, RTLD_LAZY); + if ( indirectHandle == NULL ) { + FAIL("dlopen(\"%s\") failed", indirectLibrary); + exit(0); + } + + void* indirectFoo = (TestProc)dlsym(indirectHandle, "foo"); + if ( indirectFoo == NULL ) { + FAIL("dlsym(handle, \"test\") failed"); + exit(0); + } + + void* handle = dlopen(pathToLoad, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", pathToLoad); + exit(0); + } + + TestProc sym = (TestProc)dlsym(handle, "test"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"test\") failed"); + exit(0); + } + + void* targetFoo = (*sym)(); + + //printf("targetFoo = %p, indirectFoo = %p\n", targetFoo, indirectFoo); + + if ( targetFoo != indirectFoo ) { + FAIL("dlsym-RTLD_NEXT wrong foo found"); + exit(0); + } + +} + + + +int main() +{ + trySO("test.bundle", "foo1.dylib"); + trySO("test.dylib", "foo2.dylib"); + + PASS("dlsym-RTLD_NEXT bundle and dylib"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_NEXT/test.c b/unit-tests/test-cases/dlsym-RTLD_NEXT/test.c new file mode 100644 index 0000000..0d4b463 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_NEXT/test.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +void* test() +{ + return dlsym(RTLD_NEXT, "foo"); +} + +int foo() +{ + return 2; +} \ No newline at end of file diff --git a/unit-tests/test-cases/dlsym-RTLD_SELF/Makefile b/unit-tests/test-cases/dlsym-RTLD_SELF/Makefile new file mode 100644 index 0000000..af0dec0 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_SELF/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c test.bundle test.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +test.bundle : test.c foo1.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -bundle test.c foo1.dylib -o test.bundle + +test.dylib : test.c foo2.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c foo2.dylib -o test.dylib + +foo1.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo1.dylib + +foo2.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo2.dylib + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle test.dylib foo1.dylib foo2.dylib + diff --git a/unit-tests/test-cases/dlsym-RTLD_SELF/foo.c b/unit-tests/test-cases/dlsym-RTLD_SELF/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_SELF/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_SELF/main.c b/unit-tests/test-cases/dlsym-RTLD_SELF/main.c new file mode 100644 index 0000000..ce7c3a8 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_SELF/main.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This process has five foo functions. They are in: +/// main, test.bundle, test.dylib, foo1.dylib, foo2.dylib +/// +/// Both test.bundle and test.dylib call dlsym(RTLD_SELF, "foo"); +/// They should find the ones in their own linkage unit and +/// call FAIL() otherwise. +/// We also check that this works in the main executable. +/// + +#ifdef RTLD_SELF + +int foo() +{ + return 0; +} + +typedef void (*TestProc)(void); + +static void trySO(const char* pathToLoad) +{ + void* handle = dlopen(pathToLoad, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlopen(\"%s\") failed", pathToLoad); + exit(0); + } + + TestProc sym = (TestProc)dlsym(handle, "test"); + if ( sym == NULL ) { + FAIL("dlsym(handle, \"test\") failed"); + exit(0); + } + + (*sym)(); +} + +#endif + + +int main() +{ +#ifdef RTLD_SELF + trySO("test.bundle"); + trySO("test.dylib"); + + if ( dlsym(RTLD_SELF, "foo") != &foo ) { + FAIL("dlsym(RTLD_SELF, \"foo\") returned wrong value"); + } + + PASS("dlsym-RTLD_SELF bundle and dylib"); +#else + XFAIL("dlsym-RTLD_SELF not implemented"); +#endif + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlsym-RTLD_SELF/test.c b/unit-tests/test-cases/dlsym-RTLD_SELF/test.c new file mode 100644 index 0000000..b4ae941 --- /dev/null +++ b/unit-tests/test-cases/dlsym-RTLD_SELF/test.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +int foo() +{ + return 2; +} + +void test() +{ +#ifdef RTLD_SELF + if ( dlsym(RTLD_SELF, "foo") != &foo ) + FAIL("dlsym(RTLD_SELF, \"foo\") returned wrong value"); +#endif +} diff --git a/unit-tests/test-cases/dlsym-error/Makefile b/unit-tests/test-cases/dlsym-error/Makefile new file mode 100644 index 0000000..92ea1b0 --- /dev/null +++ b/unit-tests/test-cases/dlsym-error/Makefile @@ -0,0 +1,37 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/dlsym-error/main.c b/unit-tests/test-cases/dlsym-error/main.c new file mode 100644 index 0000000..cb4a9d6 --- /dev/null +++ b/unit-tests/test-cases/dlsym-error/main.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +int foo() +{ + return 42; +} + + +int main() +{ + void* handle = (void*)0x12345; // bogus value + + // expect dlsym() to return NULL + void* sym = dlsym(handle, "foo"); + if ( sym != NULL ) { + FAIL("dlsym(handle, \"foo\") should not have succeeded"); + exit(1); + } + // expect dlerro() to mention "handle" + if ( strstr(dlerror(), "handle") == NULL ) { + FAIL("dlerror() after dlsym(handle, \"foo\") does not mention \"handle\""); + exit(1); + } + + PASS("dlsym-error"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dlsym-indirect/Makefile b/unit-tests/test-cases/dlsym-indirect/Makefile new file mode 100644 index 0000000..b363103 --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/Makefile @@ -0,0 +1,53 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main foo.dylib + ./main foo.bundle + +all: main + +main : main.c foo.bundle foo.dylib foo3.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + + +foo.bundle : foo.c foo1.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -bundle foo.c foo1.dylib -o foo.bundle + +foo.dylib : foo.c foo1.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo.c foo1.dylib -o foo.dylib + +foo1.dylib : foo1.c foo2.dylib + ${CC} ${CCFLAGS} -dynamiclib foo1.c -o foo1.dylib foo2.dylib + +foo2.dylib : foo2.c + ${CC} ${CCFLAGS} -dynamiclib foo2.c -o foo2.dylib + +foo3.dylib : foo3.c + ${CC} ${CCFLAGS} -dynamiclib foo3.c -o foo3.dylib + +clean: + ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib foo1.dylib foo2.dylib foo3.dylib + diff --git a/unit-tests/test-cases/dlsym-indirect/foo.c b/unit-tests/test-cases/dlsym-indirect/foo.c new file mode 100644 index 0000000..81f7dcf --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-indirect/foo1.c b/unit-tests/test-cases/dlsym-indirect/foo1.c new file mode 100644 index 0000000..eda5424 --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/foo1.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo1() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-indirect/foo2.c b/unit-tests/test-cases/dlsym-indirect/foo2.c new file mode 100644 index 0000000..a17cf3d --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/foo2.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo2() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-indirect/foo3.c b/unit-tests/test-cases/dlsym-indirect/foo3.c new file mode 100644 index 0000000..923e363 --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/foo3.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int foo3() +{ + return 10; +} diff --git a/unit-tests/test-cases/dlsym-indirect/main.c b/unit-tests/test-cases/dlsym-indirect/main.c new file mode 100644 index 0000000..e619d82 --- /dev/null +++ b/unit-tests/test-cases/dlsym-indirect/main.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +/// +/// This tests that dlsym() will search indirect libraries +/// rdar://problem/4047391 +/// + + + +int main(int argc, const char* argv[]) +{ + const char* path = argv[1]; + const char* otherPath = "foo3.dylib"; + + void* handle = dlopen(path, RTLD_LAZY); + if ( handle == NULL ) { + FAIL("dlsym-indirect dlopen(\"%s\") failed", path); + exit(0); + } + + void* handle3 = dlopen(otherPath, RTLD_LAZY); + if ( handle3 == NULL ) { + FAIL("dlsym-indirect dlopen(\"%s\") failed", otherPath); + exit(0); + } + + void* foo = dlsym(handle, "foo"); + if ( foo == NULL ) { + FAIL("dlsym-indirect dlsym(handle, \"foo\") failed"); + exit(0); + } + + void* foo1 = dlsym(handle, "foo1"); + if ( foo1 == NULL ) { + FAIL("dlsym-indirect dlsym(handle, \"foo1\") failed"); + //exit(0); + } + + void* foo2 = dlsym(handle, "foo2"); + if ( foo2 == NULL ) { + FAIL("dlsym-indirect dlsym(handle, \"foo2\") failed"); + //exit(0); + } + + void* foo3 = dlsym(handle, "foo3"); + if ( foo3 != NULL ) { + FAIL("dlsym-indirect dlsym(handle, \"foo3\") should have failed"); + //exit(0); + } + + PASS("dlsym-indirect %s", path); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dyld-launched-prebound/Makefile b/unit-tests/test-cases/dyld-launched-prebound/Makefile new file mode 100644 index 0000000..4eb418a --- /dev/null +++ b/unit-tests/test-cases/dyld-launched-prebound/Makefile @@ -0,0 +1,34 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ${TESTROOT}/bin/exit-zero-pass.pl "_dyld_launched_prebound() was implemented" "_dyld_launched_prebound() was not implemented" ./main + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/dyld-launched-prebound/main.c b/unit-tests/test-cases/dyld-launched-prebound/main.c new file mode 100644 index 0000000..b4bf269 --- /dev/null +++ b/unit-tests/test-cases/dyld-launched-prebound/main.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int +main(int argc, char **argv, char **envp, char**appl) +{ + _dyld_launched_prebound(); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/dyld-slide/Makefile b/unit-tests/test-cases/dyld-slide/Makefile new file mode 100644 index 0000000..35f422d --- /dev/null +++ b/unit-tests/test-cases/dyld-slide/Makefile @@ -0,0 +1,33 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +clean: + ${RM} ${RMFLAGS} main diff --git a/unit-tests/test-cases/dyld-slide/main.c b/unit-tests/test-cases/dyld-slide/main.c new file mode 100644 index 0000000..ad5b149 --- /dev/null +++ b/unit-tests/test-cases/dyld-slide/main.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // EXIT_SUCCESS +#include + +#include "test.h" + +// +// This builds an executable that is just big enough to force dyld to slide a bit +// + +#define ARRAY_SIZE 301800000 + +int bigarray1[ARRAY_SIZE]; +int bigarray2[ARRAY_SIZE]; + +int +main() +{ + // call a dyld function that will internally throw an exception to test dyld slide properly + NSAddImage("/foo/bar", NSADDIMAGE_OPTION_RETURN_ON_ERROR); + + return EXIT_SUCCESS; +} + + diff --git a/unit-tests/test-cases/fallback-with-suid/Makefile b/unit-tests/test-cases/fallback-with-suid/Makefile new file mode 100644 index 0000000..f2a630d --- /dev/null +++ b/unit-tests/test-cases/fallback-with-suid/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export HOME="`pwd`/hide" && ./main user + export HOME="`pwd`/hide" && ./main-suid root + +all: main main-suid + +main: main.c hide/lib/libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +main-suid: main + cp main main-suid + sudo chown root main-suid + sudo chmod 4755 main-suid + +hide/lib/libfoo.dylib : foo.c + mkdir -p hide/lib + ${CC} ${CCFLAGS} foo.c -dynamiclib -o hide/lib/libfoo.dylib + +clean: + ${RM} ${RMFLAGS} *~ main main-suid hide + diff --git a/unit-tests/test-cases/fallback-with-suid/foo.c b/unit-tests/test-cases/fallback-with-suid/foo.c new file mode 100644 index 0000000..fa1d6fe --- /dev/null +++ b/unit-tests/test-cases/fallback-with-suid/foo.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + diff --git a/unit-tests/test-cases/fallback-with-suid/main.c b/unit-tests/test-cases/fallback-with-suid/main.c new file mode 100644 index 0000000..a0ce919 --- /dev/null +++ b/unit-tests/test-cases/fallback-with-suid/main.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include // strcmp(), strncmp() +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +// +// binaries set to run as some other user id never use $HOME part of fallback-path +// + +int main(int argc, const char *argv[]) +{ + const struct mach_header* mh = NSAddImage("/foo/bar/libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR); + + if ( strcmp(argv[1], "root") == 0 ) { + if ( mh == NULL ) + PASS("fallback-with-suid root"); + else + FAIL("fallback-with-suid root"); + } + else { + if ( mh != NULL ) + PASS("fallback-with-suid user"); + else + FAIL("fallback-with-suid user"); + } + + return EXIT_SUCCESS; +} + diff --git a/unit-tests/test-cases/flat-data/Makefile b/unit-tests/test-cases/flat-data/Makefile new file mode 100644 index 0000000..5f54e4b --- /dev/null +++ b/unit-tests/test-cases/flat-data/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c libbar.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib + + +libbar.dylib : bar.c getbar.c + ${CC} ${CCFLAGS} -dynamiclib getbar.c bar.c -o libbar.dylib -flat_namespace + + + +clean: + ${RM} ${RMFLAGS} *~ main libbar.dylib + diff --git a/unit-tests/test-cases/flat-data/bar.c b/unit-tests/test-cases/flat-data/bar.c new file mode 100644 index 0000000..a53bfdd --- /dev/null +++ b/unit-tests/test-cases/flat-data/bar.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +int bar = 2; diff --git a/unit-tests/test-cases/flat-data/getbar.c b/unit-tests/test-cases/flat-data/getbar.c new file mode 100644 index 0000000..020d7ad --- /dev/null +++ b/unit-tests/test-cases/flat-data/getbar.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int bar; + +int* getbar() +{ + return &bar; +} + diff --git a/unit-tests/test-cases/flat-data/main.c b/unit-tests/test-cases/flat-data/main.c new file mode 100644 index 0000000..fc85a6e --- /dev/null +++ b/unit-tests/test-cases/flat-data/main.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +// getbar() is implemented in libbar.dylib which has its own bar +// libbar.dylib is built flat-namespace so it should use the bar from main +// libbar.dylib is built multi_module so that the static linker won't complain +// about two bar's. + +extern int* getbar(); +int bar = 1; + +int main() +{ + if ( getbar() != &bar ) + FAIL("flat-data found wrong bar"); + else + PASS("flat-data"); + + return EXIT_SUCCESS; +} + diff --git a/unit-tests/test-cases/flat-lookup-everywhere/Makefile b/unit-tests/test-cases/flat-lookup-everywhere/Makefile new file mode 100644 index 0000000..d1b99b5 --- /dev/null +++ b/unit-tests/test-cases/flat-lookup-everywhere/Makefile @@ -0,0 +1,34 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + DYLD_INSERT_LIBRARIES="/usr/lib/libMallocDebug.A.dylib" DYLD_FORCE_FLAT_NAMESPACE="" ./main + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -framework CoreFoundation -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/flat-lookup-everywhere/main.c b/unit-tests/test-cases/flat-lookup-everywhere/main.c new file mode 100644 index 0000000..fb2c2a1 --- /dev/null +++ b/unit-tests/test-cases/flat-lookup-everywhere/main.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int +main() +{ + CFStringRef string = CFStringCreateWithFormat(NULL, NULL, CFSTR("")); + PASS("flat-lookup-everywhere"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/flat-prebound/Makefile b/unit-tests/test-cases/flat-prebound/Makefile new file mode 100644 index 0000000..b30c674 --- /dev/null +++ b/unit-tests/test-cases/flat-prebound/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib + + +libfoo.dylib : foo.c libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -flat_namespace -prebind -seg1addr 20000 + + +libbar.dylib : bar.c + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -prebind -seg1addr 30000 + + + +clean: + ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib + diff --git a/unit-tests/test-cases/flat-prebound/bar.c b/unit-tests/test-cases/flat-prebound/bar.c new file mode 100644 index 0000000..4bf747a --- /dev/null +++ b/unit-tests/test-cases/flat-prebound/bar.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int bar() +{ + return 1; +} diff --git a/unit-tests/test-cases/flat-prebound/foo.c b/unit-tests/test-cases/flat-prebound/foo.c new file mode 100644 index 0000000..5f951e8 --- /dev/null +++ b/unit-tests/test-cases/flat-prebound/foo.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int bar(); + +int foo() +{ + return bar(); +} diff --git a/unit-tests/test-cases/flat-prebound/main.c b/unit-tests/test-cases/flat-prebound/main.c new file mode 100644 index 0000000..b43924f --- /dev/null +++ b/unit-tests/test-cases/flat-prebound/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +// foo() internally calls bar() +// libfoo.dylib is build flat and prebound to libbar.dylib +// but the bar in this main executable should override the prebound bar + +extern int foo(); + +int main() +{ + if ( foo() != 0 ) + FAIL("flat-prebound found wrong bar"); + else + PASS("flat-prebound"); + + return EXIT_SUCCESS; +} + +int bar() +{ + return 0; +} diff --git a/unit-tests/test-cases/framework-fallback/Makefile b/unit-tests/test-cases/framework-fallback/Makefile new file mode 100644 index 0000000..adf063d --- /dev/null +++ b/unit-tests/test-cases/framework-fallback/Makefile @@ -0,0 +1,37 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all : main + +main: main.c + ${CC} main.c -o main -I${TESTROOT}/include + +clean: + ${RM} ${RMFLAGS} main + + diff --git a/unit-tests/test-cases/framework-fallback/main.c b/unit-tests/test-cases/framework-fallback/main.c new file mode 100644 index 0000000..13f8146 --- /dev/null +++ b/unit-tests/test-cases/framework-fallback/main.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" + +/// +/// rdar://problem/3736945 +/// +/// Test that a std framework can be dynamically loaded via the fallback paths +/// +/// + + + +int +main(int argc, const char* argv[]) +{ + const struct mach_header *image; + + image = NSAddImage("Carbon.framework/Carbon", + NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING); + if ( image != NULL ) + PASS("Carbon loaded"); + else + FAIL("Could not load Carbon"); + + return 0; +} + diff --git a/unit-tests/test-cases/ignore-bad-files/Makefile b/unit-tests/test-cases/ignore-bad-files/Makefile new file mode 100644 index 0000000..b5c0a4c --- /dev/null +++ b/unit-tests/test-cases/ignore-bad-files/Makefile @@ -0,0 +1,71 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# This test the ability of dyld to continue searching if a file was found but not usable. +# Uses DYLD_LIBRARY_PATH to search through many bogus files +# +# + + +run: all + export DYLD_LIBRARY_PATH=locations/datafile:locations/exec:locations/dir && ${TESTROOT}/bin/exit-non-zero-pass.pl "ignore-bad-files intended failure" "ignore-bad-files intended failure" ./main + export DYLD_LIBRARY_PATH=locations/datafile:locations/exec:locations/dir:locations/real && ${TESTROOT}/bin/exit-zero-pass.pl "ignore-bad-files intended success" "ignore-bad-files intended success" ./main + +all: main locations/real/libfoo.dylib locations/exec/libfoo.dylib locations/datafile/libfoo.dylib locations/dir/libfoo.dylib + +main: main.c locations/real/libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c locations/real/libfoo.dylib + + +# real dylib to use +locations/real/libfoo.dylib : foo.c + mkdir -p locations/real + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o locations/real/libfoo.dylib foo.c -install_name libfoo.dylib + +# not a dylib - but a mach-o main executable +locations/exec/libfoo.dylib : main.c + mkdir -p locations/exec + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o locations/exec/libfoo.dylib main.c foo.c + +# some random data file +locations/datafile/libfoo.dylib : main.c + mkdir -p locations/datafile + cat main.c > locations/datafile/libfoo.dylib + +# not a file - but a directory +locations/dir/libfoo.dylib : + mkdir -p locations/dir/libfoo.dylib + +# file with wrong architecture +#locations/wrongarch/libfoo.dylib : +# mkdir -p locations/wrongarch +# ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o locations/wrongarch/libfoo.dylib foo.c -install_name libfoo.dylib -arch ppc64 + + + +clean: + ${RM} ${RMFLAGS} *~ main locations + diff --git a/unit-tests/test-cases/ignore-bad-files/foo.c b/unit-tests/test-cases/ignore-bad-files/foo.c new file mode 100644 index 0000000..4315d22 --- /dev/null +++ b/unit-tests/test-cases/ignore-bad-files/foo.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +void foo() {} diff --git a/unit-tests/test-cases/ignore-bad-files/main.c b/unit-tests/test-cases/ignore-bad-files/main.c new file mode 100644 index 0000000..72d7abe --- /dev/null +++ b/unit-tests/test-cases/ignore-bad-files/main.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +extern void foo(); + +int +main(int argc, const char* argv[]) +{ + foo(); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/image-suffix/Makefile b/unit-tests/test-cases/image-suffix/Makefile new file mode 100644 index 0000000..3c39e98 --- /dev/null +++ b/unit-tests/test-cases/image-suffix/Makefile @@ -0,0 +1,152 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run : check1 check2 check3 check4 check5 check6 check7 check8 + +all : main1 main2 main3 main4 main5 main6 main7 main8 + +main : main.c libfoo.dylib + ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib + +libfoo.dylib : foo.c + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/libfoo.dylib + +libfoo_debug.dylib : foo.c + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -DDEBUG -o $$PWD/libfoo_debug.dylib -install_name $$PWD/libfoo.dylib + +hide/libfoo.dylib : foo.c + mkdir -p $$PWD/hide + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/hide/libfoo.dylib -install_name $$PWD/libfoo.dylib + +hide/libfoo_debug.dylib : foo.c + mkdir -p $$PWD/hide + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/hide/libfoo_debug.dylib -install_name $$PWD/libfoo.dylib + +# bar_debug has bar_debug as install name +libbar.dylib : foo.c + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/libbar.dylib + +libbar_debug.dylib : foo.c + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -DDEBUG -o $$PWD/libbar_debug.dylib + +hide/libbar.dylib : foo.c + mkdir -p $$PWD/hide + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/hide/libbar.dylib -install_name $$PWD/libbar.dylib + +hide/libbar_debug.dylib : foo.c + mkdir -p $$PWD/hide + ${CC} -I${TESTROOT}/include foo.c -dynamiclib -o $$PWD/hide/libbar_debug.dylib -install_name $$PWD/libbar_debug.dylib + +clean: + rm -rf libfoo.dylib libfoo_debug.dylib hide libbar.dylib libbar_debug.dylib main1 main2 main3 main4 main5 main6 main7 main8 + + +# +# check1: main links with libfoo.dylib sets DYLD_IMAGE_SUFFIX=_debug and dynamically loads libfoo.dylib +# (fails on 10.3) +# +main1 : main.c libfoo.dylib + ${CC} -I${TESTROOT}/include main.c -o main1 libfoo.dylib + +check1: main1 + DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 libfoo.dylib + DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 $$PWD/libfoo.dylib + + +# +# check2: main links with libfoo_debug.dylib and dynamically loads libfoo.dylib +# +main2 : main.c libfoo_debug.dylib + ${CC} -I${TESTROOT}/include main.c -o main2 libfoo_debug.dylib + +check2: main2 + echo "pwd-1 is ${PWD}" + echo "pwd-2 is $$PWD" + pwd + ./main2 $$PWD/libfoo.dylib + + +# +# check3: main links with libfoo.dylib sets DYLD_LIBRARY_PATH=hide and dynamically loads libfoo.dylib +# +main3 : main.c libfoo.dylib + ${CC} -I${TESTROOT}/include main.c -o main3 libfoo.dylib + +check3: main3 + DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && ./main3 $$PWD/libfoo.dylib + + +# +# check4: main links with libfoo.dylib sets DYLD_LIBRARY_PATH=hide, DYLD_IMAGE_SUFFIX=_debug and dynamically loads libfoo.dylib +# (fails on 10.3) +# +main4 : main.c libfoo.dylib + ${CC} -I${TESTROOT}/include main.c -o main4 libfoo.dylib + +check4: main4 + DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main4 $$PWD/libfoo.dylib + + +# +# check5: main links with libbar.dylib sets DYLD_IMAGE_SUFFIX=_debug and dynamically loads libbar.dylib +# (fails on 10.3) +# +main5 : main.c libbar.dylib libbar_debug.dylib + ${CC} -I${TESTROOT}/include main.c -o main5 libbar.dylib + +check5: main5 + DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main5 $$PWD/libbar.dylib + + +# +# check6: main links with libbar_debug.dylib and dynamically loads libbar.dylib +# (fails on 10.3) +# +main6 : main.c libbar_debug.dylib + ${CC} -I${TESTROOT}/include main.c -o main6 libbar_debug.dylib + +check6: main6 + DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main6 $$PWD/libbar.dylib + + +# +# check7: main links with libbar.dylib sets DYLD_LIBRARY_PATH=hide and dynamically loads libbar.dylib +# +main7 : main.c libbar.dylib + ${CC} -I${TESTROOT}/include main.c -o main7 libbar.dylib + +check7: main7 + DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && ./main7 $$PWD/libbar.dylib + + +# +# check8: main links with libbar.dylib sets DYLD_LIBRARY_PATH=hide, DYLD_IMAGE_SUFFIX=_debug and dynamically loads libbar.dylib +# (fails on 10.3) +# +main8 : main.c libbar.dylib + ${CC} -I${TESTROOT}/include main.c -o main8 libbar.dylib + +check8: main8 + DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main8 $$PWD/libbar.dylib diff --git a/unit-tests/test-cases/image-suffix/foo.c b/unit-tests/test-cases/image-suffix/foo.c new file mode 100644 index 0000000..a267f20 --- /dev/null +++ b/unit-tests/test-cases/image-suffix/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +void foo() +{ + printf("foo"); +} diff --git a/unit-tests/test-cases/image-suffix/main.c b/unit-tests/test-cases/image-suffix/main.c new file mode 100644 index 0000000..79edd75 --- /dev/null +++ b/unit-tests/test-cases/image-suffix/main.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" + +int main(int argc, const char* argv[]) +{ + if ( argc < 2 ) { + FAIL("too few arguments to main()"); + return EXIT_SUCCESS; + } + + uint32_t imageCount = _dyld_image_count(); + const struct mach_header* mh = NSAddImage(argv[1], 0); + if ( imageCount != _dyld_image_count() ) { + FAIL("image count changed"); + return EXIT_SUCCESS; + } + + PASS("images loaded properly"); + return EXIT_SUCCESS; +} + diff --git a/unit-tests/test-cases/init-order/Makefile b/unit-tests/test-cases/init-order/Makefile new file mode 100644 index 0000000..dfa47dd --- /dev/null +++ b/unit-tests/test-cases/init-order/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + + +main: main.c libtest.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libtest.dylib + +libtest.dylib: foo1.c foo2.c base.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libtest.dylib foo1.c foo2.c base.c -init _myDashInit + + +clean: + ${RM} ${RMFLAGS} *~ main libtest.dylib + diff --git a/unit-tests/test-cases/init-order/base.c b/unit-tests/test-cases/init-order/base.c new file mode 100644 index 0000000..2cdb40a --- /dev/null +++ b/unit-tests/test-cases/init-order/base.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "base.h" +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +static int state = 1; +bool badOrder = false; + +void setState(int nextState) +{ + if ( nextState == state ) + ++state; + else + badOrder = true; + +} + + +void baseCheck() +{ + if ( badOrder ) { + switch ( state ) { + case 1: + FAIL("init-order -init not run first"); + break; + case 2: + FAIL("init-order myInit1 not run second"); + break; + case 3: + FAIL("init-order myInit2 not run third"); + break; + case 4: + FAIL("init-order myInit3 not run fourth"); + break; + } + } + else + PASS("init-order"); +} + diff --git a/unit-tests/test-cases/init-order/base.h b/unit-tests/test-cases/init-order/base.h new file mode 100644 index 0000000..1dbf697 --- /dev/null +++ b/unit-tests/test-cases/init-order/base.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +extern void setState(int); +extern void baseCheck(); + diff --git a/unit-tests/test-cases/init-order/foo1.c b/unit-tests/test-cases/init-order/foo1.c new file mode 100644 index 0000000..b8808ae --- /dev/null +++ b/unit-tests/test-cases/init-order/foo1.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + + + + +// should run second because first initiallzer in first .o file +static __attribute__((constructor)) void myInit1() +{ + //fprintf(stderr, "myInit1()\n"); + setState(2); +} + + +// should run thrid because second initiallzer in first .o file +static __attribute__((constructor)) void myInit2() +{ + //fprintf(stderr, "myInit2()\n"); + setState(3); +} + + +// should run first becuase -init runs first +void myDashInit() +{ + //fprintf(stderr, "myDashInit()\n"); + setState(1); +} + diff --git a/unit-tests/test-cases/init-order/foo2.c b/unit-tests/test-cases/init-order/foo2.c new file mode 100644 index 0000000..646358b --- /dev/null +++ b/unit-tests/test-cases/init-order/foo2.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + + +// should run fourth because first initiallzer in second .o file +static __attribute__((constructor)) void myInit3() +{ + //fprintf(stderr, "myInit3()\n"); + setState(4); +} + diff --git a/unit-tests/test-cases/init-order/foo3.c b/unit-tests/test-cases/init-order/foo3.c new file mode 100644 index 0000000..c92a444 --- /dev/null +++ b/unit-tests/test-cases/init-order/foo3.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + +int __attribute__((weak)) coal1 = 3; +int __attribute__((weak)) coal2 = 2; + +static __attribute__((constructor)) void myinit() +{ + //fprintf(stderr, "myinit() in foo1.c\n"); + baseVerifyCoal1("in foo3", &coal1); + baseVerifyCoal2("in foo3", &coal2); +} + diff --git a/unit-tests/test-cases/init-order/main.c b/unit-tests/test-cases/init-order/main.c new file mode 100644 index 0000000..b210384 --- /dev/null +++ b/unit-tests/test-cases/init-order/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +#include "base.h" + +int main() +{ + baseCheck(); + return EXIT_SUCCESS; +} + + diff --git a/unit-tests/test-cases/initializer-args/Makefile b/unit-tests/test-cases/initializer-args/Makefile new file mode 100644 index 0000000..3b5e6be --- /dev/null +++ b/unit-tests/test-cases/initializer-args/Makefile @@ -0,0 +1,34 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main arg1 arg2 + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/initializer-args/main.c b/unit-tests/test-cases/initializer-args/main.c new file mode 100644 index 0000000..79e43e0 --- /dev/null +++ b/unit-tests/test-cases/initializer-args/main.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +static int my_argc = 0; +static char **my_argv = NULL; +static char **my_envp = NULL; +static char **my_appl = NULL; + +void +__attribute__((constructor)) +my_init(int argc, char **argv, char **envp, char **appl) +{ + my_argc = argc; + my_argv = argv; + my_envp = envp; + my_appl = appl; +} + +int +main(int argc, char **argv, char **envp, char**appl) +{ + if(argc == my_argc + && argv == my_argv + && envp == my_envp + && appl == my_appl) + { + PASS("initializer/constructor was called with arguments"); + } + else + { + FAIL("initializer/constructor was not called with arguments"); + } + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/Makefile b/unit-tests/test-cases/insert-libraries-with-initializer/Makefile new file mode 100644 index 0000000..352ec10 --- /dev/null +++ b/unit-tests/test-cases/insert-libraries-with-initializer/Makefile @@ -0,0 +1,35 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export DYLD_INSERT_LIBRARIES="libfoo.dylib" && ./main + +all: + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib + diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/foo.c b/unit-tests/test-cases/insert-libraries-with-initializer/foo.c new file mode 100644 index 0000000..60a2d84 --- /dev/null +++ b/unit-tests/test-cases/insert-libraries-with-initializer/foo.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +#include "test.h" + +static +void +__attribute__((constructor)) +my_init() +{ + PASS("initializer/constructor was called"); + exit(EXIT_SUCCESS); +} + diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/main.c b/unit-tests/test-cases/insert-libraries-with-initializer/main.c new file mode 100644 index 0000000..bb193e7 --- /dev/null +++ b/unit-tests/test-cases/insert-libraries-with-initializer/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int +main(int argc, char **argv, char **envp, char**appl) +{ + FAIL("initializer/constructor was not called"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/insert-libraries-with-suid/Makefile b/unit-tests/test-cases/insert-libraries-with-suid/Makefile new file mode 100644 index 0000000..7e6ad2a --- /dev/null +++ b/unit-tests/test-cases/insert-libraries-with-suid/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export DYLD_INSERT_LIBRARIES="/usr/lib/libldap.dylib:/usr/lib/libpcap.dylib" && ./main + +all: main + +main: main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + sudo chown root main + sudo chmod 4755 main + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/unit-tests/test-cases/insert-libraries-with-suid/main.c b/unit-tests/test-cases/insert-libraries-with-suid/main.c new file mode 100644 index 0000000..0571cd9 --- /dev/null +++ b/unit-tests/test-cases/insert-libraries-with-suid/main.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include // strcmp(), strncmp() + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +// +// binaries set to run as some other user id never use DYLD_INSERT_LIBRARIES +// That environment variable is cleared by dyld (its right-hand-side is set to empty) +// + +int main(int argc, const char *argv[]) +{ + const char* rhs = getenv("DYLD_INSERT_LIBRARIES"); + if ( rhs == NULL ) + FAIL("insert-libraries-with-suid DYLD_INSERT_LIBRARIES not set"); + else if ( rhs[0] != '\0' ) + FAIL("insert-libraries-with-suid DYLD_INSERT_LIBRARIES not cleared"); + else + PASS("insert-libraries-with-suid"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/lazy-pointer-binding/Makefile b/unit-tests/test-cases/lazy-pointer-binding/Makefile new file mode 100644 index 0000000..9a7f756 --- /dev/null +++ b/unit-tests/test-cases/lazy-pointer-binding/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +main : main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib + + +libfoo.dylib : foo.c + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib + + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib + diff --git a/unit-tests/test-cases/lazy-pointer-binding/foo.c b/unit-tests/test-cases/lazy-pointer-binding/foo.c new file mode 100644 index 0000000..53d2618 --- /dev/null +++ b/unit-tests/test-cases/lazy-pointer-binding/foo.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL + +bool floattest(double p1, float p2, double p3, float p4, double p5, float p6, + double p7, float p8, double p9, float p10, double p11, float p12, + double p13, float p14) +{ + if ( p1 != 1.0 ) + return false; + if ( p2 != 2.0 ) + return false; + if ( p3 != 3.0 ) + return false; + if ( p4 != 4.0 ) + return false; + if ( p5 != 5.0 ) + return false; + if ( p6 != 6.0 ) + return false; + if ( p7 != 7.0 ) + return false; + if ( p8 != 8.0 ) + return false; + if ( p9 != 9.0 ) + return false; + if ( p10 != 10.0 ) + return false; + if ( p11 != 11.0 ) + return false; + if ( p12 != 12.0 ) + return false; + if ( p13 != 13.0 ) + return false; + if ( p14 != 14.0 ) + return false; + return true; +} + +bool inttest(long long p1, long long p2, long long p3, long long p4, long long p5) +{ + if ( p1 != 0x100000002) + return false; + if ( p2 != 0x300000004) + return false; + if ( p3 != 0x500000006) + return false; + if ( p4 != 0x700000008) + return false; + if ( p5 != 0x90000000A) + return false; + return true; +} + + diff --git a/unit-tests/test-cases/lazy-pointer-binding/main.c b/unit-tests/test-cases/lazy-pointer-binding/main.c new file mode 100644 index 0000000..c2554b2 --- /dev/null +++ b/unit-tests/test-cases/lazy-pointer-binding/main.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +extern bool floattest(double p1, float p2, double p3, float p4, double p5, float p6, + double p7, float p8, double p9, float p10, double p11, float p12, + double p13, float p14); + +extern bool inttest(long long p1, long long p2, long long p3, long long p4, long long p5); + + + +int main() +{ + if ( ! floattest(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0) ) { + FAIL("lazy-pointer-binding float parameters"); + return EXIT_SUCCESS; + } + + if ( ! inttest(0x100000002, 0x300000004, 0x500000006, 0x700000008, 0x90000000A) ) { + FAIL("lazy-pointer-binding int parameters"); + return EXIT_SUCCESS; + } + + PASS("lazy-pointer-binding"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/lib-name-overload/Makefile b/unit-tests/test-cases/lib-name-overload/Makefile new file mode 100644 index 0000000..52c2e50 --- /dev/null +++ b/unit-tests/test-cases/lib-name-overload/Makefile @@ -0,0 +1,59 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +### +### rdar://problem/3684168 +### +### The process has two different libfoo.dylib. +### When DYLD_LIBRARY_PATH is used, both resolve to the same library. +### It gets worse. One of the libraries re-exports from the other. +### So, without loop detection in dyld, it will infinitely recurse. +### + +PWD = `pwd` + + +run : all + # verify it runs as-is + ./main + # verify dyld doesn't hang on the circularity + DYLD_LIBRARY_PATH=$(PWD) && export DYLD_LIBRARY_PATH && ${TESTROOT}/bin/exit-zero-pass.pl "lib-name-overload" "lib-name-overload" ./main + +all : main + +other/libfoo.dylib : foo2.c + mkdir -p other + gcc foo2.c -dynamiclib -o $(PWD)/other/libfoo.dylib + +libfoo.dylib : foo.c other/libfoo.dylib + gcc foo.c -dynamiclib $(PWD)/other/libfoo.dylib -sub_library libfoo -o $(PWD)/libfoo.dylib + +main : main.c libfoo.dylib + gcc main.c -I${TESTROOT}/include -o main libfoo.dylib + + +clean: + rm -rf main other libfoo.dylib \ No newline at end of file diff --git a/unit-tests/test-cases/lib-name-overload/foo.c b/unit-tests/test-cases/lib-name-overload/foo.c new file mode 100644 index 0000000..4b2ea98 --- /dev/null +++ b/unit-tests/test-cases/lib-name-overload/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +int foo = 0; + diff --git a/unit-tests/test-cases/lib-name-overload/foo2.c b/unit-tests/test-cases/lib-name-overload/foo2.c new file mode 100644 index 0000000..b34dc76 --- /dev/null +++ b/unit-tests/test-cases/lib-name-overload/foo2.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +int foo2 = 0; + + diff --git a/unit-tests/test-cases/lib-name-overload/main.c b/unit-tests/test-cases/lib-name-overload/main.c new file mode 100644 index 0000000..73cc95a --- /dev/null +++ b/unit-tests/test-cases/lib-name-overload/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" + +/// +/// rdar://problem/3684168 +/// + + + +extern int foo2; + +int main() +{ + return foo2; +} diff --git a/unit-tests/test-cases/loader_path-dup/Makefile b/unit-tests/test-cases/loader_path-dup/Makefile new file mode 100644 index 0000000..a89a431 --- /dev/null +++ b/unit-tests/test-cases/loader_path-dup/Makefile @@ -0,0 +1,66 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +### +### This test case is to verify that two different dylibs with the same name +### and each loaded via the same @loader_path does not confuse dyld +### into just loading one of them. +### + +## Note, until ld understands @loader_path we have to do a funky make + + +run: all + ./main + +all: main + +foo/libfoo.dylib : foo.c foo/libbase.dylib + mkdir -p foo + ${CC} foo.c foo/libbase.dylib -dynamiclib -o "`pwd`/foo/libfoo.dylib" + +foo/libbase.dylib : base.c + mkdir -p foo + ${CC} base.c -DFOO -dynamiclib -o foo/libbase.dylib + + +bar/libbar.dylib : bar.c bar/libbase.dylib + mkdir -p bar + ${CC} bar.c bar/libbase.dylib -dynamiclib -o "`pwd`/bar/libbar.dylib" + +bar/libbase.dylib : base.c + mkdir -p bar + ${CC} base.c -Dbar -dynamiclib -o bar/libbase.dylib + + +main : main.c foo/libfoo.dylib bar/libbar.dylib + ${CC} -I${TESTROOT}/include main.c -o main foo/libfoo.dylib bar/libbar.dylib + # this breaks partial makes, but ld can't see @loader_path or it freaks + install_name_tool -change foo/libbase.dylib '@loader_path/libbase.dylib' foo/libfoo.dylib + install_name_tool -change bar/libbase.dylib '@loader_path/libbase.dylib' bar/libbar.dylib + + +clean: + ${RM} ${RMFLAGS} *~ main foo bar diff --git a/unit-tests/test-cases/loader_path-dup/bar.c b/unit-tests/test-cases/loader_path-dup/bar.c new file mode 100644 index 0000000..edd9f35 --- /dev/null +++ b/unit-tests/test-cases/loader_path-dup/bar.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +extern int base; + +bool bar() +{ + return (base == 2); +} diff --git a/unit-tests/test-cases/loader_path-dup/base.c b/unit-tests/test-cases/loader_path-dup/base.c new file mode 100644 index 0000000..03b9160 --- /dev/null +++ b/unit-tests/test-cases/loader_path-dup/base.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if FOO +int base = 1; +#else +int base = 2; +#endif + diff --git a/unit-tests/test-cases/loader_path-dup/foo.c b/unit-tests/test-cases/loader_path-dup/foo.c new file mode 100644 index 0000000..7f0cfbb --- /dev/null +++ b/unit-tests/test-cases/loader_path-dup/foo.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + + +extern int base; + +bool foo() +{ + return (base == 1); +} diff --git a/unit-tests/test-cases/loader_path-dup/main.c b/unit-tests/test-cases/loader_path-dup/main.c new file mode 100644 index 0000000..9c12ccc --- /dev/null +++ b/unit-tests/test-cases/loader_path-dup/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include + +#include "test.h" + +extern bool foo(); +extern bool bar(); + +int main() +{ + if ( foo() && bar() ) + PASS("loader_path"); + else + FAIL("loader_path-dup both libraries not loaded"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/loader_path/Makefile b/unit-tests/test-cases/loader_path/Makefile new file mode 100644 index 0000000..6b34207 --- /dev/null +++ b/unit-tests/test-cases/loader_path/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + ./main + +all: main + +hide/hole/libfoo.dylib : foo.c + mkdir -p hide/hole + ${CC} foo.c -dynamiclib -o hide/hole/libfoo.dylib -install_name libfoo.dylib + +hide/libbar.dylib : bar.c hide/hole/libfoo.dylib + ${CC} bar.c -dynamiclib -o hide/libbar.dylib -install_name libbar.dylib hide/hole/libfoo.dylib + install_name_tool -change libfoo.dylib '@loader_path/hole/libfoo.dylib' hide/libbar.dylib + +hide/libfoo3.dylib : foo.c + ${CC} foo.c -dynamiclib -o hide/libfoo3.dylib -install_name libfoo3.dylib + +libfoo2.dylib : foo.c + ${CC} foo.c -dynamiclib -o libfoo2.dylib + + +main : main.c libfoo2.dylib hide/libbar.dylib hide/libfoo3.dylib + ${CC} -I${TESTROOT}/include main.c -o main hide/libbar.dylib libfoo2.dylib + install_name_tool -change libfoo2.dylib '@loader_path/libfoo2.dylib' main + install_name_tool -change libbar.dylib '@loader_path/hide/libbar.dylib' main + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib hide libfoo2.dylib diff --git a/unit-tests/test-cases/loader_path/bar.c b/unit-tests/test-cases/loader_path/bar.c new file mode 100644 index 0000000..902e563 --- /dev/null +++ b/unit-tests/test-cases/loader_path/bar.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +void bar() {} diff --git a/unit-tests/test-cases/loader_path/foo.c b/unit-tests/test-cases/loader_path/foo.c new file mode 100644 index 0000000..1bcf3c2 --- /dev/null +++ b/unit-tests/test-cases/loader_path/foo.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +void foo() +{ +} diff --git a/unit-tests/test-cases/loader_path/main.c b/unit-tests/test-cases/loader_path/main.c new file mode 100644 index 0000000..141931f --- /dev/null +++ b/unit-tests/test-cases/loader_path/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" + + +int main() +{ + NSAddImage("@loader_path/hide/libfoo3.dylib", 0); + + PASS("loader_path"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/missing-symlink-framework-fallback-path/Foo.c b/unit-tests/test-cases/missing-symlink-framework-fallback-path/Foo.c new file mode 100644 index 0000000..100cfc6 --- /dev/null +++ b/unit-tests/test-cases/missing-symlink-framework-fallback-path/Foo.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ diff --git a/unit-tests/test-cases/missing-symlink-framework-fallback-path/Makefile b/unit-tests/test-cases/missing-symlink-framework-fallback-path/Makefile new file mode 100644 index 0000000..4cfeb68 --- /dev/null +++ b/unit-tests/test-cases/missing-symlink-framework-fallback-path/Makefile @@ -0,0 +1,48 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export DYLD_FALLBACK_FRAMEWORK_PATH="dir" && ${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main + +all: main dir/Foo.framework/Versions/Current/Foo + +Foo.framework/Versions/Current/Foo: + mkdir -p Foo.framework/Versions/A + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o Foo.framework/Versions/A/Foo Foo.c + cd Foo.framework/Versions/ && ln -s A Current + cd Foo.framework/ && ln -s Versions/Current/Foo Foo + +dir/Foo.framework/Versions/Current/Foo: + $(MAKE) Foo.framework/Versions/Current/Foo + rm -f Foo.framework/Foo + mkdir dir + mv Foo.framework dir + +main: + $(MAKE) Foo.framework/Versions/Current/Foo + ${CC} ${CCFLAGS} -I${TESTROOT}/include -F. -framework Foo -o main main.c + +clean: + ${RM} ${RMFLAGS} *~ main dir/ Foo.framework/ diff --git a/unit-tests/test-cases/missing-symlink-framework-fallback-path/main.c b/unit-tests/test-cases/missing-symlink-framework-fallback-path/main.c new file mode 100644 index 0000000..46698ad --- /dev/null +++ b/unit-tests/test-cases/missing-symlink-framework-fallback-path/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +int +main(int argc, char **argv, char **envp, char**appl) +{ + + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/non-weak-library/Makefile b/unit-tests/test-cases/non-weak-library/Makefile new file mode 100644 index 0000000..41f097c --- /dev/null +++ b/unit-tests/test-cases/non-weak-library/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + cd absent/ && ../${TESTROOT}/bin/exit-non-zero-pass.pl "pass message" "fail message" ./main + cd present/ && ./main + +all: foo.c main.c + ${CC} -dynamiclib -prebind -seg1addr 400000 -o libfoo.dylib foo.c + mkdir -p absent/ + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_ABSENT -o absent/main main.c + mkdir -p present/ + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_PRESENT -o present/main main.c + mv libfoo.dylib present/ + +clean: + ${RM} ${RMFLAGS} *~ libfoo.dylib absent/main present/{main,libfoo.dylib} diff --git a/unit-tests/test-cases/non-weak-library/foo.c b/unit-tests/test-cases/non-weak-library/foo.c new file mode 100644 index 0000000..c57adba --- /dev/null +++ b/unit-tests/test-cases/non-weak-library/foo.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/non-weak-library/main.c b/unit-tests/test-cases/non-weak-library/main.c new file mode 100644 index 0000000..de02062 --- /dev/null +++ b/unit-tests/test-cases/non-weak-library/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" + +int +main(int argc, char **argv) +{ +#if defined(LIB_PRESENT) + PASS("pass message"); +#endif +#if defined(LIB_ABSENT) + FAIL("fail message"); +#endif + + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/partial-library-load/Makefile b/unit-tests/test-cases/partial-library-load/Makefile new file mode 100644 index 0000000..2cff519 --- /dev/null +++ b/unit-tests/test-cases/partial-library-load/Makefile @@ -0,0 +1,57 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +### +### rdar://problem/3884004 Libraries can be half-baked if an error occurs during their first use +### +### We indirectly load libfoo which depends on libbar. The libbar that is loaded does not contain +### what libfoo needs, so libfoo fails to bind. The bug was that libfoo was left marked as bound, +### so the next use of libfoo seemed to succeed, when it should have failed. +### + + +run: all + export DYLD_IMAGE_SUFFIX="_missing" && ${TESTROOT}/bin/exit-zero-pass.pl "partial-library-load" "partial-library-load" ./main + +all: main test.bundle + +main : main.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c + +test.bundle : bundle.c libfoo.dylib + ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c libfoo.dylib + +libfoo.dylib : foo.c libbar_missing.dylib libbar.dylib + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib libbar.dylib + +libbar_missing.dylib : bar.c + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar_missing.dylib -install_name libbar.dylib + +libbar.dylib : bar.c + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -DHAS_BAR2=1 + +clean: + ${RM} ${RMFLAGS} *~ main test.bundle libfoo.dylib libbar.dylib libbar_missing.dylib + diff --git a/unit-tests/test-cases/partial-library-load/bar.c b/unit-tests/test-cases/partial-library-load/bar.c new file mode 100644 index 0000000..400e1bf --- /dev/null +++ b/unit-tests/test-cases/partial-library-load/bar.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +int bar1 = 1; +#if HAS_BAR2 +int bar2 = 2; +#endif +int bar3 = 3; + diff --git a/unit-tests/test-cases/partial-library-load/bundle.c b/unit-tests/test-cases/partial-library-load/bundle.c new file mode 100644 index 0000000..a7aad9e --- /dev/null +++ b/unit-tests/test-cases/partial-library-load/bundle.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +extern int foo(); + +void bun() +{ + foo(); + +} + diff --git a/unit-tests/test-cases/partial-library-load/foo.c b/unit-tests/test-cases/partial-library-load/foo.c new file mode 100644 index 0000000..8abc708 --- /dev/null +++ b/unit-tests/test-cases/partial-library-load/foo.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int bar1; +extern int bar2; +extern int bar3; + + + +int foo() +{ + return bar1 + bar2 + bar3; +} diff --git a/unit-tests/test-cases/partial-library-load/main.c b/unit-tests/test-cases/partial-library-load/main.c new file mode 100644 index 0000000..0c81554 --- /dev/null +++ b/unit-tests/test-cases/partial-library-load/main.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include + +#include "test.h" // PASS(), FAIL() + + +int main() +{ + // load bundle which indirectly loads libfoo and libbar + NSObjectFileImage ofi; + if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) { + FAIL("NSCreateObjectFileImageFromFile failed"); + return 1; + } + + // link bundle, this will fail because bar2 is missing from libbar + NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_RETURN_ON_ERROR); + if ( mod != NULL ) { + FAIL("NSLinkModule succeeded but should have failed"); + return 1; + } + + // load libfoo, this should fail because it can't be loaded + const struct mach_header* mh = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR); + if ( mh != NULL ) { + return 1; + } + +#if 0 + // find foo + NSSymbol sym = NSLookupSymbolInImage(mh, "_foo", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND); + if ( sym == NULL ) { + FAIL("NSLookupSymbolInImage failed"); + return 1; + } + + // if foo() was only partially bound, this will crash + int (*fooPtr)() = NSAddressOfSymbol(sym); + (*fooPtr)(); +#endif + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/sym-link-load/Makefile b/unit-tests/test-cases/sym-link-load/Makefile new file mode 100644 index 0000000..00dd9ac --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/Makefile @@ -0,0 +1,83 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +### +### This test case is to verify that dyld cannot be tricked into loading +### the "same" library twice. +### +### The tricky scenario is: +### 1) a library dyld is to load is specified with a symlink path +### 2) the library the that is the target of the symlink is already loaded +### via a different path. In this case becuase of DYLD_LIBRARY_PATH. +### +### +### +### + + + +run: all + ./main + export DYLD_LIBRARY_PATH="`pwd`/fake" && ./main + + +all: main real/liblink.dylib real/libtest.dylib fake/libtest.dylib + + +main: main.c stub/libtest.dylib stub/liblink.dylib real/libbase.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c stub/libtest.dylib stub/liblink.dylib real/libbase.dylib + +stub/libtest.dylib: test.c + mkdir -p stub + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c -DDO_NOTHING -o stub/libtest.dylib -install_name "`pwd`/real/libtest.dylib" + +stub/liblink.dylib: link.c + mkdir -p stub + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib link.c -o stub/liblink.dylib -install_name "`pwd`/real/liblink.dylib" + + +real/libbase.dylib: base.c + mkdir -p real + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib base.c -o "`pwd`/real/libbase.dylib" + +real/libtest.dylib: test.c real/libbase.dylib + mkdir -p real + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "`pwd`/real/libtest.dylib" + +real/liblink.dylib: link.c + mkdir -p real + cd real && ln -s libtest.dylib liblink.dylib + + +fake/libtest.dylib: test.c real/libbase.dylib + mkdir -p fake + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "`pwd`/fake/libtest.dylib" -install_name "`pwd`/real/libtest.dylib" + + + + +clean: + ${RM} ${RMFLAGS} *~ main real stub fake + diff --git a/unit-tests/test-cases/sym-link-load/base.c b/unit-tests/test-cases/sym-link-load/base.c new file mode 100644 index 0000000..663274e --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/base.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "base.h" +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +static int initCount = 0; + +void setState(int x) +{ + ++initCount; +} + + +void baseCheck() +{ + switch ( initCount ) { + case 0: + FAIL("sym-link-load no initializers run"); + break; + case 1: + PASS("sym-link-load"); + break; + case 2: + default: + FAIL("sym-link-load initializers double run (library double loaded)"); + break; + } +} + diff --git a/unit-tests/test-cases/sym-link-load/base.h b/unit-tests/test-cases/sym-link-load/base.h new file mode 100644 index 0000000..1dbf697 --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/base.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +extern void setState(int); +extern void baseCheck(); + diff --git a/unit-tests/test-cases/sym-link-load/link.c b/unit-tests/test-cases/sym-link-load/link.c new file mode 100644 index 0000000..42c87ba --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/link.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + diff --git a/unit-tests/test-cases/sym-link-load/main.c b/unit-tests/test-cases/sym-link-load/main.c new file mode 100644 index 0000000..b210384 --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +#include "base.h" + +int main() +{ + baseCheck(); + return EXIT_SUCCESS; +} + + diff --git a/unit-tests/test-cases/sym-link-load/test.c b/unit-tests/test-cases/sym-link-load/test.c new file mode 100644 index 0000000..5b1e221 --- /dev/null +++ b/unit-tests/test-cases/sym-link-load/test.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + + +#ifndef DO_NOTHING + +// should run second because first initiallzer in first .o file +static __attribute__((constructor)) void test_init() +{ + //fprintf(stderr, "test_init()\n"); + setState(1); +} + +#endif diff --git a/unit-tests/test-cases/text-relocs/Makefile b/unit-tests/test-cases/text-relocs/Makefile new file mode 100644 index 0000000..92225e9 --- /dev/null +++ b/unit-tests/test-cases/text-relocs/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +### +### This test case is to verify __TEXT reliocations work +### +### + + + +run: all + ./main + +all: main + +main: main.c libbar.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib + +libbar.dylib: foo.s bar.c + ${CC} ${CCFLAGS} -dynamiclib -o libbar.dylib bar.c foo.s -read_only_relocs suppress -Os + +clean: + ${RM} ${RMFLAGS} *~ main libbar.dylib + diff --git a/unit-tests/test-cases/text-relocs/bar.c b/unit-tests/test-cases/text-relocs/bar.c new file mode 100644 index 0000000..9224e92 --- /dev/null +++ b/unit-tests/test-cases/text-relocs/bar.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +extern int* foo; + +bool testBar() +{ + return (*foo == 10); +} + +int bar = 10; + diff --git a/unit-tests/test-cases/text-relocs/foo.s b/unit-tests/test-cases/text-relocs/foo.s new file mode 100644 index 0000000..7f8821e --- /dev/null +++ b/unit-tests/test-cases/text-relocs/foo.s @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + .text + .globl _foo +_foo: + .long _bar + + diff --git a/unit-tests/test-cases/text-relocs/main.c b/unit-tests/test-cases/text-relocs/main.c new file mode 100644 index 0000000..a702c2e --- /dev/null +++ b/unit-tests/test-cases/text-relocs/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +extern bool testBar(); + +int main(int argc, const char* argv[]) +{ + if ( testBar() ) + PASS("text-reloc"); + else + FAIL("text-reloc"); + return EXIT_SUCCESS; +} + + diff --git a/unit-tests/test-cases/weak-coalesce-c++/Makefile b/unit-tests/test-cases/weak-coalesce-c++/Makefile new file mode 100644 index 0000000..4f38eeb --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce-c++/Makefile @@ -0,0 +1,53 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +run: all + ./dynamic-test + +all: dynamic-test static-test + + +static-test: a1.o a2.o main.o + $(CXX) -I${TESTROOT}/include a1.o a2.o main.o -o static-test + +dynamic-test: main.o a1.o liba2.dylib + $(CXX) -I${TESTROOT}/include main.o a1.o -L. -la2 -o dynamic-test + +liba2.dylib: a2.o + $(CXX) -I${TESTROOT}/include a2.o -dynamiclib -o liba2.dylib + +a1.o: a1.cc a.h + $(CXX) -I${TESTROOT}/include -c a1.cc + +a2.o: a2.cc a.h + $(CXX) -I${TESTROOT}/include -c a2.cc + +main.o: main.cc + $(CXX) -I${TESTROOT}/include -c main.cc + + +clean: + ${RM} ${RMFLAGS} *.o *.dylib static-test dynamic-test diff --git a/unit-tests/test-cases/weak-coalesce-c++/a.h b/unit-tests/test-cases/weak-coalesce-c++/a.h new file mode 100644 index 0000000..574026d --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce-c++/a.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +template +struct wrapper { + static X x; +}; + +template X wrapper::x; diff --git a/unit-tests/test-cases/weak-coalesce-c++/a1.cc b/unit-tests/test-cases/weak-coalesce-c++/a1.cc new file mode 100644 index 0000000..0395912 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce-c++/a1.cc @@ -0,0 +1,4 @@ +#include "a.h" + +int get_x_1 (void) { return wrapper::x; } +void set_x_1 (int x_) { wrapper::x = x_; } diff --git a/unit-tests/test-cases/weak-coalesce-c++/a2.cc b/unit-tests/test-cases/weak-coalesce-c++/a2.cc new file mode 100644 index 0000000..b3a3fed --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce-c++/a2.cc @@ -0,0 +1,4 @@ +#include "a.h" + +int get_x_2 (void) { return wrapper::x; } +void set_x_2 (int x_) { wrapper::x = x_; } diff --git a/unit-tests/test-cases/weak-coalesce-c++/main.cc b/unit-tests/test-cases/weak-coalesce-c++/main.cc new file mode 100644 index 0000000..3915e94 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce-c++/main.cc @@ -0,0 +1,20 @@ +#include +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +extern void set_x_1(int); +extern void set_x_2(int); +extern int get_x_1(void); +extern int get_x_2(void); + +int main() +{ + set_x_1 (17); + set_x_2 (76); + + if (get_x_1() == 76 && get_x_2() == 76) + PASS("weak-coalesce=c++"); + else + FAIL("weak-coalesce=c++"); +} diff --git a/unit-tests/test-cases/weak-coalesce/Makefile b/unit-tests/test-cases/weak-coalesce/Makefile new file mode 100644 index 0000000..13bdf37 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +run: all + ./main + +all: main + + +main: main.c libfoo1.dylib libbase.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo1.dylib libbase.dylib + +libfoo1.dylib: foo1.c libfoo2.dylib libbase.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo1.dylib foo1.c libfoo2.dylib libbase.dylib + +libfoo2.dylib: foo2.c libfoo3.dylib libbase.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo2.dylib foo2.c libfoo3.dylib libbase.dylib + +libfoo3.dylib: foo3.c libbase.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo3.dylib foo3.c libbase.dylib -prebind -seg1addr 20000 + +libbase.dylib: base.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libbase.dylib base.c -prebind -seg1addr 10000 + + + +clean: + ${RM} ${RMFLAGS} *~ main libfoo1.dylib libfoo2.dylib libfoo3.dylib libbase.dylib + diff --git a/unit-tests/test-cases/weak-coalesce/base.c b/unit-tests/test-cases/weak-coalesce/base.c new file mode 100644 index 0000000..0deff52 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/base.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "base.h" +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +static bool wasProblem = false; + +static const char* coal1Where = NULL; +static int* coal1Addr = NULL; +static int checkInCountCoal1 = 0; + +void baseVerifyCoal1(const char* where, int* addr) +{ + //fprintf(stderr, "baseVerifyCoal1(%s, %p)\n", where, addr); + ++checkInCountCoal1; + if ( coal1Where == NULL ) { + coal1Where = where; + coal1Addr = addr; + } + else { + if ( addr != coal1Addr ) { + fprintf(stderr, "coal1 resolved to different locations. %p in %s and %p in %s\n", + coal1Addr, coal1Where, addr, where); + wasProblem = true; + } + } +} + + +static const char* coal2Where = NULL; +static int* coal2Addr = NULL; +static int checkInCountCoal2 = 0; + +void baseVerifyCoal2(const char* where, int* addr) +{ + //fprintf(stderr, "baseVerifyCoal2(%s, %p)\n", where, addr); + ++checkInCountCoal2; + if ( coal2Where == NULL ) { + coal2Where = where; + coal2Addr = addr; + } + else { + if ( addr != coal2Addr ) { + fprintf(stderr, "coal2 resolved to different locations. %p in %s and %p in %s\n", + coal2Addr, coal2Where, addr, where); + wasProblem = true; + } + } +} + + + +void baseCheck() +{ + if ( wasProblem || (checkInCountCoal1 != 4) || (checkInCountCoal2 != 4) ) + FAIL("weak-coal"); + else + PASS("weak-coal"); +} + diff --git a/unit-tests/test-cases/weak-coalesce/base.h b/unit-tests/test-cases/weak-coalesce/base.h new file mode 100644 index 0000000..482b832 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/base.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +extern void baseCheck(); + +extern int coal1; +extern int coal2; + +extern void baseVerifyCoal1(const char* where, int* addr); +extern void baseVerifyCoal2(const char* where, int* addr); diff --git a/unit-tests/test-cases/weak-coalesce/foo1.c b/unit-tests/test-cases/weak-coalesce/foo1.c new file mode 100644 index 0000000..0707e0d --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/foo1.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + + + +int __attribute__((weak)) coal1 = 1; +int __attribute__((weak)) coal2 = 1; + + +static __attribute__((constructor)) void myinit() +{ + //fprintf(stderr, "myinit() in foo1.c\n"); + baseVerifyCoal1("in foo1", &coal1); + baseVerifyCoal2("in foo1", &coal2); +} + + diff --git a/unit-tests/test-cases/weak-coalesce/foo2.c b/unit-tests/test-cases/weak-coalesce/foo2.c new file mode 100644 index 0000000..a5770d4 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/foo2.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + + +int coal1 = 2; +int __attribute__((weak)) coal2 = 2; + +static __attribute__((constructor)) void myinit() +{ + //fprintf(stderr, "myinit() in foo1.c\n"); + baseVerifyCoal1("in foo2", &coal1); + baseVerifyCoal2("in foo2", &coal2); +} diff --git a/unit-tests/test-cases/weak-coalesce/foo3.c b/unit-tests/test-cases/weak-coalesce/foo3.c new file mode 100644 index 0000000..c92a444 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/foo3.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include "base.h" + +int __attribute__((weak)) coal1 = 3; +int __attribute__((weak)) coal2 = 2; + +static __attribute__((constructor)) void myinit() +{ + //fprintf(stderr, "myinit() in foo1.c\n"); + baseVerifyCoal1("in foo3", &coal1); + baseVerifyCoal2("in foo3", &coal2); +} + diff --git a/unit-tests/test-cases/weak-coalesce/main.c b/unit-tests/test-cases/weak-coalesce/main.c new file mode 100644 index 0000000..6f4f9e1 --- /dev/null +++ b/unit-tests/test-cases/weak-coalesce/main.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + + +#include "base.h" + +int main() +{ + + //fprintf(stderr, "myinit() in foo1.c\n"); + baseVerifyCoal1("in main", &coal1); + baseVerifyCoal2("in main", &coal2); + + baseCheck(); + return EXIT_SUCCESS; +} + + diff --git a/unit-tests/test-cases/weak-library/Makefile b/unit-tests/test-cases/weak-library/Makefile new file mode 100644 index 0000000..b4eb71c --- /dev/null +++ b/unit-tests/test-cases/weak-library/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + cd absent/ && ../${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main + cd present/ && ../${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main + +all: foo.c main.c + ${CC} -dynamiclib -prebind -seg1addr 400000 -o libfoo.dylib foo.c + mkdir -p absent/ + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o absent/main main.c + mkdir -p present/ + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o present/main main.c + mv libfoo.dylib present/ + +clean: + ${RM} ${RMFLAGS} *~ libfoo.dylib absent present diff --git a/unit-tests/test-cases/weak-library/foo.c b/unit-tests/test-cases/weak-library/foo.c new file mode 100644 index 0000000..55808e4 --- /dev/null +++ b/unit-tests/test-cases/weak-library/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include "foo.h" + +int foo() +{ + return 10; +} diff --git a/unit-tests/test-cases/weak-library/foo.h b/unit-tests/test-cases/weak-library/foo.h new file mode 100644 index 0000000..78d1afd --- /dev/null +++ b/unit-tests/test-cases/weak-library/foo.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +extern int foo(); diff --git a/unit-tests/test-cases/weak-library/main.c b/unit-tests/test-cases/weak-library/main.c new file mode 100644 index 0000000..b16a8e4 --- /dev/null +++ b/unit-tests/test-cases/weak-library/main.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include + +#include "test.h" + +int +main(int argc, char **argv) +{ + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/weak-override/Makefile b/unit-tests/test-cases/weak-override/Makefile new file mode 100644 index 0000000..26f8617 --- /dev/null +++ b/unit-tests/test-cases/weak-override/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +run: all + ./main + +all: main + + +main: main.c libfoo.dylib + ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib + +libfoo.dylib: foo.c + ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo.dylib foo.c + +clean: + ${RM} ${RMFLAGS} *~ main libfoo.dylib + diff --git a/unit-tests/test-cases/weak-override/foo.c b/unit-tests/test-cases/weak-override/foo.c new file mode 100644 index 0000000..dcce76e --- /dev/null +++ b/unit-tests/test-cases/weak-override/foo.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + + + +int __attribute__((weak)) myfunc() +{ + return 0; +} + +int __attribute__((weak)) foo() +{ + return myfunc(); +} diff --git a/unit-tests/test-cases/weak-override/main.c b/unit-tests/test-cases/weak-override/main.c new file mode 100644 index 0000000..d958a78 --- /dev/null +++ b/unit-tests/test-cases/weak-override/main.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +// foo is defined in libfoo.dylib +// it calls myfunc() +extern int foo(); + +int main() +{ + if ( foo() == 10 ) + PASS("weak-override"); + else + FAIL("weak-override"); + return EXIT_SUCCESS; +} + + +// myfunc() also defined in libfoo.dylib but weak there, so this should override +int myfunc() +{ + return 10; +} + diff --git a/unit-tests/test-cases/weak-symbol-flat/Makefile b/unit-tests/test-cases/weak-symbol-flat/Makefile new file mode 100644 index 0000000..f49610d --- /dev/null +++ b/unit-tests/test-cases/weak-symbol-flat/Makefile @@ -0,0 +1,44 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + (export DYLD_IMAGE_SUFFIX=_missing && ./main) || echo "FAIL \"weak-symbol-flat\"" + ./main 1 + +all : main libfoo.dylib libfoo_missing.dylib + +libfoo.dylib : foo.c + ${CC} -dynamiclib -DSYMBOL_PRESENT -o libfoo.dylib foo.c + +libfoo_missing.dylib : foo.c + ${CC} -dynamiclib -o libfoo_missing.dylib foo.c -install_name libfoo.dylib + +main: main.c libfoo.dylib + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -I${TESTROOT}/include -L. -lfoo -o main main.c -flat_namespace + +clean: + ${RM} ${RMFLAGS} *~ libfoo.dylib libfoo_missing.dylib main + + diff --git a/unit-tests/test-cases/weak-symbol-flat/foo.c b/unit-tests/test-cases/weak-symbol-flat/foo.c new file mode 100644 index 0000000..b4b8cea --- /dev/null +++ b/unit-tests/test-cases/weak-symbol-flat/foo.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifdef SYMBOL_PRESENT +int foo() +{ + return 10; +} + +#endif + diff --git a/unit-tests/test-cases/weak-symbol-flat/foo.h b/unit-tests/test-cases/weak-symbol-flat/foo.h new file mode 100644 index 0000000..7f4d4ab --- /dev/null +++ b/unit-tests/test-cases/weak-symbol-flat/foo.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +int foo() WEAK_IMPORT_ATTRIBUTE; diff --git a/unit-tests/test-cases/weak-symbol-flat/main.c b/unit-tests/test-cases/weak-symbol-flat/main.c new file mode 100644 index 0000000..146fe81 --- /dev/null +++ b/unit-tests/test-cases/weak-symbol-flat/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include // EXIT_SUCCESS + +#include "test.h" +#include "foo.h" + +int main(int argc, const char *argv[]) +{ + if (argc > 1) { + // when arg is passed, libfoo is used and foo should be defined + if ( &foo == NULL ) + FAIL("weak-symbol-flat foo not found"); + else if ( foo() != 10 ) + FAIL("weak-symbol-flat foo not found"); + else + PASS("weak-symbol-flat when symbol found"); + } + else { + // when no args are passed, libfoo_missing is used and foo should be undefined + if ( &foo != NULL ) + FAIL("weak-symbol-flat foo found"); + else + PASS("weak-symbol-flat when symbol missing"); + } + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/weak-symbol/Makefile b/unit-tests/test-cases/weak-symbol/Makefile new file mode 100644 index 0000000..e24ee52 --- /dev/null +++ b/unit-tests/test-cases/weak-symbol/Makefile @@ -0,0 +1,35 @@ +## +# Copyright (c) 2005 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +run: all + export DYLD_IMAGE_SUFFIX=_missing && ${TESTROOT}/bin/exit-zero-pass.pl "weak-symbol" "weak-symbol" ./main + +all: foo.c main.c + ${CC} foo.c -dynamiclib -o libfoo.dylib -DSYMBOL_PRESENT + ${CC} foo.c -dynamiclib -o libfoo_missing.dylib -install_name libfoo.dylib + export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -I${TESTROOT}/include -L. -lfoo main.c -o main + +clean: + ${RM} ${RMFLAGS} *~ libfoo.dylib libfoo_missing.dylib main diff --git a/unit-tests/test-cases/weak-symbol/foo.c b/unit-tests/test-cases/weak-symbol/foo.c new file mode 100644 index 0000000..c7a3409 --- /dev/null +++ b/unit-tests/test-cases/weak-symbol/foo.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#if SYMBOL_PRESENT +int foo() +{ + return 10; +} +#endif diff --git a/unit-tests/test-cases/weak-symbol/foo.h b/unit-tests/test-cases/weak-symbol/foo.h new file mode 100644 index 0000000..7f4d4ab --- /dev/null +++ b/unit-tests/test-cases/weak-symbol/foo.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +int foo() WEAK_IMPORT_ATTRIBUTE; diff --git a/unit-tests/test-cases/weak-symbol/main.c b/unit-tests/test-cases/weak-symbol/main.c new file mode 100644 index 0000000..e5c8905 --- /dev/null +++ b/unit-tests/test-cases/weak-symbol/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include // EXIT_SUCCESS + +#include "test.h" +#include "foo.h" + +int main(int argc, const char* argv[]) +{ + if ( &foo == NULL ) + { + PASS("weak-symbol not available"); + } + return 0; +} -- 2.45.2