teemperor created this revision.
teemperor added a reviewer: davide.

This patch adds the possibility to specify an exit code when calling quit.
We accept any int, even though it depends on the user what happens if the int is
out of the range of what the operating system supports as exit codes.

Fixes rdar://problem/38452312


https://reviews.llvm.org/D48659

Files:
  include/lldb/API/SBDebugger.h
  include/lldb/Core/Debugger.h
  lit/Quit/TestQuitExitCode-30.test
  lit/Quit/TestQuitExitCode0.test
  lit/Quit/TestQuitExitCode30.test
  lit/Quit/TestQuitExitCodeHex0.test
  lit/Quit/TestQuitExitCodeHexA.test
  lit/Quit/TestQuitExitCodeImplicit0.test
  lit/Quit/TestQuitExitCodeNonInt.test
  lit/Quit/TestQuitExitCodeTooManyArgs.test
  lit/Quit/expect_exit_code.py
  lit/Quit/lit.local.cfg
  source/API/SBDebugger.cpp
  source/Commands/CommandObjectQuit.cpp
  tools/driver/Driver.cpp
  tools/driver/Driver.h

Index: tools/driver/Driver.h
===================================================================
--- tools/driver/Driver.h
+++ 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: tools/driver/Driver.cpp
===================================================================
--- tools/driver/Driver.cpp
+++ 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);
@@ -1159,7 +1159,9 @@
   reset_stdin_termios();
   fclose(stdin);
 
+  int exit_code = m_debugger.GetExitCode();
   SBDebugger::Destroy(m_debugger);
+  return exit_code;
 }
 
 void Driver::ResizeWindow(unsigned short col) {
@@ -1237,22 +1239,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: source/Commands/CommandObjectQuit.cpp
===================================================================
--- source/Commands/CommandObjectQuit.cpp
+++ 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,29 @@
       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;
+    }
+    m_interpreter.GetDebugger().SetExitCode(exit_code);
+  }
+
   const uint32_t event_type =
       CommandInterpreter::eBroadcastBitQuitCommandReceived;
   m_interpreter.BroadcastEvent(event_type);
Index: source/API/SBDebugger.cpp
===================================================================
--- source/API/SBDebugger.cpp
+++ source/API/SBDebugger.cpp
@@ -1081,6 +1081,10 @@
   return (m_opaque_sp ? m_opaque_sp->GetID() : LLDB_INVALID_UID);
 }
 
+int SBDebugger::GetExitCode() {
+  return (m_opaque_sp ? m_opaque_sp->GetExitCode() : 0);
+}
+
 SBError SBDebugger::SetCurrentPlatform(const char *platform_name_cstr) {
   SBError sb_error;
   if (m_opaque_sp) {
Index: lit/Quit/lit.local.cfg
===================================================================
--- /dev/null
+++ lit/Quit/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.test']
Index: lit/Quit/expect_exit_code.py
===================================================================
--- /dev/null
+++ 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: lit/Quit/TestQuitExitCodeTooManyArgs.test
===================================================================
--- /dev/null
+++ 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: lit/Quit/TestQuitExitCodeNonInt.test
===================================================================
--- /dev/null
+++ 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: lit/Quit/TestQuitExitCodeImplicit0.test
===================================================================
--- /dev/null
+++ lit/Quit/TestQuitExitCodeImplicit0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q
Index: lit/Quit/TestQuitExitCodeHexA.test
===================================================================
--- /dev/null
+++ 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: lit/Quit/TestQuitExitCodeHex0.test
===================================================================
--- /dev/null
+++ lit/Quit/TestQuitExitCodeHex0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q 0x0
Index: lit/Quit/TestQuitExitCode30.test
===================================================================
--- /dev/null
+++ 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: lit/Quit/TestQuitExitCode0.test
===================================================================
--- /dev/null
+++ lit/Quit/TestQuitExitCode0.test
@@ -0,0 +1,3 @@
+# UNSUPPORTED: windows
+# RUN: %lldb -b -s %s
+q 0
Index: lit/Quit/TestQuitExitCode-30.test
===================================================================
--- /dev/null
+++ 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: include/lldb/Core/Debugger.h
===================================================================
--- include/lldb/Core/Debugger.h
+++ include/lldb/Core/Debugger.h
@@ -328,6 +328,10 @@
     return m_broadcaster_manager_sp;
   }
 
+  void SetExitCode(int i) { m_exit_code = i; }
+
+  int GetExitCode() const { return m_exit_code; }
+
 protected:
   friend class CommandInterpreter;
   friend class REPL;
@@ -404,6 +408,8 @@
   Broadcaster m_sync_broadcaster;
   lldb::ListenerSP m_forward_listener_sp;
   llvm::once_flag m_clear_once;
+  // The exit code the user has requested for the current debugger process.
+  int m_exit_code = 0;
 
   //----------------------------------------------------------------------
   // Events for m_sync_broadcaster
Index: include/lldb/API/SBDebugger.h
===================================================================
--- include/lldb/API/SBDebugger.h
+++ include/lldb/API/SBDebugger.h
@@ -222,6 +222,9 @@
 
   lldb::user_id_t GetID();
 
+  /// Returns the exit code that the user has set from the prompt.
+  int GetExitCode();
+
   const char *GetPrompt() const;
 
   void SetPrompt(const char *prompt);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to