Blame SOURCES/gdb-rhbz1491128-batch-mode-exit-status-1of2.patch

4c2ad1
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
4c2ad1
From: Gary Benson <gbenson@redhat.com>
4c2ad1
Date: Wed, 29 Aug 2018 16:11:50 +0100
4c2ad1
Subject: gdb-rhbz1491128-batch-mode-exit-status-1of2.patch
4c2ad1
4c2ad1
;; Fix for 'gdb in batch mode always exit with status 0' (Gary Benson)
4c2ad1
;; RHBZ #1491128
4c2ad1
4c2ad1
Indicate batch mode failures by exiting with nonzero status
4c2ad1
4c2ad1
This commit causes GDB in batch mode to exit with nonzero status
4c2ad1
if the last command to be executed fails.
4c2ad1
4c2ad1
gdb/ChangeLog:
4c2ad1
4c2ad1
	PR gdb/13000:
4c2ad1
	* gdb/main.c (captured_main_1): Exit with nonzero status
4c2ad1
	in batch mode if the last command to be executed failed.
4c2ad1
	* NEWS: Mention the above.
4c2ad1
4c2ad1
gdb/testsuite/ChangeLog:
4c2ad1
4c2ad1
	PR gdb/13000:
4c2ad1
	* gdb.base/batch-exit-status.exp: New file.
4c2ad1
	* gdb.base/batch-exit-status.good-commands: Likewise.
4c2ad1
	* gdb.base/batch-exit-status.bad-commands: Likewise.
4c2ad1
4c2ad1
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
4c2ad1
--- a/gdb/ChangeLog
4c2ad1
+++ b/gdb/ChangeLog
4c2ad1
@@ -1,3 +1,10 @@
4c2ad1
+2018-08-16  Gary Benson <gbenson@redhat.com>
4c2ad1
+
4c2ad1
+	PR gdb/13000:
4c2ad1
+	* gdb/main.c (captured_main_1): Exit with nonzero status
4c2ad1
+	in batch mode if the last command to be executed failed.
4c2ad1
+	* NEWS: Mention the above.
4c2ad1
+
4c2ad1
 2018-08-03  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
 
4c2ad1
 	* ser-tcp.c (net_open): Fix thinko when deciding whether to
4c2ad1
diff --git a/gdb/NEWS b/gdb/NEWS
4c2ad1
--- a/gdb/NEWS
4c2ad1
+++ b/gdb/NEWS
4c2ad1
@@ -7,6 +7,9 @@
4c2ad1
   can be passed using the '[ADDRESS]:PORT' notation, or the regular
4c2ad1
   'ADDRESS:PORT' method.
4c2ad1
 
4c2ad1
+* GDB in batch mode now exits with status 1 if the last command to be
4c2ad1
+  executed failed.
4c2ad1
+
4c2ad1
 *** Changes in GDB 8.2
4c2ad1
 
4c2ad1
 * The 'set disassembler-options' command now supports specifying options
4c2ad1
diff --git a/gdb/main.c b/gdb/main.c
4c2ad1
--- a/gdb/main.c
4c2ad1
+++ b/gdb/main.c
4c2ad1
@@ -518,6 +518,7 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
   int i;
4c2ad1
   int save_auto_load;
4c2ad1
   struct objfile *objfile;
4c2ad1
+  int ret = 1;
4c2ad1
 
4c2ad1
 #ifdef HAVE_SBRK
4c2ad1
   /* Set this before constructing scoped_command_stats.  */
4c2ad1
@@ -1051,7 +1052,7 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
      processed; it sets global parameters, which are independent of
4c2ad1
      what file you are debugging or what directory you are in.  */
4c2ad1
   if (system_gdbinit && !inhibit_gdbinit)
4c2ad1
-    catch_command_errors (source_script, system_gdbinit, 0);
4c2ad1
+    ret = catch_command_errors (source_script, system_gdbinit, 0);
4c2ad1
 
4c2ad1
   /* Read and execute $HOME/.gdbinit file, if it exists.  This is done
4c2ad1
      *before* all the command line arguments are processed; it sets
4c2ad1
@@ -1059,7 +1060,7 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
      debugging or what directory you are in.  */
4c2ad1
 
4c2ad1
   if (home_gdbinit && !inhibit_gdbinit && !inhibit_home_gdbinit)
