This revision was not accepted when it landed; it landed in state "Needs
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL336824: Allow specifying an exit code for the
'quit' command (authored by teemperor, committed by ).
Herald added a subscriber: llvm-commits.
Changed prior to commit:
https://reviews.llvm.org/D48659?vs=154318&id=155030#toc
Repository:
rL LLVM
https://reviews.llvm.org/D48659
Files:
lldb/trunk/include/lldb/API/SBCommandInterpreter.h
lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
lldb/trunk/lit/Quit/TestQuitExitCode-30.test
lldb/trunk/lit/Quit/TestQuitExitCode0.test
lldb/trunk/lit/Quit/TestQuitExitCode30.test
lldb/trunk/lit/Quit/TestQuitExitCodeHex0.test
lldb/trunk/lit/Quit/TestQuitExitCodeHexA.test
lldb/trunk/lit/Quit/TestQuitExitCodeImplicit0.test
lldb/trunk/lit/Quit/TestQuitExitCodeNonInt.test
lldb/trunk/lit/Quit/TestQuitExitCodeTooManyArgs.test
lldb/trunk/lit/Quit/expect_exit_code.py
lldb/trunk/lit/Quit/lit.local.cfg
lldb/trunk/packages/Python/lldbsuite/test/quit/TestQuit.py
lldb/trunk/scripts/interface/SBCommandInterpreter.i
lldb/trunk/source/API/SBCommandInterpreter.cpp
lldb/trunk/source/Commands/CommandObjectQuit.cpp
lldb/trunk/source/Interpreter/CommandInterpreter.cpp
lldb/trunk/tools/driver/Driver.cpp
lldb/trunk/tools/driver/Driver.h
Index: lldb/trunk/source/API/SBCommandInterpreter.cpp
===================================================================
--- lldb/trunk/source/API/SBCommandInterpreter.cpp
+++ lldb/trunk/source/API/SBCommandInterpreter.cpp
@@ -379,6 +379,23 @@
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();
Index: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
===================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp
@@ -144,6 +144,26 @@
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;
Index: lldb/trunk/source/Commands/CommandObjectQuit.cpp
===================================================================
--- lldb/trunk/source/Commands/CommandObjectQuit.cpp
+++ lldb/trunk/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 @@
CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.",
- "quit") {}
+ "quit [exit-code]") {}
CommandObjectQuit::~CommandObjectQuit() {}
@@ -77,6 +78,41 @@
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);
Index: lldb/trunk/tools/driver/Driver.cpp
===================================================================
--- lldb/trunk/tools/driver/Driver.cpp
+++ lldb/trunk/tools/driver/Driver.cpp
@@ -962,7 +962,7 @@
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 @@
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 @@
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,22 +1243,24 @@
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.
{
Driver driver;
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;
}
Index: lldb/trunk/tools/driver/Driver.h
===================================================================
--- lldb/trunk/tools/driver/Driver.h
+++ lldb/trunk/tools/driver/Driver.h
@@ -37,7 +37,10 @@
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);
Index: lldb/trunk/lit/Quit/expect_exit_code.py
===================================================================
--- lldb/trunk/lit/Quit/expect_exit_code.py
+++ lldb/trunk/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)
Index: lldb/trunk/lit/Quit/TestQuitExitCodeImplicit0.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCodeImplicit0.test
+++ lldb/trunk/lit/Quit/TestQuitExitCodeImplicit0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q
Index: lldb/trunk/lit/Quit/lit.local.cfg
===================================================================
--- lldb/trunk/lit/Quit/lit.local.cfg
+++ lldb/trunk/lit/Quit/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.test']
Index: lldb/trunk/lit/Quit/TestQuitExitCodeNonInt.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCodeNonInt.test
+++ lldb/trunk/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'
Index: lldb/trunk/lit/Quit/TestQuitExitCodeHexA.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCodeHexA.test
+++ lldb/trunk/lit/Quit/TestQuitExitCodeHexA.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: python %S/expect_exit_code.py 10 %lldb -b -s %s
+q 0xA
Index: lldb/trunk/lit/Quit/TestQuitExitCodeHex0.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCodeHex0.test
+++ lldb/trunk/lit/Quit/TestQuitExitCodeHex0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q 0x0
Index: lldb/trunk/lit/Quit/TestQuitExitCodeTooManyArgs.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCodeTooManyArgs.test
+++ lldb/trunk/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'
Index: lldb/trunk/lit/Quit/TestQuitExitCode30.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCode30.test
+++ lldb/trunk/lit/Quit/TestQuitExitCode30.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: python %S/expect_exit_code.py 30 %lldb -b -s %s
+q 30
Index: lldb/trunk/lit/Quit/TestQuitExitCode0.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCode0.test
+++ lldb/trunk/lit/Quit/TestQuitExitCode0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q 0
Index: lldb/trunk/lit/Quit/TestQuitExitCode-30.test
===================================================================
--- lldb/trunk/lit/Quit/TestQuitExitCode-30.test
+++ lldb/trunk/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
Index: lldb/trunk/scripts/interface/SBCommandInterpreter.i
===================================================================
--- lldb/trunk/scripts/interface/SBCommandInterpreter.i
+++ lldb/trunk/scripts/interface/SBCommandInterpreter.i
@@ -156,6 +156,15 @@
SetPromptOnQuit(bool b);
void
+ AllowExitCodeOnQuit(bool b);
+
+ bool
+ HasCustomQuitExitCode();
+
+ int
+ GetQuitStatus();
+
+ void
ResolveCommand(const char *command_line, SBCommandReturnObject &result);
bool
Index: lldb/trunk/include/lldb/API/SBCommandInterpreter.h
===================================================================
--- lldb/trunk/include/lldb/API/SBCommandInterpreter.h
+++ lldb/trunk/include/lldb/API/SBCommandInterpreter.h
@@ -208,6 +208,25 @@
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.
//----------------------------------------------------------------------
Index: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
===================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
@@ -455,6 +455,30 @@
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 @@
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
Index: lldb/trunk/packages/Python/lldbsuite/test/quit/TestQuit.py
===================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/quit/TestQuit.py
+++ lldb/trunk/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)
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits