diff options
-rw-r--r-- | lldb/include/lldb/API/SBCommandInterpreter.h | 19 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/CommandInterpreter.h | 30 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCode-30.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCode0.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCode30.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCodeHex0.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCodeHexA.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCodeImplicit0.test | 3 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCodeNonInt.test | 4 | ||||
-rw-r--r-- | lldb/lit/Quit/TestQuitExitCodeTooManyArgs.test | 4 | ||||
-rwxr-xr-x | lldb/lit/Quit/expect_exit_code.py | 16 | ||||
-rw-r--r-- | lldb/lit/Quit/lit.local.cfg | 1 | ||||
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/quit/TestQuit.py | 32 | ||||
-rw-r--r-- | lldb/scripts/interface/SBCommandInterpreter.i | 9 | ||||
-rw-r--r-- | lldb/source/API/SBCommandInterpreter.cpp | 17 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectQuit.cpp | 38 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 20 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.cpp | 14 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.h | 5 |
19 files changed, 222 insertions, 5 deletions
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h index 928e40bad28..8b9f0659936 100644 --- a/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/lldb/include/lldb/API/SBCommandInterpreter.h @@ -208,6 +208,25 @@ public: void SetPromptOnQuit(bool b); //---------------------------------------------------------------------- + /// Sets whether the command interpreter should allow custom exit codes + /// for the 'quit' command. + //---------------------------------------------------------------------- + void AllowExitCodeOnQuit(bool allow); + + //---------------------------------------------------------------------- + /// Returns true if the user has called the 'quit' command with a custom exit + /// code. + //---------------------------------------------------------------------- + bool HasCustomQuitExitCode(); + + //---------------------------------------------------------------------- + /// Returns the exit code that the user has specified when running the + /// 'quit' command. Returns 0 if the user hasn't called 'quit' at all or + /// without a custom exit code. + //---------------------------------------------------------------------- + int GetQuitStatus(); + + //---------------------------------------------------------------------- /// Resolve the command just as HandleCommand would, expanding abbreviations /// and aliases. If successful, result->GetOutput has the full expansion. //---------------------------------------------------------------------- diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 60e67f2271f..0a556cc6b3f 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -455,6 +455,30 @@ public: void SetPromptOnQuit(bool b); + //------------------------------------------------------------------ + /// Specify if the command interpreter should allow that the user can + /// specify a custom exit code when calling 'quit'. + //------------------------------------------------------------------ + void AllowExitCodeOnQuit(bool allow); + + //------------------------------------------------------------------ + /// Sets the exit code for the quit command. + /// @param[in] exit_code + /// The exit code that the driver should return on exit. + /// @return True if the exit code was successfully set; false if the + /// interpreter doesn't allow custom exit codes. + /// @see AllowExitCodeOnQuit + //------------------------------------------------------------------ + LLVM_NODISCARD bool SetQuitExitCode(int exit_code); + + //------------------------------------------------------------------ + /// Returns the exit code that the user has specified when running the + /// 'quit' command. + /// @param[out] exited + /// Set to true if the user has called quit with a custom exit code. + //------------------------------------------------------------------ + int GetQuitExitCode(bool &exited) const; + void ResolveCommand(const char *command_line, CommandReturnObject &result); bool GetStopCmdSourceOnError() const; @@ -558,6 +582,12 @@ private: uint32_t m_num_errors; bool m_quit_requested; bool m_stopped_for_crash; + + // The exit code the user has requested when calling the 'quit' command. + // No value means the user hasn't set a custom exit code so far. + llvm::Optional<int> m_quit_exit_code; + // If the driver is accepts custom exit codes for the 'quit' command. + bool m_allow_exit_code = false; }; } // namespace lldb_private diff --git a/lldb/lit/Quit/TestQuitExitCode-30.test b/lldb/lit/Quit/TestQuitExitCode-30.test new file mode 100644 index 00000000000..0f6eff927f0 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCode-30.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: python %S/expect_exit_code.py 226 %lldb -b -s %s +q -30 diff --git a/lldb/lit/Quit/TestQuitExitCode0.test b/lldb/lit/Quit/TestQuitExitCode0.test new file mode 100644 index 00000000000..c15cb5e9ea7 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCode0.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: %lldb -b -s %s +q 0 diff --git a/lldb/lit/Quit/TestQuitExitCode30.test b/lldb/lit/Quit/TestQuitExitCode30.test new file mode 100644 index 00000000000..b5249400ec2 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCode30.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: python %S/expect_exit_code.py 30 %lldb -b -s %s +q 30 diff --git a/lldb/lit/Quit/TestQuitExitCodeHex0.test b/lldb/lit/Quit/TestQuitExitCodeHex0.test new file mode 100644 index 00000000000..3e1fc5dbeeb --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCodeHex0.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: %lldb -b -s %s +q 0x0 diff --git a/lldb/lit/Quit/TestQuitExitCodeHexA.test b/lldb/lit/Quit/TestQuitExitCodeHexA.test new file mode 100644 index 00000000000..e06c25b0619 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCodeHexA.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: python %S/expect_exit_code.py 10 %lldb -b -s %s +q 0xA diff --git a/lldb/lit/Quit/TestQuitExitCodeImplicit0.test b/lldb/lit/Quit/TestQuitExitCodeImplicit0.test new file mode 100644 index 00000000000..1a95e8dc0bf --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCodeImplicit0.test @@ -0,0 +1,3 @@ +# UNSUPPORTED: windows +# RUN: %lldb -b -s %s +q diff --git a/lldb/lit/Quit/TestQuitExitCodeNonInt.test b/lldb/lit/Quit/TestQuitExitCodeNonInt.test new file mode 100644 index 00000000000..2b54163d648 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCodeNonInt.test @@ -0,0 +1,4 @@ +# UNSUPPORTED: windows +# RUN: %lldb -b -s %s 2>&1 | FileCheck %s +q str +// CHECK: Couldn't parse 'str' diff --git a/lldb/lit/Quit/TestQuitExitCodeTooManyArgs.test b/lldb/lit/Quit/TestQuitExitCodeTooManyArgs.test new file mode 100644 index 00000000000..05be357fd57 --- /dev/null +++ b/lldb/lit/Quit/TestQuitExitCodeTooManyArgs.test @@ -0,0 +1,4 @@ +# UNSUPPORTED: windows +# RUN: %lldb -b -s %s 2>&1 | FileCheck %s +q 1 2 +// CHECK: Too many arguments for 'quit' diff --git a/lldb/lit/Quit/expect_exit_code.py b/lldb/lit/Quit/expect_exit_code.py new file mode 100755 index 00000000000..f4a7590b7d5 --- /dev/null +++ b/lldb/lit/Quit/expect_exit_code.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python2 + +import subprocess +import sys + +args = sys.argv + +expected_exit_code = args[1] + +args = args[2:] +print("Running " + (" ".join(args))) +real_exit_code = subprocess.call(args) + +if str(real_exit_code) != expected_exit_code: + print("Got exit code %d but expected %s" % (real_exit_code, expected_exit_code)) + exit(1) diff --git a/lldb/lit/Quit/lit.local.cfg b/lldb/lit/Quit/lit.local.cfg new file mode 100644 index 00000000000..df9b335dd13 --- /dev/null +++ b/lldb/lit/Quit/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.test'] diff --git a/lldb/packages/Python/lldbsuite/test/quit/TestQuit.py b/lldb/packages/Python/lldbsuite/test/quit/TestQuit.py new file mode 100644 index 00000000000..28c05b833d6 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/quit/TestQuit.py @@ -0,0 +1,32 @@ +""" +Test lldb's quit command. +""" + +from __future__ import print_function + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class QuitCommandTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + def test_quit_exit_code_disallow(self): + self.ci.AllowExitCodeOnQuit(False) + self.expect( + "quit 20", + substrs=[ + "error: The current driver doesn't allow custom exit codes for the quit command"], + error=True) + self.assertFalse(self.ci.HasCustomQuitExitCode()) + + @no_debug_info_test + def test_quit_exit_code_allow(self): + self.ci.AllowExitCodeOnQuit(True) + self.runCmd("quit 10", check=False) + self.assertTrue(self.ci.HasCustomQuitExitCode()) + self.assertEqual(self.ci.GetQuitStatus(), 10) diff --git a/lldb/scripts/interface/SBCommandInterpreter.i b/lldb/scripts/interface/SBCommandInterpreter.i index 255e8ba4496..09e7c9df736 100644 --- a/lldb/scripts/interface/SBCommandInterpreter.i +++ b/lldb/scripts/interface/SBCommandInterpreter.i @@ -156,6 +156,15 @@ public: SetPromptOnQuit(bool b); void + AllowExitCodeOnQuit(bool b); + + bool + HasCustomQuitExitCode(); + + int + GetQuitStatus(); + + void ResolveCommand(const char *command_line, SBCommandReturnObject &result); bool diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index 1f4f6b886a1..cbb514abb6f 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -379,6 +379,23 @@ void SBCommandInterpreter::SetPromptOnQuit(bool b) { m_opaque_ptr->SetPromptOnQuit(b); } +void SBCommandInterpreter::AllowExitCodeOnQuit(bool allow) { + if (m_opaque_ptr) + m_opaque_ptr->AllowExitCodeOnQuit(allow); +} + +bool SBCommandInterpreter::HasCustomQuitExitCode() { + bool exited = false; + if (m_opaque_ptr) + m_opaque_ptr->GetQuitExitCode(exited); + return exited; +} + +int SBCommandInterpreter::GetQuitStatus() { + bool exited = false; + return (m_opaque_ptr ? m_opaque_ptr->GetQuitExitCode(exited) : 0); +} + void SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result) { result.Clear(); diff --git a/lldb/source/Commands/CommandObjectQuit.cpp b/lldb/source/Commands/CommandObjectQuit.cpp index 071deba6c5a..37ed12be358 100644 --- a/lldb/source/Commands/CommandObjectQuit.cpp +++ b/lldb/source/Commands/CommandObjectQuit.cpp @@ -16,6 +16,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/StreamString.h" using namespace lldb; using namespace lldb_private; @@ -26,7 +27,7 @@ using namespace lldb_private; CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.", - "quit") {} + "quit [exit-code]") {} CommandObjectQuit::~CommandObjectQuit() {} @@ -77,6 +78,41 @@ bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { return false; } } + + if (command.GetArgumentCount() > 1) { + result.AppendError("Too many arguments for 'quit'. Only an optional exit " + "code is allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() > 1) { + result.AppendError("Too many arguments for 'quit'. Only an optional exit " + "code is allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // We parse the exit code argument if there is one. + if (command.GetArgumentCount() == 1) { + llvm::StringRef arg = command.GetArgumentAtIndex(0); + int exit_code; + if (arg.getAsInteger(/*autodetect radix*/ 0, exit_code)) { + lldb_private::StreamString s; + std::string arg_str = arg.str(); + s.Printf("Couldn't parse '%s' as integer for exit code.", arg_str.data()); + result.AppendError(s.GetString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + if (!m_interpreter.SetQuitExitCode(exit_code)) { + result.AppendError("The current driver doesn't allow custom exit codes" + " for the quit command."); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + const uint32_t event_type = CommandInterpreter::eBroadcastBitQuitCommandReceived; m_interpreter.BroadcastEvent(event_type); diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index d2014afa869..d6d271acc35 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -144,6 +144,26 @@ void CommandInterpreter::SetPromptOnQuit(bool b) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } +void CommandInterpreter::AllowExitCodeOnQuit(bool allow) { + m_allow_exit_code = allow; + if (!allow) + m_quit_exit_code.reset(); +} + +bool CommandInterpreter::SetQuitExitCode(int exit_code) { + if (!m_allow_exit_code) + return false; + m_quit_exit_code = exit_code; + return true; +} + +int CommandInterpreter::GetQuitExitCode(bool &exited) const { + exited = m_quit_exit_code.hasValue(); + if (exited) + return *m_quit_exit_code; + return 0; +} + void CommandInterpreter::ResolveCommand(const char *command_line, CommandReturnObject &result) { std::string command = command_line; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 58296b2eee8..e28093482f3 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -962,7 +962,7 @@ std::string EscapeString(std::string arg) { return '"' + arg + '"'; } -void Driver::MainLoop() { +int Driver::MainLoop() { if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; atexit(reset_stdin_termios); @@ -1001,6 +1001,10 @@ void Driver::MainLoop() { result.PutOutput(m_debugger.GetOutputFileHandle()); } + // We allow the user to specify an exit code when calling quit which we will + // return when exiting. + m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true); + // Now we handle options we got from the command line SBStream commands_stream; @@ -1159,7 +1163,9 @@ void Driver::MainLoop() { reset_stdin_termios(); fclose(stdin); + int exit_code = sb_interpreter.GetQuitStatus(); SBDebugger::Destroy(m_debugger); + return exit_code; } void Driver::ResizeWindow(unsigned short col) { @@ -1237,6 +1243,7 @@ main(int argc, char const *argv[]) signal(SIGCONT, sigcont_handler); #endif + int exit_code = 0; // Create a scope for driver so that the driver object will destroy itself // before SBDebugger::Terminate() is called. { @@ -1245,14 +1252,15 @@ main(int argc, char const *argv[]) bool exiting = false; SBError error(driver.ParseArgs(argc, argv, stdout, exiting)); if (error.Fail()) { + exit_code = 1; const char *error_cstr = error.GetCString(); if (error_cstr) ::fprintf(stderr, "error: %s\n", error_cstr); } else if (!exiting) { - driver.MainLoop(); + exit_code = driver.MainLoop(); } } SBDebugger::Terminate(); - return 0; + return exit_code; } diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h index 2be697ccc44..34746a23999 100644 --- a/lldb/tools/driver/Driver.h +++ b/lldb/tools/driver/Driver.h @@ -37,7 +37,10 @@ public: virtual ~Driver(); - void MainLoop(); + /// Runs the main loop. + /// + /// @return The exit code that the process should return. + int MainLoop(); lldb::SBError ParseArgs(int argc, const char *argv[], FILE *out_fh, bool &do_exit); |