lldb-server link failure with shared library configuration

I’ve built lldb in tree on Linux (RHEL 7.3) with a shared library configuration:

CC=/usr/bin/clang CXX=/usr/bin/clang++ \

cmake -G Ninja …/llvm \

*-DBUILD_SHARED_LIBS=true *

The lldb-server binary does not link for me, as I get unresolved symbols including:

llvm::RuntimeDyld::MemoryManager::anchor()

I’ve worked around this by changing the link rules for lldb-server like so:

diff --git a/tools/lldb-server/CMakeLists.txt b/tools/lldb-server/CMakeLists.txt

index f8c57cb…35311a8 100644

— a/tools/lldb-server/CMakeLists.txt

+++ b/tools/lldb-server/CMakeLists.txt

@@ -82,6 +85,7 @@ add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK

lldbHost

lldbInitialization

lldbInterpreter

  • LLVMRuntimeDyld

${LLDB_PLUGINS}

${LLDB_SYSTEM_LIBS}

Is this a known issue, and what would the proper fix for this look like?

Looks like a dependency issue in LLVM? Who was using this function? Why do we need LLVMRuntimeDyld in lldb-server? We shouldn’t have to use it. I know we currently have some issues in lldb-server where it is pulling in too much stuff, so we definitely don’t want to include this just to fix a link issue. lldb-server shouldn’t require the LLDB expression parser AFAIK.

Does the link line mention who was wanting llvm::RuntimeDyld::MemoryManager::anchor()?

Hi Greg,

IRExecutionUnit.cpp looks like the origin of at least some of the undefined symbols:

…/llvm/include/llvm/ExecutionEngine/RTDyldMemoryManager.h:61: undefined reference to `vtable for llvm::RTDyldMemoryManager’

…/llvm/include/llvm/ExecutionEngine/JITSymbol.h:223: undefined reference to `vtable for llvm::JITSymbolResolver’

…/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h:96: undefined reference to `vtable for llvm::RuntimeDyld::MemoryManager’

lib/liblldbExpression.a(IRExecutionUnit.cpp.o):(.data.rel.ro+0x90): undefined reference to `llvm::RTDyldMemoryManager::deregisterEHFrames()’

lib/liblldbExpression.a(IRExecutionUnit.cpp.o):(.data.rel.ro+0xa8): undefined reference to `llvm::RuntimeDyld::MemoryManager::anchor()’

lib/liblldbExpression.a(IRExecutionUnit.cpp.o):(.data.rel.ro+0x118): undefined reference to `llvm::JITSymbolResolver::anchor()’

lib/liblldbExpression.a(IRExecutionUnit.cpp.o):(.data.rel.ro._ZTVN4llvm18MCJITMemoryManagerE[_ZTVN4llvm18MCJITMemoryManagerE]+0x60): undefined reference to `llvm::RuntimeDyld:

:MemoryManager::anchor()’

there are a couple of undefined vtable references in headers (also above), but it’s not clear to me if these also neccessarily come from IRExectionUnix.cpp.

If we are pulling in the expression parser, that would explain our issues. If this currently happens in lldb-server we need to add LLVMRuntimeDyld to the link libraries. I know some people at Google have looked into getting lldb-server to link against as little as possible, and maybe this is just how things are for the time being. We should verify that. It would be nice if lldb-server didn’t link against the expression parser if possible.

Greg

Hi All,

We are trying to keep the size of lldb-server as small as possible as it have to be copied over to the android device for every debug session. The way we currently achieve this is by using linker garbage collection to get rid of the unused code.

In the log term it would be nice to be more explicit about the list of dependencies but currently we don’t have clear enough boundaries for doing that. Pavel and Zachary spent some time on improving it but I think we are still quite far from that.

For your problem I think a better short term option would be to add LLVMRuntimeDyld as a dependency for lldbExpression instead of lldb-server directly (assuming it works). Optionally if you are feeling more adventurous you can try to replace ${LLDB_PLUGINS} and ${LLDB_SYSTEM_LIBS} with a more explicit list of dependencies what might remove the dependency between lldb-server and LLVMRuntimeDyld but I am not certain.

Tamas

Hi Tamas,

I was able to use your suggestion as follows:

diff --git a/source/Expression/CMakeLists.txt b/source/Expression/CMakeLists.txt

index 7d9643a…b53b095 100644

— a/source/Expression/CMakeLists.txt

+++ b/source/Expression/CMakeLists.txt

@@ -2,6 +2,12 @@ if(NOT LLDB_BUILT_STANDALONE)

set(tablegen_deps intrinsics_gen)

endif()

+set(LLDB_EXP_DEPS)

Hi Peeter,

Why do you have to make the dependency conditional on BUILD_SHARED_LIBS? If lldbExpression depends on LLVMRuntimeDyld it should depend on it independently of the build config.

Also I gave it a try to build lldb using shared libraries locally and I haven’t hit any issue when I used the following command (on Ubuntu 14.04): cmake …/…/llvm -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=true

Are you using some other cmake flags as well? Also can you check the link command used for the final linking step if it contains LLVMRuntimeDyld without your change? Can it be just a library ordering issue where some symbols are dropped before they are used?

Cheers,
Tamas

Hi Tamas,

It looks like lldb-server only fails if I build with a Debug configuration, which I didn’t realize until now. In Release configuration, I don’t need any changes to CMakefiles and lldb-server links without error. My full build configuration in debug mode was:

mkdir lldb50.1708110153

cd lldb50.1708110153

PATH=$PATH:/opt/lzlabs/bin

CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake \

-G \

Ninja \

…/llvm \

-DBUILD_SHARED_LIBS=true \

-DLLVM_TARGETS_TO_BUILD=‘X86’ \

-DCMAKE_BUILD_TYPE=Debug \

-DLLVM_ENABLE_ASSERTIONS=TRUE \

-DCMAKE_INSTALL_PREFIX=/home/pjoot/clang/lldb50.1708110153 \

-DLLVM_OPTIMIZED_TABLEGEN=ON \

-DICU_LIBRARY=/opt/lzlabs/lib64 \

-DICU_INCLUDE_DIR=/opt/lzlabs/include

Without any changes LLVMRuntimeDyld is not in the lldb-server link list, so this is not an ordering issue. I’m not sure why this ends up as an issue only with Debug.

I tried to build using the following command what should be a reasonably close approximation to the one you used (I don’t have ICU installed at the moment) and it still links fine for me:
CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -G Ninja …/…/llvm -DBUILD_SHARED_LIBS=true -DLLVM_TARGETS_TO_BUILD=‘X86’ -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=TRUE -DLLVM_OPTIMIZED_TABLEGEN=ON

It would be great to understand what exactly causes the difference between the 2 cases by some sort of bisecting as I see nothing in the source code what would explain this. If changing from -DCMAKE_BUILD_TYPE=Debug to -DCMAKE_BUILD_TYPE=Release fixes the issue then it would be nice to diff the ninja build graph and the different cmake caches to try to figure out where the different starts.

Tamas

I tried to build using the following command what should be a reasonably
close approximation to the one you used (I don't have ICU installed at the
moment) and it still links fine for me:
CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -G Ninja ../../llvm
-DBUILD_SHARED_LIBS=true -DLLVM_TARGETS_TO_BUILD='X86'
-DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=TRUE
-DLLVM_OPTIMIZED_TABLEGEN=ON

It would be great to understand what exactly causes the difference between
the 2 cases by some sort of bisecting as I see nothing in the source code
what would explain this. If changing from -DCMAKE_BUILD_TYPE=Debug to
-DCMAKE_BUILD_TYPE=Release fixes the issue then it would be nice to diff the
ninja build graph and the different cmake caches to try to figure out where
the different starts.

Debug info tends to alter the order in which the linker pulls in
object files from archives (which matters a lot when you have a large
number of cyclical inter-archive dependencies like we do). In the past
I have needed to increase the LINK_INTERFACE_MULTIPLICITY property to
make lldb build in debug mode (although the release mode was fine). It
is possible increasing that number will fix things
(source/Core/CMakeLists.txt).