mib updated this revision to Diff 262999. mib added a comment. With the first implementation, I thought it'd be a good idea to have separate Command Objects for `platform shell` and `shell` because I was imagining the latter could be more "powerful": `shell` could have an interactive mode like the `script` command, which might not be as relevant for `platform shell` when debugging a remote target.
That was my original idea, but I agree we should avoid code duplication, so here is a different implementation following @jingham's suggestions. `shell` is an alias to `platform shell -h --` in this case. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D79659/new/ https://reviews.llvm.org/D79659 Files: lldb/source/Commands/CommandObjectPlatform.cpp lldb/source/Commands/Options.td lldb/source/Interpreter/CommandInterpreter.cpp lldb/test/API/commands/shell/TestShellCommand.py
Index: lldb/test/API/commands/shell/TestShellCommand.py =================================================================== --- /dev/null +++ lldb/test/API/commands/shell/TestShellCommand.py @@ -0,0 +1,45 @@ +""" +Test the lldb host shell command. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ShellCommandTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + def test_help_platform(self): + self.expect("help shell", substrs=["shell <shell-command>", + "Run a shell command on the host."]) + + @expectedFailureAll(oslist=["windows"]) + @no_debug_info_test + def test_shell(self): + """ Test that the shell command can invoke ls. """ + triple = self.dbg.GetSelectedPlatform().GetTriple() + if re.match(".*-.*-windows", triple): + self.expect("shell dir c:\\", substrs=["Windows", "Program Files"]) + elif re.match(".*-.*-.*-android", triple): + self.expect("shell ls /", + substrs=["cache", "dev", "system"]) + else: + 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("shell echo hello lldb", + substrs=["hello lldb"]) + + @no_debug_info_test + def test_shell_timeout(self): + """ Test a shell built-in command (sleep) that times out """ + self.expect("shell -t 1 -- sleep 3", error=True, substrs=[ + "error: timed out waiting for shell command to complete"]) Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -381,6 +381,16 @@ } } + 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); Index: lldb/source/Commands/Options.td =================================================================== --- lldb/source/Commands/Options.td +++ lldb/source/Commands/Options.td @@ -622,6 +622,8 @@ } 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.">; } @@ -701,6 +703,7 @@ 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.">; Index: lldb/source/Commands/CommandObjectPlatform.cpp =================================================================== --- lldb/source/Commands/CommandObjectPlatform.cpp +++ lldb/source/Commands/CommandObjectPlatform.cpp @@ -1567,6 +1567,9 @@ 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 @@ "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,12 @@ return error; } - void OptionParsingStarting(ExecutionContext *execution_context) override {} + void OptionParsingStarting(ExecutionContext *execution_context) override { + 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) @@ -1616,8 +1622,14 @@ if (!ParseOptions(args.GetArgs(), result)) return false; + // When called from the `shell` alias with no argument, exit. + if (args.GetRawPart().empty()) + 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 +1637,7 @@ 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) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits