mib created this revision.
mib added reviewers: labath, JDevlieghere, jingham.
mib added a project: LLDB.
Herald added subscribers: lldb-commits, dang.
mib requested review of this revision.
This patch adds the ability to use a custom interpreter with the
`platform shell` command. If the user enables the `-i|--interpreter`
option, and passes it the path to a binary, lldb will prepend that path
before the rest of the command and set a flag so the host interpreter
isn't fetched.
The `Platform::RunShellCommand` method already had a default parameter
`m_run_in_default_shell`, so it was mostly a matter of hooking up the
the CommandObject flag to the method parameter.
rdar://67759256
Signed-off-by: Med Ismail Bennani <[email protected]>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D86667
Files:
lldb/bindings/interface/SBPlatform.i
lldb/include/lldb/API/SBPlatform.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/Commands/Options.td
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/Target/Platform.cpp
lldb/source/Target/RemoteAwarePlatform.cpp
lldb/test/API/commands/platform/basic/TestPlatformCommand.py
Index: lldb/test/API/commands/platform/basic/TestPlatformCommand.py
===================================================================
--- lldb/test/API/commands/platform/basic/TestPlatformCommand.py
+++ lldb/test/API/commands/platform/basic/TestPlatformCommand.py
@@ -92,3 +92,24 @@
"error: timed out waiting for shell command to complete"])
self.expect("shell -t 1 -- sleep 3", error=True, substrs=[
"error: timed out waiting for shell command to complete"])
+
+ @expectedFailureAll(oslist=["windows"])
+ @no_debug_info_test
+ def test_shell_interpreter(self):
+ """ Test a shell with a different interpreter """
+ platform = self.dbg.GetSelectedPlatform()
+ self.assertTrue(platform.IsValid())
+
+ sh_cmd = lldb.SBPlatformShellCommand('/bin/sh', 'echo $0')
+ self.assertIn('/bin/sh', sh_cmd.GetCommand())
+ self.assertIn('echo $0', sh_cmd.GetCommand())
+
+ err = platform.Run(sh_cmd)
+ self.assertTrue(err.Success())
+ self.assertIn("/bin/sh", sh_cmd.GetOutput())
+
+ @expectedFailureAll(oslist=["windows"])
+ @no_debug_info_test
+ def test_shell_interpreter(self):
+ """ Test a shell with a different interpreter """
+ self.expect("platform shell -h -i /bin/sh -- 'echo $0'", substrs=['/bin/sh'])
Index: lldb/source/Target/RemoteAwarePlatform.cpp
===================================================================
--- lldb/source/Target/RemoteAwarePlatform.cpp
+++ lldb/source/Target/RemoteAwarePlatform.cpp
@@ -170,16 +170,19 @@
return error;
}
-Status RemoteAwarePlatform::RunShellCommand(
- const char *command, const FileSpec &working_dir, int *status_ptr,
- int *signo_ptr, std::string *command_output,
- const Timeout<std::micro> &timeout) {
+Status RemoteAwarePlatform::RunShellCommand(const char *command,
+ const FileSpec &working_dir,
+ int *status_ptr, int *signo_ptr,
+ std::string *command_output,
+ const Timeout<std::micro> &timeout,
+ const bool run_in_default_shell) {
if (IsHost())
return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
- command_output, timeout);
+ command_output, timeout, run_in_default_shell);
if (m_remote_platform_sp)
return m_remote_platform_sp->RunShellCommand(
- command, working_dir, status_ptr, signo_ptr, command_output, timeout);
+ command, working_dir, status_ptr, signo_ptr, command_output, timeout,
+ run_in_default_shell);
return Status("unable to run a remote command without a platform");
}
Index: lldb/source/Target/Platform.cpp
===================================================================
--- lldb/source/Target/Platform.cpp
+++ lldb/source/Target/Platform.cpp
@@ -1327,10 +1327,10 @@
// process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
- const Timeout<std::micro> &timeout) {
+ const Timeout<std::micro> &timeout, const bool run_in_default_shell) {
if (IsHost())
return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
- command_output, timeout);
+ command_output, timeout, run_in_default_shell);
else
return Status("unimplemented");
}
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -407,7 +407,8 @@
// the process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
- const Timeout<std::micro> &timeout);
+ const Timeout<std::micro> &timeout,
+ const bool run_in_default_shell = true);
bool CalculateMD5(const FileSpec &file_spec, uint64_t &high, uint64_t &low);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2825,7 +2825,7 @@
// process to exit
std::string
*command_output, // Pass NULL if you don't want the command output
- const Timeout<std::micro> &timeout) {
+ const Timeout<std::micro> &timeout, const bool run_in_default_shell) {
lldb_private::StreamString stream;
stream.PutCString("qPlatform_shell:");
stream.PutBytesAsRawHex8(command, strlen(command));
Index: lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
===================================================================
--- lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -148,7 +148,8 @@
// process to exit
std::string
*command_output, // Pass NULL if you don't want the command output
- const lldb_private::Timeout<std::micro> &timeout) override;
+ const lldb_private::Timeout<std::micro> &timeout,
+ const bool run_in_default_shell = true) override;
void CalculateTrapHandlerSymbolNames() override;
Index: lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
===================================================================
--- lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -719,9 +719,10 @@
// process to exit
std::string
*command_output, // Pass NULL if you don't want the command output
- const Timeout<std::micro> &timeout) {
+ const Timeout<std::micro> &timeout, const bool run_in_default_shell) {
return m_gdb_client.RunShellCommand(command, working_dir, status_ptr,
- signo_ptr, command_output, timeout);
+ signo_ptr, command_output, timeout,
+ run_in_default_shell);
}
void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -631,6 +631,8 @@
Desc<"Run the commands on the host shell when enabled.">;
def platform_shell_timeout : Option<"timeout", "t">, Arg<"Value">,
Desc<"Seconds to wait for the remote host to finish running the command.">;
+ def platform_shell_interpreter : Option<"interpreter", "i">, Arg<"Path">,
+ Desc<"Shell interpreter path. This is the binary used to run the command.">;
}
let Command = "process attach" in {
Index: lldb/source/Commands/CommandObjectPlatform.cpp
===================================================================
--- lldb/source/Commands/CommandObjectPlatform.cpp
+++ lldb/source/Commands/CommandObjectPlatform.cpp
@@ -1611,6 +1611,29 @@
else
m_timeout = std::chrono::seconds(timeout_sec);
break;
+ case 'i': {
+ if (option_arg.empty()) {
+ error.SetErrorStringWithFormat(
+ "missing shell interpreter path for option -i|--interpreter.");
+ return error;
+ }
+
+ if (!FileSystem::Instance().Exists(option_arg)) {
+ error.SetErrorStringWithFormat("File \"%s\" doesn't exist.",
+ option_arg.str().c_str());
+ return error;
+ }
+
+ if (!FileSystem::Instance().Readable(option_arg)) {
+ error.SetErrorStringWithFormat("File \"%s\" is not readable.",
+ option_arg.str().c_str());
+ return error;
+ }
+
+ m_shell_interpreter.SetFile(option_arg, FileSpec::Style::native);
+
+ break;
+ }
default:
llvm_unreachable("Unimplemented option");
}
@@ -1621,10 +1644,12 @@
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_timeout.reset();
m_use_host_platform = false;
+ m_shell_interpreter.Clear();
}
Timeout<std::micro> m_timeout = std::chrono::seconds(10);
bool m_use_host_platform;
+ FileSpec m_shell_interpreter;
};
CommandObjectPlatformShell(CommandInterpreter &interpreter)
@@ -1650,7 +1675,6 @@
const bool is_alias = !raw_command_line.contains("platform");
OptionsWithRaw args(raw_command_line);
- const char *expr = args.GetRawPart().c_str();
if (args.HasArgs())
if (!ParseOptions(args.GetArgs(), result))
@@ -1662,6 +1686,14 @@
return false;
}
+ std::string expr;
+ bool use_default_shell = true;
+ if (m_options.m_shell_interpreter) {
+ expr += m_options.m_shell_interpreter.GetPath() + " -c ";
+ use_default_shell = false;
+ }
+ expr += args.GetRawPart();
+
PlatformSP platform_sp(
m_options.m_use_host_platform
? Platform::GetHostPlatform()
@@ -1672,8 +1704,9 @@
std::string output;
int status = -1;
int signo = -1;
- error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo,
- &output, m_options.m_timeout));
+ error = (platform_sp->RunShellCommand(
+ expr.c_str(), working_dir, &status, &signo, &output,
+ m_options.m_timeout, use_default_shell));
if (!output.empty())
result.GetOutputStream().PutCString(output);
if (status > 0) {
Index: lldb/source/API/SBPlatform.cpp
===================================================================
--- lldb/source/API/SBPlatform.cpp
+++ lldb/source/API/SBPlatform.cpp
@@ -50,8 +50,31 @@
// PlatformShellCommand
struct PlatformShellCommand {
+ PlatformShellCommand(const char *command_interpreter,
+ const char *shell_command)
+ : m_command(), m_working_dir(), m_status(0), m_signo(0),
+ m_run_in_default_shell(false) {
+ std::string full_command;
+
+ if (command_interpreter && command_interpreter[0]) {
+ full_command += command_interpreter;
+ full_command += " -c ";
+ }
+
+ if (shell_command && shell_command[0]) {
+ full_command += " \"";
+ full_command += shell_command;
+ full_command += "\"";
+ }
+
+ if (!full_command.empty()) {
+ m_command = full_command.c_str();
+ }
+ }
+
PlatformShellCommand(const char *shell_command = nullptr)
- : m_command(), m_working_dir(), m_status(0), m_signo(0) {
+ : m_command(), m_working_dir(), m_status(0), m_signo(0),
+ m_run_in_default_shell(true) {
if (shell_command && shell_command[0])
m_command = shell_command;
}
@@ -64,6 +87,7 @@
int m_status;
int m_signo;
Timeout<std::ratio<1>> m_timeout = llvm::None;
+ bool m_run_in_default_shell;
};
// SBPlatformConnectOptions
SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
@@ -163,6 +187,13 @@
}
// SBPlatformShellCommand
+SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter,
+ const char *shell_command)
+ : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) {
+ LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand, (const char *, const char *),
+ shell_interpreter, shell_command);
+}
+
SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
: m_opaque_ptr(new PlatformShellCommand(shell_command)) {
LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand, (const char *),
@@ -557,11 +588,12 @@
if (working_dir)
shell_command.SetWorkingDirectory(working_dir);
}
- return platform_sp->RunShellCommand(command, FileSpec(working_dir),
- &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_timeout);
+ return platform_sp->RunShellCommand(
+ command, FileSpec(working_dir), &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_timeout,
+ shell_command.m_opaque_ptr->m_run_in_default_shell);
}));
}
Index: lldb/include/lldb/Target/RemoteAwarePlatform.h
===================================================================
--- lldb/include/lldb/Target/RemoteAwarePlatform.h
+++ lldb/include/lldb/Target/RemoteAwarePlatform.h
@@ -71,7 +71,8 @@
Status RunShellCommand(const char *command, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr,
std::string *command_output,
- const Timeout<std::micro> &timeout) override;
+ const Timeout<std::micro> &timeout,
+ const bool run_in_default_shell = true) override;
const char *GetHostname() override;
UserIDResolver &GetUserIDResolver() override;
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ lldb/include/lldb/Target/Platform.h
@@ -629,7 +629,8 @@
// the process to exit
std::string
*command_output, // Pass nullptr if you don't want the command output
- const Timeout<std::micro> &timeout);
+ const Timeout<std::micro> &timeout,
+ const bool run_in_default_shell = true);
virtual void SetLocalCacheDirectory(const char *local);
Index: lldb/include/lldb/API/SBPlatform.h
===================================================================
--- lldb/include/lldb/API/SBPlatform.h
+++ lldb/include/lldb/API/SBPlatform.h
@@ -51,6 +51,8 @@
class LLDB_API SBPlatformShellCommand {
public:
+ SBPlatformShellCommand(const char *shell_interpreter,
+ const char *shell_command);
SBPlatformShellCommand(const char *shell_command);
SBPlatformShellCommand(const SBPlatformShellCommand &rhs);
Index: lldb/bindings/interface/SBPlatform.i
===================================================================
--- lldb/bindings/interface/SBPlatform.i
+++ lldb/bindings/interface/SBPlatform.i
@@ -45,6 +45,7 @@
class SBPlatformShellCommand
{
public:
+ SBPlatformShellCommand (const char *shell_interpreter, const char *shell_command);
SBPlatformShellCommand (const char *shell_command);
SBPlatformShellCommand (const SBPlatformShellCommand &rhs);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits