On macOS 10.12.6, I have a shared library and an executable (both built myself, SIP should not apply AFAIK) and I'd like to preload the library for the executable. It fails, with a return code of 1, and silently otherwise:
$ ./bar/exec
<does stuff>
$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=./foo/my.dylib ./bar/exec
<returns immediately>
$ echo $?
1
# 1 is not an explicitly returned value from ./bar/exec
If I add either DYLD_PRINT_LIBRARIES
or DYLD_PRINT_LIBRARIES_POST_LAUNCH
options as documented in man dyld
, they both show that both the library and the executable have been loaded successfully:
...
dyld: loaded: /full/path/to/exec
dyld: loaded: ./foo/my.dylib
...
If I try to run the executable with preload in either dtruss or lldb, it runs, without the library preloaded. This might make sense because these tools are SIP-protected.
How do I go about debugging this?
UPDATE
Thanks to @macmoonshine, I am able to reproduce the return code 1 exit under lldb by setting the preload environment from LLDB itself as opposed for LLDB:
(lldb) env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=./foo/my.dylib
(lldb) run
...
Process 24130 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x00007fffc8aac310 libsystem_kernel.dylib`__exit
...
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x00007fffc8aac310 libsystem_kernel.dylib`__exit
frame #1: 0x000000010008ebac my.dylib`my_init at my.c:86 [opt]
frame #2: 0x0000000100018a1b dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 385
frame #3: 0x0000000100018c1e dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40
frame #4: 0x00000001000144aa dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 338
frame #5: 0x0000000100013524 dyld`ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 138
frame #6: 0x00000001000135b9 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 75
frame #7: 0x0000000100005434 dyld`dyld::initializeMainExecutable() + 125
frame #8: 0x00000001000098c6 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3966
frame #9: 0x0000000100004249 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 470
frame #10: 0x0000000100004036 dyld`_dyld_start + 54
This is a start for debugging.
You can run your code in lldb
, where you can set the environment with the env
command:
env DYLD_FORCE_FLAT_NAMESPACE=1
env DYLD_INSERT_LIBRARIES=./foo/my.dylib
run
With lldb
you can run your program until it crashes. If it exists abnormally with exit()
(or _exit()
), you should set symbolic breakpoints with b exit
and b _exit
. So you have the chance to get a backtrace where it fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With