4c2ad1
-    catch_command_errors (source_script, home_gdbinit, 0);
4c2ad1
+    ret = catch_command_errors (source_script, home_gdbinit, 0);
4c2ad1
 
4c2ad1
   /* Process '-ix' and '-iex' options early.  */
4c2ad1
   for (i = 0; i < cmdarg_vec.size (); i++)
4c2ad1
@@ -1069,12 +1070,12 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
       switch (cmdarg_p.type)
4c2ad1
 	{
4c2ad1
 	case CMDARG_INIT_FILE:
4c2ad1
-	  catch_command_errors (source_script, cmdarg_p.string,
4c2ad1
-				!batch_flag);
4c2ad1
+	  ret = catch_command_errors (source_script, cmdarg_p.string,
4c2ad1
+				      !batch_flag);
4c2ad1
 	  break;
4c2ad1
 	case CMDARG_INIT_COMMAND:
4c2ad1
-	  catch_command_errors (execute_command, cmdarg_p.string,
4c2ad1
-				!batch_flag);
4c2ad1
+	  ret = catch_command_errors (execute_command, cmdarg_p.string,
4c2ad1
+				      !batch_flag);
4c2ad1
 	  break;
4c2ad1
 	}
4c2ad1
     }
4c2ad1
@@ -1082,11 +1083,11 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
   /* Now perform all the actions indicated by the arguments.  */
4c2ad1
   if (cdarg != NULL)
4c2ad1
     {
4c2ad1
-      catch_command_errors (cd_command, cdarg, 0);
4c2ad1
+      ret = catch_command_errors (cd_command, cdarg, 0);
4c2ad1
     }
4c2ad1
 
4c2ad1
   for (i = 0; i < dirarg.size (); i++)
4c2ad1
-    catch_command_errors (directory_switch, dirarg[i], 0);
4c2ad1
+    ret = catch_command_errors (directory_switch, dirarg[i], 0);
4c2ad1
 
4c2ad1
   /* Skip auto-loading section-specified scripts until we've sourced
4c2ad1
      local_gdbinit (which is often used to augment the source search
4c2ad1
@@ -1115,19 +1116,19 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
          catch_command_errors returns non-zero on success!
4c2ad1
 	 Do not load EXECARG as a symbol file if it has been already processed
4c2ad1
 	 as a core file.  */
4c2ad1
-      if (catch_command_errors (func, execarg, !batch_flag)
4c2ad1
-	  && core_bfd == NULL)
4c2ad1
-	catch_command_errors (symbol_file_add_main_adapter, symarg,
4c2ad1
-			      !batch_flag);
4c2ad1
+      ret = catch_command_errors (func, execarg, !batch_flag);
4c2ad1
+      if (ret != 0 && core_bfd == NULL)
4c2ad1
+	ret = catch_command_errors (symbol_file_add_main_adapter,
4c2ad1
+				    symarg, !batch_flag);
4c2ad1
     }
4c2ad1
   else
4c2ad1
     {
4c2ad1
       if (execarg != NULL)
4c2ad1
-	catch_command_errors (exec_file_attach, execarg,
4c2ad1
-			      !batch_flag);
4c2ad1
+	ret = catch_command_errors (exec_file_attach, execarg,
4c2ad1
+				    !batch_flag);
4c2ad1
       if (symarg != NULL)
4c2ad1
-	catch_command_errors (symbol_file_add_main_adapter, symarg,
4c2ad1
-			      !batch_flag);
4c2ad1
+	ret = catch_command_errors (symbol_file_add_main_adapter,
4c2ad1
+				    symarg, !batch_flag);
4c2ad1
     }
4c2ad1
 
4c2ad1
   if (corearg && pidarg)
4c2ad1
@@ -1135,9 +1136,14 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
 	     "a core file at the same time."));
4c2ad1
 
4c2ad1
   if (corearg != NULL)
4c2ad1
-    catch_command_errors (core_file_command, corearg, !batch_flag);
4c2ad1
+    {
4c2ad1
+      ret = catch_command_errors (core_file_command, corearg,
4c2ad1
+				  !batch_flag);
4c2ad1
+    }
4c2ad1
   else if (pidarg != NULL)
4c2ad1
-    catch_command_errors (attach_command, pidarg, !batch_flag);
4c2ad1
+    {
4c2ad1
+      ret = catch_command_errors (attach_command, pidarg, !batch_flag);
4c2ad1
+    }
4c2ad1
   else if (pid_or_core_arg)
