[Lldb-commits] [lldb] [lldb] Resolve symlinks when transferring files to remote devices (PR #189177)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Tue Mar 31 22:18:24 PDT 2026
https://github.com/medismailben updated https://github.com/llvm/llvm-project/pull/189177
>From 72a7d5b71181b495f0b16eff7a31eae77875a33f Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Tue, 31 Mar 2026 22:17:48 -0700
Subject: [PATCH] [lldb] Resolve symlinks when transferring files to remote
devices
When installing files to a remote device, Platform::Install handles
symlinks by recreating them on the remote via CreateSymlink. For
absolute symlinks this fails because the target is a local path that
doesn't exist on the device. Platform::PutFile also explicitly sets
DontFollowSymlinks when opening symlinked source files, causing
"Too many levels of symbolic links" errors.
This means shared libraries built as symlinks (common with framework
builds using @executable_path install names) are silently never
transferred, causing dyld "Library not loaded" failures on launch.
For the recursive directory copy path, distinguish between absolute
and relative symlinks: absolute symlinks are resolved and the actual
file content is transferred via PutFile, while relative symlinks
(e.g. inside framework bundles) are recreated on the remote with
CreateSymlink since they are relocatable.
For single-file installs via Platform::Install, always resolve the
symlink and transfer the file content since the symlink target may
not exist on the remote device.
This also changes PutFile to resolve symlinks before opening the
source file instead of adding DontFollowSymlinks.
rdar://173566256
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
lldb/source/Target/Platform.cpp | 35 ++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 14 deletions(-)
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 55eaa88b562d4..e22f71a2bab65 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -501,23 +501,27 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft,
} break;
case fs::file_type::symlink_file: {
- // copy the file and keep going
FileSpec dst_file = rc_baton->dst;
if (!dst_file.GetFilename())
dst_file.SetFilename(src.GetFilename());
FileSpec src_resolved;
-
rc_baton->error = FileSystem::Instance().Readlink(src, src_resolved);
-
if (rc_baton->error.Fail())
- return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out
-
- rc_baton->error =
- rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved);
+ return FileSystem::eEnumerateDirectoryResultQuit;
+ if (src_resolved.IsAbsolute()) {
+ // Absolute symlinks won't be valid on the remote device — transfer
+ // the actual file content instead.
+ rc_baton->error = rc_baton->platform_ptr->PutFile(src_resolved, dst_file);
+ } else {
+ // Relative symlinks (e.g. inside framework bundles) are relocatable
+ // and valid on the remote as-is — recreate them.
+ rc_baton->error =
+ rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved);
+ }
if (rc_baton->error.Fail())
- return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out
+ return FileSystem::eEnumerateDirectoryResultQuit;
return FileSystem::eEnumerateDirectoryResultNext;
} break;
@@ -634,11 +638,13 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) {
break;
case fs::file_type::symlink_file: {
+ // Resolve the symlink and transfer the actual file content. The symlink
+ // target may be a local absolute path that won't exist on the device.
llvm::sys::fs::remove(fixed_dst.GetPath());
FileSpec src_resolved;
error = FileSystem::Instance().Readlink(src, src_resolved);
if (error.Success())
- error = CreateSymlink(dst, src_resolved);
+ error = PutFile(src_resolved, fixed_dst);
} break;
case fs::file_type::fifo_file:
error = Status::FromErrorString("platform install doesn't handle pipes");
@@ -1189,14 +1195,15 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "[PutFile] Using block by block transfer....\n");
+ // Resolve symlinks so we transfer the actual file content.
+ FileSpec resolved_source(source);
+ FileSystem::Instance().Resolve(resolved_source);
+
auto source_open_options =
File::eOpenOptionReadOnly | File::eOpenOptionCloseOnExec;
- namespace fs = llvm::sys::fs;
- if (fs::is_symlink_file(source.GetPath()))
- source_open_options |= File::eOpenOptionDontFollowSymlinks;
- auto source_file = FileSystem::Instance().Open(source, source_open_options,
- lldb::eFilePermissionsUserRW);
+ auto source_file = FileSystem::Instance().Open(
+ resolved_source, source_open_options, lldb::eFilePermissionsUserRW);
if (!source_file)
return Status::FromError(source_file.takeError());
Status error;
More information about the lldb-commits
mailing list