xcodemacoslldbotool

otool vs lldb image list: where additional libraries come from?


I want to find why my program uses libsqlite3.dylib, when I not linking with it.

otool -L my/program shows:

    /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.12)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 2420.0.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 2420.0.0)
    /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration (compatibility version 1.0.0, current version 1300.100.9)
    /System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 61123.100.169)
    @rpath/QtConcurrent.framework/Versions/5/QtConcurrent (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtBluetooth.framework/Versions/5/QtBluetooth (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtSvg.framework/Versions/5/QtSvg (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtQuick.framework/Versions/5/QtQuick (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtQmlModels.framework/Versions/5/QtQmlModels (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtQml.framework/Versions/5/QtQml (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.15.0, current version 5.15.9)
    @rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.15.0, current version 5.15.9)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)

this is looks exactly what I linking with my program.

But if I run lldb my/program, and then image list before running my program in debugger, I got 338 shared libraries, including /usr/lib/libsqlite3.dylib.

And looks like lldb is right, because of during debugging I see usage of libsqlite3.dylib instead of statically linked sqlite3.

So why otool -L not matched lldb image list, before execution of program, and so no one call dlopen or something similar ?


Solution

  • lldb starts from the load commands in the binary - which just list the direct dependencies of the binary. But it doesn't stop there, it then looks in each of the binary's direct dependencies, reads their load commands, then keeps walking the tree of dependencies until it enumerates all the at-launch dependencies.

    otool just presents the binary's direct dependencies, but pre-launch lldb presents the closure of its dependencies.

    Since the point of loading all these libraries is so that you can list functions, set breakpoints, disassemble functions, etc. it's more useful to present everything lldb can figure out will load in the process, not just the direct dependencies.

    Note, however, pre-run lldb is guessing where each of these libraries will actually come from. For instance, if you do:

    $ lldb my_binary
    (lldb) image list
    (lldb) env DYLD_LIBRARY_PATH=/some/directory/with/another/version/of/library
    (lldb) run
    

    Then when you run, lldb will listen to the dynamic loader to learn what actually got loaded into the program. In this case, the loader will pick up not the one from the system (which was the one lldb knew about) but the one from the DYLD_LIBRARY_PATHS. When you do image list while running, that's directly reporting what the loader said loaded, including dependencies and any dlopen calls that have happened.