28

I have not been able to figure out why my binary is not loading. It is a dylib loaded by MATLAB (MEX-file), and links to quite a few dylibs in different locations. MATLAB tells me it cannot load the MEX-file, but I cannot figure out which of its dependencies it cannot find.

Does anybody have any suggestions for how to debug something like this?

On Linux, ldd is the perfect tool to debug this problem. People keep saying that otool -L is the MacOS equivalent to the Linux ldd, but this is not true. ldd actually looks for the libraries, and tells you which ones can be found, and where they were found. otool -L only tells you what libraries are needed to link against. It does not effort to check to see if they are there. It doesn't even tell you where libraries are searched for when they use @rpath.

otool -l (lowercase L) gives you a dump of the "load commands", there you can see the LC_RPATH commands, which establish where @rpath libraries are searched for. But these have not been able to explain to me which dependency is not found.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Also, for inspecting Linux binaries on a macOS, `greadelf` from MacPorts can be used, as well as `nm`: https://unix.stackexchange.com/a/418357/43390, also relevant to: https://stackoverflow.com/a/23698812/1959808. – 0 _ May 29 '21 at 20:58
  • When trying `otool -L` for a Linux executable, an error was raised "object is not a Mach-O file type.". – 0 _ May 29 '21 at 21:00
  • 1
    @Ioannis: Yes, `otool` is for macOS binaries, not Linux ones. The SO answer you link talks about `otool -L`, which I already mention in the question is not useful in this particular case. `readelf` and `nm` are useful to see what symbols are in the binary, and serve a similar purpose to `otool` with other flags. None of them attempt to replicate the `ldd` functionality. – Cris Luengo May 29 '21 at 21:06
  • Thank you for noting that none of `readelf`, `nm`, and `otool` operate similarly to how `ldd` does. This comment motivated me to read further, and the information I collected does not fit in a comment, so I posted it in an answer to a question that seems closer to what I was searching for: https://stackoverflow.com/a/67818921/1959808 – 0 _ Jun 03 '21 at 09:32
  • I arrived to this thread while searching for analysis on macOS of ELF executables (compiled on Linux). My understanding is that this use case is related to the question here, which is phrased about `dylib`, so Mach-O analysis on macOS, and what for Mach-O on macOS is the closest thing to `ldd` for ELF on Linux. My purpose for commenting was informational, to provide pointers for others that might find this thread while searching for ELF analysis on macOS. – 0 _ Jun 03 '21 at 09:33
  • I thought I was using macOS's `otool`, but was actually using the `otool` that is part of MacPorts package the `cctools` (installed as `/opt/local/bin/otool`). Both variants raise an error when given an ELF file, with tiny differences in the error message: `/opt/local/bin/otool -L file_name` says "llvm-objdump: error: file_name': object is not a Mach-O file type.", whereas `/usr/bin/otool -L` says: "llvm-objdump: 'file_name': Object is not a Mach-O file type.". – 0 _ Jun 03 '21 at 09:33
  • My comment about `otool` was intended for the ELF case only. If `otool` supported ELF files, it might have sufficed for what I was trying to confirm (I was looking for some specific versioned symbols). I did not intend to suggest that `otool` is equivalent to `ldd`. As you have noted, in general, `otool` does not perform the kind of analysis that `ldd` does. – 0 _ Jun 03 '21 at 09:33
  • Above, I linked to the SO answer: https://stackoverflow.com/a/23698812/1959808 with the purpose of linking the two threads. – 0 _ Jun 03 '21 at 09:33

3 Answers3

25

Try setting these environment variables before running matlab:

export DYLD_PRINT_LIBRARIES=1
export DYLD_PRINT_LIBRARIES_POST_LAUNCH=1
export DYLD_PRINT_RPATHS=1

Run man dyld for more possibilities.

You can also set the variables for just the matlab command like this:

DYLD_PRINT_LIBRARIES=1 DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 DYLD_PRINT_RPATHS=1 matlab
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • This is excellent, thank you so much! Matlab has a boot script that seems to not pass on environment variables to the executable, so I added these variables to the script. I also used `DYLD_PRINT_TO_FILE`. – Cris Luengo Aug 02 '17 at 22:03
12

Rob Mayoff's answer is a great solution when working with executables. If you find you need to check the runtime dependencies of a dylib, the following script my-ldd may be useful.

#!/usr/bin/env bash 

while getopts "r" OPTION; do
  case $OPTION in   
    r) export DYLD_PRINT_RPATHS=1;;
  esac
done
shift $((OPTIND-1))

cp `which true` .
DYLD_PRINT_LIBRARIES=1 \
DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 \
DYLD_INSERT_LIBRARIES=$1 \
./true
rm ./true

where a the script may be invoked as

my-ldd ./foo.dylib

or (with rpath attempts echo'd)

my-ldd -r ./foo.dylib
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
apmccartney
  • 743
  • 8
  • 16
  • 2
    Nice! What is the reason this needs a local copy of the `true` binary? I tried running `/usr/bin/true` in this way and it doesn't work. – Cris Luengo May 22 '19 at 04:05
  • 3
    I encountered the same issue. It's an enhanced security measure put in place by Apple. See [this](https://stackoverflow.com/a/48478771/2471708) link for more discussion – apmccartney May 22 '19 at 04:23
  • On my MacOS version 22.5.0 it does not work with `/usr/bin/true` nor with other pre-installed binaries. Yet I compiled my own trivial `true` command, this way it works also without copying the binary. – dvo Jul 29 '23 at 13:33
1

Your my-ldd script was a great idea!

I also encountered some issues with the apple SIP limitation, plus I also found a bit tricky to deal with multiple architecture.

So I extended it to detect the dylib architecture and I workarounded the SIP by creating an simple executable on the spot (credit to the thread of @okutane)

The result is at: https://github.com/tetractius/ldd-apple/blob/main/ldd-apple.sh

FilTius
  • 13
  • 3