4c2ad1
     {
4c2ad1
       /* The user specified 'gdb program pid' or gdb program core'.
4c2ad1
@@ -1146,17 +1152,23 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
 
4c2ad1
       if (isdigit (pid_or_core_arg[0]))
4c2ad1
 	{
4c2ad1
-	  if (catch_command_errors (attach_command, pid_or_core_arg,
4c2ad1
-				    !batch_flag) == 0
4c2ad1
+	  ret = catch_command_errors (attach_command, pid_or_core_arg,
4c2ad1
+				      !batch_flag);
4c2ad1
+	  if (ret == 0
4c2ad1
 	      /* attach_command could succeed partially and core_file_command
4c2ad1
 		 would try to kill it.  */
4c2ad1
 	      && !have_inferiors ())
4c2ad1
-	    catch_command_errors (core_file_command, pid_or_core_arg,
4c2ad1
-				  !batch_flag);
4c2ad1
+	    ret = catch_command_errors (core_file_command,
4c2ad1
+					pid_or_core_arg,
4c2ad1
+					!batch_flag);
4c2ad1
+	}
4c2ad1
+      else
4c2ad1
+	{
4c2ad1
+	  /* Can't be a pid, better be a corefile.  */
4c2ad1
+	  ret = catch_command_errors (core_file_command,
4c2ad1
+				      pid_or_core_arg,
4c2ad1
+				      !batch_flag);
4c2ad1
 	}
4c2ad1
-      else /* Can't be a pid, better be a corefile.  */
4c2ad1
-	catch_command_errors (core_file_command, pid_or_core_arg,
4c2ad1
-			      !batch_flag);
4c2ad1
     }
4c2ad1
 
4c2ad1
   if (ttyarg != NULL)
4c2ad1
@@ -1180,7 +1192,7 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
 	{
4c2ad1
 	  auto_load_local_gdbinit_loaded = 1;
4c2ad1
 
4c2ad1
-	  catch_command_errors (source_script, local_gdbinit, 0);
4c2ad1
+	  ret = catch_command_errors (source_script, local_gdbinit, 0);
4c2ad1
 	}
4c2ad1
     }
4c2ad1
 
4c2ad1
@@ -1200,12 +1212,12 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
       switch (cmdarg_p.type)
4c2ad1
 	{
4c2ad1
 	case CMDARG_FILE:
4c2ad1
-	  catch_command_errors (source_script, cmdarg_p.string,
4c2ad1
-				!batch_flag);
4c2ad1
+	  ret = catch_command_errors (source_script, cmdarg_p.string,
4c2ad1
+				      !batch_flag);
4c2ad1
 	  break;
4c2ad1
 	case CMDARG_COMMAND:
4c2ad1
-	  catch_command_errors (execute_command, cmdarg_p.string,
4c2ad1
-				!batch_flag);
4c2ad1
+	  ret = catch_command_errors (execute_command, cmdarg_p.string,
4c2ad1
+				      !batch_flag);
4c2ad1
 	  break;
4c2ad1
 	}
4c2ad1
     }
4c2ad1
@@ -1217,8 +1229,11 @@ captured_main_1 (struct captured_main_args *context, int &python_script)
4c2ad1
 
4c2ad1
   if (batch_flag)
4c2ad1
     {
4c2ad1
+      int error_status = EXIT_FAILURE;
4c2ad1
+      int *exit_arg = ret == 0 ? &error_status : NULL;
4c2ad1
+
4c2ad1
       /* We have hit the end of the batch file.  */
4c2ad1
-      quit_force (NULL, 0);
4c2ad1
+      quit_force (exit_arg, 0);
4c2ad1
     }
4c2ad1
 }
4c2ad1
 
4c2ad1
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
4c2ad1
--- a/gdb/testsuite/ChangeLog
4c2ad1
+++ b/gdb/testsuite/ChangeLog
4c2ad1
@@ -1,3 +1,10 @@
4c2ad1
+2018-08-16  Gary Benson <gbenson@redhat.com>
4c2ad1
+
4c2ad1
+	PR gdb/13000:
4c2ad1
+	* gdb.base/batch-exit-status.exp: New file.
4c2ad1
+	* gdb.base/batch-exit-status.good-commands: Likewise.
4c2ad1
+	* gdb.base/batch-exit-status.bad-commands: Likewise.
4c2ad1
+
4c2ad1
 2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
 	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
 	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
