Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=./foo/my.dylib ./bar/exec returns 1 w/o running my executable

Tags:

macos

dyld

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.

like image 970
Laurynas Biveinis Avatar asked Aug 01 '17 08:08

Laurynas Biveinis


1 Answers

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 exitand b _exit. So you have the chance to get a backtrace where it fails.

like image 105
clemens Avatar answered Sep 30 '22 16:09

clemens