Skip to content

Commit a86f4ee

Browse files
[lldb] Use correct path for debugserver (#131609)
This solves an issue that arises when running lldb-server through a symlink which is not named exactly `lldb-server`. For example, in many distros lldb-server is packaged as e.g. `/usr/lib/llvm-19/bin/lldb-server` which is then accessed through a symlink such as `/usr/bin/lldb-server-19`. It turns out that there is a cascade of bugs here: * `GetShlibDir` attempts to locate the LLVM library directory by calling `GetModuleFileSpecForHostAddress` on the address of the function `ComputeSharedLibraryDirectory`, assuming that it is inside `liblldb.so`. However, in every packaging I've seen of lldb-server the function `ComputeSharedLibraryDirectory` is statically linked into the `lldb-server` binary and is not in `liblldb.so`. * When run through a symlink, `GetModuleFileSpecForHostAddress` on an address that is in `lldb-server` returns the path of the symlink, not the path of the binary itself. So we get e.g. `/usr/bin/` and not `/usr/lib/llvm-19/bin/`. * `GetDebugserverPath` attempts to concat `"lldb-server"` to the directory we obtained, and thus fails when the symlink is not named exactly `lldb-server`. * Ironically, the reason that this works in the first place is precisely because `GetModuleFileSpecForHostAddress` returns an incorrect path - when the server is run as `lldb-server-19 ...` it returns `"lldb-server-19"` which then causes `ComputePathRelativeToLibrary` to fail and then `ComputeSupportExeDirectory` falls back to just using `GetProgramFileSpec` instead (which is the only option that actually yields a correct path).
1 parent adb671e commit a86f4ee

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

lldb/test/API/commands/platform/launchgdbserver/TestPlatformLaunchGDBServer.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,42 @@ def test_platform_process_launch_gdb_server(self):
5858

5959
self.runCmd("target create {}".format(self.getBuildArtifact("a.out")))
6060
self.expect("run", substrs=["unable to launch a GDB server on"], error=True)
61+
62+
@skipIfRemote
63+
@skipUnlessPlatform(["linux"])
64+
@add_test_categories(["lldb-server"])
65+
def test_lldb_server_weird_symlinks(self):
66+
self.build()
67+
68+
hostname = socket.getaddrinfo("localhost", 0, proto=socket.IPPROTO_TCP)[0][4][0]
69+
listen_url = "[%s]:0" % hostname
70+
71+
port_file = self.getBuildArtifact("port")
72+
commandline_args = [
73+
"platform",
74+
"--listen",
75+
listen_url,
76+
"--socket-file",
77+
port_file,
78+
]
79+
80+
# Run lldb-server from a symlink without any binary called "lldb-server" in the directory.
81+
new_lldb_server = self.getBuildArtifact(
82+
"lldb-server-with-an-unconventional-name"
83+
)
84+
os.symlink(lldbgdbserverutils.get_lldb_server_exe(), new_lldb_server)
85+
86+
proc = self.spawnSubprocess(new_lldb_server, commandline_args)
87+
socket_id = lldbutil.wait_for_file_on_target(self, port_file)
88+
89+
new_platform = lldb.SBPlatform("remote-" + self.getPlatform())
90+
self.dbg.SetSelectedPlatform(new_platform)
91+
92+
connect_url = "connect://[%s]:%s" % (hostname, socket_id)
93+
self.runCmd("platform connect %s" % connect_url)
94+
self.runCmd("target create {}".format(self.getBuildArtifact("a.out")))
95+
self.runCmd("run")
96+
self.expect(
97+
"process status",
98+
patterns=["Process .* exited with status = 0"],
99+
)

lldb/tools/lldb-server/SystemInitializerLLGS.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@
1111

1212
#include "lldb/Initialization/SystemInitializer.h"
1313
#include "lldb/Initialization/SystemInitializerCommon.h"
14+
#include "lldb/Utility/FileSpec.h"
1415

1516
class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
1617
public:
17-
SystemInitializerLLGS() : SystemInitializerCommon(nullptr) {}
18+
SystemInitializerLLGS()
19+
: SystemInitializerCommon(
20+
// Finding the shared libraries directory on lldb-server is broken
21+
// since lldb-server isn't dynamically linked with liblldb.so.
22+
// Clearing the filespec here causes GetShlibDir to fail and
23+
// GetSupportExeDir to fall-back to using the binary path instead.
24+
[](lldb_private::FileSpec &file) { file.Clear(); }) {}
1825

1926
llvm::Error Initialize() override;
2027
void Terminate() override;

0 commit comments

Comments
 (0)