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

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