diff --git a/gdb/testsuite/gdb.base/batch-exit-status.bad-commands b/gdb/testsuite/gdb.base/batch-exit-status.bad-commands
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/testsuite/gdb.base/batch-exit-status.bad-commands
4c2ad1
@@ -0,0 +1 @@
4c2ad1
+bork
4c2ad1
diff --git a/gdb/testsuite/gdb.base/batch-exit-status.exp b/gdb/testsuite/gdb.base/batch-exit-status.exp
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/testsuite/gdb.base/batch-exit-status.exp
4c2ad1
@@ -0,0 +1,63 @@
4c2ad1
+# Copyright (C) 2018 Free Software Foundation, Inc.
4c2ad1
+
4c2ad1
+# This program is free software; you can redistribute it and/or modify
4c2ad1
+# it under the terms of the GNU General Public License as published by
4c2ad1
+# the Free Software Foundation; either version 3 of the License, or
4c2ad1
+# (at your option) any later version.
4c2ad1
+#
4c2ad1
+# This program is distributed in the hope that it will be useful,
4c2ad1
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4c2ad1
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c2ad1
+# GNU General Public License for more details.
4c2ad1
+#
4c2ad1
+# You should have received a copy of the GNU General Public License
4c2ad1
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
4c2ad1
+
4c2ad1
+# Check that "gdb -batch" exits with appropriate status.
4c2ad1
+
4c2ad1
+standard_testfile
4c2ad1
+
4c2ad1
+set good_commands "$srcdir/$subdir/batch-exit-status.good-commands"
4c2ad1
+set bad_commands "$srcdir/$subdir/batch-exit-status.bad-commands"
4c2ad1
+
4c2ad1
+proc _test_exit_status {expect_status cmdline_opts} {
4c2ad1
+    global gdb_spawn_id
4c2ad1
+
4c2ad1
+    gdb_exit
4c2ad1
+    if {[gdb_spawn_with_cmdline_opts $cmdline_opts] != 0} {
4c2ad1
+	fail "spawn"
4c2ad1
+	return
4c2ad1
+    }
4c2ad1
+
4c2ad1
+    set result [wait -i $gdb_spawn_id]
4c2ad1
+    verbose $result
4c2ad1
+    gdb_assert { [lindex $result 2] == 0 }
4c2ad1
+    set actual_status [lindex $result 3]
4c2ad1
+    gdb_assert { $actual_status == $expect_status }
4c2ad1
+}
4c2ad1
+
4c2ad1
+proc test_exit_status {expect_status cmdline_opts} {
4c2ad1
+    with_test_prefix $cmdline_opts {
4c2ad1
+	_test_exit_status $expect_status $cmdline_opts
4c2ad1
+    }
4c2ad1
+}
4c2ad1
+
4c2ad1
+# gdb -batch with nothing to do should exit 0.
4c2ad1
+test_exit_status 0 "-batch"
4c2ad1
+
4c2ad1
+# Bad command-line options should cause exit 1.
4c2ad1
+test_exit_status 1 "-batch -jslkflsdjlkfjlksdjf"
4c2ad1
+
4c2ad1
+# gdb -batch with good commands should exit 0.
4c2ad1
+test_exit_status 0 "-batch -ex \"info source\""
4c2ad1
+test_exit_status 0 "-batch -x $good_commands"
4c2ad1
+
4c2ad1
+# gdb -batch with bad commands should exit 1.
4c2ad1
+test_exit_status 1 "-batch -ex \"set not-a-thing 4\""
4c2ad1
+test_exit_status 1 "-batch -x $bad_commands"
4c2ad1
+
4c2ad1
+# Success or failure of the last thing determines the exit code.
4c2ad1
+test_exit_status 0 "-batch -ex \"set not-a-thing 4\" -x $good_commands"
4c2ad1
+test_exit_status 0 "-batch -x $bad_commands -ex \"info source\""
4c2ad1
+test_exit_status 1 "-batch -x $good_commands -x $bad_commands"
4c2ad1
+test_exit_status 1 "-batch -x $good_commands -ex \"set not-a-thing 4\""
4c2ad1
diff --git a/gdb/testsuite/gdb.base/batch-exit-status.good-commands b/gdb/testsuite/gdb.base/batch-exit-status.good-commands
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/testsuite/gdb.base/batch-exit-status.good-commands
4c2ad1
@@ -0,0 +1 @@
4c2ad1
+info mem