Author: Med Ismail Bennani Date: 2020-05-15T22:14:39+02:00 New Revision: 4e9e0488ab67c54be57e303ce3085466fbc8e886
URL: https://github.com/llvm/llvm-project/commit/4e9e0488ab67c54be57e303ce3085466fbc8e886 DIFF: https://github.com/llvm/llvm-project/commit/4e9e0488ab67c54be57e303ce3085466fbc8e886.diff LOG: [lldb/Commands] Add ability to run shell command on the host. This patch introduces the `(-h|--host)` option to the `platform shell` command. It allows the user to run shell commands from the host platform (always available) without putting lldb in the background. Since the default behaviour of `platform shell` is to run the command of the selected platform, having such a choice can be quite handy when debugging remote targets, for instances. This patch also introduces a `shell` alias, to improve the command discoverability and make it more convenient to use for the user. rdar://62856024 Differential Revision: https://reviews.llvm.org/D79659 Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com> Added: Modified: lldb/source/Commands/CommandObjectPlatform.cpp lldb/source/Commands/Options.td lldb/source/Interpreter/CommandInterpreter.cpp lldb/test/API/commands/platform/basic/TestPlatformCommand.py Removed: ################################################################################ diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index 5a6573307c61..4b19592af75a 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -1567,6 +1567,9 @@ class CommandObjectPlatformShell : public CommandObjectRaw { const char short_option = (char)GetDefinitions()[option_idx].short_option; switch (short_option) { + case 'h': + m_use_host_platform = true; + break; case 't': uint32_t timeout_sec; if (option_arg.getAsInteger(10, timeout_sec)) @@ -1574,7 +1577,7 @@ class CommandObjectPlatformShell : public CommandObjectRaw { "could not convert \"%s\" to a numeric value.", option_arg.str().c_str()); else - timeout = std::chrono::seconds(timeout_sec); + m_timeout = std::chrono::seconds(timeout_sec); break; default: llvm_unreachable("Unimplemented option"); @@ -1583,9 +1586,13 @@ class CommandObjectPlatformShell : public CommandObjectRaw { return error; } - void OptionParsingStarting(ExecutionContext *execution_context) override {} + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_timeout.reset(); + m_use_host_platform = false; + } - Timeout<std::micro> timeout = std::chrono::seconds(10); + Timeout<std::micro> m_timeout = std::chrono::seconds(10); + bool m_use_host_platform; }; CommandObjectPlatformShell(CommandInterpreter &interpreter) @@ -1609,6 +1616,7 @@ class CommandObjectPlatformShell : public CommandObjectRaw { return true; } + const bool is_alias = !raw_command_line.contains("platform"); OptionsWithRaw args(raw_command_line); const char *expr = args.GetRawPart().c_str(); @@ -1616,8 +1624,16 @@ class CommandObjectPlatformShell : public CommandObjectRaw { if (!ParseOptions(args.GetArgs(), result)) return false; + if (args.GetRawPart().empty()) { + result.GetOutputStream().Printf("%s <shell-command>\n", + is_alias ? "shell" : "platform shell"); + return false; + } + PlatformSP platform_sp( - GetDebugger().GetPlatformList().GetSelectedPlatform()); + m_options.m_use_host_platform + ? Platform::GetHostPlatform() + : GetDebugger().GetPlatformList().GetSelectedPlatform()); Status error; if (platform_sp) { FileSpec working_dir{}; @@ -1625,7 +1641,7 @@ class CommandObjectPlatformShell : public CommandObjectRaw { int status = -1; int signo = -1; error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo, - &output, m_options.timeout)); + &output, m_options.m_timeout)); if (!output.empty()) result.GetOutputStream().PutCString(output); if (status > 0) { diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index addfec53b39c..d6f1e0a3c96d 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -624,6 +624,8 @@ let Command = "platform process attach" in { } let Command = "platform shell" in { + def platform_shell_host : Option<"host", "h">, + 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.">; } @@ -703,6 +705,7 @@ let Command = "script add" in { Desc<"Set the synchronicity of this command's executions with regard to " "LLDB event system.">; } + let Command = "source info" in { def source_info_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of line entries to display.">; diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 2cc3d47406b7..df19855b5f8c 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -381,6 +381,16 @@ void CommandInterpreter::Initialize() { } } + cmd_obj_sp = GetCommandSPExact("platform shell", false); + if (cmd_obj_sp) { + CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --"); + if (shell_alias) { + shell_alias->SetHelp("Run a shell command on the host."); + shell_alias->SetHelpLong(""); + shell_alias->SetSyntax("shell <shell-command>"); + } + } + cmd_obj_sp = GetCommandSPExact("process kill", false); if (cmd_obj_sp) { AddAlias("kill", cmd_obj_sp); diff --git a/lldb/test/API/commands/platform/basic/TestPlatformCommand.py b/lldb/test/API/commands/platform/basic/TestPlatformCommand.py index 9c16da8ad005..570f9b3f828d 100644 --- a/lldb/test/API/commands/platform/basic/TestPlatformCommand.py +++ b/lldb/test/API/commands/platform/basic/TestPlatformCommand.py @@ -18,6 +18,12 @@ class PlatformCommandTestCase(TestBase): def test_help_platform(self): self.runCmd("help platform") + @no_debug_info_test + def test_help_platform(self): + self.expect("help shell", substrs=["Run a shell command on the host.", + "shell <shell-command>"]) + + @no_debug_info_test def test_list(self): self.expect("platform list", @@ -55,6 +61,7 @@ def test_shell(self): self.expect( "platform shell dir c:\\", substrs=[ "Windows", "Program Files"]) + self.expect("shell dir c:\\", substrs=["Windows", "Program Files"]) elif re.match(".*-.*-.*-android", triple): self.expect( "platform shell ls /", @@ -62,19 +69,26 @@ def test_shell(self): "cache", "dev", "system"]) + self.expect("shell ls /", + substrs=["cache", "dev", "system"]) else: self.expect("platform shell ls /", substrs=["dev", "tmp", "usr"]) + self.expect("shell ls /", substrs=["dev", "tmp", "usr"]) @no_debug_info_test def test_shell_builtin(self): """ Test a shell built-in command (echo) """ self.expect("platform shell echo hello lldb", substrs=["hello lldb"]) + self.expect("shell echo hello lldb", + substrs=["hello lldb"]) + - # FIXME: re-enable once platform shell -t can specify the desired timeout @no_debug_info_test def test_shell_timeout(self): """ Test a shell built-in command (sleep) that times out """ - self.skipTest("due to taking too long to complete.") - self.expect("platform shell sleep 15", error=True, substrs=[ + self.skipTest("Alias with option not supported by the command interpreter.") + self.expect("platform shell -t 1 -- sleep 15", error=True, substrs=[ + "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"]) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits