[Lldb-commits] [lldb] 1c228a0 - [lldb] Have Host::RunShellCommand ret stderr & stdout seperately (#184548)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Mar 10 13:48:59 PDT 2026
Author: Jason Molenda
Date: 2026-03-10T13:48:55-07:00
New Revision: 1c228a0533ae76bace6a3e3fe1c22fc2858dbf75
URL: https://github.com/llvm/llvm-project/commit/1c228a0533ae76bace6a3e3fe1c22fc2858dbf75
DIFF: https://github.com/llvm/llvm-project/commit/1c228a0533ae76bace6a3e3fe1c22fc2858dbf75.diff
LOG: [lldb] Have Host::RunShellCommand ret stderr & stdout seperately (#184548)
Host::RunShellCommand takes a std::string *command_output argument and a
bool hide_stderr=false defaulted argument. If the shell command returns
stderr and stdout text, it is intermixed in the same command_output,
unless hide_stderr=true.
In SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile we call an
external program to find a binary and dSYM by uuid, and the external
program returns a plist (xml) output. In some cases, it printed a
(harmless) warning message to stderr, and then a complete plist output
to stdout. We attempt to parse the combination of these two streams, and
the parse fails - we don't get the output.
This patch removes hide_stderr and instead adds a `std::string
*separated_error_output` argument. If `separated_error_output` is
nullptr, output and error texts are returned combined in the
`command_output` argument. If a std::string object address is provided
for `separated_error_output`, then standard error output is separated
into this string. A caller which wants the old `hide_stderr=true`
behavior should pass a throwaway std::string object to `RunShellCommand`
and ignore it.
rdar://168621579
Added:
Modified:
lldb/include/lldb/Host/Host.h
lldb/include/lldb/Target/Platform.h
lldb/include/lldb/Target/RemoteAwarePlatform.h
lldb/source/API/SBPlatform.cpp
lldb/source/Commands/CommandObjectPlatform.cpp
lldb/source/Host/common/Host.cpp
lldb/source/Host/macosx/objcxx/Host.mm
lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
lldb/source/Host/windows/Host.cpp
lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
lldb/source/Target/Platform.cpp
lldb/source/Target/RemoteAwarePlatform.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h
index 4e19d15b06743..4538fd206251b 100644
--- a/lldb/include/lldb/Host/Host.h
+++ b/lldb/include/lldb/Host/Host.h
@@ -195,65 +195,117 @@ class Host {
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info);
/// Run a shell command.
- /// \arg command shouldn't be empty
- /// \arg working_dir Pass empty FileSpec to use the current working directory
- /// \arg status_ptr Pass NULL if you don't want the process exit status
- /// \arg signo_ptr Pass NULL if you don't want the signal that caused the
- /// process to exit
- /// \arg command_output Pass NULL if you don't want the command output
- /// \arg hide_stderr if this is false, redirect stderr to stdout
+ /// \param[in] command
+ /// Command to execute, should not be empty.
+ /// \param[in] working_dir
+ /// Pass empty FileSpec to use the current working directory
+ /// \param[out] status_ptr
+ /// Pass nullptr if you don't want the process exit status
+ /// \param[out] signo_ptr
+ /// Pass nullptr if you don't want the signal that caused the
+ /// process to exit
+ /// \param[out] command_output
+ /// Pass nullptr if you don't want the command output
+ /// \param[out] separated_error_output
+ /// If a std::string is specified, error output is routed
+ /// into a separate string. If nullptr is provided,
+ /// command output and error text will be returned combined
+ /// in \a command_output.
+ /// \param[in] timeout
+ /// Timeout duration to enforce
+ /// \param[in] run_in_shell
+ /// Run in a subshell, with glob expansion of args
static Status RunShellCommand(llvm::StringRef command,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
+ std::string *error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell = true,
- bool hide_stderr = false);
+ bool run_in_shell = true);
/// Run a shell command.
- /// \arg shell Pass an empty string if you want to use the default shell
- /// interpreter \arg command \arg working_dir Pass empty FileSpec to use the
- /// current working directory \arg status_ptr Pass NULL if you don't want
- /// the process exit status \arg signo_ptr Pass NULL if you don't want the
- /// signal that caused
- /// the process to exit
- /// \arg command_output Pass NULL if you don't want the command output
- /// \arg hide_stderr If this is \b false, redirect stderr to stdout
+ /// \param[in] shell
+ /// Pass an empty string to use the default shell
+ /// \param[in] command
+ /// Command to execute, should not be empty.
+ /// \param[in] working_dir
+ /// Pass empty FileSpec to use the current working directory
+ /// \param[out] status_ptr
+ /// Pass nullptr if you don't want the process exit status
+ /// \param[out] signo_ptr
+ /// Pass nullptr if you don't want the signal that caused the
+ /// process to exit
+ /// \param[out] command_output
+ /// Pass nullptr if you don't want the command output
+ /// \param[out] separated_error_output
+ /// If a std::string is specified, error output is routed
+ /// into a separate string. If nullptr is provided,
+ /// command output and error text will be returned combined
+ /// \param[in] timeout
+ /// Timeout duration to enforce
+ /// \param[in] run_in_shell
+ /// Run in a subshell, with glob expansion of args
static Status RunShellCommand(llvm::StringRef shell, llvm::StringRef command,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell = true,
- bool hide_stderr = false);
+ bool run_in_shell = true);
/// Run a shell command.
- /// \arg working_dir Pass empty FileSpec to use the current working directory
- /// \arg status_ptr Pass NULL if you don't want the process exit status
- /// \arg signo_ptr Pass NULL if you don't want the signal that caused the
- /// process to exit
- /// \arg command_output Pass NULL if you don't want the command output
- /// \arg hide_stderr if this is false, redirect stderr to stdout
+ /// \param[in] args
+ /// Command to execute
+ /// \param[in] working_dir
+ /// Pass empty FileSpec to use the current working directory
+ /// \param[out] status_ptr
+ /// Pass nullptr if you don't want the process exit status
+ /// \param[out] signo_ptr
+ /// Pass nullptr if you don't want the signal that caused the
+ /// process to exit
+ /// \param[out] command_output
+ /// Pass nullptr if you don't want the command output
+ /// \param[out] separated_error_output
+ /// If a std::string is specified, error output is routed
+ /// into a separate string. If nullptr is provided,
+ /// command output and error text will be returned combined
+ /// \param[in] timeout
+ /// Timeout duration to enforce
+ /// \param[in] run_in_shell
+ /// Run in a subshell, with glob expansion of args
static Status RunShellCommand(const Args &args, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr,
std::string *command_output,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell = true,
- bool hide_stderr = false);
+ bool run_in_shell = true);
/// Run a shell command.
- /// \arg shell Pass an empty string if you want to use the default
- /// shell interpreter \arg command \arg working_dir Pass empty FileSpec to use
- /// the current working directory \arg status_ptr Pass NULL if you don't
- /// want the process exit status \arg signo_ptr Pass NULL if you don't
- /// want the signal that caused the
- /// process to exit
- /// \arg command_output Pass NULL if you don't want the command output
- /// \arg hide_stderr If this is \b false, redirect stderr to stdout
+ /// \param[in] shell
+ /// Pass an empty string to use the default shell
+ /// \param[in] args
+ /// Command to execute
+ /// \param[in] working_dir
+ /// Pass empty FileSpec to use the current working directory
+ /// \param[out] status_ptr
+ /// Pass nullptr if you don't want the process exit status
+ /// \param[out] signo_ptr
+ /// Pass nullptr if you don't want the signal that caused the
+ /// process to exit
+ /// \param[out] command_output
+ /// Pass nullptr if you don't want the command output
+ /// \param[out] separated_error_output
+ /// If a std::string is specified, error output is routed
+ /// into a separate string. If nullptr is provided,
+ /// command output and error text will be returned combined
+ /// \param[in] timeout
+ /// Timeout duration to enforce
+ /// \param[in] run_in_shell
+ /// Run in a subshell, with glob expansion of args
static Status RunShellCommand(llvm::StringRef shell, const Args &args,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell = true,
- bool hide_stderr = false);
+ bool run_in_shell = true);
static llvm::Error OpenFileInExternalEditor(llvm::StringRef editor,
const FileSpec &file_spec,
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index fe9d4f7982bbf..1ba7516f0102c 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -679,6 +679,9 @@ class Platform : public PluginInterface {
// the process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
+ std::string
+ *separated_error_output, // Pass nullptr to have error and command
+ // output combined in command_output.
const Timeout<std::micro> &timeout);
virtual lldb_private::Status RunShellCommand(
@@ -690,6 +693,9 @@ class Platform : public PluginInterface {
// the process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
+ std::string
+ *separated_error_output, // Pass nullptr to have error and command
+ // output combined in command_output.
const Timeout<std::micro> &timeout);
virtual void SetLocalCacheDirectory(const char *local);
diff --git a/lldb/include/lldb/Target/RemoteAwarePlatform.h b/lldb/include/lldb/Target/RemoteAwarePlatform.h
index de13b18f30d85..ac2d7ca943f11 100644
--- a/lldb/include/lldb/Target/RemoteAwarePlatform.h
+++ b/lldb/include/lldb/Target/RemoteAwarePlatform.h
@@ -71,11 +71,13 @@ class RemoteAwarePlatform : public Platform {
Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr,
std::string *command_output,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout) override;
Status RunShellCommand(llvm::StringRef interpreter, llvm::StringRef command,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout) override;
const char *GetHostname() override;
diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp
index 9a0b47ce80336..567744e36829f 100644
--- a/lldb/source/API/SBPlatform.cpp
+++ b/lldb/source/API/SBPlatform.cpp
@@ -564,7 +564,7 @@ SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
FileSpec(shell_command.GetWorkingDirectory()),
&shell_command.m_opaque_ptr->m_status,
&shell_command.m_opaque_ptr->m_signo,
- &shell_command.m_opaque_ptr->m_output,
+ &shell_command.m_opaque_ptr->m_output, nullptr,
shell_command.m_opaque_ptr->m_timeout);
});
}
diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp
index 9bdb3de388bea..0bca26d89e18d 100644
--- a/lldb/source/Commands/CommandObjectPlatform.cpp
+++ b/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -1707,9 +1707,9 @@ class CommandObjectPlatformShell : public CommandObjectRaw {
std::string output;
int status = -1;
int signo = -1;
- error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,
- working_dir, &status, &signo,
- &output, m_options.m_timeout));
+ error = (platform_sp->RunShellCommand(
+ m_options.m_shell_interpreter, cmd, working_dir, &status, &signo,
+ &output, nullptr, m_options.m_timeout));
if (!output.empty())
result.GetOutputStream().PutCString(output);
if (status > 0) {
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 510f9c7696d12..68456e199cd04 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -389,39 +389,43 @@ MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid,
Status Host::RunShellCommand(llvm::StringRef command,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output_ptr,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell, bool hide_stderr) {
+ bool run_in_shell) {
return RunShellCommand(llvm::StringRef(), Args(command), working_dir,
- status_ptr, signo_ptr, command_output_ptr, timeout,
- run_in_shell, hide_stderr);
+ status_ptr, signo_ptr, command_output_ptr,
+ separated_error_output, timeout, run_in_shell);
}
Status Host::RunShellCommand(llvm::StringRef shell_path,
llvm::StringRef command,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output_ptr,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell, bool hide_stderr) {
+ bool run_in_shell) {
return RunShellCommand(shell_path, Args(command), working_dir, status_ptr,
- signo_ptr, command_output_ptr, timeout, run_in_shell,
- hide_stderr);
+ signo_ptr, command_output_ptr, separated_error_output,
+ timeout, run_in_shell);
}
Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr,
std::string *command_output_ptr,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell, bool hide_stderr) {
+ bool run_in_shell) {
return RunShellCommand(llvm::StringRef(), args, working_dir, status_ptr,
- signo_ptr, command_output_ptr, timeout, run_in_shell,
- hide_stderr);
+ signo_ptr, command_output_ptr, separated_error_output,
+ timeout, run_in_shell);
}
Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output_ptr,
+ std::string *separated_error_output,
const Timeout<std::micro> &timeout,
- bool run_in_shell, bool hide_stderr) {
+ bool run_in_shell) {
Status error;
ProcessLaunchInfo launch_info;
launch_info.SetArchitecture(HostInfo::GetArchitecture());
@@ -448,9 +452,10 @@ Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
if (working_dir)
launch_info.SetWorkingDirectory(working_dir);
llvm::SmallString<64> output_file_path;
+ llvm::SmallString<64> error_file_path;
if (command_output_ptr) {
- // Create a temporary file to get the stdout/stderr and redirect the output
+ // Create a temporary file to get the stdout and redirect the output
// of the command into this file. We will later read this file if all goes
// well and fill the data into "command_output_ptr"
if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) {
@@ -463,7 +468,22 @@ Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
}
}
+ if (separated_error_output) {
+ // Create a temporary file to get the stderr and redirect the output
+ // of the command into this file. We will later read this file if all goes
+ // well and fill the data into "separated_error_output".
+ if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) {
+ tmpdir_file_spec.AppendPathComponent("lldb-shell-error.%%%%%%");
+ llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
+ error_file_path);
+ } else {
+ llvm::sys::fs::createTemporaryFile("lldb-shell-error.%%%%%%", "",
+ error_file_path);
+ }
+ }
+
FileSpec output_file_spec(output_file_path.str());
+ FileSpec error_file_spec(error_file_path.str());
// Set up file descriptors.
launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
if (output_file_spec)
@@ -472,10 +492,11 @@ Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
else
launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
- if (output_file_spec && !hide_stderr)
- launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
+ if (error_file_spec)
+ launch_info.AppendOpenFileAction(STDERR_FILENO, error_file_spec, false,
+ true);
else
- launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
+ launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo());
launch_info.SetMonitorProcessCallback(
@@ -524,10 +545,33 @@ Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
}
}
}
+ if (separated_error_output) {
+ separated_error_output->clear();
+ uint64_t file_size =
+ FileSystem::Instance().GetByteSize(error_file_spec);
+ if (file_size > 0) {
+ if (file_size > separated_error_output->max_size()) {
+ error = Status::FromErrorStringWithFormat(
+ "shell command error output is too large to fit into a "
+ "std::string");
+ } else {
+ WritableDataBufferSP Buffer =
+ FileSystem::Instance().CreateWritableDataBuffer(
+ error_file_spec);
+ if (error.Success())
+ separated_error_output->assign(
+ reinterpret_cast<char *>(Buffer->GetBytes()),
+ Buffer->GetByteSize());
+ }
+ }
+ }
}
}
- llvm::sys::fs::remove(output_file_spec.GetPath());
+ if (output_file_spec)
+ llvm::sys::fs::remove(output_file_spec.GetPath());
+ if (error_file_spec)
+ llvm::sys::fs::remove(error_file_spec.GetPath());
return error;
}
diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm
index f52b78f257ca8..1aa6b5376b6b1 100644
--- a/lldb/source/Host/macosx/objcxx/Host.mm
+++ b/lldb/source/Host/macosx/objcxx/Host.mm
@@ -1530,10 +1530,11 @@ static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
}
}
bool run_in_shell = true;
- bool hide_stderr = true;
+ std::string error_output; // Pass stderr string arg so it is not mixed with
+ // stdout.
Status e =
RunShellCommand(expand_command, cwd, &status, nullptr, &output,
- std::chrono::seconds(10), run_in_shell, hide_stderr);
+ &error_output, std::chrono::seconds(10), run_in_shell);
if (e.Fail())
return e;
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 63cef827a91c3..d60b551765d95 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -456,8 +456,9 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
// xcrun can take surprisingly long to build up its database.
auto timeout = std::chrono::seconds(60);
bool run_in_shell = false;
- lldb_private::Status error = Host::RunShellCommand(
- args, FileSpec(), &status, &signo, &output_str, timeout, run_in_shell);
+ lldb_private::Status error =
+ Host::RunShellCommand(args, FileSpec(), &status, &signo, &output_str,
+ nullptr, timeout, run_in_shell);
// Check that xcrun returned something useful.
if (error.Fail()) {
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index d5704eed10ecb..1610f52b3b27d 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -231,9 +231,9 @@ Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
int status;
std::string output;
std::string command = expand_command.GetString().str();
- Status e =
- RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(),
- &status, nullptr, &output, std::chrono::seconds(10));
+ Status e = RunShellCommand(
+ command.c_str(), launch_info.GetWorkingDirectory(), &status, nullptr,
+ &output, nullptr, std::chrono::seconds(10));
if (e.Fail())
return e;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index c49bd69618227..fa1dbc0eeda98 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -683,7 +683,7 @@ static FileSpec GetXcodeSelectPath() {
Status status =
Host::RunShellCommand("/usr/bin/xcode-select --print-path",
FileSpec(), // current working directory
- &exit_status, &signo, &command_output,
+ &exit_status, &signo, &command_output, nullptr,
std::chrono::seconds(2), // short timeout
false); // don't run in a shell
if (status.Success() && exit_status == 0 && !command_output.empty()) {
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index ea2a22b154345..fdc52d29d2a33 100644
--- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -84,7 +84,7 @@ static uint32_t chown_file(Platform *platform, const char *path,
command.Printf("%s", path);
int status;
platform->RunShellCommand(command.GetData(), FileSpec(), &status, nullptr,
- nullptr, std::chrono::seconds(10));
+ nullptr, nullptr, std::chrono::seconds(10));
return status;
}
@@ -109,7 +109,7 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
int status;
RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, nullptr,
- std::chrono::seconds(10));
+ nullptr, std::chrono::seconds(10));
if (status != 0)
return Status::FromErrorString("unable to perform copy");
if (uid == UINT32_MAX && gid == UINT32_MAX)
@@ -140,7 +140,7 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
LLDB_LOGF(log, "[PutFile] Running command: %s\n", command.GetData());
int retcode;
Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr,
- nullptr, std::chrono::minutes(1));
+ nullptr, nullptr, std::chrono::minutes(1));
if (retcode == 0) {
// Don't chown a local file for a remote system
// if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
@@ -178,7 +178,7 @@ lldb_private::Status PlatformPOSIX::GetFile(
cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
int status;
RunShellCommand(cp_command.GetData(), FileSpec(), &status, nullptr, nullptr,
- std::chrono::seconds(10));
+ nullptr, std::chrono::seconds(10));
if (status != 0)
return Status::FromErrorString("unable to perform copy");
return Status();
@@ -199,7 +199,7 @@ lldb_private::Status PlatformPOSIX::GetFile(
LLDB_LOGF(log, "[GetFile] Running command: %s\n", command.GetData());
int retcode;
Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr,
- nullptr, std::chrono::minutes(1));
+ nullptr, nullptr, std::chrono::minutes(1));
if (retcode == 0)
return Status();
// If we are here, rsync has failed - let's try the slow way before
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index a4e6e69aba18b..1f69ef5f3f6ca 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -684,12 +684,15 @@ Status PlatformRemoteGDBServer::RunShellCommand(
int *signo_ptr, // Pass NULL if you don't want the signal that caused the
// process to exit
std::string
- *command_output, // Pass NULL if you don't want the command output
+ *command_output, // Pass nullptr if you don't want the command output
+ std::string *separated_error_output, // Pass nullptr if you don't want the
+ // error output
const Timeout<std::micro> &timeout) {
if (!IsConnected())
return Status::FromErrorStringWithFormat("Not connected.");
return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output,
+ separated_error_output, timeout);
}
llvm::ErrorOr<llvm::MD5::MD5Result>
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index 1fba9f5beb115..5332f43c3c7ad 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -141,7 +141,10 @@ class PlatformRemoteGDBServer : public Platform, private UserIDResolver {
int *signo_ptr, // Pass NULL if you don't want the signal that caused the
// process to exit
std::string
- *command_output, // Pass NULL if you don't want the command output
+ *command_output, // Pass nullptr if you don't want the command output
+ std::string
+ *separated_error_outputerror_output, // Pass nullptr if you don't want
+ // the command error output
const lldb_private::Timeout<std::micro> &timeout) override;
void CalculateTrapHandlerSymbolNames() override;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 738e4013b6154..a15dc13d7076e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2983,7 +2983,9 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
int *signo_ptr, // Pass NULL if you don't want the signal that caused the
// process to exit
std::string
- *command_output, // Pass NULL if you don't want the command output
+ *command_output, // Pass nullptr if you don't want the command output
+ std::string *separated_error_output, // Pass nullptr if you don't want the
+ // command error output
const Timeout<std::micro> &timeout) {
lldb_private::StreamString stream;
stream.PutCString("qPlatform_shell:");
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d04f6370bb6ae..6b5ed99583439 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -403,6 +403,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
// the process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
+ std::string *separated_error_output, // Pass nullptr if you don't want the
+ // command error output
const Timeout<std::micro> &timeout);
llvm::ErrorOr<llvm::MD5::MD5Result> CalculateMD5(const FileSpec &file_spec);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 786ced6525364..1beec8bf87155 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -752,7 +752,7 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell(
FileSystem::Instance().Resolve(working_spec);
Status err =
Host::RunShellCommand(path.c_str(), working_spec, &status, &signo,
- &output, std::chrono::seconds(10));
+ &output, nullptr, std::chrono::seconds(10));
StreamGDBRemote response;
if (err.Fail()) {
response.PutCString("F,");
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
index 5c1aaac886d6c..8173f611c1c84 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
@@ -1095,20 +1095,24 @@ bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile(
int exit_status = -1;
int signo = -1;
std::string command_output;
+ std::string error_output;
error = Host::RunShellCommand(
command.GetData(),
FileSpec(), // current working directory
&exit_status, // Exit status
&signo, // Signal int *
&command_output, // Command output
+ &error_output, // Command error output
std::chrono::seconds(
640), // Large timeout to allow for long dsym download times
false); // Don't run in a shell (we don't need shell expansion)
if (error.Fail() || exit_status != 0 || command_output.empty()) {
- LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')",
+ LLDB_LOGF(log,
+ "'%s' failed (exit status: %d, error: '%s', stdout: '%s', "
+ "stderr: '%s')",
command.GetData(), exit_status, error.AsCString(),
- command_output.c_str());
+ command_output.c_str(), error_output.c_str());
return false;
}
@@ -1123,6 +1127,7 @@ bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile(
if (!plist.get()) {
LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
command.GetData());
+ LLDB_LOGF(log, "Response:\n%s\n", command_output.c_str());
return false;
}
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index c85c7d2b578ef..c47ef47b0f60c 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1241,9 +1241,12 @@ lldb_private::Status Platform::RunShellCommand(
// process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
+ std::string *separated_error_output, // Pass nullptr if you don't want the
+ // command error output
const Timeout<std::micro> &timeout) {
return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output, separated_error_output,
+ timeout);
}
lldb_private::Status Platform::RunShellCommand(
@@ -1257,10 +1260,13 @@ lldb_private::Status Platform::RunShellCommand(
// process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
+ std::string *separated_error_output, // Pass nullptr if you don't want the
+ // command error output
const Timeout<std::micro> &timeout) {
if (IsHost())
return Host::RunShellCommand(shell, command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output,
+ separated_error_output, timeout);
return Status::FromErrorString(
"unable to run a remote command without a platform");
}
diff --git a/lldb/source/Target/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp
index 89b946ba75162..3dc3cbbd4463b 100644
--- a/lldb/source/Target/RemoteAwarePlatform.cpp
+++ b/lldb/source/Target/RemoteAwarePlatform.cpp
@@ -55,21 +55,23 @@ Status RemoteAwarePlatform::ResolveExecutable(const ModuleSpec &module_spec,
Status RemoteAwarePlatform::RunShellCommand(
llvm::StringRef command, const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
- const Timeout<std::micro> &timeout) {
+ std::string *separated_error_output, const Timeout<std::micro> &timeout) {
return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output, separated_error_output,
+ timeout);
}
Status RemoteAwarePlatform::RunShellCommand(
llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr, std::string *command_output,
- const Timeout<std::micro> &timeout) {
+ std::string *separated_error_output, const Timeout<std::micro> &timeout) {
if (m_remote_platform_sp)
- return m_remote_platform_sp->RunShellCommand(shell, command, working_dir,
- status_ptr, signo_ptr,
- command_output, timeout);
+ return m_remote_platform_sp->RunShellCommand(
+ shell, command, working_dir, status_ptr, signo_ptr, command_output,
+ separated_error_output, timeout);
return Platform::RunShellCommand(shell, command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output,
+ separated_error_output, timeout);
}
Status RemoteAwarePlatform::MakeDirectory(const FileSpec &file_spec,
More information about the lldb-commits
mailing list