Implement proper "startup-with-shell" support on gdbserver
authorSergio Durigan Junior <sergiodj@redhat.com>
Fri, 23 Dec 2016 03:14:02 +0000 (22:14 -0500)
committerSergio Durigan Junior <sergiodj@redhat.com>
Wed, 7 Jun 2017 23:56:09 +0000 (19:56 -0400)
This patch implements the proper support for the "startup-with-shell"
feature on gdbserver.  A new packet is added, QStartupWithShell, and
it is sent on initialization.  If the host sends a
"QStartupWithShell:1", it means the inferior shall be started using a
shell.  If the host sends a "QStartupWithShell:0", it means the
inferior shall be started without using a shell.  Any other value is
considered an error.

There is no way to remotely set the shell that will be used by the
target to start the inferior.  In order to do that, the user must
start gdbserver while providing a shell via the $SHELL environment
variable.  The same is true for the host side.

The "set startup-with-shell" setting from the host side is used to
decide whether to start the remote inferior using a shell.  This same
setting is also used to decide whether to use a shell to start the
host inferior; this means that it is not really possible to start the
inferior using different mechanisms on target and host.

A documentation patch is included, along with a new testcase for the
feature.

gdb/ChangeLog:
2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>

* NEWS (Changes since GDB 8.0): Announce that GDBserver is now
able to start inferiors using a shell.
(New remote packets): Announce new packet "QStartupWithShell".
* remote.c: Add PACKET_QStartupWithShell.
(extended_remote_create_inferior): Handle new
PACKET_QStartupWithShell.
(remote_protocol_features) <QStartupWithShell>: New entry for
PACKET_QStartupWithShell.
(_initialize_remote): Call "add_packet_config_cmd" for
QStartupShell.

gdb/gdbserver/ChangeLog:
2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>

* server.c (handle_general_set): Handle new packet
"QStartupWithShell".
(handle_query): Add "QStartupWithShell" to the list of supported
packets.
(gdbserver_usage): Add help text explaining the
new "--startup-with-shell" and "--no-startup-with-shell" CLI
options.
(captured_main): Recognize and act upon the presence of the new
CLI options.

gdb/testsuite/ChangeLog:
2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>

* gdb.base/startup-with-shell.c: New file.
* gdb.base/startup-with-shell.exp: Likewise.

gdb/doc/ChangeLog:
2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>

* gdb.texinfo (Starting) <startup-with-shell>: Add @anchor.
(Connecting) <Remote Packet>: Add "startup-with-shell"
and "QStartupWithShell" to the table.
(Remote Protocol) <QStartupWithShell>: New item, explaining the
packet.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbserver/ChangeLog
gdb/gdbserver/server.c
gdb/remote.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/startup-with-shell.c [new file with mode: 0644]
gdb/testsuite/gdb.base/startup-with-shell.exp [new file with mode: 0644]

index 8bcdf052fe6c73071d2c243888b6dbfdc133508c..673210a179c80e6d211fcf319413bbf145681b09 100644 (file)
@@ -1,3 +1,16 @@
+2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * NEWS (Changes since GDB 8.0): Announce that GDBserver is now
+       able to start inferiors using a shell.
+       (New remote packets): Announce new packet "QStartupWithShell".
+       * remote.c: Add PACKET_QStartupWithShell.
+       (extended_remote_create_inferior): Handle new
+       PACKET_QStartupWithShell.
+       (remote_protocol_features) <QStartupWithShell>: New entry for
+       PACKET_QStartupWithShell.
+       (_initialize_remote): Call "add_packet_config_cmd" for
+       QStartupShell.
+
 2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
            Pedro Alves  <palves@redhat.com>
 
index 112aa2f489649788b33b97d899e23d13a1d29914..8dab5d3d8fbca8c9266e9698e36f11ee7fad5d90 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,20 @@
 
 *** Changes since GDB 8.0
 
+* On Unix systems, GDBserver now does globbing expansion and variable
+  substitution in inferior command line arguments.
+
+  This is done by starting inferiors using a shell, like GDB does.
+  See "set startup-with-shell" in the user manual for how to disable
+  this from GDB when using "target extended-remote".  When using
+  "target remote", you can disable the startup with shell by using the
+  new "--no-startup-with-shell" GDBserver command line option.
+
+* New remote packets
+
+QStartupWithShell
+  Indicates whether the inferior must be started with a shell or not.
+
 *** Changes in GDB 8.0
 
 * GDB now supports access to the PKU register on GNU/Linux. The register is
@@ -409,6 +423,9 @@ show max-value-size
 
 * New remote packets
 
+QStartupWithShell
+  Indicates whether the inferior must be started with a shell or not.
+
 exec stop reason
   Indicates that an exec system call was executed.
 
index 000f3c813d7c9993631ce689ddeaaf7c8f3a8a1d..868cde90dd8c305dce31a37c4b3b4f59d422e0ea 100644 (file)
@@ -1,3 +1,11 @@
+2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * gdb.texinfo (Starting) <startup-with-shell>: Add @anchor.
+       (Connecting) <Remote Packet>: Add "startup-with-shell"
+       and "QStartupWithShell" to the table.
+       (Remote Protocol) <QStartupWithShell>: New item, explaining the
+       packet.
+
 2017-05-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb.texinfo (Packets): Document vMustReplyEmpty packet.
index 9fb70f6d2aeb95881ba885482971001ade4e5938..8d7a1c956c9a8cf1290ec13af80daf6e89a33319 100644 (file)
@@ -2153,6 +2153,7 @@ This command is available when debugging locally on most targets, excluding
 @sc{djgpp}, Cygwin, MS Windows, and QNX Neutrino.
 
 @kindex set startup-with-shell
+@anchor{set startup-with-shell}
 @item set startup-with-shell
 @itemx set startup-with-shell on
 @itemx set startup-with-shell off
@@ -20811,6 +20812,10 @@ are:
 @tab @code{QDisableRandomization}
 @tab @code{set disable-randomization}
 
+@item @code{startup-with-shell}
+@tab @code{QStartupWithShell}
+@tab @code{set startup-with-shell}
+
 @item @code{conditional-breakpoints-packet}
 @tab @code{Z0 and Z1}
 @tab @code{Support for target-side breakpoint condition evaluation}
@@ -36435,6 +36440,40 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
 This should only be done on targets that actually support disabling
 address space randomization.
 
+@item QStartupWithShell:@var{value}
+@cindex startup with shell, remote request
+@cindex @samp{QStartupWithShell} packet
+On UNIX-like targets, it is possible to start the inferior using a
+shell program.  This is the default behavior on both @value{GDBN} and
+@command{gdbserver} (@pxref{set startup-with-shell}).  This packet is
+used to inform @command{gdbserver} whether it should start the
+inferior using a shell or not.
+
+If @var{value} is @samp{0}, @command{gdbserver} will not use a shell
+to start the inferior.  If @var{value} is @samp{1},
+@command{gdbserver} will use a shell to start the inferior.  All other
+values are considered an error.
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
+
+@item E @var{nn}
+An error occurred.  The error number @var{nn} is given as hex digits.
+@end table
+
+This packet is not probed by default; the remote stub must request it,
+by supplying an appropriate @samp{qSupported} response
+(@pxref{qSupported}).  This should only be done on targets that
+actually support starting the inferior using a shell.
+
+Use of this packet is controlled by the @code{set startup-with-shell}
+command; @pxref{set startup-with-shell}.
+
 @item qfThreadInfo
 @itemx qsThreadInfo
 @cindex list active threads, remote request
index 275f65c250052d218df566c4bae8e5b4432e138f..a5effe2d9c027e2cda10981b8db6e54898f72455 100644 (file)
@@ -1,3 +1,15 @@
+2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * server.c (handle_general_set): Handle new packet
+       "QStartupWithShell".
+       (handle_query): Add "QStartupWithShell" to the list of supported
+       packets.
+       (gdbserver_usage): Add help text explaining the
+       new "--startup-with-shell" and "--no-startup-with-shell" CLI
+       options.
+       (captured_main): Recognize and act upon the presence of the new
+       CLI options.
+
 2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
            Pedro Alves  <palves@redhat.com>
 
index 3ab042d2965a0852fc31772685fe0d6d92228638..1d7a8b0278e688de5b5a7b101be3ff946aeade87 100644 (file)
@@ -767,6 +767,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      const char *value = own_buf + strlen ("QStartupWithShell:");
+
+      if (strcmp (value, "1") == 0)
+       startup_with_shell = true;
+      else if (strcmp (value, "0") == 0)
+       startup_with_shell = false;
+      else
+       {
+         /* Unknown value.  */
+         fprintf (stderr, "Unknown value to startup-with-shell: %s\n",
+                  own_buf);
+         write_enn (own_buf);
+         return;
+       }
+
+      if (remote_debug)
+       debug_printf (_("[Inferior will %s started with shell]"),
+                     startup_with_shell ? "be" : "not be");
+
+      write_ok (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -2203,7 +2228,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
        }
 
       sprintf (own_buf,
-              "PacketSize=%x;QPassSignals+;QProgramSignals+",
+              "PacketSize=%x;QPassSignals+;QProgramSignals+;QStartupWithShell+",
               PBUFSIZ - 1);
 
       if (target_supports_catch_syscall ())
@@ -3309,6 +3334,13 @@ gdbserver_usage (FILE *stream)
           "  --no-disable-randomization\n"
           "                        Don't disable address space randomization when\n"
           "                        starting PROG.\n"
+          "  --startup-with-shell\n"
+          "                        Start PROG using a shell.  I.e., execs a shell that\n"
+          "                        then execs PROG.  (default)\n"
+          "  --no-startup-with-shell\n"
+          "                        Exec PROG directly instead of using a shell.\n"
+          "                        Disables argument globbing and variable substitution\n"
+          "                        on UNIX-like systems.\n"
           "\n"
           "Debug options:\n"
           "\n"
@@ -3601,6 +3633,10 @@ captured_main (int argc, char *argv[])
        disable_randomization = 1;
       else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
        disable_randomization = 0;
+      else if (strcmp (*next_arg, "--startup-with-shell") == 0)
+       startup_with_shell = true;
+      else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
+       startup_with_shell = false;
       else if (strcmp (*next_arg, "--once") == 0)
        run_once = 1;
       else
index 1f8607988444fb0221b87e9ef3e93fbec04c42ea..b66ecee7f6db8e2a691b9e12f6ce314da22d69eb 100644 (file)
@@ -1428,6 +1428,7 @@ enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QStartupWithShell,
   PACKET_qCRC,
   PACKET_qSearch_memory,
   PACKET_vAttach,
@@ -4633,6 +4634,8 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_QCatchSyscalls },
   { "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
     PACKET_QProgramSignals },
+  { "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
+    PACKET_QStartupWithShell },
   { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
     PACKET_QStartNoAckMode },
   { "multiprocess", PACKET_DISABLE, remote_supported_packet,
@@ -9614,6 +9617,20 @@ extended_remote_create_inferior (struct target_ops *ops,
   if (extended_remote_supports_disable_randomization (ops))
     extended_remote_disable_randomization (disable_randomization);
 
+  /* If startup-with-shell is on, we inform gdbserver to start the
+     remote inferior using a shell.  */
+  if (packet_support (PACKET_QStartupWithShell) != PACKET_DISABLE)
+    {
+      xsnprintf (rs->buf, get_remote_packet_size (),
+                "QStartupWithShell:%d", startup_with_shell ? 1 : 0);
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      if (strcmp (rs->buf, "OK") != 0)
+       error (_("\
+Remote replied unexpectedly while setting startup-with-shell: %s"),
+              rs->buf);
+    }
+
   /* Now restart the remote server.  */
   run_worked = extended_remote_run (args) != -1;
   if (!run_worked)
@@ -14104,6 +14121,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
                         "QProgramSignals", "program-signals", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
+                        "QStartupWithShell", "startup-with-shell", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol],
                         "qSymbol", "symbol-lookup", 0);
 
index d52d9c1bd62a9e6457c9d44c9d52cb70a78fa515..6df961ff37107dcce5fc4d426cb594c63b4048db 100644 (file)
@@ -1,3 +1,8 @@
+2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * gdb.base/startup-with-shell.c: New file.
+       * gdb.base/startup-with-shell.exp: Likewise.
+
 2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        * gdb.server/non-existing-program.exp: Update regex in order to
diff --git a/gdb/testsuite/gdb.base/startup-with-shell.c b/gdb/testsuite/gdb.base/startup-with-shell.c
new file mode 100644 (file)
index 0000000..6278447
--- /dev/null
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+
+  for (i = 0; argv[i] != NULL; ++i)
+    printf ("ARG %d = %s\n", i, argv[i]);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/startup-with-shell.exp b/gdb/testsuite/gdb.base/startup-with-shell.exp
new file mode 100644 (file)
index 0000000..af06c88
--- /dev/null
@@ -0,0 +1,89 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This test doesn't make sense on native-gdbserver.
+if { [use_gdb_stub] } {
+    untested "not supported"
+    return
+}
+
+# There's no easy way to set environment variables on remote targets
+# (via dejagnu) yet.
+if { [is_remote target] } {
+    untested "remote board"
+    return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+set unique_file [standard_output_file "unique-file.unique-extension"]
+set unique_file_dir [standard_output_file ""]
+
+run_on_host "touch $unique_file" "touch" "$unique_file"
+
+# Initial setup for simple test (wildcard expansion, variable substitution).
+
+proc initial_setup_simple { startup_with_shell run_args } {
+    global hex decimal binfile unique_file
+
+    clean_restart $binfile
+
+    gdb_test_no_output "set startup-with-shell $startup_with_shell"
+
+    gdb_test_no_output "set args $run_args"
+
+    set test "inferior started"
+    if { [runto_main] } {
+       pass $test
+    } else {
+       fail $test
+    }
+}
+
+## Run the actual tests
+
+with_test_prefix "startup_with_shell = on; run_args = *.unique-extension" {
+    initial_setup_simple "on" "$unique_file_dir/*.unique-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"$unique_file\"" \
+       "first argument expanded"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.unique-extension" {
+    initial_setup_simple "off" "$unique_file_dir/*.unique-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"$unique_file_dir/\\\*\.unique-extension\"" \
+       "first argument not expanded"
+}
+
+with_test_prefix "startup_with_shell = on; run_args = \$TEST" {
+    set env(TEST) "1234"
+    initial_setup_simple "on" "\$TEST"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"1234\"" \
+       "testing first argument"
+    unset env(TEST)
+}
+
+with_test_prefix "startup_with_shell = off; run_args = \$TEST" {
+    set env(TEST) "1234"
+    initial_setup_simple "off" "\$TEST"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\$TEST\"" \
+       "testing first argument"
+    unset env(TEST)
+}