public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver
@ 2016-12-23  3:39 Sergio Durigan Junior
  2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
                   ` (10 more replies)
  0 siblings, 11 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:39 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves

Hi there,

This patch series took a long time to complete due to many and varied
reasons, but finally here it is.

It implements the "startup-with-shell" feature on gdbserver.  This
means that it will be possible to start inferiors using the shell
(instead of calling execv*), which brings many advantages.

First of all, it will be possible to use I/O redirection, variable
substitution and globbing expansion on gdbserver just like we do today
on GDB.  This is great because, among other things, it brings
gdbserver on a pair with GDB when considering the Feature Parity
project.

Secondly, a great deal of code had to be shared between GDB and
gdbserver, especially the fork_inferior function, which means that now
both programs are using virtually the same code to start inferiors.
I've also had to touch on other areas, like terminal.h, inflow.c and
gdbthread.h, and even though only the APIs were shared (i.e.,
gdbserver's version of a gdbthread.h function may differ from GDB's
version), this is also beneficial in the long run when we start to
unify the code more deeply.  But I'm "raining in the wet" here; all
this has been explained in better terms before.

I did my best to split the patches, but unfortunately the
fork_inferior patch is big and I couldn't see a better way to do that.
But it shouldn't be very hard to review them, because most of it is
just "code movement".

Thank you, and happy holidays!

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 1/6] Share gdb/environ.[ch] with gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
  2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
@ 2016-12-23  3:39 ` Sergio Durigan Junior
  2016-12-26 21:34   ` Luis Machado
  2016-12-23  3:39 ` [PATCH 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:39 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

We will need access to the environment functions when we share
fork_inferior between GDB and gdbserver, therefore we simply make the
API on gdb/environ.[ch] available on common/.  No extra adjustments
are needed to make it compile on gdbserver.

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Replace "environ.c" with
	"common/environ.c".
	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
	to...
	* common/environ.c: ... here.
	* environ.h: Moved to...
	* common/environ.h: ... here.

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/environ.c".
	(OBJS): Add "common/environ.h".
---
 gdb/Makefile.in            | 4 ++--
 gdb/{ => common}/environ.c | 2 +-
 gdb/{ => common}/environ.h | 0
 gdb/gdbserver/Makefile.in  | 5 +++++
 4 files changed, 8 insertions(+), 3 deletions(-)
 rename gdb/{ => common}/environ.c (99%)
 rename gdb/{ => common}/environ.h (100%)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 946d440..051f07d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1047,7 +1047,6 @@ SFILES = \
 	dwarf2loc.c \
 	dwarf2read.c \
 	elfread.c \
-	environ.c \
 	eval.c \
 	event-loop.c \
 	event-top.c \
@@ -1192,6 +1191,7 @@ SFILES = \
 	common/common-regcache.c \
 	common/common-utils.c \
 	common/errors.c \
+	common/environ.c \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
@@ -1270,7 +1270,6 @@ HFILES_NO_SRCDIR = \
 	dwarf2-frame-tailcall.h \
 	dwarf2expr.h \
 	dwarf2loc.h \
-	environ.h \
 	event-loop.h \
 	event-top.h \
 	exceptions.h \
@@ -1471,6 +1470,7 @@ HFILES_NO_SRCDIR = \
 	common/common-types.h \
 	common/common-utils.h \
 	common/errors.h \
+	common/environ.h \
 	common/fileio.h \
 	common/format.h \
 	common/gdb_assert.h \
diff --git a/gdb/environ.c b/gdb/common/environ.c
similarity index 99%
rename from gdb/environ.c
rename to gdb/common/environ.c
index 5c73757..105f854 100644
--- a/gdb/environ.c
+++ b/gdb/common/environ.c
@@ -15,7 +15,7 @@
    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 "defs.h"
+#include "common-defs.h"
 #include "environ.h"
 #include <algorithm>
 \f
diff --git a/gdb/environ.h b/gdb/common/environ.h
similarity index 100%
rename from gdb/environ.h
rename to gdb/common/environ.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index e17cf70..fe40842 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -201,6 +201,7 @@ SFILES = \
 	$(srcdir)/common/common-regcache.c \
 	$(srcdir)/common/common-utils.c \
 	$(srcdir)/common/errors.c \
+	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
 	$(srcdir)/common/gdb_vecs.c \
@@ -238,6 +239,7 @@ OBS = \
 	debug.o \
 	dll.o \
 	errors.o \
+	environ.o \
 	event-loop.o \
 	fileio.o \
 	filestuff.o \
@@ -774,6 +776,9 @@ agent.o: ../common/agent.c
 errors.o: ../common/errors.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+environ.o: ../common/environ.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-debug.o: ../common/common-debug.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 2/6] Share parts of gdb/terminal.h with gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
  2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
  2016-12-23  3:39 ` [PATCH 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2016-12-23  3:39 ` Sergio Durigan Junior
  2016-12-26 21:35   ` Luis Machado
  2016-12-23  3:45 ` [PATCH 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:39 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

As part of the bigger work of sharing fork_inferior with gdbserver,
some parts of gdb/terminal.h also needed to be moved to a common
place.  These parts are:

- The code responsible for determining some terminal-based define's
  based on available features;

- job control;

- terminal-related functions needed by fork_inferior;

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
	* common/common-terminal.h: New file, with parts of "terminal.h".
	* terminal.h: Move terminal-related defines to
	"common/common-terminal.h".
	(new_tty_prefork): Move to "common/common-terminal.h".
	(new_tty): Likewise.
	(new_tty_postfork): Likewise.
	(job_control): Likewise.
	(create_tty_session): Likewise.
	(gdb_setpgid): Likewise.
	* utils.c: Include "terminal.h".

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* terminal.c: New file.
---
 gdb/Makefile.in                              |  1 +
 gdb/{terminal.h => common/common-terminal.h} | 55 +++++++++++++--------
 gdb/gdbserver/terminal.c                     | 72 +++++++++++++++++++++++++++
 gdb/terminal.h                               | 73 +---------------------------
 gdb/utils.c                                  |  1 +
 5 files changed, 109 insertions(+), 93 deletions(-)
 copy gdb/{terminal.h => common/common-terminal.h} (66%)
 create mode 100644 gdb/gdbserver/terminal.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 051f07d..51c0f73 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/common-terminal.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
diff --git a/gdb/terminal.h b/gdb/common/common-terminal.h
similarity index 66%
copy from gdb/terminal.h
copy to gdb/common/common-terminal.h
index 0deced4..0ec8a23 100644
--- a/gdb/terminal.h
+++ b/gdb/common/common-terminal.h
@@ -16,9 +16,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#if !defined (TERMINAL_H)
-#define TERMINAL_H 1
-
+#ifndef COMMON_TERMINAL_H
+#define COMMON_TERMINAL_H
 
 /* If we're using autoconf, it will define HAVE_TERMIOS_H,
    HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
@@ -76,37 +75,51 @@
 #endif /* sgtty */
 #endif
 
-struct inferior;
+#include <sys/types.h>
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
 
-extern void new_tty_prefork (const char *);
+extern int job_control;
 
 extern void new_tty (void);
 
-extern void new_tty_postfork (void);
+/* NEW_TTY_PREFORK is called before forking a new child process,
+   so we can record the state of ttys in the child to be formed.
+   TTYNAME is null if we are to share the terminal with gdb;
+   or points to a string containing the name of the desired tty.
 
-extern void copy_terminal_info (struct inferior *to, struct inferior *from);
+   NEW_TTY is called in new child processes under Unix, which will
+   become debugger target processes.  This actually switches to
+   the terminal specified in the NEW_TTY_PREFORK call.  */
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
+extern void new_tty_prefork (const char *ttyname);
 
-extern pid_t create_tty_session (void);
+/* NEW_TTY_POSTFORK is called after forking a new child process, and
+   adding it to the inferior table, to store the TTYNAME being used by
+   the child, or null if it sharing the terminal with gdb.  */
 
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
+extern void new_tty_postfork (void);
 
-/* Set up a serial structure describing standard input.  In inflow.c.  */
-extern void initialize_stdin_serial (void);
+/* Create a new session if the inferior will run in a different tty.
+   A session is UNIX's way of grouping processes that share a controlling
+   terminal, so a new one is needed if the inferior terminal will be
+   different from GDB's.
 
-extern void gdb_save_tty_state (void);
+   Returns the session id of the new session, 0 if no session was created
+   or -1 if an error occurred.  */
 
-/* Take a snapshot of our initial tty state before readline/ncurses
-   have had a chance to alter it.  */
-extern void set_initial_gdb_ttystate (void);
+extern pid_t create_tty_session (void);
 
 /* Set the process group of the caller to its own pid, or do nothing
    if we lack job control.  */
+
 extern int gdb_setpgid (void);
 
-#endif /* !defined (TERMINAL_H) */
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  */
+
+extern void have_job_control (void);
+
+#endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
new file mode 100644
index 0000000..9813018
--- /dev/null
+++ b/gdb/gdbserver/terminal.c
@@ -0,0 +1,72 @@
+/* Terminal interface definitions for the GDB remote server.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "common-terminal.h"
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty (void)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_prefork (const char *ttyname)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_postfork (void)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-terminal.h.  */
+
+pid_t
+create_tty_session (void)
+{
+  /* For now we just return a dummy value.  This function will be
+     properly implemented later.  */
+  return (pid_t) 1;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+set_inferior_io_terminal (const char *terminal_name)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-inferior.h.  */
+
+const char *
+get_inferior_io_terminal (void)
+{
+  /* Return a dummy value.  This function will be properly implemented
+     later.  */
+  return NULL;
+}
diff --git a/gdb/terminal.h b/gdb/terminal.h
index 0deced4..810b597 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,83 +19,12 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
+#include "common-terminal.h"
 
 struct inferior;
 
-extern void new_tty_prefork (const char *);
-
-extern void new_tty (void);
-
-extern void new_tty_postfork (void);
-
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
-extern pid_t create_tty_session (void);
-
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 3a88e2a..bc1dfe5 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -53,6 +53,7 @@
 #include "top.h"
 #include "main.h"
 #include "solist.h"
+#include "terminal.h"
 
 #include "inferior.h"		/* for signed_pointer_to_address */
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
@ 2016-12-23  3:39 ` Sergio Durigan Junior
  2016-12-26 21:34   ` Luis Machado
  2016-12-23  3:39 ` [PATCH 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:39 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

After sharing parts of gdb/terminal.h, it is also needed to share the
two functions on gdb/inflow.c that are going to be needed by the
fork_inferior sharing.  They are 'gdb_setpgid' and the new
'have_job_control'.

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-inflow.c".
	(COMMON_OBS): Add "common/common-inflow.o".
	* common/common-inflow.c: New file, with contents from
	"gdb/inflow.c".
	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to a specific
	function on "common/common-inflow.c".
	* utils.c (job_control): Delete.

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in: Add rule for "common-inflow.o".
	(SFILE): Add "common/common-inflow.c".
	(OBS): Add "common-inflow.o".
---
 gdb/Makefile.in            |  2 +
 gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/Makefile.in  |  5 +++
 gdb/inflow.c               | 63 +-------------------------------
 gdb/utils.c                |  4 --
 5 files changed, 100 insertions(+), 65 deletions(-)
 create mode 100644 gdb/common/common-inflow.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 51c0f73..8372b4a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1195,6 +1195,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1622,6 +1623,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
new file mode 100644
index 0000000..595eb51
--- /dev/null
+++ b/gdb/common/common-inflow.c
@@ -0,0 +1,91 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "common-terminal.h"
+
+/* Nonzero if we have job control.  */
+
+int job_control;
+
+/* This is here because this is where we figure out whether we (probably)
+   have job control.  Just using job_control only does part of it because
+   setpgid or setpgrp might not exist on a system without job control.
+   It might be considered misplaced (on the other hand, process groups and
+   job control are closely related to ttys).
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index fe40842..2add910 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
@@ -770,6 +772,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-inflow.o: ../common/common-inflow.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 agent.o: ../common/agent.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 5b55cec..80909ea 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -803,43 +803,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -860,30 +823,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index bc1dfe5..6bf3716 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 5/6] Share fork_inferior et al with gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (3 preceding siblings ...)
  2016-12-23  3:45 ` [PATCH 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2016-12-23  3:45 ` Sergio Durigan Junior
  2017-01-03 23:32   ` Luis Machado
  2018-02-21  3:58   ` [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver") Joel Brobecker
  2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:45 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.  For some
feature, like the target_terminal_* functions, I chose to just use
placeholders for the real functions on gdbserver, that should be
implemented in the future.  For now, we don't need them in order to
make things work.

I've had to take into account the fact that gdbserver uses global
variables to control which thread is currently running, so you will
see a few modifications to accomodate that: for example, the new
argument added to "startup_inferior", or the one added to
"set_executing".

Last, but not least, I did a major revamp on the way gdbserver
computes and stores the inferior's arguments.  It's now using a
std::vector<char *> and std::string where applicable, which makes
things much easier even to understand.  This simplification was also
interesting for the "create_inferior" method of gdbserver's target.c;
now, it only needs one argument (a vector containing the full inferior
argv) instead of two char * that were confusing to
manipulate/generate.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  For now, the user won't have the option to disable
the startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
	"common/common-top.h".
	(COMMON_OBS): Add "common-fork-child.o".
	* common-fork-child.c: New file, with the majority of
	"gdb/fork-child.c".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* common/common-top.h: New file.
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Update call of
	"startup_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(fork_inferior): Likewise.  Update function to support gdbserver.
	(startup_inferior): Likewise.
	(_initialize_fork_child): Update documentation for "set/show
	startup-with-shell" command.
	* gnu-nat.c (gnu_create_inferior): Update call to
	"startup_inferior".
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* inferior.h: Include "common-inferior.h".
	(fork_inferior): Move prototype to "common-inferior.h".
	(startup_inferior): Likewise.
	* procfs.c (procfs_init_inferior): Update call to
	"startup_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* top.h: Include "common-top.h".
	(main_ui): Move
	(current_ui): Move
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "terminal.c" and
	"common/common-fork-child.c".
	(OBS): Add common-fork-child.o and terminal.o.
	(common-fork-child.o): New rule.
	* inferiors (inferior_ptid): New variable.
	(inferior_appeared): New function.
	(current_inferior): Likewise.
	(have_inferiors): Likewise.
	* linux-low.c: Include "common-inferior.h" and "environ.h".
	(linux_update_process): New function.
	(linux_add_process): Update comment.  Adjust function to call
	"linux_update_process".
	(update_thread_lwp): New function.
	(linux_ptrace_fun): Likewise.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c (lynx_update_process): New function.
	(lynx_add_process): Update comment.  Adjust function to call
	"lynx_update_process".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".
	* server.c: Include "common-inferior.h", "common-terminal.h",
	"common-top.h", "environ.h".
	(main_ui): New variable.
	(current_ui): Likewise.
	(our_environ): Likewise.
	(startup_with_shell): Likewise.
	(startup_shell): Likewise.
	(program_argv): Convert to std::vector<char *>.
	(wrapper_argv): Likewise.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(pre_fork_inferior): New function, with parts of "start_inferior".
	(post_fork_inferior): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h (startup_shell): New variable.
	(pre_fork_inferior): New prototype.
	(post_fork_inferior): Likewise.
	(get_environ): Likewise.
	* spu-low.c (spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h (struct target_ops) <create_inferior>: Update prototype
	to accept one std::vector<char *> representing the full program
	argv.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	(free_vector_argv): Likewise.
	(stringify_argv): Likewise.
	* utils.h (free_vector_argv): New prototype.
	(stringify_argv): Likewise.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

gdb/testsuite/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   4 +
 gdb/{fork-child.c => common/common-fork-child.c}  | 318 ++++++-------
 gdb/common/common-inferior.h                      | 113 +++++
 gdb/{gdbserver/utils.h => common/common-top.h}    |  20 +-
 gdb/common/common-utils.h                         |   5 +
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |   2 +-
 gdb/fork-child.c                                  | 530 +---------------------
 gdb/gdbserver/Makefile.in                         |   7 +
 gdb/gdbserver/inferiors.c                         |  27 ++
 gdb/gdbserver/linux-low.c                         | 124 +++--
 gdb/gdbserver/lynx-low.c                          |  66 +--
 gdb/gdbserver/nto-low.c                           |   9 +-
 gdb/gdbserver/server.c                            | 279 +++++++-----
 gdb/gdbserver/server.h                            |  19 +
 gdb/gdbserver/spu-low.c                           |  43 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |   7 +-
 gdb/gdbserver/utils.c                             |  37 ++
 gdb/gdbserver/utils.h                             |  12 +
 gdb/gdbserver/win32-low.c                         |  25 +-
 gdb/gnu-nat.c                                     |   2 +-
 gdb/inf-ptrace.c                                  |   2 +-
 gdb/inferior.h                                    |  12 +-
 gdb/procfs.c                                      |   2 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  17 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
 gdb/top.h                                         |   9 +-
 gdb/utils.c                                       |   9 +
 30 files changed, 796 insertions(+), 959 deletions(-)
 copy gdb/{fork-child.c => common/common-fork-child.c} (76%)
 create mode 100644 gdb/common/common-inferior.h
 copy gdb/{gdbserver/utils.h => common/common-top.h} (62%)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ca13a80..a7d06f9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1195,6 +1195,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-fork-child.c \
 	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
@@ -1483,6 +1484,8 @@ HFILES_NO_SRCDIR = \
 	common/gdb_sys_time.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
+	common/common-top.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1624,6 +1627,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
diff --git a/gdb/fork-child.c b/gdb/common/common-fork-child.c
similarity index 76%
copy from gdb/fork-child.c
copy to gdb/common/common-fork-child.c
index 38fca60..ab0cafc 100644
--- a/gdb/fork-child.c
+++ b/gdb/common/common-fork-child.c
@@ -19,28 +19,22 @@
    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 "defs.h"
-#include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
-#include "gdbcmd.h"
-#include "solib.h"
+#include "common-defs.h"
+#include "target/waitstatus.h"
+#include "common-terminal.h"
 #include "filestuff.h"
-#include "top.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "common-top.h"
 #include "signals-state-save-restore.h"
-#include <signal.h>
-
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
 
 extern char **environ;
 
-static char *exec_wrapper;
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+
+#define SHELL_FILE "/bin/sh"
 
 /* Break up SCRATCH into an argument vector suitable for passing to
    execvp and store it in ARGV.  E.g., on "run a b c d" this routine
@@ -48,7 +42,7 @@ static char *exec_wrapper;
    fill in ARGV with the four arguments "a", "b", "c", "d".  */
 
 static void
-breakup_args (char *scratch, char **argv)
+breakup_args_for_exec (char *scratch, char **argv)
 {
   char *cp = scratch, *tmp;
 
@@ -109,15 +103,120 @@ escape_bang_in_quoted_argument (const char *shell_file)
   return 0;
 }
 
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
+/* See common/common-inferior.h.  */
+
+char *
+get_startup_shell (void)
+{
+  static char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* Quote the shell command that will be executed.  This function is
+   called when the inferior is going to be executed under a shell
+   (i.e., when 'startup-with-shell' is set).
+
+   SHELL_FILE is the shell which will be used to execute the inferior
+   (e.g., /bin/sh).
+
+   EXEC_FILE is the inferior executable itself.
+
+   ALLARGS contains all the arguments that will be passed to the
+   inferior.
+
+   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
+   the inferior.
+
+   SHELL_CMD is a pointer to the resulting shell command that will be
+   executed.  The resulting shell command will be returned in it.  It
+   must be pre-allocated and have a reasonable size.  For an example
+   on how to determine its size, see 'fork_inferior' on
+   fork-child.c.  */
+
+static void
+quote_shell_command (const char *shell_file, const char *exec_file,
+		     const char *allargs, const char *exec_wrapper,
+		     char **shell_cmd)
+{
+  char *shell_command = *shell_cmd;
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  shell_command[0] = '\0';
+  strcat (shell_command, "exec ");
+
+  /* Add any exec wrapper.  That may be a program name with arguments, so
+     the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      strcat (shell_command, exec_wrapper);
+      strcat (shell_command, " ");
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But
+     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
+     we need to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      strcat (shell_command, "'");
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    strcat (shell_command, "'\\''");
+	  else if (*p == '!' && escape_bang)
+	    strcat (shell_command, "\\!");
+	  else
+	    strncat (shell_command, p, 1);
+	}
+      strcat (shell_command, "'");
+    }
+  else
+    strcat (shell_command, exec_file);
+
+  strcat (shell_command, " ");
+  strcat (shell_command, allargs);
+}
 
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
+/* See common/common-inferior.h.  */
 
 int
 fork_inferior (char *exec_file_arg, char *allargs, char **env,
@@ -127,7 +226,6 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
                                 char * const *env))
 {
   int pid;
-  static char default_shell_file[] = SHELL_FILE;
   /* Set debug_fork then attach to the child while it sleeps, to debug.  */
   static int debug_fork = 0;
   /* This is set to the result of setpgrp, which if vforked, will be visible
@@ -158,9 +256,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
     {
       /* Figure out what shell to start up the user program under.  */
       if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
       shell = 1;
     }
 
@@ -174,92 +272,28 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
       argv = XALLOCAVEC (char *, argc);
       argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
+      breakup_args_for_exec (allargs, &argv[1]);
     }
   else
     {
       /* We're going to call a shell.  */
       char *shell_command;
-      int len;
-      char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+      char *exec_wrapper = get_exec_wrapper ();
+      size_t len;
 
       /* Multiplying the length of exec_file by 4 is to account for the
          fact that it may expand when quoted; it is a worst-case number
          based on every character being '.  */
       len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
+      if (exec_wrapper != NULL)
         len += strlen (exec_wrapper) + 1;
 
       shell_command = (char *) alloca (len);
       shell_command[0] = '\0';
 
-      strcat (shell_command, "exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  strcat (shell_command, "'");
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
-	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
-	      else
-		strncat (shell_command, p, 1);
-	    }
-	  strcat (shell_command, "'");
-	}
-      else
-	strcat (shell_command, exec_file);
-
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
+      quote_shell_command (shell_file, exec_file,
+			   allargs,
+			   exec_wrapper, &shell_command);
 
       /* If we decided above to start up with a shell, we exec the
 	 shell, "-c" says to interpret the next arg as a shell command
@@ -287,8 +321,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
   /* It is generally good practice to flush any possible pending stdio
      output prior to doing a fork, to avoid the possibility of both
      the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
+  gdb_flush_out_err ();
 
   /* If there's any initialization of the target layers that must
      happen to prepare to handle the child we're about fork, do it
@@ -382,13 +415,13 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
       /* If we get here, it's an error.  */
       save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
+      warning ("Cannot exec %s", argv[0]);
+
       for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
       _exit (0177);
     }
 
@@ -428,10 +461,12 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
   return pid;
 }
 
-/* Accept NTRAPS traps from the inferior.  */
+/* See common/common-inferior.h.  */
 
 void
-startup_inferior (int ntraps)
+startup_inferior (int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
 {
   int pending_execs = ntraps;
   int terminal_initted = 0;
@@ -451,8 +486,7 @@ startup_inferior (int ntraps)
   /* The process was started by the fork that created it, but it will
      have stopped one instruction after execing the shell.  Here we
      must get it up to actual execution of the real program.  */
-
-  if (exec_wrapper)
+  if (get_exec_wrapper () != NULL)
     pending_execs++;
 
   while (1)
@@ -464,6 +498,11 @@ startup_inferior (int ntraps)
       memset (&ws, 0, sizeof (ws));
       event_ptid = target_wait (resume_ptid, &ws, 0);
 
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
       if (ws.kind == TARGET_WAITKIND_IGNORE)
 	/* The inferior didn't really stop, keep waiting.  */
 	continue;
@@ -476,6 +515,12 @@ startup_inferior (int ntraps)
 	  case TARGET_WAITKIND_VFORKED:
 	  case TARGET_WAITKIND_SYSCALL_ENTRY:
 	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
 	    /* Ignore gracefully during startup of the inferior.  */
 	    switch_to_thread (event_ptid);
 	    break;
@@ -545,50 +590,5 @@ startup_inferior (int ntraps)
     }
 
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0, NULL);
-}
-
-/* Implement the "unset exec-wrapper" command.  */
-
-static void
-unset_exec_wrapper_command (char *args, int from_tty)
-{
-  xfree (exec_wrapper);
-  exec_wrapper = NULL;
-}
-
-static void
-show_startup_with_shell (struct ui_file *file, int from_tty,
-			 struct cmd_list_element *c, const char *value)
-{
-  fprintf_filtered (file,
-		    _("Use of shell to start subprocesses is %s.\n"),
-		    value);
-}
-
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-extern initialize_file_ftype _initialize_fork_child;
-
-void
-_initialize_fork_child (void)
-{
-  add_setshow_filename_cmd ("exec-wrapper", class_run, &exec_wrapper, _("\
-Set a wrapper for running programs.\n\
-The wrapper prepares the system and environment for the new program."),
-			    _("\
-Show the wrapper for running programs."), NULL,
-			    NULL, NULL,
-			    &setlist, &showlist);
-
-  add_cmd ("exec-wrapper", class_run, unset_exec_wrapper_command,
-           _("Disable use of an execution wrapper."),
-           &unsetlist);
-
-  add_setshow_boolean_cmd ("startup-with-shell", class_support,
-			   &startup_with_shell, _("\
-Set use of shell to start subprocesses.  The default is on."), _("\
-Show use of shell to start subprocesses."), NULL,
-			   NULL,
-			   show_startup_with_shell,
-			   &setlist, &showlist);
+  set_executing (resume_ptid, 0, last_waitstatus);
 }
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..fb78109
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,113 @@
+/* Variables that describe the inferior process running under GDB:
+   Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+struct inferior;
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+
+extern int startup_with_shell;
+
+/* Collected pid, tid, etc. of the debugged inferior.  When there's
+   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
+
+extern ptid_t inferior_ptid;
+
+/* Accept NTRAPS traps from the inferior.  */
+
+extern void startup_inferior (int ntraps,
+			      struct target_waitstatus *mystatus,
+			      ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+
+extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+               void (*exec_fun) (const char *file, char * const *argv,
+				 char * const *env));
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+
+extern char *get_startup_shell (void);
+
+/* Set/get file name for default use for standard in/out in the inferior.  */
+
+extern void set_inferior_io_terminal (const char *terminal_name);
+extern const char *get_inferior_io_terminal (void);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+
+extern char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+
+extern char *get_exec_file (int err);
+
+/* Returns true if the inferior list is not empty.  */
+
+extern int have_inferiors (void);
+
+extern void inferior_appeared (struct inferior *inf, int pid);
+
+/* Return a pointer to the current inferior.  It is an error to call
+   this if there is no current inferior.  */
+
+extern struct inferior *current_inferior (void);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/gdbserver/utils.h b/gdb/common/common-top.h
similarity index 62%
copy from gdb/gdbserver/utils.h
copy to gdb/common/common-top.h
index 5e0cead..e282116 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/common/common-top.h
@@ -1,5 +1,6 @@
-/* General utility routines for the remote server for GDB.
-   Copyright (C) 1993-2016 Free Software Foundation, Inc.
+/* Top level stuff for GDB, the GNU debugger.
+
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -16,10 +17,15 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#ifndef UTILS_H
-#define UTILS_H
+#ifndef COMMON_TOP_H
+#define COMMON_TOP_H
+
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+extern struct ui *main_ui;
 
-char *paddress (CORE_ADDR addr);
-char *pfildes (gdb_fildes_t fd);
+/* The current UI.  */
+extern struct ui *current_ui;
 
-#endif /* UTILS_H */
+#endif /* ! COMMON_TOP_H */
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index a9053ff..71a5a38 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -103,4 +103,9 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and gdbserver.  */
+
+extern void gdb_flush_out_err (void);
+
 #endif
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 64de931..694308f 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 6ca659f4..61f634d 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 }
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 38fca60..d7d2f5e 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,531 +21,19 @@
 
 #include "defs.h"
 #include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
 #include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
-#include "top.h"
-#include "signals-state-save-restore.h"
-#include <signal.h>
 
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-extern char **environ;
+static char *exec_wrapper = NULL;
 
-static char *exec_wrapper;
+/* See common/common-inferior.h.  */
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
-
-static void
-breakup_args (char *scratch, char **argv)
+char *
+get_exec_wrapper (void)
 {
-  char *cp = scratch, *tmp;
-
-  for (;;)
-    {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
-    }
-
-  /* Null-terminate the vector.  */
-  *argv = NULL;
-}
-
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static int
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  const int shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return 0;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return 1;
-
-  return 0;
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static char *exec_file;
-  char **save_our_env;
-  int shell = 0;
-  static char **argv;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
-    exec_file = get_exec_file (1);
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
-  if (startup_with_shell)
-    {
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  strcat (shell_command, "'");
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
-	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
-	      else
-		strncat (shell_command, p, 1);
-	    }
-	  strcat (shell_command, "'");
-	}
-      else
-	strcat (shell_command, exec_file);
-
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
-    }
-
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
-
-  /* Tell the terminal handling subsystem what tty we plan to run on;
-     it will just record the information for later.  */
-  new_tty_prefork (inferior_io_terminal);
-
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
-      else
-        execvp (argv[0], argv);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
-
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
-
-  if (!have_inferiors ())
-    init_thread_list ();
-
-  inf = current_inferior ();
-
-  inferior_appeared (inf, pid);
-
-  /* Needed for wait_for_inferior stuff below.  */
-  inferior_ptid = pid_to_ptid (pid);
-
-  new_tty_postfork ();
-
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
-}
-
-/* Accept NTRAPS traps from the inferior.  */
-
-void
-startup_inferior (int ntraps)
-{
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
-
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
-
-  if (exec_wrapper)
-    pending_execs++;
-
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
-
-  /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0, NULL);
+  return exec_wrapper;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
@@ -586,7 +74,9 @@ Show the wrapper for running programs."), NULL,
 
   add_setshow_boolean_cmd ("startup-with-shell", class_support,
 			   &startup_with_shell, _("\
-Set use of shell to start subprocesses.  The default is on."), _("\
+Set use of shell to start subprocesses.  The default is on.\n\
+This is also used to determine whether gdbserver will start the remote\n\
+inferior using the shell."), _("\
 Show use of shell to start subprocesses."), NULL,
 			   NULL,
 			   show_startup_with_shell,
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 2add910..2ddcfd6 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,6 +185,7 @@ SFILES = \
 	$(srcdir)/target.c \
 	$(srcdir)/thread-db.c \
 	$(srcdir)/utils.c \
+	$(srcdir)/terminal.c \
 	$(srcdir)/win32-arm-low.c \
 	$(srcdir)/win32-i386-low.c \
 	$(srcdir)/win32-low.c \
@@ -204,6 +205,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-fork-child.c \
 	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
@@ -235,6 +237,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
@@ -269,6 +272,7 @@ OBS = \
 	version.o \
 	waitstatus.o \
 	xml-utils.o \
+	terminal.o \
 	$(DEPFILES) \
 	$(LIBOBJS) \
 	$(XML_BUILTIN)
@@ -772,6 +776,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-fork-child.o: ../common/common-fork-child.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-inflow.o: ../common/common-inflow.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 6b981d0..5f65e99 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,8 @@ struct thread_info *current_thread;
 
 #define get_thread(inf) ((struct thread_info *)(inf))
 
+ptid_t inferior_ptid;
+
 void
 add_inferior_to_list (struct inferior_list *list,
 		      struct inferior_list_entry *new_inferior)
@@ -469,6 +471,23 @@ make_cleanup_restore_current_thread (void)
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
 
+/* See common/common-inferior.h.  */
+
+void
+inferior_appeared (struct inferior *inf, int pid)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-inferior.h.  */
+
+struct inferior *
+current_inferior (void)
+{
+  /* To be implemented.  */
+  return NULL;
+}
+
 /* See common/common-gdbthread.h.  */
 
 void
@@ -510,3 +529,11 @@ add_thread_silent (ptid_t ptid)
 
   return add_thread (ptid_build (pid, pid, 0), NULL);
 }
+
+/* See common/common-inferior.h.  */
+
+int
+have_inferiors (void)
+{
+  return get_first_process () != NULL;
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e3e372c..ea35796 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
-/* Add a process to the common process list, and set its private
-   data.  */
+/* Update process represented by PID with necessary info.  */
 
 static struct process_info *
-linux_add_process (int pid, int attached)
+linux_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
 
-  proc = add_process (pid, attached);
+  gdb_assert (proc != NULL);
   proc->priv = XCNEW (struct process_info_private);
 
   if (the_low_target.new_process != NULL)
@@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return linux_update_process (pid);
+}
+
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
 /* Call the target arch_setup function on the current thread.  */
@@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
   return 1;
 }
 
+/* Update the lwp associated to thread represented by PTID.  */
+
+static struct lwp_info *
+update_thread_lwp (ptid_t ptid)
+{
+  struct lwp_info *lwp;
+  struct thread_info *thread;
+
+  lwp = XCNEW (struct lwp_info);
+
+  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
+  if (the_low_target.new_thread != NULL)
+    the_low_target.new_thread (lwp);
+
+  thread = find_thread_ptid (ptid);
+  gdb_assert (thread != NULL);
+  thread->target_data = lwp;
+  lwp->thread = thread;
+
+  return lwp;
+}
+
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 {
@@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
+
+  setpgid (0, 0);
+
+  /* If gdbserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      close (0);
+      open ("/dev/null", O_RDONLY);
+      dup2 (2, 1);
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args. */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (std::vector<char *> &program_argv)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string program_args = stringify_argv (program_argv);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, startup_shell, NULL);
 
   do_cleanups (restore_personality);
 
-  linux_add_process (pid, 0);
+  linux_update_process (pid);
 
   ptid = ptid_build (pid, pid, 0);
-  new_lwp = add_lwp (ptid);
+  new_lwp = update_thread_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program_argv);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 28a9757..1abf8e3 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
-/* Call add_process with the given parameters, and initializes
-   the process' private data.  */
+/* Update existing process represented by PID with necessary info.  */
 
 static struct process_info *
-lynx_add_process (int pid, int attached)
+lynx_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
+
+  gdb_assert (proc != NULL);
 
-  proc = add_process (pid, attached);
   proc->tdesc = lynx_tdesc;
   proc->priv = XCNEW (struct process_info_private);
   proc->priv->last_wait_event_ptid = null_ptid;
@@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return lynx_update_process (pid);
+}
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect gdbserver. */
+  pgrp = getpid();
+  setpgid (0, pgrp);
+  ioctl (0, TIOCSPGRP, &pgrp);
+  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, startup_shell, NULL);
 
-  lynx_add_process (pid, 0);
+  post_fork_inferior (pid, program_argv);
+
+  lynx_update_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index ce3b8e4..17d3dc9 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM_ARGV.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (std::vector<char *> &program_argv)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string program_args = stringify_argv (program_argv);
 
-  TRACE ("%s %s\n", __func__, program);
+  TRACE ("%s %s\n", __func__, program_argv[0]);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
   signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
 
@@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index ef8dd03..55eebd9 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,31 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "common-terminal.h"
+#include "common-top.h"
+#include "environ.h"
+
+/* We don't have a concept of a UI yet.  Therefore, we just set these
+   to NULL.  */
+
+struct ui *main_ui = NULL;
+struct ui *current_ui = NULL;
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
+
+/* The shell that will be used to start the inferior will be
+   determined later.  */
+
+char *startup_shell = NULL;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +103,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -236,33 +262,64 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_wrapper (void)
 {
-  char **new_argv = argv;
+  static std::string ret;
+  static int initialized_p = 0;
+
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  if (wrapper_argv != NULL)
+  if (!initialized_p)
     {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
+      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
+	   i != wrapper_argv.end ();
+	   ++i)
+	ret += *i + std::string (" ");
+
+      /* Erasing the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = 1;
     }
 
+  return (char *) ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_argv.empty ())
+    error (_("Could not get the exec file."));
+  return program_argv[0];
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See server.h.  */
+
+void
+pre_fork_inferior (std::vector<char *> &argv)
+{
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      int idx = 0;
+
+      for (std::vector<char *>::iterator i = argv.begin ();
+	   i != argv.end ();
+	   ++i, ++idx)
+	debug_printf ("new_argv[%d] = \"%s\"\n", idx, *i);
       debug_flush ();
     }
 
@@ -271,67 +328,35 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid,
+		    std::vector<char *> &argv)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
-
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
-
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
-
-  return signal_pid;
+  startup_inferior (num_traps, &last_status, &last_ptid);
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
+  fflush (stderr);
 }
 
 static int
@@ -2852,8 +2877,10 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
-  int i, new_argc;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
+  int new_argc;
+  int i;
 
   new_argc = 0;
   for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
@@ -2862,62 +2889,91 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
-      if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+      if (p == next_p)
+	new_argv.push_back ("''");
       else
 	{
 	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = 1 + (next_p - p) / 2;
+	  char *s = (char *) xmalloc (len);
+	  char *ss = (char *) xmalloc (len * 2);
+	  char *tmp_s, *tmp_ss;
+	  int need_quote;
+
+	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
+	  s[(next_p - p) / 2] = '\0';
+
+	  tmp_s = s;
+	  tmp_ss = ss;
+	  need_quote = 0;
+	  while (*tmp_s != '\0')
+	    {
+	      switch (*tmp_s)
+		{
+		case '\n':
+		  *tmp_ss = '\'';
+		  ++tmp_ss;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  *tmp_ss = '\\';
+		  ++tmp_ss;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_ss = *tmp_s;
+	      ++tmp_ss;
+	      ++tmp_s;
+	    }
+
+	  if (need_quote)
+	    *tmp_ss++ = '\'';
+
+	  *tmp_ss = '\0';
+	  new_argv.push_back (ss);
+	  xfree (s);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
 
-  if (new_argv[0] == NULL)
+  if (new_argv.empty () || new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
 
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
+      new_argv.push_back (strdup (program_argv[0]));
+      if (new_argv.empty () || new_argv[0] == NULL)
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  create_inferior (program_argv);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3535,13 +3591,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3672,8 +3733,14 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  /* This is called when initializing inflow on GDB.  */
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3687,13 +3754,11 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      create_inferior (program_argv);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4308,9 +4373,9 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      create_inferior (program_argv);
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index f56c0f5..6b3d668 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -103,6 +103,8 @@ extern int swbreak_feature;
    Only enabled if the target supports it.  */
 extern int hwbreak_feature;
 
+extern char *startup_shell;
+
 extern int disable_randomization;
 
 #if USE_WIN32API
@@ -132,6 +134,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -148,4 +151,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* Any pre-processing needed to be done before calling fork_inferior
+   shall be implemented here.  ARGV is a vector containing the full
+   argv of the inferior.  */
+
+extern void pre_fork_inferior (std::vector<char *> &argv);
+
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and ARGV is the vector containing the full
+   argv of the inferior.  */
+
+extern void post_fork_inferior (int pid,
+				std::vector<char *> &argv);
+
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 32e7c72..ccf736f 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, 0, 0);
+  setpgid (0, 0);
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM_ARGV is a vector of program-name and args. */
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string program_args = stringify_argv (program_argv);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
+  pre_fork_inferior (program_argv);
 
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, startup_shell, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program_argv);
 
-  proc = add_process (pid, 0);
+  proc = find_process_pid (pid);
+  gdb_assert (proc != NULL);
   proc->tdesc = tdesc_spu;
 
-  ptid = ptid_build (pid, pid, 0);
-  add_thread (ptid, NULL);
   return pid;
 }
 
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index 249a063..56c734c 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index d098a92..3e74b86 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -73,7 +74,7 @@ struct target_ops
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
 
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (std::vector<char *> &program_argv);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program) \
+  (*the_target->create_inferior) (program)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 37b9c89..8fa3ce5 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,40 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (std::vector<char *>::iterator i = v.begin ();
+       i != v.end ();
+       ++i)
+    xfree (*i);
+
+  v.clear ();
+}
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (std::vector<char *> &argv)
+{
+  std::string ret ("");
+
+  for (std::vector<char *>::iterator i = argv.begin () + 1;
+       i != argv.end ();
+       ++i)
+    ret += *i + std::string (" ");
+
+  return ret;
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index 5e0cead..20c8dcd 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,7 +19,19 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
+/* Works like FREEARGV, but with std::vector.  */
+
+extern void free_vector_argv (std::vector<char *> &v);
+
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments (starting from ARGV + 1) with a
+   whitespace separating them.  */
+
+extern std::string stringify_argv (std::vector<char *> &argv);
+
 #endif /* UTILS_H */
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 70abfcd..1f7f538 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,11 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM_ARGV is the vector containing the inferior's argv.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (std::vector<char *> &program_argv)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  char *program = program_argv[0];
+  std::string program_args = stringify_argv (program_argv);
+  char *args = (char *) program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
 
   flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
 
+  pre_fork_inferior (program, argv);
+
 #ifndef USE_WIN32API
   orig_path = NULL;
   path_ptr = getenv ("PATH");
@@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
@@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
 
   do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
+  post_fork_inferior (current_process_id, program_argv);
+
   return current_process_id;
 }
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 85a53b8..3e2e226 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 64aaabe..ceb1422 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 403c096..6dae6b2 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -42,6 +42,7 @@ struct target_desc_info;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 
@@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
 
 extern void child_terminal_init_with_pgrp (int pgrp);
 
-/* From fork-child.c */
-
-extern int fork_inferior (char *, char *, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
-
 extern char *construct_inferior_arguments (int, char **);
 
 /* From infcmd.c */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index ff814ba..5b64618 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4380,7 +4380,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
diff --git a/gdb/target.h b/gdb/target.h
index a54b3db..adec5f2 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 2f4c716..2f0d8ba 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index f68029d..efdfb58 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled.
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/top.h b/gdb/top.h
index 482ed3e..0c057d7 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -22,6 +22,7 @@
 
 #include "buffer.h"
 #include "event-loop.h"
+#include "common-top.h"
 
 struct tl_interp_info;
 
@@ -144,14 +145,6 @@ struct ui
   struct ui_out *m_current_uiout;
 };
 
-/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
-   It always exists and is created automatically when GDB starts
-   up.  */
-extern struct ui *main_ui;
-
-/* The current UI.  */
-extern struct ui *current_ui;
-
 /* The list of all UIs.  */
 extern struct ui *ui_list;
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 6bf3716..026e9d7 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3435,6 +3435,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (2 preceding siblings ...)
  2016-12-23  3:39 ` [PATCH 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
@ 2016-12-23  3:45 ` Sergio Durigan Junior
  2016-12-26 21:35   ` Luis Machado
  2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:45 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

Again, it was necessary to share a few functions declared on
gdb/gdbthread.h with gdbserver, because they are needed by
fork_inferior.  I decided to implement them on
gdb/gdbserver/inferiors.c because that's where the thread functions
are also implemented on gdbserver.  As a side note, due to the way
gdbserver marks a thread as executing, a new argument needed to be
added on set_executing.  This argument is a 'struct target_waitstatus
*', and is not necessary on GDB, so it was marked with
ATTRIBUTE_UNUSED accordingly.

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* fork-child.c (fork_inferior): Update call of "set_executing".
	* gdbthread.h: Include "common-gdbthread.h".
	(init_thread_list): Moved to "common/common-gdbthread.h".
	(add_thread_silent): Likewise.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.  Added an extra argument, "struct
	target_waitstatus *".
	* infrun.c (handle_inferior_event_1): Update call of
	"set_executing".
	* linux-nat.c (attach_proc_task_lwp_callback): Likewise.
	(linux_handle_extended_wait): Likewise.
	* record-btrace.c (get_thread_current_frame): Likewise.
	* record-full.c (record_full_wait_1): Likewise.
	* remote.c (remote_add_thread): Likewise.
	(process_initial_stop_replies): Likewise.
	* solib-spu.c (spu_skip_standalone_loader): Likewise.
	* target.c (target_resume): Likewise.
	* thread.c (set_executing): Update function declaration to add
	third argument.  Mark it as unused.

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (init_thread_list): New function.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	(add_thread_silent): Likewise.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 50 +++++++++++++++++++++++++++++++++++++++++++
 gdb/fork-child.c              |  2 +-
 gdb/gdbserver/inferiors.c     | 42 ++++++++++++++++++++++++++++++++++++
 gdb/gdbthread.h               | 20 +----------------
 gdb/infrun.c                  |  2 +-
 gdb/linux-nat.c               |  4 ++--
 gdb/record-btrace.c           |  6 +++---
 gdb/record-full.c             |  4 ++--
 gdb/remote.c                  |  4 ++--
 gdb/solib-spu.c               |  2 +-
 gdb/target.c                  |  2 +-
 gdb/thread.c                  |  5 ++++-
 13 files changed, 111 insertions(+), 33 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8372b4a..ca13a80 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..3560892
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,50 @@
+/* Multi-process/thread control defs for GDB, the GNU debugger.
+   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
+   
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_THREAD_H
+#define COMMON_THREAD_H
+
+struct target_waitstatus;
+
+/* Create an empty thread list, or empty the existing one.  */
+
+extern void init_thread_list (void);
+
+/* Switch from one thread to another.  */
+
+extern void switch_to_thread (ptid_t ptid);
+
+/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
+   marks all threads.
+
+   Note that this is different from the running state.  See the
+   description of state and executing fields of struct
+   thread_info.  */
+
+extern void set_executing (ptid_t ptid, int executing,
+			   struct target_waitstatus *ws);
+
+/* Add a thread to the thread list and return the pointer to the new
+   thread.  Caller may use this pointer to initialize the private
+   thread data.  */
+
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+#endif /* ! COMMON_THREAD_H */
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 15f8249..38fca60 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -545,7 +545,7 @@ startup_inferior (int ntraps)
     }
 
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  set_executing (resume_ptid, 0, NULL);
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 574a7ba..6b981d0 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,45 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+init_thread_list (void)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED,
+	       struct target_waitstatus *ws)
+{
+  gdb_assert (current_thread != NULL);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = *ws;
+}
+
+/* See common/common-gdbthread.h.  */
+
+struct thread_info *
+add_thread_silent (ptid_t ptid)
+{
+  pid_t pid = ptid_get_pid (ptid);
+
+  /* Check if there is a process already.  */
+  if (find_process_pid (pid) == NULL)
+    add_process (pid, 0);
+
+  return add_thread (ptid_build (pid, pid, 0), NULL);
+}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 8f37fbb..d6fdc42 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -31,6 +31,7 @@ struct symtab;
 #include "common/vec.h"
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -344,19 +345,12 @@ struct thread_info
   struct thread_info *step_over_next;
 };
 
-/* Create an empty thread list, or empty the existing one.  */
-extern void init_thread_list (void);
-
 /* Add a thread to the thread list, print a message
    that a new thread is found, and return the pointer to
    the new thread.  Caller my use this pointer to 
    initialize the private thread data.  */
 extern struct thread_info *add_thread (ptid_t ptid);
 
-/* Same as add_thread, but does not print a message
-   about new thread.  */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
-
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
 						 struct private_thread_info *);
@@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
@@ -518,14 +508,6 @@ extern int is_exited (ptid_t ptid);
 /* In the frontend's perpective, is this thread stopped?  */
 extern int is_stopped (ptid_t ptid);
 
-/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
-   marks all threads.
-
-   Note that this is different from the running state.  See the
-   description of state and executing fields of struct
-   thread_info.  */
-extern void set_executing (ptid_t ptid, int executing);
-
 /* Reports if thread PTID is executing.  */
 extern int is_executing (ptid_t ptid);
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index bf0632e..f5cc965 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4947,7 +4947,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
     else
       mark_ptid = ecs->ptid;
 
-    set_executing (mark_ptid, 0);
+    set_executing (mark_ptid, 0, NULL);
 
     /* Likewise the resumed flag.  */
     set_resumed (mark_ptid, 0);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index cbf94ed..9db620c 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1190,7 +1190,7 @@ attach_proc_task_lwp_callback (ptid_t ptid)
 	     raw clone).  */
 	  add_thread (lp->ptid);
 	  set_running (lp->ptid, 1);
-	  set_executing (lp->ptid, 1);
+	  set_executing (lp->ptid, 1, NULL);
 	}
 
       return 1;
@@ -2083,7 +2083,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
 	     and the user/frontend, this new thread is running until
 	     it next reports a stop.  */
 	  set_running (new_lp->ptid, 1);
-	  set_executing (new_lp->ptid, 1);
+	  set_executing (new_lp->ptid, 1, NULL);
 
 	  if (WSTOPSIG (status) != SIGSTOP)
 	    {
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 7c0e39f..80cf274 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1928,7 +1928,7 @@ get_thread_current_frame (struct thread_info *tp)
      move the thread.  Since we need to recompute the stack, we temporarily
      set EXECUTING to flase.  */
   executing = is_executing (inferior_ptid);
-  set_executing (inferior_ptid, 0);
+  set_executing (inferior_ptid, 0, NULL);
 
   frame = NULL;
   TRY
@@ -1938,7 +1938,7 @@ get_thread_current_frame (struct thread_info *tp)
   CATCH (except, RETURN_MASK_ALL)
     {
       /* Restore the previous execution state.  */
-      set_executing (inferior_ptid, executing);
+      set_executing (inferior_ptid, executing, NULL);
 
       /* Restore the previous inferior_ptid.  */
       inferior_ptid = old_inferior_ptid;
@@ -1948,7 +1948,7 @@ get_thread_current_frame (struct thread_info *tp)
   END_CATCH
 
   /* Restore the previous execution state.  */
-  set_executing (inferior_ptid, executing);
+  set_executing (inferior_ptid, executing, NULL);
 
   /* Restore the previous inferior_ptid.  */
   inferior_ptid = old_inferior_ptid;
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 5608e70..3ad9a08 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1156,12 +1156,12 @@ record_full_wait_1 (struct target_ops *ops,
 			{
 			  /* Try to insert the software single step breakpoint.
 			     If insert success, set step to 0.  */
-			  set_executing (inferior_ptid, 0);
+			  set_executing (inferior_ptid, 0, NULL);
 			  reinit_frame_cache ();
 
 			  step = !insert_single_step_breakpoints (gdbarch);
 
-			  set_executing (inferior_ptid, 1);
+			  set_executing (inferior_ptid, 1, NULL);
 			}
 
 		      if (record_debug)
diff --git a/gdb/remote.c b/gdb/remote.c
index ef6c54e..0b5f837 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1847,7 +1847,7 @@ remote_add_thread (ptid_t ptid, int running, int executing)
     thread = add_thread (ptid);
 
   get_private_info_thread (thread)->vcont_resumed = executing;
-  set_executing (ptid, executing);
+  set_executing (ptid, executing, NULL);
   set_running (ptid, running);
 }
 
@@ -3949,7 +3949,7 @@ process_initial_stop_replies (int from_tty)
 	  || ws.value.sig != GDB_SIGNAL_0)
 	thread->suspend.waitstatus_pending_p = 1;
 
-      set_executing (event_ptid, 0);
+      set_executing (event_ptid, 0, NULL);
       set_running (event_ptid, 0);
       thread->priv->vcont_resumed = 0;
     }
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index fa2977e..f55e0a0 100644
--- a/gdb/solib-spu.c
+++ b/gdb/solib-spu.c
@@ -88,7 +88,7 @@ spu_skip_standalone_loader (void)
 
       target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
       target_wait (minus_one_ptid, &ws, 0);
-      set_executing (minus_one_ptid, 0);
+      set_executing (minus_one_ptid, 0, NULL);
 
       inferior_thread ()->control.in_infcall = 0;
     }
diff --git a/gdb/target.c b/gdb/target.c
index 246d292..e7c68bf 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2325,7 +2325,7 @@ target_resume (ptid_t ptid, int step, enum gdb_signal signal)
   registers_changed_ptid (ptid);
   /* We only set the internal executing state here.  The user/frontend
      running state is set at a higher level.  */
-  set_executing (ptid, 1);
+  set_executing (ptid, 1, NULL);
   clear_inline_frame_state (ptid);
 }
 
diff --git a/gdb/thread.c b/gdb/thread.c
index e5d6c5f..1114aac 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1011,8 +1011,11 @@ is_executing (ptid_t ptid)
   return tp->executing;
 }
 
+/* See common/common-gdbthread.h.  */
+
 void
-set_executing (ptid_t ptid, int executing)
+set_executing (ptid_t ptid, int executing,
+	       struct target_waitstatus *ws ATTRIBUTE_UNUSED)
 {
   struct thread_info *tp;
   int all = ptid_equal (ptid, minus_one_ptid);
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (4 preceding siblings ...)
  2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2016-12-23  3:49 ` Sergio Durigan Junior
  2016-12-23  8:07   ` Eli Zaretskii
                     ` (2 more replies)
  2016-12-23  7:50 ` [PATCH 0/6] Implement the ability to start inferiors with a shell " Eli Zaretskii
                   ` (4 subsequent siblings)
  10 siblings, 3 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2016-12-23  3:49 UTC (permalink / raw)
  To: GDB Patches; +Cc: palves, Sergio Durigan Junior

This patch implements the proper support for the "startup-with-shell"
feature on gdbserver.  A new packet is added, QStartupShell, and this
packet is sent on initialization.  If the host sends a
"QStartupShell:" (i.e., without arguments), it means the inferior
shall be started without using a shell.  Otherwise, the argument on
the packet is the shell to be used to start the inferior.

I decided to use the "startup-with-shell" setting from the host in
order to decide whether to start the remote inferior using a shell or
not.  However, since there is no easy way to change which shell to use
when starting things, I have also added a new command, "set/show
remote startup-shell", which can contain the shell that the remote
target will use.

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

gdb/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* remote.c (remote_startup_shell_var): New variable.
	(set_remote_startup_shell): New function.
	(show_remote_startup_shell): Likewise.
	Add PACKET_QStartupShell.
	(remote_start_remote): Handle new PACKET_QStartupShell.
	(struct protocol_feature remote_protocol_features): New entry for
	PACKET_QStartupShell.
	(_initialize_remote): Call "add_packet_config_cmd" for
	QStartupShell.  Add new set/show command "set remote
	startup-shell".

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* server.c (handle_general_set): Handle new packet
	"QStartupShell".
	(handle_query): Add "QStartupShell" to the list of supported
	packets.

gdb/testsuite/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* gdb.texinfo (startup-with-shell): Add note mentioning that the
	setting is also used by remote targets.
	(set remote startup-shell): New item.
---
 gdb/doc/gdb.texinfo                             |  14 +++
 gdb/gdbserver/server.c                          |  22 ++++-
 gdb/remote.c                                    |  62 +++++++++++++
 gdb/testsuite/gdb.server/startup-with-shell.c   |  12 +++
 gdb/testsuite/gdb.server/startup-with-shell.exp | 110 ++++++++++++++++++++++++
 5 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a0de7d1..3250cae 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2174,6 +2174,10 @@ initialization file---such as @file{.cshrc} for C-shell,
 $@file{.zshenv} for the Z shell, or the file specified in the
 @samp{BASH_ENV} environment variable for BASH.
 
+This setting is also used by @code{target extended-remote} to
+determine whether the target system will start the inferior using the
+shell (@pxref{set remote startup-shell}).
+
 @anchor{set auto-connect-native-target}
 @kindex set auto-connect-native-target
 @item set auto-connect-native-target
@@ -20486,6 +20490,16 @@ extended-remote}.  This should be set to a filename valid on the
 target system.  If it is not set, the target will use a default
 filename (e.g.@: the last program run).
 
+@item set remote startup-shell @var{shell}
+@itemx show remote startup-shell
+@anchor{set remote startup-shell}
+@cindex startup shell, for remote target
+Set the shell that is going to be used to start the inferior with
+@code{target extended-remote}.  This should be set to a valid shell on
+the target system, and is only effective when
+@code{startup-with-shell} is on.  If it is not set, the target system
+will use the shell pointed by the @code{SHELL} environment variable.
+
 @item set remote interrupt-sequence
 @cindex interrupt remote programs
 @cindex select Ctrl-C, BREAK or BREAK-g
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 55eebd9..5faf0b5 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -863,6 +863,26 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupShell:"))
+    {
+      const char *p = own_buf + strlen ("QStartupShell:");
+
+      if (*p == '\0')
+	{
+	  startup_with_shell = 0;
+	  xfree (startup_shell);
+	}
+      else
+	{
+	  startup_with_shell = 1;
+	  xfree (startup_shell);
+	  startup_shell = xstrdup (p);
+	}
+
+      write_ok (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -2299,7 +2319,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+;QStartupShell+",
 	       PBUFSIZ - 1);
 
       if (target_supports_catch_syscall ())
diff --git a/gdb/remote.c b/gdb/remote.c
index 0b5f837..2d2a87a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -86,6 +86,12 @@ static const struct program_space_data *remote_pspace_data;
    location of the remote exec-file value.  */
 static char *remote_exec_file_var;
 
+/* The variable that holds the startup shell that will be used by the
+   remote target to start the inferior.  If this variable is NULL or
+   empty, we use the value of 'get_startup_shell'.  */
+
+static char *remote_startup_shell_var;
+
 /* The size to align memory write packets, when practical.  The protocol
    does not guarantee any alignment, and gdb will generate short
    writes and unaligned writes, but even as a best-effort attempt this
@@ -727,6 +733,22 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
   fprintf_filtered (file, "%s\n", remote_exec_file_var);
 }
 
+/* The "set/show remote startup-shell" set command hook.  */
+
+static void
+set_remote_startup_shell (char *ignored, int from_tty,
+			  struct cmd_list_element *c)
+{
+  gdb_assert (remote_startup_shell_var != NULL);
+}
+
+static void
+show_remote_startup_shell (struct ui_file *file, int from_tty,
+			   struct cmd_list_element *cmd, const char *value)
+{
+  fprintf_filtered (file, "%s\n", remote_startup_shell_var);
+}
+
 static int
 compare_pnums (const void *lhs_, const void *rhs_)
 {
@@ -1423,6 +1445,7 @@ enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QStartupShell,
   PACKET_qCRC,
   PACKET_qSearch_memory,
   PACKET_vAttach,
@@ -4074,6 +4097,31 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     remote_set_permissions (target);
 
+  if (packet_support (PACKET_QStartupShell) != PACKET_DISABLE)
+    {
+      if (startup_with_shell)
+	{
+	  const char *sh;
+
+	  if (remote_startup_shell_var != NULL
+	      && *remote_startup_shell_var != '\0')
+	    sh = remote_startup_shell_var;
+	  else
+	    sh = get_startup_shell ();
+
+	  xsnprintf (rs->buf, get_remote_packet_size (),
+		     "QStartupShell:%s", sh);
+	}
+      else
+	xsnprintf (rs->buf, get_remote_packet_size (),
+		   "QStartupShell:");
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      if (strcmp (rs->buf, "OK") != 0)
+	error (_("Could not set remote startup-with-shell"));
+    }
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an
@@ -4628,6 +4676,8 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_QCatchSyscalls },
   { "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
     PACKET_QProgramSignals },
+  { "QStartupShell", PACKET_DISABLE, remote_supported_packet,
+    PACKET_QStartupShell },
   { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
     PACKET_QStartNoAckMode },
   { "multiprocess", PACKET_DISABLE, remote_supported_packet,
@@ -14081,6 +14131,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_QStartupShell],
+			 "QStartupShell", "startup-shell", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol],
 			 "qSymbol", "symbol-lookup", 0);
 
@@ -14380,6 +14433,15 @@ Show the remote pathname for \"run\""), NULL,
 				   &remote_set_cmdlist,
 				   &remote_show_cmdlist);
 
+  add_setshow_string_noescape_cmd ("startup-shell", class_files,
+				   &remote_startup_shell_var, _("\
+Set the remote shell for starting the inferior"), _("\
+Show the remote shell for starting the inferior"), NULL,
+				   set_remote_startup_shell,
+				   show_remote_startup_shell,
+				   &remote_set_cmdlist,
+				   &remote_show_cmdlist);
+
   add_setshow_boolean_cmd ("range-stepping", class_run,
 			   &use_range_stepping, _("\
 Enable or disable range stepping."), _("\
diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
new file mode 100644
index 0000000..ba77b10
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.c
@@ -0,0 +1,12 @@
+#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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
new file mode 100644
index 0000000..1bf3654
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
@@ -0,0 +1,110 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2016 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/>.
+
+# Test startup-with-shell support using extended-remote.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+if { [skip_gdbserver_tests] } {
+    return 0
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    untested "failed to compile"
+    return -1
+}
+
+# Initial setup for simple test (wildcard expansion, variable substitution).
+
+proc initial_setup_simple { startup_with_shell run_args } {
+    global hex decimal binfile
+
+    clean_restart $binfile
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+
+    gdb_test_no_output "set startup-with-shell $startup_with_shell"
+
+    set target_exec [gdbserver_download_current_prog]
+    gdbserver_start_extended
+    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+
+    gdb_breakpoint main
+
+    gdb_test "run $run_args" \
+	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
+	"run to main"
+}
+
+proc invalid_remote_shell_test { } {
+    global binfile
+
+    clean_restart $binfile
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+
+    gdb_test_no_output "set startup-with-shell on"
+    gdb_test_no_output "set remote startup-shell /path/to/invalid/shell"
+
+    set target_exec [gdbserver_download_current_prog]
+    gdbserver_start_extended
+    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+
+    gdb_breakpoint main
+
+    gdb_test "run" \
+	"Running \"$binfile\" on the remote target failed" \
+	"run to main (should fail)"
+}
+
+## Doing the actual tests
+
+with_test_prefix "startup_with_shell = on; run_args = *.log" {
+    initial_setup_simple "on" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
+	"testing first argument"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.log" {
+    initial_setup_simple "off" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
+	"testing first argument"
+}
+
+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)
+}
+
+with_test_prefix "startup_with_shell = on; invalid remote startup-shell" {
+    invalid_remote_shell_test
+}
-- 
2.7.4

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (5 preceding siblings ...)
  2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2016-12-23  7:50 ` Eli Zaretskii
  2017-01-03 20:23   ` Sergio Durigan Junior
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 157+ messages in thread
From: Eli Zaretskii @ 2016-12-23  7:50 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: palves@redhat.com
> Date: Thu, 22 Dec 2016 22:39:15 -0500
> 
> This patch series took a long time to complete due to many and varied
> reasons, but finally here it is.
> 
> It implements the "startup-with-shell" feature on gdbserver.  This
> means that it will be possible to start inferiors using the shell
> (instead of calling execv*), which brings many advantages.
> 
> First of all, it will be possible to use I/O redirection, variable
> substitution and globbing expansion on gdbserver just like we do today
> on GDB.  This is great because, among other things, it brings
> gdbserver on a pair with GDB when considering the Feature Parity
> project.

In Windows native debugging, GDB doesn't use the shell to start the
inferior, but redirection is still supported via special code in
windows-nat.c.  Can this be made available also in gdbserver?

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2016-12-23  8:07   ` Eli Zaretskii
  2017-01-03 20:48     ` Sergio Durigan Junior
  2016-12-26 21:34   ` Luis Machado
  2016-12-27  0:26   ` Tom Tromey
  2 siblings, 1 reply; 157+ messages in thread
From: Eli Zaretskii @ 2016-12-23  8:07 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: palves@redhat.com, Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Thu, 22 Dec 2016 22:39:21 -0500
> 
> gdb/doc/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* gdb.texinfo (startup-with-shell): Add note mentioning that the
> 	setting is also used by remote targets.
> 	(set remote startup-shell): New item.

The text in parentheses should be the name of the node where you make
the change.  If you want to refer to specific symbols within the node,
either mention them as part of the text or put them in <..>, like
this:

  * gdb.texinfo (Starting) <startup-with-shell>: Add note ...

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index a0de7d1..3250cae 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -2174,6 +2174,10 @@ initialization file---such as @file{.cshrc} for C-shell,
>  $@file{.zshenv} for the Z shell, or the file specified in the
>  @samp{BASH_ENV} environment variable for BASH.
>  
> +This setting is also used by @code{target extended-remote} to
> +determine whether the target system will start the inferior using the
> +shell (@pxref{set remote startup-shell}).

I would add here a qualification: only on Unix-like target systems.
(Is it true that this is a necessary condition for the applicability
of that feature?)

> +@item set remote startup-shell @var{shell}
> +@itemx show remote startup-shell
> +@anchor{set remote startup-shell}
> +@cindex startup shell, for remote target
> +Set the shell that is going to be used to start the inferior with
> +@code{target extended-remote}.  This should be set to a valid shell on
> +the target system, and is only effective when
> +@code{startup-with-shell} is on.  If it is not set, the target system
> +will use the shell pointed by the @code{SHELL} environment variable.

Three comments on this:

  . What is a "valid shell" in this context?  Is the DOS command.com a
    valid shell, for example (probably not)?  I think we should be
    more explicit about which shells are acceptable.

  . What exactly is the value supposed to be?  Is it a full absolute
    file name of the shell executable?  We should say so explicitly,
    IMO.

  . Does it really make sense to require that both this option and
    startup-with-shell be on?  Why cannot the user set only this
    option to achieve that effect, with some special value standing
    for "use $SHELL"?  Also, is it possible that a user will want
    remote targets to use a shell, while avoiding that for native
    debugging, in the same session?

A minor nit: environment variables should have the @env markup, not
@code.

I think this warrants a NEWS entry.

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver
  2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
@ 2016-12-26 21:34   ` Luis Machado
  2017-01-03 21:16     ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2016-12-26 21:34 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> After sharing parts of gdb/terminal.h, it is also needed to share the
> two functions on gdb/inflow.c that are going to be needed by the
> fork_inferior sharing.  They are 'gdb_setpgid' and the new
> 'have_job_control'.
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/common-inflow.c".
> 	(COMMON_OBS): Add "common/common-inflow.o".
> 	* common/common-inflow.c: New file, with contents from
> 	"gdb/inflow.c".
> 	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
> 	(_initialize_inflow): Move setting of "job_control" to a specific
> 	function on "common/common-inflow.c".
> 	* utils.c (job_control): Delete.
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in: Add rule for "common-inflow.o".
> 	(SFILE): Add "common/common-inflow.c".
> 	(OBS): Add "common-inflow.o".
> ---
>  gdb/Makefile.in            |  2 +
>  gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/Makefile.in  |  5 +++
>  gdb/inflow.c               | 63 +-------------------------------
>  gdb/utils.c                |  4 --
>  5 files changed, 100 insertions(+), 65 deletions(-)
>  create mode 100644 gdb/common/common-inflow.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 51c0f73..8372b4a 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1195,6 +1195,7 @@ SFILES = \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> +	common/common-inflow.c \
>  	common/gdb_vecs.c \
>  	common/new-op.c \
>  	common/print-utils.c \
> @@ -1622,6 +1623,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	common-agent.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
>  	complaints.o \
> diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
> new file mode 100644
> index 0000000..595eb51
> --- /dev/null
> +++ b/gdb/common/common-inflow.c
> @@ -0,0 +1,91 @@
> +/* Low level interface to ptrace, for GDB when running under Unix.
> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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 "common-defs.h"
> +#include "common-terminal.h"
> +
> +/* Nonzero if we have job control.  */
> +

Spurious newline?

> +int job_control;
> +
> +/* This is here because this is where we figure out whether we (probably)
> +   have job control.  Just using job_control only does part of it because
> +   setpgid or setpgrp might not exist on a system without job control.
> +   It might be considered misplaced (on the other hand, process groups and
> +   job control are closely related to ttys).
> +
> +   For a more clean implementation, in libiberty, put a setpgid which merely
> +   calls setpgrp and a setpgrp which does nothing (any system with job control
> +   will have one or the other).  */

newline between comment and function.

> +int
> +gdb_setpgid (void)
> +{
> +  int retval = 0;
> +
> +  if (job_control)
> +    {
> +#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
> +#ifdef HAVE_SETPGID
> +      /* The call setpgid (0, 0) is supposed to work and mean the same
> +         thing as this, but on Ultrix 4.2A it fails with EPERM (and
> +         setpgid (getpid (), getpid ()) succeeds).  */
> +      retval = setpgid (getpid (), getpid ());
> +#else
> +#ifdef HAVE_SETPGRP
> +#ifdef SETPGRP_VOID
> +      retval = setpgrp ();
> +#else
> +      retval = setpgrp (getpid (), getpid ());
> +#endif
> +#endif /* HAVE_SETPGRP */
> +#endif /* HAVE_SETPGID */
> +#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
> +    }
> +
> +  return retval;
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +have_job_control (void)
> +{
> +  /* OK, figure out whether we have job control.  If neither termios nor
> +     sgtty (i.e. termio or go32), leave job_control 0.  */
> +#if defined (HAVE_TERMIOS)
> +  /* Do all systems with termios have the POSIX way of identifying job
> +     control?  I hope so.  */
> +#ifdef _POSIX_JOB_CONTROL
> +  job_control = 1;
> +#else
> +#ifdef _SC_JOB_CONTROL
> +  job_control = sysconf (_SC_JOB_CONTROL);
> +#else
> +  job_control = 0;		/* Have to assume the worst.  */
> +#endif /* _SC_JOB_CONTROL */
> +#endif /* _POSIX_JOB_CONTROL */
> +#endif /* HAVE_TERMIOS */
> +
> +#ifdef HAVE_SGTTY
> +#ifdef TIOCGPGRP
> +  job_control = 1;
> +#else
> +  job_control = 0;
> +#endif /* TIOCGPGRP */
> +#endif /* sgtty */
> +}
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index fe40842..2add910 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -204,6 +204,7 @@ SFILES = \
>  	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
> +	$(srcdir)/common/common-inflow.c \
>  	$(srcdir)/common/gdb_vecs.c \
>  	$(srcdir)/common/new-op.c \
>  	$(srcdir)/common/print-utils.c \
> @@ -234,6 +235,7 @@ OBS = \
>  	cleanups.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
>  	debug.o \
> @@ -770,6 +772,9 @@ format.o: ../common/format.c
>  filestuff.o: ../common/filestuff.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +common-inflow.o: ../common/common-inflow.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  agent.o: ../common/agent.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> diff --git a/gdb/inflow.c b/gdb/inflow.c
> index 5b55cec..80909ea 100644
> --- a/gdb/inflow.c
> +++ b/gdb/inflow.c
> @@ -803,43 +803,6 @@ create_tty_session (void)
>  #endif /* HAVE_SETSID */
>  }
>
> -/* This is here because this is where we figure out whether we (probably)
> -   have job control.  Just using job_control only does part of it because
> -   setpgid or setpgrp might not exist on a system without job control.
> -   It might be considered misplaced (on the other hand, process groups and
> -   job control are closely related to ttys).
> -
> -   For a more clean implementation, in libiberty, put a setpgid which merely
> -   calls setpgrp and a setpgrp which does nothing (any system with job control
> -   will have one or the other).  */
> -int
> -gdb_setpgid (void)
> -{
> -  int retval = 0;
> -
> -  if (job_control)
> -    {
> -#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
> -#ifdef HAVE_SETPGID
> -      /* The call setpgid (0, 0) is supposed to work and mean the same
> -         thing as this, but on Ultrix 4.2A it fails with EPERM (and
> -         setpgid (getpid (), getpid ()) succeeds).  */
> -      retval = setpgid (getpid (), getpid ());
> -#else
> -#ifdef HAVE_SETPGRP
> -#ifdef SETPGRP_VOID
> -      retval = setpgrp ();
> -#else
> -      retval = setpgrp (getpid (), getpid ());
> -#endif
> -#endif /* HAVE_SETPGRP */
> -#endif /* HAVE_SETPGID */
> -#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
> -    }
> -
> -  return retval;
> -}
> -
>  /* Get all the current tty settings (including whether we have a
>     tty at all!).  We can't do this in _initialize_inflow because
>     serial_fdopen() won't work until the serial_ops_list is
> @@ -860,30 +823,8 @@ _initialize_inflow (void)
>
>    terminal_is_ours = 1;
>
> -  /* OK, figure out whether we have job control.  If neither termios nor
> -     sgtty (i.e. termio or go32), leave job_control 0.  */
> -
> -#if defined (HAVE_TERMIOS)
> -  /* Do all systems with termios have the POSIX way of identifying job
> -     control?  I hope so.  */
> -#ifdef _POSIX_JOB_CONTROL
> -  job_control = 1;
> -#else
> -#ifdef _SC_JOB_CONTROL
> -  job_control = sysconf (_SC_JOB_CONTROL);
> -#else
> -  job_control = 0;		/* Have to assume the worst.  */
> -#endif /* _SC_JOB_CONTROL */
> -#endif /* _POSIX_JOB_CONTROL */
> -#endif /* HAVE_TERMIOS */
> -
> -#ifdef HAVE_SGTTY
> -#ifdef TIOCGPGRP
> -  job_control = 1;
> -#else
> -  job_control = 0;
> -#endif /* TIOCGPGRP */
> -#endif /* sgtty */
> +  /* OK, figure out whether we have job control.  */
> +  have_job_control ();
>
>    observer_attach_inferior_exit (inflow_inferior_exit);
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index bc1dfe5..6bf3716 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
>
>  static int debug_timestamp = 0;
>
> -/* Nonzero if we have job control.  */
> -
> -int job_control;
> -
>  /* Nonzero means that strings with character values >0x7F should be printed
>     as octal escapes.  Zero means just print the value (e.g. it's an
>     international character, and the terminal or window can cope.)  */
>

Otherwise looks fine.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  2016-12-23  8:07   ` Eli Zaretskii
@ 2016-12-26 21:34   ` Luis Machado
  2017-01-03 21:35     ` Sergio Durigan Junior
  2016-12-27  0:26   ` Tom Tromey
  2 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2016-12-26 21:34 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> This patch implements the proper support for the "startup-with-shell"
> feature on gdbserver.  A new packet is added, QStartupShell, and this
> packet is sent on initialization.  If the host sends a
> "QStartupShell:" (i.e., without arguments), it means the inferior
> shall be started without using a shell.  Otherwise, the argument on
> the packet is the shell to be used to start the inferior.
>
> I decided to use the "startup-with-shell" setting from the host in
> order to decide whether to start the remote inferior using a shell or
> not.  However, since there is no easy way to change which shell to use
> when starting things, I have also added a new command, "set/show
> remote startup-shell", which can contain the shell that the remote
> target will use.
>
> A documentation patch is included, along with a new testcase for the
> feature.
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* remote.c (remote_startup_shell_var): New variable.
> 	(set_remote_startup_shell): New function.
> 	(show_remote_startup_shell): Likewise.
> 	Add PACKET_QStartupShell.
> 	(remote_start_remote): Handle new PACKET_QStartupShell.
> 	(struct protocol_feature remote_protocol_features): New entry for
> 	PACKET_QStartupShell.
> 	(_initialize_remote): Call "add_packet_config_cmd" for
> 	QStartupShell.  Add new set/show command "set remote
> 	startup-shell".
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* server.c (handle_general_set): Handle new packet
> 	"QStartupShell".
> 	(handle_query): Add "QStartupShell" to the list of supported
> 	packets.
>
> gdb/testsuite/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* gdb.server/startup-with-shell.c: New file.
> 	* gdb.server/startup-with-shell.exp: Likewise.
>
> gdb/doc/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* gdb.texinfo (startup-with-shell): Add note mentioning that the
> 	setting is also used by remote targets.
> 	(set remote startup-shell): New item.
> ---
>  gdb/doc/gdb.texinfo                             |  14 +++
>  gdb/gdbserver/server.c                          |  22 ++++-
>  gdb/remote.c                                    |  62 +++++++++++++
>  gdb/testsuite/gdb.server/startup-with-shell.c   |  12 +++
>  gdb/testsuite/gdb.server/startup-with-shell.exp | 110 ++++++++++++++++++++++++
>  5 files changed, 219 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index a0de7d1..3250cae 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -2174,6 +2174,10 @@ initialization file---such as @file{.cshrc} for C-shell,
>  $@file{.zshenv} for the Z shell, or the file specified in the
>  @samp{BASH_ENV} environment variable for BASH.
>
> +This setting is also used by @code{target extended-remote} to
> +determine whether the target system will start the inferior using the
> +shell (@pxref{set remote startup-shell}).
> +
>  @anchor{set auto-connect-native-target}
>  @kindex set auto-connect-native-target
>  @item set auto-connect-native-target
> @@ -20486,6 +20490,16 @@ extended-remote}.  This should be set to a filename valid on the
>  target system.  If it is not set, the target will use a default
>  filename (e.g.@: the last program run).
>
> +@item set remote startup-shell @var{shell}
> +@itemx show remote startup-shell
> +@anchor{set remote startup-shell}
> +@cindex startup shell, for remote target
> +Set the shell that is going to be used to start the inferior with
> +@code{target extended-remote}.  This should be set to a valid shell on
> +the target system, and is only effective when
> +@code{startup-with-shell} is on.  If it is not set, the target system
> +will use the shell pointed by the @code{SHELL} environment variable.
> +
>  @item set remote interrupt-sequence
>  @cindex interrupt remote programs
>  @cindex select Ctrl-C, BREAK or BREAK-g
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 55eebd9..5faf0b5 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -863,6 +863,26 @@ handle_general_set (char *own_buf)
>        return;
>      }
>
> +  if (startswith (own_buf, "QStartupShell:"))
> +    {
> +      const char *p = own_buf + strlen ("QStartupShell:");
> +
> +      if (*p == '\0')
> +	{
> +	  startup_with_shell = 0;
> +	  xfree (startup_shell);
> +	}
> +      else
> +	{
> +	  startup_with_shell = 1;
> +	  xfree (startup_shell);
> +	  startup_shell = xstrdup (p);
> +	}
> +
> +      write_ok (own_buf);
> +      return;
> +    }
> +
>    /* Otherwise we didn't know what packet it was.  Say we didn't
>       understand it.  */
>    own_buf[0] = 0;
> @@ -2299,7 +2319,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+;QStartupShell+",
>  	       PBUFSIZ - 1);
>
>        if (target_supports_catch_syscall ())
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 0b5f837..2d2a87a 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -86,6 +86,12 @@ static const struct program_space_data *remote_pspace_data;
>     location of the remote exec-file value.  */
>  static char *remote_exec_file_var;
>
> +/* The variable that holds the startup shell that will be used by the
> +   remote target to start the inferior.  If this variable is NULL or
> +   empty, we use the value of 'get_startup_shell'.  */
> +

Spurious newline.

> +static char *remote_startup_shell_var;
> +
>  /* The size to align memory write packets, when practical.  The protocol
>     does not guarantee any alignment, and gdb will generate short
>     writes and unaligned writes, but even as a best-effort attempt this
> @@ -727,6 +733,22 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
>    fprintf_filtered (file, "%s\n", remote_exec_file_var);
>  }
>
> +/* The "set/show remote startup-shell" set command hook.  */
> +

Technically shouldn't we break this up into a couple comments?

Or maybe "... set command hooks."

> +static void
> +set_remote_startup_shell (char *ignored, int from_tty,
> +			  struct cmd_list_element *c)
> +{
> +  gdb_assert (remote_startup_shell_var != NULL);
> +}
> +
> +static void
> +show_remote_startup_shell (struct ui_file *file, int from_tty,
> +			   struct cmd_list_element *cmd, const char *value)
> +{
> +  fprintf_filtered (file, "%s\n", remote_startup_shell_var);
> +}
> +
>  static int
>  compare_pnums (const void *lhs_, const void *rhs_)
>  {
> @@ -1423,6 +1445,7 @@ enum {
>    PACKET_QPassSignals,
>    PACKET_QCatchSyscalls,
>    PACKET_QProgramSignals,
> +  PACKET_QStartupShell,
>    PACKET_qCRC,
>    PACKET_qSearch_memory,
>    PACKET_vAttach,
> @@ -4074,6 +4097,31 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
>    if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
>      remote_set_permissions (target);
>
> +  if (packet_support (PACKET_QStartupShell) != PACKET_DISABLE)
> +    {
> +      if (startup_with_shell)
> +	{
> +	  const char *sh;
> +
> +	  if (remote_startup_shell_var != NULL
> +	      && *remote_startup_shell_var != '\0')
> +	    sh = remote_startup_shell_var;
> +	  else
> +	    sh = get_startup_shell ();
> +
> +	  xsnprintf (rs->buf, get_remote_packet_size (),
> +		     "QStartupShell:%s", sh);
> +	}
> +      else
> +	xsnprintf (rs->buf, get_remote_packet_size (),
> +		   "QStartupShell:");
> +
> +      putpkt (rs->buf);
> +      getpkt (&rs->buf, &rs->buf_size, 0);
> +      if (strcmp (rs->buf, "OK") != 0)
> +	error (_("Could not set remote startup-with-shell"));
> +    }
> +
>    /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
>       unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
>       as a reply to known packet.  For packet "vFile:setfs:" it is an
> @@ -4628,6 +4676,8 @@ static const struct protocol_feature remote_protocol_features[] = {
>      PACKET_QCatchSyscalls },
>    { "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
>      PACKET_QProgramSignals },
> +  { "QStartupShell", PACKET_DISABLE, remote_supported_packet,
> +    PACKET_QStartupShell },
>    { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
>      PACKET_QStartNoAckMode },
>    { "multiprocess", PACKET_DISABLE, remote_supported_packet,
> @@ -14081,6 +14131,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_QStartupShell],
> +			 "QStartupShell", "startup-shell", 0);
> +
>    add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol],
>  			 "qSymbol", "symbol-lookup", 0);
>
> @@ -14380,6 +14433,15 @@ Show the remote pathname for \"run\""), NULL,
>  				   &remote_set_cmdlist,
>  				   &remote_show_cmdlist);
>
> +  add_setshow_string_noescape_cmd ("startup-shell", class_files,
> +				   &remote_startup_shell_var, _("\
> +Set the remote shell for starting the inferior"), _("\
> +Show the remote shell for starting the inferior"), NULL,
> +				   set_remote_startup_shell,
> +				   show_remote_startup_shell,
> +				   &remote_set_cmdlist,
> +				   &remote_show_cmdlist);
> +
>    add_setshow_boolean_cmd ("range-stepping", class_run,
>  			   &use_range_stepping, _("\
>  Enable or disable range stepping."), _("\
> diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
> new file mode 100644
> index 0000000..ba77b10
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.c
> @@ -0,0 +1,12 @@

Missing copyright notice in the source file?

> +#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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
> new file mode 100644
> index 0000000..1bf3654
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
> @@ -0,0 +1,110 @@
> +# This testcase is part of GDB, the GNU debugger.
> +
> +# Copyright 2016 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/>.
> +
> +# Test startup-with-shell support using extended-remote.
> +
> +load_lib gdbserver-support.exp
> +
> +standard_testfile
> +
> +if { [skip_gdbserver_tests] } {

untested "skipping gdbserver tests"

> +    return 0
> +}
> +
> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
> +    untested "failed to compile"

The above untested call is not needed as prepare_for_testing will handle 
it with the "failed to prepare" message.

> +    return -1
> +}
> +
> +# Initial setup for simple test (wildcard expansion, variable substitution).
> +
> +proc initial_setup_simple { startup_with_shell run_args } {
> +    global hex decimal binfile
> +
> +    clean_restart $binfile
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +
> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
> +
> +    set target_exec [gdbserver_download_current_prog]
> +    gdbserver_start_extended
> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
> +
> +    gdb_breakpoint main
> +
> +    gdb_test "run $run_args" \
> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
> +	"run to main"
> +}
> +
> +proc invalid_remote_shell_test { } {
> +    global binfile
> +
> +    clean_restart $binfile
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +
> +    gdb_test_no_output "set startup-with-shell on"
> +    gdb_test_no_output "set remote startup-shell /path/to/invalid/shell"
> +
> +    set target_exec [gdbserver_download_current_prog]
> +    gdbserver_start_extended
> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
> +
> +    gdb_breakpoint main
> +
> +    gdb_test "run" \
> +	"Running \"$binfile\" on the remote target failed" \
> +	"run to main (should fail)"
> +}
> +
> +## Doing the actual tests
> +
> +with_test_prefix "startup_with_shell = on; run_args = *.log" {
> +    initial_setup_simple "on" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
> +	"testing first argument"
> +}
> +
> +with_test_prefix "startup_with_shell = off; run_args = *.log" {
> +    initial_setup_simple "off" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
> +	"testing first argument"
> +}
> +
> +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)
> +}
> +
> +with_test_prefix "startup_with_shell = on; invalid remote startup-shell" {
> +    invalid_remote_shell_test
> +}
>

Otherwise looks OK.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 1/6] Share gdb/environ.[ch] with gdbserver
  2016-12-23  3:39 ` [PATCH 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2016-12-26 21:34   ` Luis Machado
  0 siblings, 0 replies; 157+ messages in thread
From: Luis Machado @ 2016-12-26 21:34 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> We will need access to the environment functions when we share
> fork_inferior between GDB and gdbserver, therefore we simply make the
> API on gdb/environ.[ch] available on common/.  No extra adjustments
> are needed to make it compile on gdbserver.
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Replace "environ.c" with
> 	"common/environ.c".
> 	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
> 	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
> 	to...
> 	* common/environ.c: ... here.
> 	* environ.h: Moved to...
> 	* common/environ.h: ... here.
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/environ.c".
> 	(OBJS): Add "common/environ.h".
> ---
>  gdb/Makefile.in            | 4 ++--
>  gdb/{ => common}/environ.c | 2 +-
>  gdb/{ => common}/environ.h | 0
>  gdb/gdbserver/Makefile.in  | 5 +++++
>  4 files changed, 8 insertions(+), 3 deletions(-)
>  rename gdb/{ => common}/environ.c (99%)
>  rename gdb/{ => common}/environ.h (100%)
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 946d440..051f07d 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1047,7 +1047,6 @@ SFILES = \
>  	dwarf2loc.c \
>  	dwarf2read.c \
>  	elfread.c \
> -	environ.c \
>  	eval.c \
>  	event-loop.c \
>  	event-top.c \
> @@ -1192,6 +1191,7 @@ SFILES = \
>  	common/common-regcache.c \
>  	common/common-utils.c \
>  	common/errors.c \
> +	common/environ.c \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> @@ -1270,7 +1270,6 @@ HFILES_NO_SRCDIR = \
>  	dwarf2-frame-tailcall.h \
>  	dwarf2expr.h \
>  	dwarf2loc.h \
> -	environ.h \
>  	event-loop.h \
>  	event-top.h \
>  	exceptions.h \
> @@ -1471,6 +1470,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-types.h \
>  	common/common-utils.h \
>  	common/errors.h \
> +	common/environ.h \
>  	common/fileio.h \
>  	common/format.h \
>  	common/gdb_assert.h \
> diff --git a/gdb/environ.c b/gdb/common/environ.c
> similarity index 99%
> rename from gdb/environ.c
> rename to gdb/common/environ.c
> index 5c73757..105f854 100644
> --- a/gdb/environ.c
> +++ b/gdb/common/environ.c
> @@ -15,7 +15,7 @@
>     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 "defs.h"
> +#include "common-defs.h"
>  #include "environ.h"
>  #include <algorithm>
>  \f
> diff --git a/gdb/environ.h b/gdb/common/environ.h
> similarity index 100%
> rename from gdb/environ.h
> rename to gdb/common/environ.h
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index e17cf70..fe40842 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -201,6 +201,7 @@ SFILES = \
>  	$(srcdir)/common/common-regcache.c \
>  	$(srcdir)/common/common-utils.c \
>  	$(srcdir)/common/errors.c \
> +	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
>  	$(srcdir)/common/gdb_vecs.c \
> @@ -238,6 +239,7 @@ OBS = \
>  	debug.o \
>  	dll.o \
>  	errors.o \
> +	environ.o \
>  	event-loop.o \
>  	fileio.o \
>  	filestuff.o \
> @@ -774,6 +776,9 @@ agent.o: ../common/agent.c
>  errors.o: ../common/errors.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +environ.o: ../common/environ.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  common-debug.o: ../common/common-debug.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
>

Looks good to me.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2016-12-23  3:45 ` [PATCH 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2016-12-26 21:35   ` Luis Machado
  2017-01-03 21:31     ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2016-12-26 21:35 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> Again, it was necessary to share a few functions declared on
> gdb/gdbthread.h with gdbserver, because they are needed by
> fork_inferior.  I decided to implement them on
> gdb/gdbserver/inferiors.c because that's where the thread functions
> are also implemented on gdbserver.  As a side note, due to the way
> gdbserver marks a thread as executing, a new argument needed to be
> added on set_executing.  This argument is a 'struct target_waitstatus
> *', and is not necessary on GDB, so it was marked with
> ATTRIBUTE_UNUSED accordingly.
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
> 	* common/common-gdbthread.h: New file, with parts from
> 	"gdb/gdbthread.h".
> 	* fork-child.c (fork_inferior): Update call of "set_executing".
> 	* gdbthread.h: Include "common-gdbthread.h".
> 	(init_thread_list): Moved to "common/common-gdbthread.h".
> 	(add_thread_silent): Likewise.
> 	(switch_to_thread): Likewise.
> 	(set_executing): Likewise.  Added an extra argument, "struct
> 	target_waitstatus *".
> 	* infrun.c (handle_inferior_event_1): Update call of
> 	"set_executing".
> 	* linux-nat.c (attach_proc_task_lwp_callback): Likewise.
> 	(linux_handle_extended_wait): Likewise.
> 	* record-btrace.c (get_thread_current_frame): Likewise.
> 	* record-full.c (record_full_wait_1): Likewise.
> 	* remote.c (remote_add_thread): Likewise.
> 	(process_initial_stop_replies): Likewise.
> 	* solib-spu.c (spu_skip_standalone_loader): Likewise.
> 	* target.c (target_resume): Likewise.
> 	* thread.c (set_executing): Update function declaration to add
> 	third argument.  Mark it as unused.
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* inferiors.c (init_thread_list): New function.
> 	(switch_to_thread): Likewise.
> 	(set_executing): Likewise.
> 	(add_thread_silent): Likewise.
> ---
>  gdb/Makefile.in               |  1 +
>  gdb/common/common-gdbthread.h | 50 +++++++++++++++++++++++++++++++++++++++++++
>  gdb/fork-child.c              |  2 +-
>  gdb/gdbserver/inferiors.c     | 42 ++++++++++++++++++++++++++++++++++++
>  gdb/gdbthread.h               | 20 +----------------
>  gdb/infrun.c                  |  2 +-
>  gdb/linux-nat.c               |  4 ++--
>  gdb/record-btrace.c           |  6 +++---
>  gdb/record-full.c             |  4 ++--
>  gdb/remote.c                  |  4 ++--
>  gdb/solib-spu.c               |  2 +-
>  gdb/target.c                  |  2 +-
>  gdb/thread.c                  |  5 ++++-
>  13 files changed, 111 insertions(+), 33 deletions(-)
>  create mode 100644 gdb/common/common-gdbthread.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 8372b4a..ca13a80 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-debug.h \
>  	common/common-defs.h \
>  	common/common-exceptions.h \
> +	common/common-gdbthread.h \
>  	common/common-regcache.h \
>  	common/common-types.h \
>  	common/common-utils.h \
> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
> new file mode 100644
> index 0000000..3560892
> --- /dev/null
> +++ b/gdb/common/common-gdbthread.h
> @@ -0,0 +1,50 @@
> +/* Multi-process/thread control defs for GDB, the GNU debugger.
> +   Copyright (C) 1987-2016 Free Software Foundation, Inc.
> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
> +
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_THREAD_H
> +#define COMMON_THREAD_H
> +
> +struct target_waitstatus;
> +
> +/* Create an empty thread list, or empty the existing one.  */
> +

Spurious newline, multiple cases of this throughout.

> +extern void init_thread_list (void);
> +
> +/* Switch from one thread to another.  */
> +
> +extern void switch_to_thread (ptid_t ptid);
> +
> +/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
> +   marks all threads.
> +
> +   Note that this is different from the running state.  See the
> +   description of state and executing fields of struct
> +   thread_info.  */
> +
> +extern void set_executing (ptid_t ptid, int executing,
> +			   struct target_waitstatus *ws);
> +
> +/* Add a thread to the thread list and return the pointer to the new
> +   thread.  Caller may use this pointer to initialize the private
> +   thread data.  */
> +
> +extern struct thread_info *add_thread_silent (ptid_t ptid);
> +
> +#endif /* ! COMMON_THREAD_H */
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 15f8249..38fca60 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -545,7 +545,7 @@ startup_inferior (int ntraps)
>      }
>
>    /* Mark all threads non-executing.  */
> -  set_executing (resume_ptid, 0);
> +  set_executing (resume_ptid, 0, NULL);
>  }
>
>  /* Implement the "unset exec-wrapper" command.  */
> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index 574a7ba..6b981d0 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -468,3 +468,45 @@ make_cleanup_restore_current_thread (void)
>  {
>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>  }
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +init_thread_list (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +switch_to_thread (ptid_t ptid)
> +{
> +  if (!ptid_equal (ptid, minus_one_ptid))
> +    current_thread = find_thread_ptid (ptid);
> +}
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED,
> +	       struct target_waitstatus *ws)
> +{
> +  gdb_assert (current_thread != NULL);
> +  current_thread->last_resume_kind = resume_stop;
> +  current_thread->last_status = *ws;

Is there a chance ws will be NULL and cause a crash here? Should we assert?

> +}
> +
> +/* See common/common-gdbthread.h.  */
> +
> +struct thread_info *
> +add_thread_silent (ptid_t ptid)
> +{
> +  pid_t pid = ptid_get_pid (ptid);
> +
> +  /* Check if there is a process already.  */
> +  if (find_process_pid (pid) == NULL)
> +    add_process (pid, 0);
> +
> +  return add_thread (ptid_build (pid, pid, 0), NULL);
> +}
> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
> index 8f37fbb..d6fdc42 100644
> --- a/gdb/gdbthread.h
> +++ b/gdb/gdbthread.h
> @@ -31,6 +31,7 @@ struct symtab;
>  #include "common/vec.h"
>  #include "target/waitstatus.h"
>  #include "cli/cli-utils.h"
> +#include "common-gdbthread.h"
>
>  /* Frontend view of the thread state.  Possible extensions: stepping,
>     finishing, until(ling),...  */
> @@ -344,19 +345,12 @@ struct thread_info
>    struct thread_info *step_over_next;
>  };
>
> -/* Create an empty thread list, or empty the existing one.  */
> -extern void init_thread_list (void);
> -
>  /* Add a thread to the thread list, print a message
>     that a new thread is found, and return the pointer to
>     the new thread.  Caller my use this pointer to
>     initialize the private thread data.  */
>  extern struct thread_info *add_thread (ptid_t ptid);
>
> -/* Same as add_thread, but does not print a message
> -   about new thread.  */
> -extern struct thread_info *add_thread_silent (ptid_t ptid);
> -
>  /* Same as add_thread, and sets the private info.  */
>  extern struct thread_info *add_thread_with_info (ptid_t ptid,
>  						 struct private_thread_info *);
> @@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
>
>  extern int thread_count (void);
>
> -/* Switch from one thread to another.  Also sets the STOP_PC
> -   global.  */
> -extern void switch_to_thread (ptid_t ptid);
> -
>  /* Switch from one thread to another.  Does not read registers and
>     sets STOP_PC to -1.  */
>  extern void switch_to_thread_no_regs (struct thread_info *thread);
> @@ -518,14 +508,6 @@ extern int is_exited (ptid_t ptid);
>  /* In the frontend's perpective, is this thread stopped?  */
>  extern int is_stopped (ptid_t ptid);
>
> -/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
> -   marks all threads.
> -
> -   Note that this is different from the running state.  See the
> -   description of state and executing fields of struct
> -   thread_info.  */
> -extern void set_executing (ptid_t ptid, int executing);
> -
>  /* Reports if thread PTID is executing.  */
>  extern int is_executing (ptid_t ptid);
>
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index bf0632e..f5cc965 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -4947,7 +4947,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
>      else
>        mark_ptid = ecs->ptid;
>
> -    set_executing (mark_ptid, 0);
> +    set_executing (mark_ptid, 0, NULL);
>
>      /* Likewise the resumed flag.  */
>      set_resumed (mark_ptid, 0);
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index cbf94ed..9db620c 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -1190,7 +1190,7 @@ attach_proc_task_lwp_callback (ptid_t ptid)
>  	     raw clone).  */
>  	  add_thread (lp->ptid);
>  	  set_running (lp->ptid, 1);
> -	  set_executing (lp->ptid, 1);
> +	  set_executing (lp->ptid, 1, NULL);
>  	}
>
>        return 1;
> @@ -2083,7 +2083,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
>  	     and the user/frontend, this new thread is running until
>  	     it next reports a stop.  */
>  	  set_running (new_lp->ptid, 1);
> -	  set_executing (new_lp->ptid, 1);
> +	  set_executing (new_lp->ptid, 1, NULL);
>
>  	  if (WSTOPSIG (status) != SIGSTOP)
>  	    {
> diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
> index 7c0e39f..80cf274 100644
> --- a/gdb/record-btrace.c
> +++ b/gdb/record-btrace.c
> @@ -1928,7 +1928,7 @@ get_thread_current_frame (struct thread_info *tp)
>       move the thread.  Since we need to recompute the stack, we temporarily
>       set EXECUTING to flase.  */
>    executing = is_executing (inferior_ptid);
> -  set_executing (inferior_ptid, 0);
> +  set_executing (inferior_ptid, 0, NULL);
>
>    frame = NULL;
>    TRY
> @@ -1938,7 +1938,7 @@ get_thread_current_frame (struct thread_info *tp)
>    CATCH (except, RETURN_MASK_ALL)
>      {
>        /* Restore the previous execution state.  */
> -      set_executing (inferior_ptid, executing);
> +      set_executing (inferior_ptid, executing, NULL);
>
>        /* Restore the previous inferior_ptid.  */
>        inferior_ptid = old_inferior_ptid;
> @@ -1948,7 +1948,7 @@ get_thread_current_frame (struct thread_info *tp)
>    END_CATCH
>
>    /* Restore the previous execution state.  */
> -  set_executing (inferior_ptid, executing);
> +  set_executing (inferior_ptid, executing, NULL);
>
>    /* Restore the previous inferior_ptid.  */
>    inferior_ptid = old_inferior_ptid;
> diff --git a/gdb/record-full.c b/gdb/record-full.c
> index 5608e70..3ad9a08 100644
> --- a/gdb/record-full.c
> +++ b/gdb/record-full.c
> @@ -1156,12 +1156,12 @@ record_full_wait_1 (struct target_ops *ops,
>  			{
>  			  /* Try to insert the software single step breakpoint.
>  			     If insert success, set step to 0.  */
> -			  set_executing (inferior_ptid, 0);
> +			  set_executing (inferior_ptid, 0, NULL);
>  			  reinit_frame_cache ();
>
>  			  step = !insert_single_step_breakpoints (gdbarch);
>
> -			  set_executing (inferior_ptid, 1);
> +			  set_executing (inferior_ptid, 1, NULL);
>  			}
>
>  		      if (record_debug)
> diff --git a/gdb/remote.c b/gdb/remote.c
> index ef6c54e..0b5f837 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -1847,7 +1847,7 @@ remote_add_thread (ptid_t ptid, int running, int executing)
>      thread = add_thread (ptid);
>
>    get_private_info_thread (thread)->vcont_resumed = executing;
> -  set_executing (ptid, executing);
> +  set_executing (ptid, executing, NULL);
>    set_running (ptid, running);
>  }
>
> @@ -3949,7 +3949,7 @@ process_initial_stop_replies (int from_tty)
>  	  || ws.value.sig != GDB_SIGNAL_0)
>  	thread->suspend.waitstatus_pending_p = 1;
>
> -      set_executing (event_ptid, 0);
> +      set_executing (event_ptid, 0, NULL);
>        set_running (event_ptid, 0);
>        thread->priv->vcont_resumed = 0;
>      }
> diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
> index fa2977e..f55e0a0 100644
> --- a/gdb/solib-spu.c
> +++ b/gdb/solib-spu.c
> @@ -88,7 +88,7 @@ spu_skip_standalone_loader (void)
>
>        target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
>        target_wait (minus_one_ptid, &ws, 0);
> -      set_executing (minus_one_ptid, 0);
> +      set_executing (minus_one_ptid, 0, NULL);
>
>        inferior_thread ()->control.in_infcall = 0;
>      }
> diff --git a/gdb/target.c b/gdb/target.c
> index 246d292..e7c68bf 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -2325,7 +2325,7 @@ target_resume (ptid_t ptid, int step, enum gdb_signal signal)
>    registers_changed_ptid (ptid);
>    /* We only set the internal executing state here.  The user/frontend
>       running state is set at a higher level.  */
> -  set_executing (ptid, 1);
> +  set_executing (ptid, 1, NULL);
>    clear_inline_frame_state (ptid);
>  }
>
> diff --git a/gdb/thread.c b/gdb/thread.c
> index e5d6c5f..1114aac 100644
> --- a/gdb/thread.c
> +++ b/gdb/thread.c
> @@ -1011,8 +1011,11 @@ is_executing (ptid_t ptid)
>    return tp->executing;
>  }
>
> +/* See common/common-gdbthread.h.  */
> +
>  void
> -set_executing (ptid_t ptid, int executing)
> +set_executing (ptid_t ptid, int executing,
> +	       struct target_waitstatus *ws ATTRIBUTE_UNUSED)

I'm thinking about this change. Isn't there a better way to do this 
without adding gdb/gdbserver-specific parameters and then passing dummy 
values for the unused parameters depending on who's calling?

Maybe making gdbserver accept the same parameters as gdb and then do 
some extra processing in gdbserver to get at the waitstatus data if it 
still needs that? Or maybe unifying the function and making gdb and 
gdbserver operate the same way in this regard.

>  {
>    struct thread_info *tp;
>    int all = ptid_equal (ptid, minus_one_ptid);
>

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 2/6] Share parts of gdb/terminal.h with gdbserver
  2016-12-23  3:39 ` [PATCH 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
@ 2016-12-26 21:35   ` Luis Machado
  2017-01-03 21:14     ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2016-12-26 21:35 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> As part of the bigger work of sharing fork_inferior with gdbserver,
> some parts of gdb/terminal.h also needed to be moved to a common
> place.  These parts are:
>
> - The code responsible for determining some terminal-based define's
>   based on available features;
>
> - job control;
>
> - terminal-related functions needed by fork_inferior;
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
> 	* common/common-terminal.h: New file, with parts of "terminal.h".
> 	* terminal.h: Move terminal-related defines to
> 	"common/common-terminal.h".
> 	(new_tty_prefork): Move to "common/common-terminal.h".
> 	(new_tty): Likewise.
> 	(new_tty_postfork): Likewise.
> 	(job_control): Likewise.
> 	(create_tty_session): Likewise.
> 	(gdb_setpgid): Likewise.
> 	* utils.c: Include "terminal.h".
>
> gdb/ChangeLog:

gdb/gdbserver/ChangeLog

> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* terminal.c: New file.
> ---
>  gdb/Makefile.in                              |  1 +
>  gdb/{terminal.h => common/common-terminal.h} | 55 +++++++++++++--------
>  gdb/gdbserver/terminal.c                     | 72 +++++++++++++++++++++++++++
>  gdb/terminal.h                               | 73 +---------------------------
>  gdb/utils.c                                  |  1 +
>  5 files changed, 109 insertions(+), 93 deletions(-)
>  copy gdb/{terminal.h => common/common-terminal.h} (66%)
>  create mode 100644 gdb/gdbserver/terminal.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 051f07d..51c0f73 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-regcache.h \
>  	common/common-types.h \
>  	common/common-utils.h \
> +	common/common-terminal.h \
>  	common/errors.h \
>  	common/environ.h \
>  	common/fileio.h \
> diff --git a/gdb/terminal.h b/gdb/common/common-terminal.h
> similarity index 66%
> copy from gdb/terminal.h
> copy to gdb/common/common-terminal.h

Creating a new common/common-terminal.[h|c] may be cleaner than 
git-copying and then modifying it. With a new file we get all the 
included changes, whereas with git-copying we get a number of unrelated 
changes that need to be removed.


> index 0deced4..0ec8a23 100644
> --- a/gdb/terminal.h
> +++ b/gdb/common/common-terminal.h
> @@ -16,9 +16,8 @@
>     You should have received a copy of the GNU General Public License
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>
> -#if !defined (TERMINAL_H)
> -#define TERMINAL_H 1
> -
> +#ifndef COMMON_TERMINAL_H
> +#define COMMON_TERMINAL_H
>
>  /* If we're using autoconf, it will define HAVE_TERMIOS_H,
>     HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
> @@ -76,37 +75,51 @@
>  #endif /* sgtty */
>  #endif
>
> -struct inferior;
> +#include <sys/types.h>
> +
> +/* Do we have job control?  Can be assumed to always be the same
> +   within a given run of GDB.  Use in gdb/inflow.c and
> +   common/common-inflow.c.  */
>
> -extern void new_tty_prefork (const char *);
> +extern int job_control;
>
>  extern void new_tty (void);
>
> -extern void new_tty_postfork (void);
> +/* NEW_TTY_PREFORK is called before forking a new child process,
> +   so we can record the state of ttys in the child to be formed.
> +   TTYNAME is null if we are to share the terminal with gdb;

This mentions gdb, but it may be used for gdbserver as well? We may need 
generic wording here to account for that fact. This happens in other 
places as well...

> +   or points to a string containing the name of the desired tty.
>
> -extern void copy_terminal_info (struct inferior *to, struct inferior *from);
> +   NEW_TTY is called in new child processes under Unix, which will
> +   become debugger target processes.  This actually switches to
> +   the terminal specified in the NEW_TTY_PREFORK call.  */
>
> -/* Do we have job control?  Can be assumed to always be the same within
> -   a given run of GDB.  In inflow.c.  */
> -extern int job_control;
> +extern void new_tty_prefork (const char *ttyname);
>
> -extern pid_t create_tty_session (void);
> +/* NEW_TTY_POSTFORK is called after forking a new child process, and
> +   adding it to the inferior table, to store the TTYNAME being used by
> +   the child, or null if it sharing the terminal with gdb.  */
>
> -/* Set the process group of the caller to its own pid, or do nothing if
> -   we lack job control.  */
> -extern int gdb_setpgid (void);
> +extern void new_tty_postfork (void);
>
> -/* Set up a serial structure describing standard input.  In inflow.c.  */
> -extern void initialize_stdin_serial (void);
> +/* Create a new session if the inferior will run in a different tty.
> +   A session is UNIX's way of grouping processes that share a controlling
> +   terminal, so a new one is needed if the inferior terminal will be
> +   different from GDB's.

... like here.

>
> -extern void gdb_save_tty_state (void);
> +   Returns the session id of the new session, 0 if no session was created
> +   or -1 if an error occurred.  */
>
> -/* Take a snapshot of our initial tty state before readline/ncurses
> -   have had a chance to alter it.  */
> -extern void set_initial_gdb_ttystate (void);
> +extern pid_t create_tty_session (void);
>
>  /* Set the process group of the caller to its own pid, or do nothing
>     if we lack job control.  */
> +

Spurious newline?

>  extern int gdb_setpgid (void);
>
> -#endif /* !defined (TERMINAL_H) */
> +/* Determine whether we have job control, and set variable JOB_CONTROL
> +   accordingly.  */
> +
> +extern void have_job_control (void);
> +
> +#endif /* ! COMMON_TERMINAL_H */
> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
> new file mode 100644
> index 0000000..9813018
> --- /dev/null
> +++ b/gdb/gdbserver/terminal.c
> @@ -0,0 +1,72 @@
> +/* Terminal interface definitions for the GDB remote server.
> +   Copyright (C) 2016 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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 "server.h"
> +#include "common-terminal.h"
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty_prefork (const char *ttyname)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty_postfork (void)
> +{
> +  /* To be implemented.  */
> +}

Are these going to be implemented at some point or is this something 
that may not be addressed until much later on?

It wouldn't be great to have a number of these lying around with no 
clear plan to have them addressed.

Are these counterparts of what gdb always has? Does it make sense to 
unify those functions instead of adding placeholders for a potentially 
different implementation?

> +
> +/* See common/common-terminal.h.  */
> +
> +pid_t
> +create_tty_session (void)
> +{
> +  /* For now we just return a dummy value.  This function will be
> +     properly implemented later.  */
> +  return (pid_t) 1;
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +void
> +set_inferior_io_terminal (const char *terminal_name)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +const char *
> +get_inferior_io_terminal (void)
> +{
> +  /* Return a dummy value.  This function will be properly implemented
> +     later.  */
> +  return NULL;
> +}
> diff --git a/gdb/terminal.h b/gdb/terminal.h
> index 0deced4..810b597 100644
> --- a/gdb/terminal.h
> +++ b/gdb/terminal.h
> @@ -19,83 +19,12 @@
>  #if !defined (TERMINAL_H)
>  #define TERMINAL_H 1
>
> -
> -/* If we're using autoconf, it will define HAVE_TERMIOS_H,
> -   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
> -   ser-unix.c and inflow.c to inspect those names instead of
> -   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
> -   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
> -   nothing has already defined the one of the names, and do the right
> -   thing.  */
> -
> -#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
> -#if defined(HAVE_TERMIOS_H)
> -#define HAVE_TERMIOS
> -#else /* ! defined (HAVE_TERMIOS_H) */
> -#if defined(HAVE_TERMIO_H)
> -#define HAVE_TERMIO
> -#else /* ! defined (HAVE_TERMIO_H) */
> -#if defined(HAVE_SGTTY_H)
> -#define HAVE_SGTTY
> -#endif /* ! defined (HAVE_SGTTY_H) */
> -#endif /* ! defined (HAVE_TERMIO_H) */
> -#endif /* ! defined (HAVE_TERMIOS_H) */
> -#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
> -	  !defined (HAVE_SGTTY) */
> -
> -#if defined(HAVE_TERMIOS)
> -#include <termios.h>
> -#endif
> -
> -#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
> -
> -/* Define a common set of macros -- BSD based -- and redefine whatever
> -   the system offers to make it look like that.  FIXME: serial.h and
> -   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
> -   is converted to use them, can get rid of this crap.  */
> -
> -#ifdef HAVE_TERMIO
> -
> -#include <termio.h>
> -
> -#undef TIOCGETP
> -#define TIOCGETP TCGETA
> -#undef TIOCSETN
> -#define TIOCSETN TCSETA
> -#undef TIOCSETP
> -#define TIOCSETP TCSETAF
> -#define TERMINAL struct termio
> -
> -#else /* sgtty */
> -
> -#include <fcntl.h>
> -#include <sgtty.h>
> -#include <sys/ioctl.h>
> -#define TERMINAL struct sgttyb
> -
> -#endif /* sgtty */
> -#endif

Did the above defines get moved to common/common-terminal.h or did they 
vanish? The git-copying doesn't make that too obvious. I suppose they 
are still in common/common-terminal.h, they just did not get changed, 
and thus we get no mention of this in the patch.

> +#include "common-terminal.h"
>
>  struct inferior;
>
> -extern void new_tty_prefork (const char *);
> -
> -extern void new_tty (void);
> -
> -extern void new_tty_postfork (void);
> -
>  extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>
> -/* Do we have job control?  Can be assumed to always be the same within
> -   a given run of GDB.  In inflow.c.  */
> -extern int job_control;
> -
> -extern pid_t create_tty_session (void);
> -
> -/* Set the process group of the caller to its own pid, or do nothing if
> -   we lack job control.  */
> -extern int gdb_setpgid (void);
> -
>  /* Set up a serial structure describing standard input.  In inflow.c.  */
>  extern void initialize_stdin_serial (void);
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 3a88e2a..bc1dfe5 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -53,6 +53,7 @@
>  #include "top.h"
>  #include "main.h"
>  #include "solist.h"
> +#include "terminal.h"
>
>  #include "inferior.h"		/* for signed_pointer_to_address */
>
>

Otherwise looks OK to me.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  2016-12-23  8:07   ` Eli Zaretskii
  2016-12-26 21:34   ` Luis Machado
@ 2016-12-27  0:26   ` Tom Tromey
  2017-01-03 21:32     ` Sergio Durigan Junior
  2 siblings, 1 reply; 157+ messages in thread
From: Tom Tromey @ 2016-12-27  0:26 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, palves

>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:

[...]
Sergio> A new packet is added, QStartupShell, and this
Sergio> packet is sent on initialization.

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

I didn't see a documentation patch for the new packet.  I think this is
important to have.

thanks,
Tom

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  7:50 ` [PATCH 0/6] Implement the ability to start inferiors with a shell " Eli Zaretskii
@ 2017-01-03 20:23   ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 20:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, palves

On Friday, December 23 2016, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: palves@redhat.com
>> Date: Thu, 22 Dec 2016 22:39:15 -0500
>> 
>> This patch series took a long time to complete due to many and varied
>> reasons, but finally here it is.
>> 
>> It implements the "startup-with-shell" feature on gdbserver.  This
>> means that it will be possible to start inferiors using the shell
>> (instead of calling execv*), which brings many advantages.
>> 
>> First of all, it will be possible to use I/O redirection, variable
>> substitution and globbing expansion on gdbserver just like we do today
>> on GDB.  This is great because, among other things, it brings
>> gdbserver on a pair with GDB when considering the Feature Parity
>> project.
>
> In Windows native debugging, GDB doesn't use the shell to start the
> inferior, but redirection is still supported via special code in
> windows-nat.c.  Can this be made available also in gdbserver?

Looking at windows-nat.c, it seems that the code responsible for
implementing this behaviour is not complex, so in theory it should be
possible to make it available on gdbserver without much effort.  I don't
feel I'm the best person to hack this, though, because I don't use
Windows and cannot reliably test the feature.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-23  8:07   ` Eli Zaretskii
@ 2017-01-03 20:48     ` Sergio Durigan Junior
  2017-01-04 16:08       ` Eli Zaretskii
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 20:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, palves

Thanks for the review, Eli.

Comments below.

On Friday, December 23 2016, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: palves@redhat.com, Sergio Durigan Junior <sergiodj@redhat.com>
>> Date: Thu, 22 Dec 2016 22:39:21 -0500
>> 
>> gdb/doc/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* gdb.texinfo (startup-with-shell): Add note mentioning that the
>> 	setting is also used by remote targets.
>> 	(set remote startup-shell): New item.
>
> The text in parentheses should be the name of the node where you make
> the change.  If you want to refer to specific symbols within the node,
> either mention them as part of the text or put them in <..>, like
> this:
>
>   * gdb.texinfo (Starting) <startup-with-shell>: Add note ...

Ops, thanks for pointing that out.  I'll fix it.

>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index a0de7d1..3250cae 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -2174,6 +2174,10 @@ initialization file---such as @file{.cshrc} for C-shell,
>>  $@file{.zshenv} for the Z shell, or the file specified in the
>>  @samp{BASH_ENV} environment variable for BASH.
>>  
>> +This setting is also used by @code{target extended-remote} to
>> +determine whether the target system will start the inferior using the
>> +shell (@pxref{set remote startup-shell}).
>
> I would add here a qualification: only on Unix-like target systems.
> (Is it true that this is a necessary condition for the applicability
> of that feature?)

The target must be able to start the inferior using a shell.  Of all the
non-UNIX-like systems that GDB supports, I am not aware of any that can
do it, so I think this is a fair qualification.

>> +@item set remote startup-shell @var{shell}
>> +@itemx show remote startup-shell
>> +@anchor{set remote startup-shell}
>> +@cindex startup shell, for remote target
>> +Set the shell that is going to be used to start the inferior with
>> +@code{target extended-remote}.  This should be set to a valid shell on
>> +the target system, and is only effective when
>> +@code{startup-with-shell} is on.  If it is not set, the target system
>> +will use the shell pointed by the @code{SHELL} environment variable.
>
> Three comments on this:
>
>   . What is a "valid shell" in this context?  Is the DOS command.com a
>     valid shell, for example (probably not)?  I think we should be
>     more explicit about which shells are acceptable.

Right.  "Valid shells" are shells that are present on the target system
(i.e., they are installed there), and that can be used to start the
inferior.  I know almost nothing about command.com, but ISTR that it
cannot be used to start programs.

I will explain it better in the text.

>   . What exactly is the value supposed to be?  Is it a full absolute
>     file name of the shell executable?  We should say so explicitly,
>     IMO.

It all depends on what is in the $PATH.  But you're right, I'll mention
that explicitly.

>   . Does it really make sense to require that both this option and
>     startup-with-shell be on?

They don't need to be both on.  The only setting that needs to be on is
the startup-with-shell.  The 'remote startup-shell' option only needs to
be set if the user wants to explicitly specify which shell to use.

>     Why cannot the user set only this
>     option to achieve that effect, with some special value standing
>     for "use $SHELL"?

The "special value", in this case, is an empty value.  I.e., if the user
doesn't touch the 'remote startup-shell' option and the
startup-with-shell option is on, the target will use $SHELL to start the
inferior.

Now, it is questionable whether to 

>     Also, is it possible that a user will want
>     remote targets to use a shell, while avoiding that for native
>     debugging, in the same session?

Yeah, I thought about that.  My first thought was to add a 'set/show
remote startup-with-shell' option, but I thought this was going to be
too much for the user.  Maybe not.

With this new setting, we'd have:

- startup-with-shell: Used only locally, default on.  Instructs GDB to
  start the inferior using the shell.

- remote startup-with-shell: Used only remotely, default on.  Instructs
  gdbserver to start the inferior using the shell.

- remote startup-shell: Used only remotely (if remote startup-with-shell
  is on), default "" (empty).  Tells which shell to be used by gdbserver
  to start the inferior.  If empty, use $SHELL.

WDYT?

> A minor nit: environment variables should have the @env markup, not
> @code.

Will fix.

> I think this warrants a NEWS entry.

Will write.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 2/6] Share parts of gdb/terminal.h with gdbserver
  2016-12-26 21:35   ` Luis Machado
@ 2017-01-03 21:14     ` Sergio Durigan Junior
  2017-01-03 21:27       ` Luis Machado
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:14 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

Hey Luis, thanks for the review.

Comments below.

On Monday, December 26 2016, Luis Machado wrote:

> On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
>> As part of the bigger work of sharing fork_inferior with gdbserver,
>> some parts of gdb/terminal.h also needed to be moved to a common
>> place.  These parts are:
>>
>> - The code responsible for determining some terminal-based define's
>>   based on available features;
>>
>> - job control;
>>
>> - terminal-related functions needed by fork_inferior;
>>
>> gdb/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
>> 	* common/common-terminal.h: New file, with parts of "terminal.h".
>> 	* terminal.h: Move terminal-related defines to
>> 	"common/common-terminal.h".
>> 	(new_tty_prefork): Move to "common/common-terminal.h".
>> 	(new_tty): Likewise.
>> 	(new_tty_postfork): Likewise.
>> 	(job_control): Likewise.
>> 	(create_tty_session): Likewise.
>> 	(gdb_setpgid): Likewise.
>> 	* utils.c: Include "terminal.h".
>>
>> gdb/ChangeLog:
>
> gdb/gdbserver/ChangeLog

Thanks, will fix.

>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* terminal.c: New file.
>> ---
>>  gdb/Makefile.in                              |  1 +
>>  gdb/{terminal.h => common/common-terminal.h} | 55 +++++++++++++--------
>>  gdb/gdbserver/terminal.c                     | 72 +++++++++++++++++++++++++++
>>  gdb/terminal.h                               | 73 +---------------------------
>>  gdb/utils.c                                  |  1 +
>>  5 files changed, 109 insertions(+), 93 deletions(-)
>>  copy gdb/{terminal.h => common/common-terminal.h} (66%)
>>  create mode 100644 gdb/gdbserver/terminal.c
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 051f07d..51c0f73 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
>>  	common/common-regcache.h \
>>  	common/common-types.h \
>>  	common/common-utils.h \
>> +	common/common-terminal.h \
>>  	common/errors.h \
>>  	common/environ.h \
>>  	common/fileio.h \
>> diff --git a/gdb/terminal.h b/gdb/common/common-terminal.h
>> similarity index 66%
>> copy from gdb/terminal.h
>> copy to gdb/common/common-terminal.h
>
> Creating a new common/common-terminal.[h|c] may be cleaner than
> git-copying and then modifying it. With a new file we get all the
> included changes, whereas with git-copying we get a number of
> unrelated changes that need to be removed.

I actually created a new file and moved the necessary things by hand.  I
think git marked this as a copy because I have a special setting on my
$HOME/.gitconfig telling it to detect copies on diff's.  But if you look
below, you'll see that gdb/terminal.h is still there.

Anyway, I can send a different diff if you want.

>> index 0deced4..0ec8a23 100644
>> --- a/gdb/terminal.h
>> +++ b/gdb/common/common-terminal.h
>> @@ -16,9 +16,8 @@
>>     You should have received a copy of the GNU General Public License
>>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>>
>> -#if !defined (TERMINAL_H)
>> -#define TERMINAL_H 1
>> -
>> +#ifndef COMMON_TERMINAL_H
>> +#define COMMON_TERMINAL_H
>>
>>  /* If we're using autoconf, it will define HAVE_TERMIOS_H,
>>     HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>> @@ -76,37 +75,51 @@
>>  #endif /* sgtty */
>>  #endif
>>
>> -struct inferior;
>> +#include <sys/types.h>
>> +
>> +/* Do we have job control?  Can be assumed to always be the same
>> +   within a given run of GDB.  Use in gdb/inflow.c and
>> +   common/common-inflow.c.  */
>>
>> -extern void new_tty_prefork (const char *);
>> +extern int job_control;
>>
>>  extern void new_tty (void);
>>
>> -extern void new_tty_postfork (void);
>> +/* NEW_TTY_PREFORK is called before forking a new child process,
>> +   so we can record the state of ttys in the child to be formed.
>> +   TTYNAME is null if we are to share the terminal with gdb;
>
> This mentions gdb, but it may be used for gdbserver as well? We may
> need generic wording here to account for that fact. This happens in
> other places as well...

Right, I'll fix these comments.

>> +   or points to a string containing the name of the desired tty.
>>
>> -extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>> +   NEW_TTY is called in new child processes under Unix, which will
>> +   become debugger target processes.  This actually switches to
>> +   the terminal specified in the NEW_TTY_PREFORK call.  */
>>
>> -/* Do we have job control?  Can be assumed to always be the same within
>> -   a given run of GDB.  In inflow.c.  */
>> -extern int job_control;
>> +extern void new_tty_prefork (const char *ttyname);
>>
>> -extern pid_t create_tty_session (void);
>> +/* NEW_TTY_POSTFORK is called after forking a new child process, and
>> +   adding it to the inferior table, to store the TTYNAME being used by
>> +   the child, or null if it sharing the terminal with gdb.  */
>>
>> -/* Set the process group of the caller to its own pid, or do nothing if
>> -   we lack job control.  */
>> -extern int gdb_setpgid (void);
>> +extern void new_tty_postfork (void);
>>
>> -/* Set up a serial structure describing standard input.  In inflow.c.  */
>> -extern void initialize_stdin_serial (void);
>> +/* Create a new session if the inferior will run in a different tty.
>> +   A session is UNIX's way of grouping processes that share a controlling
>> +   terminal, so a new one is needed if the inferior terminal will be
>> +   different from GDB's.
>
> ... like here.
>
>>
>> -extern void gdb_save_tty_state (void);
>> +   Returns the session id of the new session, 0 if no session was created
>> +   or -1 if an error occurred.  */
>>
>> -/* Take a snapshot of our initial tty state before readline/ncurses
>> -   have had a chance to alter it.  */
>> -extern void set_initial_gdb_ttystate (void);
>> +extern pid_t create_tty_session (void);
>>
>>  /* Set the process group of the caller to its own pid, or do nothing
>>     if we lack job control.  */
>> +
>
> Spurious newline?

Not really.  Even though this is a cosmetic change and could be removed
from the patch, I decided to leave it there.  Our coding standards
explain this:

  https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Blank_Line_After_Block_Comment_Preceding_Variable_Definitions

>>  extern int gdb_setpgid (void);
>>
>> -#endif /* !defined (TERMINAL_H) */
>> +/* Determine whether we have job control, and set variable JOB_CONTROL
>> +   accordingly.  */
>> +
>> +extern void have_job_control (void);
>> +
>> +#endif /* ! COMMON_TERMINAL_H */
>> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
>> new file mode 100644
>> index 0000000..9813018
>> --- /dev/null
>> +++ b/gdb/gdbserver/terminal.c
>> @@ -0,0 +1,72 @@
>> +/* Terminal interface definitions for the GDB remote server.
>> +   Copyright (C) 2016 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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 "server.h"
>> +#include "common-terminal.h"
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty_prefork (const char *ttyname)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty_postfork (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>
> Are these going to be implemented at some point or is this something
> that may not be addressed until much later on?

They're not exactly on my radar, but they're a part of the local/remote
feature parity, so they will be tackled soon, I'd figure.

> It wouldn't be great to have a number of these lying around with no
> clear plan to have them addressed.

I agree.

> Are these counterparts of what gdb always has? Does it make sense to
> unify those functions instead of adding placeholders for a potentially
> different implementation?

I'll try to give these a try and implementing them.  My only concern is
that I don't want these to explode into a giant new task to implement
inferior I/O on gdbserver, but it may be possible to just touch the
necessary bits and make it simple.

>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +pid_t
>> +create_tty_session (void)
>> +{
>> +  /* For now we just return a dummy value.  This function will be
>> +     properly implemented later.  */
>> +  return (pid_t) 1;
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +set_inferior_io_terminal (const char *terminal_name)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +const char *
>> +get_inferior_io_terminal (void)
>> +{
>> +  /* Return a dummy value.  This function will be properly implemented
>> +     later.  */
>> +  return NULL;
>> +}
>> diff --git a/gdb/terminal.h b/gdb/terminal.h
>> index 0deced4..810b597 100644
>> --- a/gdb/terminal.h
>> +++ b/gdb/terminal.h
>> @@ -19,83 +19,12 @@
>>  #if !defined (TERMINAL_H)
>>  #define TERMINAL_H 1
>>
>> -
>> -/* If we're using autoconf, it will define HAVE_TERMIOS_H,
>> -   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>> -   ser-unix.c and inflow.c to inspect those names instead of
>> -   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
>> -   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
>> -   nothing has already defined the one of the names, and do the right
>> -   thing.  */
>> -
>> -#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
>> -#if defined(HAVE_TERMIOS_H)
>> -#define HAVE_TERMIOS
>> -#else /* ! defined (HAVE_TERMIOS_H) */
>> -#if defined(HAVE_TERMIO_H)
>> -#define HAVE_TERMIO
>> -#else /* ! defined (HAVE_TERMIO_H) */
>> -#if defined(HAVE_SGTTY_H)
>> -#define HAVE_SGTTY
>> -#endif /* ! defined (HAVE_SGTTY_H) */
>> -#endif /* ! defined (HAVE_TERMIO_H) */
>> -#endif /* ! defined (HAVE_TERMIOS_H) */
>> -#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
>> -	  !defined (HAVE_SGTTY) */
>> -
>> -#if defined(HAVE_TERMIOS)
>> -#include <termios.h>
>> -#endif
>> -
>> -#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
>> -
>> -/* Define a common set of macros -- BSD based -- and redefine whatever
>> -   the system offers to make it look like that.  FIXME: serial.h and
>> -   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
>> -   is converted to use them, can get rid of this crap.  */
>> -
>> -#ifdef HAVE_TERMIO
>> -
>> -#include <termio.h>
>> -
>> -#undef TIOCGETP
>> -#define TIOCGETP TCGETA
>> -#undef TIOCSETN
>> -#define TIOCSETN TCSETA
>> -#undef TIOCSETP
>> -#define TIOCSETP TCSETAF
>> -#define TERMINAL struct termio
>> -
>> -#else /* sgtty */
>> -
>> -#include <fcntl.h>
>> -#include <sgtty.h>
>> -#include <sys/ioctl.h>
>> -#define TERMINAL struct sgttyb
>> -
>> -#endif /* sgtty */
>> -#endif
>
> Did the above defines get moved to common/common-terminal.h or did
> they vanish? The git-copying doesn't make that too obvious. I suppose
> they are still in common/common-terminal.h, they just did not get
> changed, and thus we get no mention of this in the patch.

They were moved, and the reason why they didn't show up is because of
the git option that I mentioned before.  I'll make sure to list these
changes in the next patch iteration.

>> +#include "common-terminal.h"
>>
>>  struct inferior;
>>
>> -extern void new_tty_prefork (const char *);
>> -
>> -extern void new_tty (void);
>> -
>> -extern void new_tty_postfork (void);
>> -
>>  extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>>
>> -/* Do we have job control?  Can be assumed to always be the same within
>> -   a given run of GDB.  In inflow.c.  */
>> -extern int job_control;
>> -
>> -extern pid_t create_tty_session (void);
>> -
>> -/* Set the process group of the caller to its own pid, or do nothing if
>> -   we lack job control.  */
>> -extern int gdb_setpgid (void);
>> -
>>  /* Set up a serial structure describing standard input.  In inflow.c.  */
>>  extern void initialize_stdin_serial (void);
>>
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index 3a88e2a..bc1dfe5 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -53,6 +53,7 @@
>>  #include "top.h"
>>  #include "main.h"
>>  #include "solist.h"
>> +#include "terminal.h"
>>
>>  #include "inferior.h"		/* for signed_pointer_to_address */
>>
>>
>
> Otherwise looks OK to me.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver
  2016-12-26 21:34   ` Luis Machado
@ 2017-01-03 21:16     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:16 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

Thanks for the review.

Comments below.

On Monday, December 26 2016, Luis Machado wrote:

> On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
>> After sharing parts of gdb/terminal.h, it is also needed to share the
>> two functions on gdb/inflow.c that are going to be needed by the
>> fork_inferior sharing.  They are 'gdb_setpgid' and the new
>> 'have_job_control'.
>>
>> gdb/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (SFILES): Add "common/common-inflow.c".
>> 	(COMMON_OBS): Add "common/common-inflow.o".
>> 	* common/common-inflow.c: New file, with contents from
>> 	"gdb/inflow.c".
>> 	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
>> 	(_initialize_inflow): Move setting of "job_control" to a specific
>> 	function on "common/common-inflow.c".
>> 	* utils.c (job_control): Delete.
>>
>> gdb/gdbserver/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in: Add rule for "common-inflow.o".
>> 	(SFILE): Add "common/common-inflow.c".
>> 	(OBS): Add "common-inflow.o".
>> ---
>>  gdb/Makefile.in            |  2 +
>>  gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
>>  gdb/gdbserver/Makefile.in  |  5 +++
>>  gdb/inflow.c               | 63 +-------------------------------
>>  gdb/utils.c                |  4 --
>>  5 files changed, 100 insertions(+), 65 deletions(-)
>>  create mode 100644 gdb/common/common-inflow.c
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 51c0f73..8372b4a 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1195,6 +1195,7 @@ SFILES = \
>>  	common/fileio.c \
>>  	common/filestuff.c \
>>  	common/format.c \
>> +	common/common-inflow.c \
>>  	common/gdb_vecs.c \
>>  	common/new-op.c \
>>  	common/print-utils.c \
>> @@ -1622,6 +1623,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>>  	common-agent.o \
>>  	common-debug.o \
>>  	common-exceptions.o \
>> +	common-inflow.o \
>>  	common-regcache.o \
>>  	common-utils.o \
>>  	complaints.o \
>> diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
>> new file mode 100644
>> index 0000000..595eb51
>> --- /dev/null
>> +++ b/gdb/common/common-inflow.c
>> @@ -0,0 +1,91 @@
>> +/* Low level interface to ptrace, for GDB when running under Unix.
>> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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 "common-defs.h"
>> +#include "common-terminal.h"
>> +
>> +/* Nonzero if we have job control.  */
>> +
>
> Spurious newline?

Nope:

  https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation

>> +int job_control;
>> +
>> +/* This is here because this is where we figure out whether we (probably)
>> +   have job control.  Just using job_control only does part of it because
>> +   setpgid or setpgrp might not exist on a system without job control.
>> +   It might be considered misplaced (on the other hand, process groups and
>> +   job control are closely related to ttys).
>> +
>> +   For a more clean implementation, in libiberty, put a setpgid which merely
>> +   calls setpgrp and a setpgrp which does nothing (any system with job control
>> +   will have one or the other).  */
>
> newline between comment and function.

This is OK:

  https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation

>> +int
>> +gdb_setpgid (void)
>> +{
>> +  int retval = 0;
>> +
>> +  if (job_control)
>> +    {
>> +#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
>> +#ifdef HAVE_SETPGID
>> +      /* The call setpgid (0, 0) is supposed to work and mean the same
>> +         thing as this, but on Ultrix 4.2A it fails with EPERM (and
>> +         setpgid (getpid (), getpid ()) succeeds).  */
>> +      retval = setpgid (getpid (), getpid ());
>> +#else
>> +#ifdef HAVE_SETPGRP
>> +#ifdef SETPGRP_VOID
>> +      retval = setpgrp ();
>> +#else
>> +      retval = setpgrp (getpid (), getpid ());
>> +#endif
>> +#endif /* HAVE_SETPGRP */
>> +#endif /* HAVE_SETPGID */
>> +#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
>> +    }
>> +
>> +  return retval;
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +have_job_control (void)
>> +{
>> +  /* OK, figure out whether we have job control.  If neither termios nor
>> +     sgtty (i.e. termio or go32), leave job_control 0.  */
>> +#if defined (HAVE_TERMIOS)
>> +  /* Do all systems with termios have the POSIX way of identifying job
>> +     control?  I hope so.  */
>> +#ifdef _POSIX_JOB_CONTROL
>> +  job_control = 1;
>> +#else
>> +#ifdef _SC_JOB_CONTROL
>> +  job_control = sysconf (_SC_JOB_CONTROL);
>> +#else
>> +  job_control = 0;		/* Have to assume the worst.  */
>> +#endif /* _SC_JOB_CONTROL */
>> +#endif /* _POSIX_JOB_CONTROL */
>> +#endif /* HAVE_TERMIOS */
>> +
>> +#ifdef HAVE_SGTTY
>> +#ifdef TIOCGPGRP
>> +  job_control = 1;
>> +#else
>> +  job_control = 0;
>> +#endif /* TIOCGPGRP */
>> +#endif /* sgtty */
>> +}
>> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
>> index fe40842..2add910 100644
>> --- a/gdb/gdbserver/Makefile.in
>> +++ b/gdb/gdbserver/Makefile.in
>> @@ -204,6 +204,7 @@ SFILES = \
>>  	$(srcdir)/common/environ.c \
>>  	$(srcdir)/common/fileio.c \
>>  	$(srcdir)/common/filestuff.c \
>> +	$(srcdir)/common/common-inflow.c \
>>  	$(srcdir)/common/gdb_vecs.c \
>>  	$(srcdir)/common/new-op.c \
>>  	$(srcdir)/common/print-utils.c \
>> @@ -234,6 +235,7 @@ OBS = \
>>  	cleanups.o \
>>  	common-debug.o \
>>  	common-exceptions.o \
>> +	common-inflow.o \
>>  	common-regcache.o \
>>  	common-utils.o \
>>  	debug.o \
>> @@ -770,6 +772,9 @@ format.o: ../common/format.c
>>  filestuff.o: ../common/filestuff.c
>>  	$(COMPILE) $<
>>  	$(POSTCOMPILE)
>> +common-inflow.o: ../common/common-inflow.c
>> +	$(COMPILE) $<
>> +	$(POSTCOMPILE)
>>  agent.o: ../common/agent.c
>>  	$(COMPILE) $<
>>  	$(POSTCOMPILE)
>> diff --git a/gdb/inflow.c b/gdb/inflow.c
>> index 5b55cec..80909ea 100644
>> --- a/gdb/inflow.c
>> +++ b/gdb/inflow.c
>> @@ -803,43 +803,6 @@ create_tty_session (void)
>>  #endif /* HAVE_SETSID */
>>  }
>>
>> -/* This is here because this is where we figure out whether we (probably)
>> -   have job control.  Just using job_control only does part of it because
>> -   setpgid or setpgrp might not exist on a system without job control.
>> -   It might be considered misplaced (on the other hand, process groups and
>> -   job control are closely related to ttys).
>> -
>> -   For a more clean implementation, in libiberty, put a setpgid which merely
>> -   calls setpgrp and a setpgrp which does nothing (any system with job control
>> -   will have one or the other).  */
>> -int
>> -gdb_setpgid (void)
>> -{
>> -  int retval = 0;
>> -
>> -  if (job_control)
>> -    {
>> -#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
>> -#ifdef HAVE_SETPGID
>> -      /* The call setpgid (0, 0) is supposed to work and mean the same
>> -         thing as this, but on Ultrix 4.2A it fails with EPERM (and
>> -         setpgid (getpid (), getpid ()) succeeds).  */
>> -      retval = setpgid (getpid (), getpid ());
>> -#else
>> -#ifdef HAVE_SETPGRP
>> -#ifdef SETPGRP_VOID
>> -      retval = setpgrp ();
>> -#else
>> -      retval = setpgrp (getpid (), getpid ());
>> -#endif
>> -#endif /* HAVE_SETPGRP */
>> -#endif /* HAVE_SETPGID */
>> -#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
>> -    }
>> -
>> -  return retval;
>> -}
>> -
>>  /* Get all the current tty settings (including whether we have a
>>     tty at all!).  We can't do this in _initialize_inflow because
>>     serial_fdopen() won't work until the serial_ops_list is
>> @@ -860,30 +823,8 @@ _initialize_inflow (void)
>>
>>    terminal_is_ours = 1;
>>
>> -  /* OK, figure out whether we have job control.  If neither termios nor
>> -     sgtty (i.e. termio or go32), leave job_control 0.  */
>> -
>> -#if defined (HAVE_TERMIOS)
>> -  /* Do all systems with termios have the POSIX way of identifying job
>> -     control?  I hope so.  */
>> -#ifdef _POSIX_JOB_CONTROL
>> -  job_control = 1;
>> -#else
>> -#ifdef _SC_JOB_CONTROL
>> -  job_control = sysconf (_SC_JOB_CONTROL);
>> -#else
>> -  job_control = 0;		/* Have to assume the worst.  */
>> -#endif /* _SC_JOB_CONTROL */
>> -#endif /* _POSIX_JOB_CONTROL */
>> -#endif /* HAVE_TERMIOS */
>> -
>> -#ifdef HAVE_SGTTY
>> -#ifdef TIOCGPGRP
>> -  job_control = 1;
>> -#else
>> -  job_control = 0;
>> -#endif /* TIOCGPGRP */
>> -#endif /* sgtty */
>> +  /* OK, figure out whether we have job control.  */
>> +  have_job_control ();
>>
>>    observer_attach_inferior_exit (inflow_inferior_exit);
>>
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index bc1dfe5..6bf3716 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
>>
>>  static int debug_timestamp = 0;
>>
>> -/* Nonzero if we have job control.  */
>> -
>> -int job_control;
>> -
>>  /* Nonzero means that strings with character values >0x7F should be printed
>>     as octal escapes.  Zero means just print the value (e.g. it's an
>>     international character, and the terminal or window can cope.)  */
>>
>
> Otherwise looks fine.
>

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-01-03 21:14     ` Sergio Durigan Junior
@ 2017-01-03 21:27       ` Luis Machado
  2017-01-03 21:38         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2017-01-03 21:27 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, palves

On 01/03/2017 03:14 PM, Sergio Durigan Junior wrote:
> Hey Luis, thanks for the review.
>
> Comments below.
>
> On Monday, December 26 2016, Luis Machado wrote:
>
>> On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
>>> As part of the bigger work of sharing fork_inferior with gdbserver,
>>> some parts of gdb/terminal.h also needed to be moved to a common
>>> place.  These parts are:
>>>
>>> - The code responsible for determining some terminal-based define's
>>>   based on available features;
>>>
>>> - job control;
>>>
>>> - terminal-related functions needed by fork_inferior;
>>>
>>> gdb/ChangeLog:
>>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>
>>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
>>> 	* common/common-terminal.h: New file, with parts of "terminal.h".
>>> 	* terminal.h: Move terminal-related defines to
>>> 	"common/common-terminal.h".
>>> 	(new_tty_prefork): Move to "common/common-terminal.h".
>>> 	(new_tty): Likewise.
>>> 	(new_tty_postfork): Likewise.
>>> 	(job_control): Likewise.
>>> 	(create_tty_session): Likewise.
>>> 	(gdb_setpgid): Likewise.
>>> 	* utils.c: Include "terminal.h".
>>>
>>> gdb/ChangeLog:
>>
>> gdb/gdbserver/ChangeLog
>
> Thanks, will fix.
>
>>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>
>>> 	* terminal.c: New file.
>>> ---
>>>  gdb/Makefile.in                              |  1 +
>>>  gdb/{terminal.h => common/common-terminal.h} | 55 +++++++++++++--------
>>>  gdb/gdbserver/terminal.c                     | 72 +++++++++++++++++++++++++++
>>>  gdb/terminal.h                               | 73 +---------------------------
>>>  gdb/utils.c                                  |  1 +
>>>  5 files changed, 109 insertions(+), 93 deletions(-)
>>>  copy gdb/{terminal.h => common/common-terminal.h} (66%)
>>>  create mode 100644 gdb/gdbserver/terminal.c
>>>
>>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>>> index 051f07d..51c0f73 100644
>>> --- a/gdb/Makefile.in
>>> +++ b/gdb/Makefile.in
>>> @@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
>>>  	common/common-regcache.h \
>>>  	common/common-types.h \
>>>  	common/common-utils.h \
>>> +	common/common-terminal.h \
>>>  	common/errors.h \
>>>  	common/environ.h \
>>>  	common/fileio.h \
>>> diff --git a/gdb/terminal.h b/gdb/common/common-terminal.h
>>> similarity index 66%
>>> copy from gdb/terminal.h
>>> copy to gdb/common/common-terminal.h
>>
>> Creating a new common/common-terminal.[h|c] may be cleaner than
>> git-copying and then modifying it. With a new file we get all the
>> included changes, whereas with git-copying we get a number of
>> unrelated changes that need to be removed.
>
> I actually created a new file and moved the necessary things by hand.  I
> think git marked this as a copy because I have a special setting on my
> $HOME/.gitconfig telling it to detect copies on diff's.  But if you look
> below, you'll see that gdb/terminal.h is still there.
>
> Anyway, I can send a different diff if you want.
>

No need. It just looked slightly off. But i got it once i noticed that 
git handled the copy on its own.

>>> index 0deced4..0ec8a23 100644
>>> --- a/gdb/terminal.h
>>> +++ b/gdb/common/common-terminal.h
>>> @@ -16,9 +16,8 @@
>>>     You should have received a copy of the GNU General Public License
>>>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>>>
>>> -#if !defined (TERMINAL_H)
>>> -#define TERMINAL_H 1
>>> -
>>> +#ifndef COMMON_TERMINAL_H
>>> +#define COMMON_TERMINAL_H
>>>
>>>  /* If we're using autoconf, it will define HAVE_TERMIOS_H,
>>>     HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>>> @@ -76,37 +75,51 @@
>>>  #endif /* sgtty */
>>>  #endif
>>>
>>> -struct inferior;
>>> +#include <sys/types.h>
>>> +
>>> +/* Do we have job control?  Can be assumed to always be the same
>>> +   within a given run of GDB.  Use in gdb/inflow.c and
>>> +   common/common-inflow.c.  */
>>>
>>> -extern void new_tty_prefork (const char *);
>>> +extern int job_control;
>>>
>>>  extern void new_tty (void);
>>>
>>> -extern void new_tty_postfork (void);
>>> +/* NEW_TTY_PREFORK is called before forking a new child process,
>>> +   so we can record the state of ttys in the child to be formed.
>>> +   TTYNAME is null if we are to share the terminal with gdb;
>>
>> This mentions gdb, but it may be used for gdbserver as well? We may
>> need generic wording here to account for that fact. This happens in
>> other places as well...
>
> Right, I'll fix these comments.
>
>>> +   or points to a string containing the name of the desired tty.
>>>
>>> -extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>>> +   NEW_TTY is called in new child processes under Unix, which will
>>> +   become debugger target processes.  This actually switches to
>>> +   the terminal specified in the NEW_TTY_PREFORK call.  */
>>>
>>> -/* Do we have job control?  Can be assumed to always be the same within
>>> -   a given run of GDB.  In inflow.c.  */
>>> -extern int job_control;
>>> +extern void new_tty_prefork (const char *ttyname);
>>>
>>> -extern pid_t create_tty_session (void);
>>> +/* NEW_TTY_POSTFORK is called after forking a new child process, and
>>> +   adding it to the inferior table, to store the TTYNAME being used by
>>> +   the child, or null if it sharing the terminal with gdb.  */
>>>
>>> -/* Set the process group of the caller to its own pid, or do nothing if
>>> -   we lack job control.  */
>>> -extern int gdb_setpgid (void);
>>> +extern void new_tty_postfork (void);
>>>
>>> -/* Set up a serial structure describing standard input.  In inflow.c.  */
>>> -extern void initialize_stdin_serial (void);
>>> +/* Create a new session if the inferior will run in a different tty.
>>> +   A session is UNIX's way of grouping processes that share a controlling
>>> +   terminal, so a new one is needed if the inferior terminal will be
>>> +   different from GDB's.
>>
>> ... like here.
>>
>>>
>>> -extern void gdb_save_tty_state (void);
>>> +   Returns the session id of the new session, 0 if no session was created
>>> +   or -1 if an error occurred.  */
>>>
>>> -/* Take a snapshot of our initial tty state before readline/ncurses
>>> -   have had a chance to alter it.  */
>>> -extern void set_initial_gdb_ttystate (void);
>>> +extern pid_t create_tty_session (void);
>>>
>>>  /* Set the process group of the caller to its own pid, or do nothing
>>>     if we lack job control.  */
>>> +
>>
>> Spurious newline?
>
> Not really.  Even though this is a cosmetic change and could be removed
> from the patch, I decided to leave it there.  Our coding standards
> explain this:
>
>   https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Blank_Line_After_Block_Comment_Preceding_Variable_Definitions
>

Ok. Thanks for clarifying this. GDB's codebase seems to be inconsistent 
here. Some places add a newline while others don't.

>>>  extern int gdb_setpgid (void);
>>>
>>> -#endif /* !defined (TERMINAL_H) */
>>> +/* Determine whether we have job control, and set variable JOB_CONTROL
>>> +   accordingly.  */
>>> +
>>> +extern void have_job_control (void);
>>> +
>>> +#endif /* ! COMMON_TERMINAL_H */
>>> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
>>> new file mode 100644
>>> index 0000000..9813018
>>> --- /dev/null
>>> +++ b/gdb/gdbserver/terminal.c
>>> @@ -0,0 +1,72 @@
>>> +/* Terminal interface definitions for the GDB remote server.
>>> +   Copyright (C) 2016 Free Software Foundation, Inc.
>>> +
>>> +   This file is part of GDB.
>>> +
>>> +   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 "server.h"
>>> +#include "common-terminal.h"
>>> +
>>> +/* See common/common-terminal.h.  */
>>> +
>>> +void
>>> +new_tty (void)
>>> +{
>>> +  /* To be implemented.  */
>>> +}
>>> +
>>> +/* See common/common-terminal.h.  */
>>> +
>>> +void
>>> +new_tty_prefork (const char *ttyname)
>>> +{
>>> +  /* To be implemented.  */
>>> +}
>>> +
>>> +/* See common/common-terminal.h.  */
>>> +
>>> +void
>>> +new_tty_postfork (void)
>>> +{
>>> +  /* To be implemented.  */
>>> +}
>>
>> Are these going to be implemented at some point or is this something
>> that may not be addressed until much later on?
>
> They're not exactly on my radar, but they're a part of the local/remote
> feature parity, so they will be tackled soon, I'd figure.
>
>> It wouldn't be great to have a number of these lying around with no
>> clear plan to have them addressed.
>
> I agree.
>
>> Are these counterparts of what gdb always has? Does it make sense to
>> unify those functions instead of adding placeholders for a potentially
>> different implementation?
>
> I'll try to give these a try and implementing them.  My only concern is
> that I don't want these to explode into a giant new task to implement
> inferior I/O on gdbserver, but it may be possible to just touch the
> necessary bits and make it simple.
>

The rule is that the patch sender automatically volunteers for 
additional bits of work. :-P

Honestly, if it gets too complicated, then it should be fine to have the 
placeholders. But then it would be nice to add some more interesting 
comments on how these ought to be implemented in the future, along with 
bits on how these should be synched with what gdb already supports.

Just an idea.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2016-12-26 21:35   ` Luis Machado
@ 2017-01-03 21:31     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:31 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

Thanks for the review.

Comments below.

On Monday, December 26 2016, Luis Machado wrote:

> On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
>> Again, it was necessary to share a few functions declared on
>> gdb/gdbthread.h with gdbserver, because they are needed by
>> fork_inferior.  I decided to implement them on
>> gdb/gdbserver/inferiors.c because that's where the thread functions
>> are also implemented on gdbserver.  As a side note, due to the way
>> gdbserver marks a thread as executing, a new argument needed to be
>> added on set_executing.  This argument is a 'struct target_waitstatus
>> *', and is not necessary on GDB, so it was marked with
>> ATTRIBUTE_UNUSED accordingly.
>>
>> gdb/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
>> 	* common/common-gdbthread.h: New file, with parts from
>> 	"gdb/gdbthread.h".
>> 	* fork-child.c (fork_inferior): Update call of "set_executing".
>> 	* gdbthread.h: Include "common-gdbthread.h".
>> 	(init_thread_list): Moved to "common/common-gdbthread.h".
>> 	(add_thread_silent): Likewise.
>> 	(switch_to_thread): Likewise.
>> 	(set_executing): Likewise.  Added an extra argument, "struct
>> 	target_waitstatus *".
>> 	* infrun.c (handle_inferior_event_1): Update call of
>> 	"set_executing".
>> 	* linux-nat.c (attach_proc_task_lwp_callback): Likewise.
>> 	(linux_handle_extended_wait): Likewise.
>> 	* record-btrace.c (get_thread_current_frame): Likewise.
>> 	* record-full.c (record_full_wait_1): Likewise.
>> 	* remote.c (remote_add_thread): Likewise.
>> 	(process_initial_stop_replies): Likewise.
>> 	* solib-spu.c (spu_skip_standalone_loader): Likewise.
>> 	* target.c (target_resume): Likewise.
>> 	* thread.c (set_executing): Update function declaration to add
>> 	third argument.  Mark it as unused.
>>
>> gdb/gdbserver/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* inferiors.c (init_thread_list): New function.
>> 	(switch_to_thread): Likewise.
>> 	(set_executing): Likewise.
>> 	(add_thread_silent): Likewise.
>> ---
>>  gdb/Makefile.in               |  1 +
>>  gdb/common/common-gdbthread.h | 50 +++++++++++++++++++++++++++++++++++++++++++
>>  gdb/fork-child.c              |  2 +-
>>  gdb/gdbserver/inferiors.c     | 42 ++++++++++++++++++++++++++++++++++++
>>  gdb/gdbthread.h               | 20 +----------------
>>  gdb/infrun.c                  |  2 +-
>>  gdb/linux-nat.c               |  4 ++--
>>  gdb/record-btrace.c           |  6 +++---
>>  gdb/record-full.c             |  4 ++--
>>  gdb/remote.c                  |  4 ++--
>>  gdb/solib-spu.c               |  2 +-
>>  gdb/target.c                  |  2 +-
>>  gdb/thread.c                  |  5 ++++-
>>  13 files changed, 111 insertions(+), 33 deletions(-)
>>  create mode 100644 gdb/common/common-gdbthread.h
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 8372b4a..ca13a80 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
>>  	common/common-debug.h \
>>  	common/common-defs.h \
>>  	common/common-exceptions.h \
>> +	common/common-gdbthread.h \
>>  	common/common-regcache.h \
>>  	common/common-types.h \
>>  	common/common-utils.h \
>> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
>> new file mode 100644
>> index 0000000..3560892
>> --- /dev/null
>> +++ b/gdb/common/common-gdbthread.h
>> @@ -0,0 +1,50 @@
>> +/* Multi-process/thread control defs for GDB, the GNU debugger.
>> +   Copyright (C) 1987-2016 Free Software Foundation, Inc.
>> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
>> +
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_THREAD_H
>> +#define COMMON_THREAD_H
>> +
>> +struct target_waitstatus;
>> +
>> +/* Create an empty thread list, or empty the existing one.  */
>> +
>
> Spurious newline, multiple cases of this throughout.

Yeah, now you're right:

  https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation

  "Note that this only applies to the case where the comment is placed
  besides the subprogram implementation (typically in a .c file). In the
  case of the documentation being placed next to the subprogram
  declaration, then the comment should be placed immediately before the
  declaration."

I'll fix these.  Thanks.

>> +extern void init_thread_list (void);
>> +
>> +/* Switch from one thread to another.  */
>> +
>> +extern void switch_to_thread (ptid_t ptid);
>> +
>> +/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
>> +   marks all threads.
>> +
>> +   Note that this is different from the running state.  See the
>> +   description of state and executing fields of struct
>> +   thread_info.  */
>> +
>> +extern void set_executing (ptid_t ptid, int executing,
>> +			   struct target_waitstatus *ws);
>> +
>> +/* Add a thread to the thread list and return the pointer to the new
>> +   thread.  Caller may use this pointer to initialize the private
>> +   thread data.  */
>> +
>> +extern struct thread_info *add_thread_silent (ptid_t ptid);
>> +
>> +#endif /* ! COMMON_THREAD_H */
>> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
>> index 15f8249..38fca60 100644
>> --- a/gdb/fork-child.c
>> +++ b/gdb/fork-child.c
>> @@ -545,7 +545,7 @@ startup_inferior (int ntraps)
>>      }
>>
>>    /* Mark all threads non-executing.  */
>> -  set_executing (resume_ptid, 0);
>> +  set_executing (resume_ptid, 0, NULL);
>>  }
>>
>>  /* Implement the "unset exec-wrapper" command.  */
>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>> index 574a7ba..6b981d0 100644
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -468,3 +468,45 @@ make_cleanup_restore_current_thread (void)
>>  {
>>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>>  }
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +init_thread_list (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +switch_to_thread (ptid_t ptid)
>> +{
>> +  if (!ptid_equal (ptid, minus_one_ptid))
>> +    current_thread = find_thread_ptid (ptid);
>> +}
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED,
>> +	       struct target_waitstatus *ws)
>> +{
>> +  gdb_assert (current_thread != NULL);
>> +  current_thread->last_resume_kind = resume_stop;
>> +  current_thread->last_status = *ws;
>
> Is there a chance ws will be NULL and cause a crash here? Should we assert?

Yeah, I was also thinking about that, but currently there is no chance
of it being NULL.  The only place that calls this function for gdbserver
is fork_inferior, and if the function is called without a current_thread
then something really wrong happened.

>> +}
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +struct thread_info *
>> +add_thread_silent (ptid_t ptid)
>> +{
>> +  pid_t pid = ptid_get_pid (ptid);
>> +
>> +  /* Check if there is a process already.  */
>> +  if (find_process_pid (pid) == NULL)
>> +    add_process (pid, 0);
>> +
>> +  return add_thread (ptid_build (pid, pid, 0), NULL);
>> +}
>> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
>> index 8f37fbb..d6fdc42 100644
>> --- a/gdb/gdbthread.h
>> +++ b/gdb/gdbthread.h
>> @@ -31,6 +31,7 @@ struct symtab;
>>  #include "common/vec.h"
>>  #include "target/waitstatus.h"
>>  #include "cli/cli-utils.h"
>> +#include "common-gdbthread.h"
>>
>>  /* Frontend view of the thread state.  Possible extensions: stepping,
>>     finishing, until(ling),...  */
>> @@ -344,19 +345,12 @@ struct thread_info
>>    struct thread_info *step_over_next;
>>  };
>>
>> -/* Create an empty thread list, or empty the existing one.  */
>> -extern void init_thread_list (void);
>> -
>>  /* Add a thread to the thread list, print a message
>>     that a new thread is found, and return the pointer to
>>     the new thread.  Caller my use this pointer to
>>     initialize the private thread data.  */
>>  extern struct thread_info *add_thread (ptid_t ptid);
>>
>> -/* Same as add_thread, but does not print a message
>> -   about new thread.  */
>> -extern struct thread_info *add_thread_silent (ptid_t ptid);
>> -
>>  /* Same as add_thread, and sets the private info.  */
>>  extern struct thread_info *add_thread_with_info (ptid_t ptid,
>>  						 struct private_thread_info *);
>> @@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
>>
>>  extern int thread_count (void);
>>
>> -/* Switch from one thread to another.  Also sets the STOP_PC
>> -   global.  */
>> -extern void switch_to_thread (ptid_t ptid);
>> -
>>  /* Switch from one thread to another.  Does not read registers and
>>     sets STOP_PC to -1.  */
>>  extern void switch_to_thread_no_regs (struct thread_info *thread);
>> @@ -518,14 +508,6 @@ extern int is_exited (ptid_t ptid);
>>  /* In the frontend's perpective, is this thread stopped?  */
>>  extern int is_stopped (ptid_t ptid);
>>
>> -/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
>> -   marks all threads.
>> -
>> -   Note that this is different from the running state.  See the
>> -   description of state and executing fields of struct
>> -   thread_info.  */
>> -extern void set_executing (ptid_t ptid, int executing);
>> -
>>  /* Reports if thread PTID is executing.  */
>>  extern int is_executing (ptid_t ptid);
>>
>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>> index bf0632e..f5cc965 100644
>> --- a/gdb/infrun.c
>> +++ b/gdb/infrun.c
>> @@ -4947,7 +4947,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
>>      else
>>        mark_ptid = ecs->ptid;
>>
>> -    set_executing (mark_ptid, 0);
>> +    set_executing (mark_ptid, 0, NULL);
>>
>>      /* Likewise the resumed flag.  */
>>      set_resumed (mark_ptid, 0);
>> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
>> index cbf94ed..9db620c 100644
>> --- a/gdb/linux-nat.c
>> +++ b/gdb/linux-nat.c
>> @@ -1190,7 +1190,7 @@ attach_proc_task_lwp_callback (ptid_t ptid)
>>  	     raw clone).  */
>>  	  add_thread (lp->ptid);
>>  	  set_running (lp->ptid, 1);
>> -	  set_executing (lp->ptid, 1);
>> +	  set_executing (lp->ptid, 1, NULL);
>>  	}
>>
>>        return 1;
>> @@ -2083,7 +2083,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
>>  	     and the user/frontend, this new thread is running until
>>  	     it next reports a stop.  */
>>  	  set_running (new_lp->ptid, 1);
>> -	  set_executing (new_lp->ptid, 1);
>> +	  set_executing (new_lp->ptid, 1, NULL);
>>
>>  	  if (WSTOPSIG (status) != SIGSTOP)
>>  	    {
>> diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
>> index 7c0e39f..80cf274 100644
>> --- a/gdb/record-btrace.c
>> +++ b/gdb/record-btrace.c
>> @@ -1928,7 +1928,7 @@ get_thread_current_frame (struct thread_info *tp)
>>       move the thread.  Since we need to recompute the stack, we temporarily
>>       set EXECUTING to flase.  */
>>    executing = is_executing (inferior_ptid);
>> -  set_executing (inferior_ptid, 0);
>> +  set_executing (inferior_ptid, 0, NULL);
>>
>>    frame = NULL;
>>    TRY
>> @@ -1938,7 +1938,7 @@ get_thread_current_frame (struct thread_info *tp)
>>    CATCH (except, RETURN_MASK_ALL)
>>      {
>>        /* Restore the previous execution state.  */
>> -      set_executing (inferior_ptid, executing);
>> +      set_executing (inferior_ptid, executing, NULL);
>>
>>        /* Restore the previous inferior_ptid.  */
>>        inferior_ptid = old_inferior_ptid;
>> @@ -1948,7 +1948,7 @@ get_thread_current_frame (struct thread_info *tp)
>>    END_CATCH
>>
>>    /* Restore the previous execution state.  */
>> -  set_executing (inferior_ptid, executing);
>> +  set_executing (inferior_ptid, executing, NULL);
>>
>>    /* Restore the previous inferior_ptid.  */
>>    inferior_ptid = old_inferior_ptid;
>> diff --git a/gdb/record-full.c b/gdb/record-full.c
>> index 5608e70..3ad9a08 100644
>> --- a/gdb/record-full.c
>> +++ b/gdb/record-full.c
>> @@ -1156,12 +1156,12 @@ record_full_wait_1 (struct target_ops *ops,
>>  			{
>>  			  /* Try to insert the software single step breakpoint.
>>  			     If insert success, set step to 0.  */
>> -			  set_executing (inferior_ptid, 0);
>> +			  set_executing (inferior_ptid, 0, NULL);
>>  			  reinit_frame_cache ();
>>
>>  			  step = !insert_single_step_breakpoints (gdbarch);
>>
>> -			  set_executing (inferior_ptid, 1);
>> +			  set_executing (inferior_ptid, 1, NULL);
>>  			}
>>
>>  		      if (record_debug)
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index ef6c54e..0b5f837 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -1847,7 +1847,7 @@ remote_add_thread (ptid_t ptid, int running, int executing)
>>      thread = add_thread (ptid);
>>
>>    get_private_info_thread (thread)->vcont_resumed = executing;
>> -  set_executing (ptid, executing);
>> +  set_executing (ptid, executing, NULL);
>>    set_running (ptid, running);
>>  }
>>
>> @@ -3949,7 +3949,7 @@ process_initial_stop_replies (int from_tty)
>>  	  || ws.value.sig != GDB_SIGNAL_0)
>>  	thread->suspend.waitstatus_pending_p = 1;
>>
>> -      set_executing (event_ptid, 0);
>> +      set_executing (event_ptid, 0, NULL);
>>        set_running (event_ptid, 0);
>>        thread->priv->vcont_resumed = 0;
>>      }
>> diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
>> index fa2977e..f55e0a0 100644
>> --- a/gdb/solib-spu.c
>> +++ b/gdb/solib-spu.c
>> @@ -88,7 +88,7 @@ spu_skip_standalone_loader (void)
>>
>>        target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
>>        target_wait (minus_one_ptid, &ws, 0);
>> -      set_executing (minus_one_ptid, 0);
>> +      set_executing (minus_one_ptid, 0, NULL);
>>
>>        inferior_thread ()->control.in_infcall = 0;
>>      }
>> diff --git a/gdb/target.c b/gdb/target.c
>> index 246d292..e7c68bf 100644
>> --- a/gdb/target.c
>> +++ b/gdb/target.c
>> @@ -2325,7 +2325,7 @@ target_resume (ptid_t ptid, int step, enum gdb_signal signal)
>>    registers_changed_ptid (ptid);
>>    /* We only set the internal executing state here.  The user/frontend
>>       running state is set at a higher level.  */
>> -  set_executing (ptid, 1);
>> +  set_executing (ptid, 1, NULL);
>>    clear_inline_frame_state (ptid);
>>  }
>>
>> diff --git a/gdb/thread.c b/gdb/thread.c
>> index e5d6c5f..1114aac 100644
>> --- a/gdb/thread.c
>> +++ b/gdb/thread.c
>> @@ -1011,8 +1011,11 @@ is_executing (ptid_t ptid)
>>    return tp->executing;
>>  }
>>
>> +/* See common/common-gdbthread.h.  */
>> +
>>  void
>> -set_executing (ptid_t ptid, int executing)
>> +set_executing (ptid_t ptid, int executing,
>> +	       struct target_waitstatus *ws ATTRIBUTE_UNUSED)
>
> I'm thinking about this change. Isn't there a better way to do this
> without adding gdb/gdbserver-specific parameters and then passing
> dummy values for the unused parameters depending on who's calling?
>
> Maybe making gdbserver accept the same parameters as gdb and then do
> some extra processing in gdbserver to get at the waitstatus data if it
> still needs that? Or maybe unifying the function and making gdb and
> gdbserver operate the same way in this regard.

Hm.  Re-reading the code now, I've realized there is a way to make
things work.

startup_inferior already sets the global "last_status" (from
gdbserver/server.c) when it's executing.  Therefore, it is possible to
access this variable (maybe through a getter on server.c), and there is
no need to pass it to set_executing.  Of course, that'd mean relying on
a global value to set current_thread->last_status, but that doesn't
really change what is already being done today.

With this modification, there is no need to extend set_executing and
make it receive a target_waitstatus.  However, for gdbserver, both the
PTID and the EXECUTING arguments will still be useless.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-27  0:26   ` Tom Tromey
@ 2017-01-03 21:32     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:32 UTC (permalink / raw)
  To: Tom Tromey; +Cc: GDB Patches, palves

On Monday, December 26 2016, Tom Tromey wrote:

>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> [...]
> Sergio> A new packet is added, QStartupShell, and this
> Sergio> packet is sent on initialization.
>
> Sergio> A documentation patch is included, along with a new testcase for the
> Sergio> feature.
>
> I didn't see a documentation patch for the new packet.  I think this is
> important to have.

Thanks for the comment, Tom.  I'll make sure to write the docs.

Cheers,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2016-12-26 21:34   ` Luis Machado
@ 2017-01-03 21:35     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:35 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

On Monday, December 26 2016, Luis Machado wrote:

> On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
>> This patch implements the proper support for the "startup-with-shell"
>> feature on gdbserver.  A new packet is added, QStartupShell, and this
>> packet is sent on initialization.  If the host sends a
>> "QStartupShell:" (i.e., without arguments), it means the inferior
>> shall be started without using a shell.  Otherwise, the argument on
>> the packet is the shell to be used to start the inferior.
>>
>> I decided to use the "startup-with-shell" setting from the host in
>> order to decide whether to start the remote inferior using a shell or
>> not.  However, since there is no easy way to change which shell to use
>> when starting things, I have also added a new command, "set/show
>> remote startup-shell", which can contain the shell that the remote
>> target will use.
>>
>> A documentation patch is included, along with a new testcase for the
>> feature.
>>
>> gdb/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* remote.c (remote_startup_shell_var): New variable.
>> 	(set_remote_startup_shell): New function.
>> 	(show_remote_startup_shell): Likewise.
>> 	Add PACKET_QStartupShell.
>> 	(remote_start_remote): Handle new PACKET_QStartupShell.
>> 	(struct protocol_feature remote_protocol_features): New entry for
>> 	PACKET_QStartupShell.
>> 	(_initialize_remote): Call "add_packet_config_cmd" for
>> 	QStartupShell.  Add new set/show command "set remote
>> 	startup-shell".
>>
>> gdb/gdbserver/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* server.c (handle_general_set): Handle new packet
>> 	"QStartupShell".
>> 	(handle_query): Add "QStartupShell" to the list of supported
>> 	packets.
>>
>> gdb/testsuite/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* gdb.server/startup-with-shell.c: New file.
>> 	* gdb.server/startup-with-shell.exp: Likewise.
>>
>> gdb/doc/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* gdb.texinfo (startup-with-shell): Add note mentioning that the
>> 	setting is also used by remote targets.
>> 	(set remote startup-shell): New item.
>> ---
>>  gdb/doc/gdb.texinfo                             |  14 +++
>>  gdb/gdbserver/server.c                          |  22 ++++-
>>  gdb/remote.c                                    |  62 +++++++++++++
>>  gdb/testsuite/gdb.server/startup-with-shell.c   |  12 +++
>>  gdb/testsuite/gdb.server/startup-with-shell.exp | 110 ++++++++++++++++++++++++
>>  5 files changed, 219 insertions(+), 1 deletion(-)
>>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
>>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp
>>
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index a0de7d1..3250cae 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -2174,6 +2174,10 @@ initialization file---such as @file{.cshrc} for C-shell,
>>  $@file{.zshenv} for the Z shell, or the file specified in the
>>  @samp{BASH_ENV} environment variable for BASH.
>>
>> +This setting is also used by @code{target extended-remote} to
>> +determine whether the target system will start the inferior using the
>> +shell (@pxref{set remote startup-shell}).
>> +
>>  @anchor{set auto-connect-native-target}
>>  @kindex set auto-connect-native-target
>>  @item set auto-connect-native-target
>> @@ -20486,6 +20490,16 @@ extended-remote}.  This should be set to a filename valid on the
>>  target system.  If it is not set, the target will use a default
>>  filename (e.g.@: the last program run).
>>
>> +@item set remote startup-shell @var{shell}
>> +@itemx show remote startup-shell
>> +@anchor{set remote startup-shell}
>> +@cindex startup shell, for remote target
>> +Set the shell that is going to be used to start the inferior with
>> +@code{target extended-remote}.  This should be set to a valid shell on
>> +the target system, and is only effective when
>> +@code{startup-with-shell} is on.  If it is not set, the target system
>> +will use the shell pointed by the @code{SHELL} environment variable.
>> +
>>  @item set remote interrupt-sequence
>>  @cindex interrupt remote programs
>>  @cindex select Ctrl-C, BREAK or BREAK-g
>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>> index 55eebd9..5faf0b5 100644
>> --- a/gdb/gdbserver/server.c
>> +++ b/gdb/gdbserver/server.c
>> @@ -863,6 +863,26 @@ handle_general_set (char *own_buf)
>>        return;
>>      }
>>
>> +  if (startswith (own_buf, "QStartupShell:"))
>> +    {
>> +      const char *p = own_buf + strlen ("QStartupShell:");
>> +
>> +      if (*p == '\0')
>> +	{
>> +	  startup_with_shell = 0;
>> +	  xfree (startup_shell);
>> +	}
>> +      else
>> +	{
>> +	  startup_with_shell = 1;
>> +	  xfree (startup_shell);
>> +	  startup_shell = xstrdup (p);
>> +	}
>> +
>> +      write_ok (own_buf);
>> +      return;
>> +    }
>> +
>>    /* Otherwise we didn't know what packet it was.  Say we didn't
>>       understand it.  */
>>    own_buf[0] = 0;
>> @@ -2299,7 +2319,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+;QStartupShell+",
>>  	       PBUFSIZ - 1);
>>
>>        if (target_supports_catch_syscall ())
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index 0b5f837..2d2a87a 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -86,6 +86,12 @@ static const struct program_space_data *remote_pspace_data;
>>     location of the remote exec-file value.  */
>>  static char *remote_exec_file_var;
>>
>> +/* The variable that holds the startup shell that will be used by the
>> +   remote target to start the inferior.  If this variable is NULL or
>> +   empty, we use the value of 'get_startup_shell'.  */
>> +
>
> Spurious newline.

According to my previous comments, this is OK.

>> +static char *remote_startup_shell_var;
>> +
>>  /* The size to align memory write packets, when practical.  The protocol
>>     does not guarantee any alignment, and gdb will generate short
>>     writes and unaligned writes, but even as a best-effort attempt this
>> @@ -727,6 +733,22 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
>>    fprintf_filtered (file, "%s\n", remote_exec_file_var);
>>  }
>>
>> +/* The "set/show remote startup-shell" set command hook.  */
>> +
>
> Technically shouldn't we break this up into a couple comments?
>
> Or maybe "... set command hooks."

I was lazy and copied the comments from the previous set/show
functions.  I'll split the comments in two.

>> +static void
>> +set_remote_startup_shell (char *ignored, int from_tty,
>> +			  struct cmd_list_element *c)
>> +{
>> +  gdb_assert (remote_startup_shell_var != NULL);
>> +}
>> +
>> +static void
>> +show_remote_startup_shell (struct ui_file *file, int from_tty,
>> +			   struct cmd_list_element *cmd, const char *value)
>> +{
>> +  fprintf_filtered (file, "%s\n", remote_startup_shell_var);
>> +}
>> +
>>  static int
>>  compare_pnums (const void *lhs_, const void *rhs_)
>>  {
>> @@ -1423,6 +1445,7 @@ enum {
>>    PACKET_QPassSignals,
>>    PACKET_QCatchSyscalls,
>>    PACKET_QProgramSignals,
>> +  PACKET_QStartupShell,
>>    PACKET_qCRC,
>>    PACKET_qSearch_memory,
>>    PACKET_vAttach,
>> @@ -4074,6 +4097,31 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
>>    if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
>>      remote_set_permissions (target);
>>
>> +  if (packet_support (PACKET_QStartupShell) != PACKET_DISABLE)
>> +    {
>> +      if (startup_with_shell)
>> +	{
>> +	  const char *sh;
>> +
>> +	  if (remote_startup_shell_var != NULL
>> +	      && *remote_startup_shell_var != '\0')
>> +	    sh = remote_startup_shell_var;
>> +	  else
>> +	    sh = get_startup_shell ();
>> +
>> +	  xsnprintf (rs->buf, get_remote_packet_size (),
>> +		     "QStartupShell:%s", sh);
>> +	}
>> +      else
>> +	xsnprintf (rs->buf, get_remote_packet_size (),
>> +		   "QStartupShell:");
>> +
>> +      putpkt (rs->buf);
>> +      getpkt (&rs->buf, &rs->buf_size, 0);
>> +      if (strcmp (rs->buf, "OK") != 0)
>> +	error (_("Could not set remote startup-with-shell"));
>> +    }
>> +
>>    /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
>>       unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
>>       as a reply to known packet.  For packet "vFile:setfs:" it is an
>> @@ -4628,6 +4676,8 @@ static const struct protocol_feature remote_protocol_features[] = {
>>      PACKET_QCatchSyscalls },
>>    { "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
>>      PACKET_QProgramSignals },
>> +  { "QStartupShell", PACKET_DISABLE, remote_supported_packet,
>> +    PACKET_QStartupShell },
>>    { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
>>      PACKET_QStartNoAckMode },
>>    { "multiprocess", PACKET_DISABLE, remote_supported_packet,
>> @@ -14081,6 +14131,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_QStartupShell],
>> +			 "QStartupShell", "startup-shell", 0);
>> +
>>    add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol],
>>  			 "qSymbol", "symbol-lookup", 0);
>>
>> @@ -14380,6 +14433,15 @@ Show the remote pathname for \"run\""), NULL,
>>  				   &remote_set_cmdlist,
>>  				   &remote_show_cmdlist);
>>
>> +  add_setshow_string_noescape_cmd ("startup-shell", class_files,
>> +				   &remote_startup_shell_var, _("\
>> +Set the remote shell for starting the inferior"), _("\
>> +Show the remote shell for starting the inferior"), NULL,
>> +				   set_remote_startup_shell,
>> +				   show_remote_startup_shell,
>> +				   &remote_set_cmdlist,
>> +				   &remote_show_cmdlist);
>> +
>>    add_setshow_boolean_cmd ("range-stepping", class_run,
>>  			   &use_range_stepping, _("\
>>  Enable or disable range stepping."), _("\
>> diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
>> new file mode 100644
>> index 0000000..ba77b10
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.server/startup-with-shell.c
>> @@ -0,0 +1,12 @@
>
> Missing copyright notice in the source file?

You're right, thanks.

>> +#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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
>> new file mode 100644
>> index 0000000..1bf3654
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
>> @@ -0,0 +1,110 @@
>> +# This testcase is part of GDB, the GNU debugger.
>> +
>> +# Copyright 2016 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/>.
>> +
>> +# Test startup-with-shell support using extended-remote.
>> +
>> +load_lib gdbserver-support.exp
>> +
>> +standard_testfile
>> +
>> +if { [skip_gdbserver_tests] } {
>
> untested "skipping gdbserver tests"

Will fix it, thanks.

>> +    return 0
>> +}
>> +
>> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
>> +    untested "failed to compile"
>
> The above untested call is not needed as prepare_for_testing will
> handle it with the "failed to prepare" message.

Thanks.

>> +    return -1
>> +}
>> +
>> +# Initial setup for simple test (wildcard expansion, variable substitution).
>> +
>> +proc initial_setup_simple { startup_with_shell run_args } {
>> +    global hex decimal binfile
>> +
>> +    clean_restart $binfile
>> +    # Make sure we're disconnected, in case we're testing with an
>> +    # extended-remote board, therefore already connected.
>> +    gdb_test "disconnect" ".*"
>> +
>> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
>> +
>> +    set target_exec [gdbserver_download_current_prog]
>> +    gdbserver_start_extended
>> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
>> +
>> +    gdb_breakpoint main
>> +
>> +    gdb_test "run $run_args" \
>> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
>> +	"run to main"
>> +}
>> +
>> +proc invalid_remote_shell_test { } {
>> +    global binfile
>> +
>> +    clean_restart $binfile
>> +    # Make sure we're disconnected, in case we're testing with an
>> +    # extended-remote board, therefore already connected.
>> +    gdb_test "disconnect" ".*"
>> +
>> +    gdb_test_no_output "set startup-with-shell on"
>> +    gdb_test_no_output "set remote startup-shell /path/to/invalid/shell"
>> +
>> +    set target_exec [gdbserver_download_current_prog]
>> +    gdbserver_start_extended
>> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
>> +
>> +    gdb_breakpoint main
>> +
>> +    gdb_test "run" \
>> +	"Running \"$binfile\" on the remote target failed" \
>> +	"run to main (should fail)"
>> +}
>> +
>> +## Doing the actual tests
>> +
>> +with_test_prefix "startup_with_shell = on; run_args = *.log" {
>> +    initial_setup_simple "on" "*.log"
>> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
>> +	"testing first argument"
>> +}
>> +
>> +with_test_prefix "startup_with_shell = off; run_args = *.log" {
>> +    initial_setup_simple "off" "*.log"
>> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
>> +	"testing first argument"
>> +}
>> +
>> +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)
>> +}
>> +
>> +with_test_prefix "startup_with_shell = on; invalid remote startup-shell" {
>> +    invalid_remote_shell_test
>> +}
>>
>
> Otherwise looks OK.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-01-03 21:27       ` Luis Machado
@ 2017-01-03 21:38         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-03 21:38 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

On Tuesday, January 03 2017, Luis Machado wrote:

>>>> +void
>>>> +new_tty (void)
>>>> +{
>>>> +  /* To be implemented.  */
>>>> +}
>>>> +
>>>> +/* See common/common-terminal.h.  */
>>>> +
>>>> +void
>>>> +new_tty_prefork (const char *ttyname)
>>>> +{
>>>> +  /* To be implemented.  */
>>>> +}
>>>> +
>>>> +/* See common/common-terminal.h.  */
>>>> +
>>>> +void
>>>> +new_tty_postfork (void)
>>>> +{
>>>> +  /* To be implemented.  */
>>>> +}
>>>
>>> Are these going to be implemented at some point or is this something
>>> that may not be addressed until much later on?
>>
>> They're not exactly on my radar, but they're a part of the local/remote
>> feature parity, so they will be tackled soon, I'd figure.
>>
>>> It wouldn't be great to have a number of these lying around with no
>>> clear plan to have them addressed.
>>
>> I agree.
>>
>>> Are these counterparts of what gdb always has? Does it make sense to
>>> unify those functions instead of adding placeholders for a potentially
>>> different implementation?
>>
>> I'll try to give these a try and implementing them.  My only concern is
>> that I don't want these to explode into a giant new task to implement
>> inferior I/O on gdbserver, but it may be possible to just touch the
>> necessary bits and make it simple.
>>
>
> The rule is that the patch sender automatically volunteers for
> additional bits of work. :-P

"Additional bits" it totally fine!  The problem is "additional
gigabytes" ;-).

> Honestly, if it gets too complicated, then it should be fine to have
> the placeholders. But then it would be nice to add some more
> interesting comments on how these ought to be implemented in the
> future, along with bits on how these should be synched with what gdb
> already supports.
>
> Just an idea.

Sure, it's a great idea indeed.  Thanks for bringing this up; I'll work
on this and will come back when I have more news.

Thanks

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 5/6] Share fork_inferior et al with gdbserver
  2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-01-03 23:32   ` Luis Machado
  2017-01-05 20:11     ` Sergio Durigan Junior
  2018-02-21  3:58   ` [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver") Joel Brobecker
  1 sibling, 1 reply; 157+ messages in thread
From: Luis Machado @ 2017-01-03 23:32 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: palves

Not a lot of comments at this point, but a few.

On 12/22/2016 09:39 PM, Sergio Durigan Junior wrote:
> This is the most important (and the biggest, sorry) patch of the
> series.  It moves fork_inferior from gdb/fork-child.c to
> common/common-fork-child.c and makes all the necessary adjustments to
> both GDB and gdbserver to make sure everything works OK.
>
> There is no "most important change" with this patch; all changes are
> made in a progressive way, making sure that gdbserver had the
> necessary features while not breaking GDB at the same time.  For some
> feature, like the target_terminal_* functions, I chose to just use
> placeholders for the real functions on gdbserver, that should be
> implemented in the future.  For now, we don't need them in order to
> make things work.
>
> I've had to take into account the fact that gdbserver uses global
> variables to control which thread is currently running, so you will
> see a few modifications to accomodate that: for example, the new
> argument added to "startup_inferior", or the one added to
> "set_executing".
>
> Last, but not least, I did a major revamp on the way gdbserver
> computes and stores the inferior's arguments.  It's now using a
> std::vector<char *> and std::string where applicable, which makes
> things much easier even to understand.  This simplification was also
> interesting for the "create_inferior" method of gdbserver's target.c;
> now, it only needs one argument (a vector containing the full inferior
> argv) instead of two char * that were confusing to
> manipulate/generate.
>
> I decided to go ahead and implement a partial support for starting the
> inferior with a shell on gdbserver, although the full feature comes in
> the next patch.  For now, the user won't have the option to disable
> the startup-with-shell, and also won't be able to change which shell
> gdbserver will use (other than setting the $SHELL environment
> variable, that is).
>
> Everything is working as expected, and no regressions were present
> during the tests.
>
> gdb/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/common-fork-child.c".
> 	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
> 	"common/common-top.h".
> 	(COMMON_OBS): Add "common-fork-child.o".
> 	* common-fork-child.c: New file, with the majority of
> 	"gdb/fork-child.c".
> 	* common/common-inferior.h: New file, with contents from
> 	"gdb/inferior.h".
> 	* common/common-top.h: New file.
> 	* common/common-utils.h (gdb_flush_out_err): New prototype.
> 	* corefile.c (get_exec_file): Update comment.
> 	* darwin-nat.c (darwin_ptrace_him): Update call of
> 	"startup_inferior".
> 	* fork-child.c: Cleanup unnecessary includes.
> 	(SHELL_FILE): Move to "common/common-fork-child.c".
> 	(environ): Likewise.
> 	(exec_wrapper): Initialize.
> 	(get_exec_wrapper): New function.
> 	(breakup_args): Move to "common/common-fork-child.c"; rename to
> 	"breakup_args_for_exec".
> 	(escape_bang_in_quoted_argument): Move to
> 	"common/common-fork-child.c".
> 	(fork_inferior): Likewise.  Update function to support gdbserver.
> 	(startup_inferior): Likewise.
> 	(_initialize_fork_child): Update documentation for "set/show
> 	startup-with-shell" command.
> 	* gnu-nat.c (gnu_create_inferior): Update call to
> 	"startup_inferior".
> 	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
> 	* inferior.h: Include "common-inferior.h".
> 	(fork_inferior): Move prototype to "common-inferior.h".
> 	(startup_inferior): Likewise.
> 	* procfs.c (procfs_init_inferior): Update call to
> 	"startup_inferior".
> 	* target.h (target_terminal_init): Move prototype to
> 	"target/target.h".
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* target/target.h (target_terminal_init): New prototype, moved
> 	from "target.h".
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* top.h: Include "common-top.h".
> 	(main_ui): Move
> 	(current_ui): Move
> 	* utils.c (gdb_flush_out_err): New function.
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "terminal.c" and
> 	"common/common-fork-child.c".
> 	(OBS): Add common-fork-child.o and terminal.o.
> 	(common-fork-child.o): New rule.
> 	* inferiors (inferior_ptid): New variable.
> 	(inferior_appeared): New function.
> 	(current_inferior): Likewise.
> 	(have_inferiors): Likewise.
> 	* linux-low.c: Include "common-inferior.h" and "environ.h".
> 	(linux_update_process): New function.
> 	(linux_add_process): Update comment.  Adjust function to call
> 	"linux_update_process".
> 	(update_thread_lwp): New function.
> 	(linux_ptrace_fun): Likewise.
> 	(linux_create_inferior): Adjust function prototype to reflect
> 	change on "target.h".  Adjust function code to use
> 	"fork_inferior".
> 	* lynx-low.c (lynx_update_process): New function.
> 	(lynx_add_process): Update comment.  Adjust function to call
> 	"lynx_update_process".
> 	(lynx_ptrace_fun): New function.
> 	(lynx_create_inferior): Adjust function prototype to reflect
> 	change on "target.h".  Adjust function code to use
> 	"fork_inferior".
> 	* nto-low.c (nto_create_inferior): Adjust function prototype and
> 	code to reflect change on "target.h".
> 	* server.c: Include "common-inferior.h", "common-terminal.h",
> 	"common-top.h", "environ.h".
> 	(main_ui): New variable.
> 	(current_ui): Likewise.
> 	(our_environ): Likewise.
> 	(startup_with_shell): Likewise.
> 	(startup_shell): Likewise.
> 	(program_argv): Convert to std::vector<char *>.
> 	(wrapper_argv): Likewise.
> 	(get_exec_wrapper): New function.
> 	(get_exec_file): Likewise.
> 	(get_environ): Likewise.
> 	(pre_fork_inferior): New function, with parts of "start_inferior".
> 	(post_fork_inferior): Likewise.
> 	(handle_v_run): Update code to deal with arguments coming from the
> 	remote host.  Update calls from "start_inferior" to
> 	"create_inferior".
> 	(captured_main): Likewise.  Initialize environment variable.  Call
> 	"have_job_control".
> 	* server.h (startup_shell): New variable.
> 	(pre_fork_inferior): New prototype.
> 	(post_fork_inferior): Likewise.
> 	(get_environ): Likewise.
> 	* spu-low.c (spu_ptrace_fun): New function.
> 	(spu_create_inferior): Adjust function prototype to reflect change
> 	on "target.h".  Adjust function code to use "fork_inferior".
> 	* target.c (target_terminal_init): New function.
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* target.h (struct target_ops) <create_inferior>: Update prototype
> 	to accept one std::vector<char *> representing the full program
> 	argv.
> 	(create_inferior): Update macro.
> 	* utils.c (gdb_flush_out_err): New function.
> 	(free_vector_argv): Likewise.
> 	(stringify_argv): Likewise.
> 	* utils.h (free_vector_argv): New prototype.
> 	(stringify_argv): Likewise.
> 	* win32-low.c (win32_create_inferior): Adjust function prototype
> 	and code to reflect change on "target.h".
>
> gdb/testsuite/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* gdb.server/non-existing-program.exp: Update regex in order to
> 	reflect the fact that gdbserver is now using fork_inferior (with a
> 	shell) to startup the inferior.
> ---
>  gdb/Makefile.in                                   |   4 +
>  gdb/{fork-child.c => common/common-fork-child.c}  | 318 ++++++-------
>  gdb/common/common-inferior.h                      | 113 +++++
>  gdb/{gdbserver/utils.h => common/common-top.h}    |  20 +-
>  gdb/common/common-utils.h                         |   5 +
>  gdb/corefile.c                                    |   4 +-
>  gdb/darwin-nat.c                                  |   2 +-
>  gdb/fork-child.c                                  | 530 +---------------------
>  gdb/gdbserver/Makefile.in                         |   7 +
>  gdb/gdbserver/inferiors.c                         |  27 ++
>  gdb/gdbserver/linux-low.c                         | 124 +++--
>  gdb/gdbserver/lynx-low.c                          |  66 +--
>  gdb/gdbserver/nto-low.c                           |   9 +-
>  gdb/gdbserver/server.c                            | 279 +++++++-----
>  gdb/gdbserver/server.h                            |  19 +
>  gdb/gdbserver/spu-low.c                           |  43 +-
>  gdb/gdbserver/target.c                            |  24 +
>  gdb/gdbserver/target.h                            |   7 +-
>  gdb/gdbserver/utils.c                             |  37 ++
>  gdb/gdbserver/utils.h                             |  12 +
>  gdb/gdbserver/win32-low.c                         |  25 +-
>  gdb/gnu-nat.c                                     |   2 +-
>  gdb/inf-ptrace.c                                  |   2 +-
>  gdb/inferior.h                                    |  12 +-
>  gdb/procfs.c                                      |   2 +-
>  gdb/target.h                                      |  17 -
>  gdb/target/target.h                               |  17 +
>  gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
>  gdb/top.h                                         |   9 +-
>  gdb/utils.c                                       |   9 +
>  30 files changed, 796 insertions(+), 959 deletions(-)
>  copy gdb/{fork-child.c => common/common-fork-child.c} (76%)
>  create mode 100644 gdb/common/common-inferior.h
>  copy gdb/{gdbserver/utils.h => common/common-top.h} (62%)
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index ca13a80..a7d06f9 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1195,6 +1195,7 @@ SFILES = \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> +	common/common-fork-child.c \
>  	common/common-inflow.c \
>  	common/gdb_vecs.c \
>  	common/new-op.c \
> @@ -1483,6 +1484,8 @@ HFILES_NO_SRCDIR = \
>  	common/gdb_sys_time.h \
>  	common/gdb_vecs.h \
>  	common/gdb_wait.h \
> +	common/common-inferior.h \
> +	common/common-top.h \
>  	common/host-defs.h \
>  	common/print-utils.h \
>  	common/ptid.h \
> @@ -1624,6 +1627,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	common-agent.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-fork-child.o \
>  	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
> diff --git a/gdb/fork-child.c b/gdb/common/common-fork-child.c
> similarity index 76%
> copy from gdb/fork-child.c
> copy to gdb/common/common-fork-child.c
> index 38fca60..ab0cafc 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/common/common-fork-child.c
> @@ -19,28 +19,22 @@
>     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 "defs.h"
> -#include "inferior.h"
> -#include "terminal.h"
> -#include "target.h"
> -#include "gdb_wait.h"
> -#include "gdb_vfork.h"
> -#include "gdbcore.h"
> -#include "gdbthread.h"
> -#include "command.h" /* for dont_repeat () */
> -#include "gdbcmd.h"
> -#include "solib.h"
> +#include "common-defs.h"
> +#include "target/waitstatus.h"
> +#include "common-terminal.h"
>  #include "filestuff.h"
> -#include "top.h"
> +#include "target/target.h"
> +#include "common-inferior.h"
> +#include "common-gdbthread.h"
> +#include "common-top.h"
>  #include "signals-state-save-restore.h"
> -#include <signal.h>
> -
> -/* This just gets used as a default if we can't find SHELL.  */
> -#define SHELL_FILE "/bin/sh"
>
>  extern char **environ;
>
> -static char *exec_wrapper;
> +/* Default shell file to be used if 'startup-with-shell' is set but
> +   $SHELL is not.  */
> +
> +#define SHELL_FILE "/bin/sh"
>
>  /* Break up SCRATCH into an argument vector suitable for passing to
>     execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> @@ -48,7 +42,7 @@ static char *exec_wrapper;
>     fill in ARGV with the four arguments "a", "b", "c", "d".  */
>
>  static void
> -breakup_args (char *scratch, char **argv)
> +breakup_args_for_exec (char *scratch, char **argv)
>  {
>    char *cp = scratch, *tmp;
>
> @@ -109,15 +103,120 @@ escape_bang_in_quoted_argument (const char *shell_file)
>    return 0;
>  }
>
> -/* Start an inferior Unix child process and sets inferior_ptid to its
> -   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> -   the arguments to the program.  ENV is the environment vector to
> -   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> -   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> -   one.  */
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_startup_shell (void)
> +{
> +  static char *ret;
> +
> +  ret = getenv ("SHELL");
> +  if (ret == NULL)
> +    ret = SHELL_FILE;
> +
> +  return ret;
> +}
> +
> +/* Quote the shell command that will be executed.  This function is
> +   called when the inferior is going to be executed under a shell
> +   (i.e., when 'startup-with-shell' is set).
> +
> +   SHELL_FILE is the shell which will be used to execute the inferior
> +   (e.g., /bin/sh).
> +
> +   EXEC_FILE is the inferior executable itself.
> +
> +   ALLARGS contains all the arguments that will be passed to the
> +   inferior.
> +
> +   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
> +   the inferior.
> +
> +   SHELL_CMD is a pointer to the resulting shell command that will be
> +   executed.  The resulting shell command will be returned in it.  It
> +   must be pre-allocated and have a reasonable size.  For an example
> +   on how to determine its size, see 'fork_inferior' on
> +   fork-child.c.  */
> +
> +static void
> +quote_shell_command (const char *shell_file, const char *exec_file,
> +		     const char *allargs, const char *exec_wrapper,
> +		     char **shell_cmd)
> +{
> +  char *shell_command = *shell_cmd;
> +  const char *p;
> +  int need_to_quote;
> +  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> +
> +  shell_command[0] = '\0';
> +  strcat (shell_command, "exec ");
> +
> +  /* Add any exec wrapper.  That may be a program name with arguments, so
> +     the user must handle quoting.  */
> +  if (exec_wrapper != NULL)
> +    {
> +      strcat (shell_command, exec_wrapper);
> +      strcat (shell_command, " ");
> +    }
> +
> +  /* Now add exec_file, quoting as necessary.  */
> +
> +  /* Quoting in this style is said to work with all shells.  But
> +     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> +     we need to.  */
> +  p = exec_file;
> +  while (1)
> +    {
> +      switch (*p)
> +	{
> +	case '\'':
> +	case '!':
> +	case '"':
> +	case '(':
> +	case ')':
> +	case '$':
> +	case '&':
> +	case ';':
> +	case '<':
> +	case '>':
> +	case ' ':
> +	case '\n':
> +	case '\t':
> +	  need_to_quote = 1;
> +	  goto end_scan;
> +
> +	case '\0':
> +	  need_to_quote = 0;
> +	  goto end_scan;
> +
> +	default:
> +	  break;
> +	}
> +      ++p;
> +    }
> + end_scan:
> +  if (need_to_quote)
> +    {
> +      strcat (shell_command, "'");
> +      for (p = exec_file; *p != '\0'; ++p)
> +	{
> +	  if (*p == '\'')
> +	    strcat (shell_command, "'\\''");
> +	  else if (*p == '!' && escape_bang)
> +	    strcat (shell_command, "\\!");
> +	  else
> +	    strncat (shell_command, p, 1);
> +	}
> +      strcat (shell_command, "'");
> +    }
> +  else
> +    strcat (shell_command, exec_file);
> +
> +  strcat (shell_command, " ");
> +  strcat (shell_command, allargs);
> +}
>
> -/* This function is NOT reentrant.  Some of the variables have been
> -   made static to ensure that they survive the vfork call.  */
> +/* See common/common-inferior.h.  */
>
>  int
>  fork_inferior (char *exec_file_arg, char *allargs, char **env,
> @@ -127,7 +226,6 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>                                  char * const *env))
>  {
>    int pid;
> -  static char default_shell_file[] = SHELL_FILE;
>    /* Set debug_fork then attach to the child while it sleeps, to debug.  */
>    static int debug_fork = 0;
>    /* This is set to the result of setpgrp, which if vforked, will be visible
> @@ -158,9 +256,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>      {
>        /* Figure out what shell to start up the user program under.  */
>        if (shell_file == NULL)
> -	shell_file = getenv ("SHELL");
> -      if (shell_file == NULL)
> -	shell_file = default_shell_file;
> +	shell_file = get_startup_shell ();
> +
> +      gdb_assert (shell_file != NULL);
>        shell = 1;
>      }
>
> @@ -174,92 +272,28 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>
>        argv = XALLOCAVEC (char *, argc);
>        argv[0] = exec_file;
> -      breakup_args (allargs, &argv[1]);
> +      breakup_args_for_exec (allargs, &argv[1]);
>      }
>    else
>      {
>        /* We're going to call a shell.  */
>        char *shell_command;
> -      int len;
> -      char *p;
> -      int need_to_quote;
> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> +      char *exec_wrapper = get_exec_wrapper ();
> +      size_t len;
>
>        /* Multiplying the length of exec_file by 4 is to account for the
>           fact that it may expand when quoted; it is a worst-case number
>           based on every character being '.  */
>        len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
> -      if (exec_wrapper)
> +      if (exec_wrapper != NULL)
>          len += strlen (exec_wrapper) + 1;
>
>        shell_command = (char *) alloca (len);
>        shell_command[0] = '\0';
>
> -      strcat (shell_command, "exec ");
> -
> -      /* Add any exec wrapper.  That may be a program name with arguments, so
> -	 the user must handle quoting.  */
> -      if (exec_wrapper)
> -	{
> -	  strcat (shell_command, exec_wrapper);
> -	  strcat (shell_command, " ");
> -	}
> -
> -      /* Now add exec_file, quoting as necessary.  */
> -
> -      /* Quoting in this style is said to work with all shells.  But
> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> -         we need to.  */
> -      p = exec_file;
> -      while (1)
> -	{
> -	  switch (*p)
> -	    {
> -	    case '\'':
> -	    case '!':
> -	    case '"':
> -	    case '(':
> -	    case ')':
> -	    case '$':
> -	    case '&':
> -	    case ';':
> -	    case '<':
> -	    case '>':
> -	    case ' ':
> -	    case '\n':
> -	    case '\t':
> -	      need_to_quote = 1;
> -	      goto end_scan;
> -
> -	    case '\0':
> -	      need_to_quote = 0;
> -	      goto end_scan;
> -
> -	    default:
> -	      break;
> -	    }
> -	  ++p;
> -	}
> -    end_scan:
> -      if (need_to_quote)
> -	{
> -	  strcat (shell_command, "'");
> -	  for (p = exec_file; *p != '\0'; ++p)
> -	    {
> -	      if (*p == '\'')
> -		strcat (shell_command, "'\\''");
> -	      else if (*p == '!' && escape_bang)
> -		strcat (shell_command, "\\!");
> -	      else
> -		strncat (shell_command, p, 1);
> -	    }
> -	  strcat (shell_command, "'");
> -	}
> -      else
> -	strcat (shell_command, exec_file);
> -
> -      strcat (shell_command, " ");
> -      strcat (shell_command, allargs);
> +      quote_shell_command (shell_file, exec_file,
> +			   allargs,
> +			   exec_wrapper, &shell_command);
>
>        /* If we decided above to start up with a shell, we exec the
>  	 shell, "-c" says to interpret the next arg as a shell command
> @@ -287,8 +321,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>    /* It is generally good practice to flush any possible pending stdio
>       output prior to doing a fork, to avoid the possibility of both
>       the parent and child flushing the same data after the fork.  */
> -  gdb_flush (main_ui->m_gdb_stdout);
> -  gdb_flush (main_ui->m_gdb_stderr);
> +  gdb_flush_out_err ();
>
>    /* If there's any initialization of the target layers that must
>       happen to prepare to handle the child we're about fork, do it
> @@ -382,13 +415,13 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>
>        /* If we get here, it's an error.  */
>        save_errno = errno;
> -      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
> +      warning ("Cannot exec %s", argv[0]);
> +
>        for (i = 1; argv[i] != NULL; i++)
> -	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
> -      fprintf_unfiltered (gdb_stderr, ".\n");
> -      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
> -			  safe_strerror (save_errno));
> -      gdb_flush (gdb_stderr);
> +	warning (" %s", argv[i]);
> +
> +      warning ("Error: %s\n", safe_strerror (save_errno));
> +
>        _exit (0177);
>      }
>
> @@ -428,10 +461,12 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
>    return pid;
>  }
>
> -/* Accept NTRAPS traps from the inferior.  */
> +/* See common/common-inferior.h.  */
>
>  void
> -startup_inferior (int ntraps)
> +startup_inferior (int ntraps,
> +		  struct target_waitstatus *last_waitstatus,
> +		  ptid_t *last_ptid)
>  {
>    int pending_execs = ntraps;
>    int terminal_initted = 0;
> @@ -451,8 +486,7 @@ startup_inferior (int ntraps)
>    /* The process was started by the fork that created it, but it will
>       have stopped one instruction after execing the shell.  Here we
>       must get it up to actual execution of the real program.  */
> -
> -  if (exec_wrapper)
> +  if (get_exec_wrapper () != NULL)
>      pending_execs++;
>
>    while (1)
> @@ -464,6 +498,11 @@ startup_inferior (int ntraps)
>        memset (&ws, 0, sizeof (ws));
>        event_ptid = target_wait (resume_ptid, &ws, 0);
>
> +      if (last_waitstatus != NULL)
> +	*last_waitstatus = ws;
> +      if (last_ptid != NULL)
> +	*last_ptid = event_ptid;
> +
>        if (ws.kind == TARGET_WAITKIND_IGNORE)
>  	/* The inferior didn't really stop, keep waiting.  */
>  	continue;
> @@ -476,6 +515,12 @@ startup_inferior (int ntraps)
>  	  case TARGET_WAITKIND_VFORKED:
>  	  case TARGET_WAITKIND_SYSCALL_ENTRY:
>  	  case TARGET_WAITKIND_SYSCALL_RETURN:
> +	  case TARGET_WAITKIND_VFORK_DONE:
> +	  case TARGET_WAITKIND_IGNORE:
> +	  case TARGET_WAITKIND_NO_HISTORY:
> +	  case TARGET_WAITKIND_NO_RESUMED:
> +	  case TARGET_WAITKIND_THREAD_CREATED:
> +	  case TARGET_WAITKIND_THREAD_EXITED:
>  	    /* Ignore gracefully during startup of the inferior.  */
>  	    switch_to_thread (event_ptid);
>  	    break;
> @@ -545,50 +590,5 @@ startup_inferior (int ntraps)
>      }
>
>    /* Mark all threads non-executing.  */
> -  set_executing (resume_ptid, 0, NULL);
> -}
> -
> -/* Implement the "unset exec-wrapper" command.  */
> -
> -static void
> -unset_exec_wrapper_command (char *args, int from_tty)
> -{
> -  xfree (exec_wrapper);
> -  exec_wrapper = NULL;
> -}
> -
> -static void
> -show_startup_with_shell (struct ui_file *file, int from_tty,
> -			 struct cmd_list_element *c, const char *value)
> -{
> -  fprintf_filtered (file,
> -		    _("Use of shell to start subprocesses is %s.\n"),
> -		    value);
> -}
> -
> -/* Provide a prototype to silence -Wmissing-prototypes.  */
> -extern initialize_file_ftype _initialize_fork_child;
> -
> -void
> -_initialize_fork_child (void)
> -{
> -  add_setshow_filename_cmd ("exec-wrapper", class_run, &exec_wrapper, _("\
> -Set a wrapper for running programs.\n\
> -The wrapper prepares the system and environment for the new program."),
> -			    _("\
> -Show the wrapper for running programs."), NULL,
> -			    NULL, NULL,
> -			    &setlist, &showlist);
> -
> -  add_cmd ("exec-wrapper", class_run, unset_exec_wrapper_command,
> -           _("Disable use of an execution wrapper."),
> -           &unsetlist);
> -
> -  add_setshow_boolean_cmd ("startup-with-shell", class_support,
> -			   &startup_with_shell, _("\
> -Set use of shell to start subprocesses.  The default is on."), _("\
> -Show use of shell to start subprocesses."), NULL,
> -			   NULL,
> -			   show_startup_with_shell,
> -			   &setlist, &showlist);
> +  set_executing (resume_ptid, 0, last_waitstatus);
>  }
> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
> new file mode 100644
> index 0000000..fb78109
> --- /dev/null
> +++ b/gdb/common/common-inferior.h
> @@ -0,0 +1,113 @@
> +/* Variables that describe the inferior process running under GDB:
> +   Where it is, why it stopped, and how to step it.

Common code that describes the inferior process under GDB/GDBserver ...?

I'd check the other files that were created in common/ to make sure 
their descriptions in the copyright block aren't unchanged from their 
original files.

> +
> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_INFERIOR_H
> +#define COMMON_INFERIOR_H
> +
> +/* Number of traps that happen between exec'ing the shell to run an
> +   inferior and when we finally get to the inferior code, not counting
> +   the exec for the shell.  This is 1 on all supported
> +   implementations.  */
> +
> +#define START_INFERIOR_TRAPS_EXPECTED 1
> +
> +struct inferior;
> +
> +/* Whether to start up the debuggee under a shell.
> +
> +   If startup-with-shell is set, GDB's "run" will attempt to start up
> +   the debuggee under a shell.
> +
> +   This is in order for argument-expansion to occur.  E.g.,
> +
> +   (gdb) run *
> +
> +   The "*" gets expanded by the shell into a list of files.
> +
> +   While this is a nice feature, it may be handy to bypass the shell
> +   in some cases.  To disable this feature, do "set startup-with-shell
> +   false".
> +
> +   The catch-exec traps expected during start-up will be one more if
> +   the target is started up with a shell.  */
> +
> +extern int startup_with_shell;
> +
> +/* Collected pid, tid, etc. of the debugged inferior.  When there's
> +   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
> +
> +extern ptid_t inferior_ptid;
> +
> +/* Accept NTRAPS traps from the inferior.  */
> +
> +extern void startup_inferior (int ntraps,
> +			      struct target_waitstatus *mystatus,
> +			      ptid_t *myptid);
> +
> +/* Start an inferior Unix child process and sets inferior_ptid to its
> +   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> +   the arguments to the program.  ENV is the environment vector to
> +   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> +   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> +   one.  */
> +
> +/* This function is NOT reentrant.  Some of the variables have been
> +   made static to ensure that they survive the vfork call.  */
> +
> +extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
> +               void (*exec_fun) (const char *file, char * const *argv,
> +				 char * const *env));
> +
> +/* Return the shell that must be used to startup the inferior.  The
> +   first attempt is the environment variable SHELL; if it is not set,
> +   then we default to SHELL_FILE.  */
> +
> +extern char *get_startup_shell (void);
> +
> +/* Set/get file name for default use for standard in/out in the inferior.  */
> +
> +extern void set_inferior_io_terminal (const char *terminal_name);
> +extern const char *get_inferior_io_terminal (void);
> +
> +/* Return the exec wrapper to be used when starting the inferior, or NULL
> +   otherwise.  */
> +
> +extern char *get_exec_wrapper (void);
> +
> +/* Return the name of the executable file as a string.
> +   ERR nonzero means get error if there is none specified;
> +   otherwise return 0 in that case.  */
> +
> +extern char *get_exec_file (int err);
> +
> +/* Returns true if the inferior list is not empty.  */
> +
> +extern int have_inferiors (void);
> +
> +extern void inferior_appeared (struct inferior *inf, int pid);
> +
> +/* Return a pointer to the current inferior.  It is an error to call
> +   this if there is no current inferior.  */
> +
> +extern struct inferior *current_inferior (void);
> +
> +#endif /* ! COMMON_INFERIOR_H */
> diff --git a/gdb/gdbserver/utils.h b/gdb/common/common-top.h
> similarity index 62%
> copy from gdb/gdbserver/utils.h
> copy to gdb/common/common-top.h
> index 5e0cead..e282116 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/common/common-top.h
> @@ -1,5 +1,6 @@
> -/* General utility routines for the remote server for GDB.
> -   Copyright (C) 1993-2016 Free Software Foundation, Inc.
> +/* Top level stuff for GDB, the GNU debugger.
> +
> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.
>
>     This file is part of GDB.
>
> @@ -16,10 +17,15 @@
>     You should have received a copy of the GNU General Public License
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>
> -#ifndef UTILS_H
> -#define UTILS_H
> +#ifndef COMMON_TOP_H
> +#define COMMON_TOP_H
> +
> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> +   It always exists and is created automatically when GDB starts
> +   up.  */
> +extern struct ui *main_ui;
>
> -char *paddress (CORE_ADDR addr);
> -char *pfildes (gdb_fildes_t fd);
> +/* The current UI.  */
> +extern struct ui *current_ui;
>
> -#endif /* UTILS_H */
> +#endif /* ! COMMON_TOP_H */
> diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
> index a9053ff..71a5a38 100644
> --- a/gdb/common/common-utils.h
> +++ b/gdb/common/common-utils.h
> @@ -103,4 +103,9 @@ extern const char *skip_spaces_const (const char *inp);
>
>  extern const char *skip_to_space_const (const char *inp);
>
> +/* Flush both stdout and stderr.  This function needs to be
> +   implemented differently on GDB and gdbserver.  */
> +
> +extern void gdb_flush_out_err (void);
> +
>  #endif
> diff --git a/gdb/corefile.c b/gdb/corefile.c
> index 64de931..694308f 100644
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
> @@ -170,9 +170,7 @@ validate_files (void)
>      }
>  }
>
> -/* Return the name of the executable file as a string.
> -   ERR nonzero means get error if there is none specified;
> -   otherwise return 0 in that case.  */
> +/* See common/common-inferior.h.  */
>
>  char *
>  get_exec_file (int err)
> diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
> index 6ca659f4..61f634d 100644
> --- a/gdb/darwin-nat.c
> +++ b/gdb/darwin-nat.c
> @@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
>
>    darwin_init_thread_list (inf);
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>  }
>
>  static void
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 38fca60..d7d2f5e 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -21,531 +21,19 @@
>
>  #include "defs.h"
>  #include "inferior.h"
> -#include "terminal.h"
> -#include "target.h"
> -#include "gdb_wait.h"
> -#include "gdb_vfork.h"
> -#include "gdbcore.h"
> -#include "gdbthread.h"
> -#include "command.h" /* for dont_repeat () */
>  #include "gdbcmd.h"
> -#include "solib.h"
> -#include "filestuff.h"
> -#include "top.h"
> -#include "signals-state-save-restore.h"
> -#include <signal.h>
>
> -/* This just gets used as a default if we can't find SHELL.  */
> -#define SHELL_FILE "/bin/sh"
> +/* The exec-wrapper, if any, that will be used when starting the
> +   inferior.  */
>
> -extern char **environ;
> +static char *exec_wrapper = NULL;
>
> -static char *exec_wrapper;
> +/* See common/common-inferior.h.  */
>
> -/* Break up SCRATCH into an argument vector suitable for passing to
> -   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> -   would get as input the string "a b c d", and as output it would
> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> -
> -static void
> -breakup_args (char *scratch, char **argv)
> +char *
> +get_exec_wrapper (void)
>  {
> -  char *cp = scratch, *tmp;
> -
> -  for (;;)
> -    {
> -      /* Scan past leading separators */
> -      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
> -	cp++;
> -
> -      /* Break if at end of string.  */
> -      if (*cp == '\0')
> -	break;
> -
> -      /* Take an arg.  */
> -      *argv++ = cp;
> -
> -      /* Scan for next arg separator.  */
> -      tmp = strchr (cp, ' ');
> -      if (tmp == NULL)
> -	tmp = strchr (cp, '\t');
> -      if (tmp == NULL)
> -	tmp = strchr (cp, '\n');
> -
> -      /* No separators => end of string => break.  */
> -      if (tmp == NULL)
> -	break;
> -      cp = tmp;
> -
> -      /* Replace the separator with a terminator.  */
> -      *cp++ = '\0';
> -    }
> -
> -  /* Null-terminate the vector.  */
> -  *argv = NULL;
> -}
> -
> -/* When executing a command under the given shell, return non-zero if
> -   the '!' character should be escaped when embedded in a quoted
> -   command-line argument.  */
> -
> -static int
> -escape_bang_in_quoted_argument (const char *shell_file)
> -{
> -  const int shell_file_len = strlen (shell_file);
> -
> -  /* Bang should be escaped only in C Shells.  For now, simply check
> -     that the shell name ends with 'csh', which covers at least csh
> -     and tcsh.  This should be good enough for now.  */
> -
> -  if (shell_file_len < 3)
> -    return 0;
> -
> -  if (shell_file[shell_file_len - 3] == 'c'
> -      && shell_file[shell_file_len - 2] == 's'
> -      && shell_file[shell_file_len - 1] == 'h')
> -    return 1;
> -
> -  return 0;
> -}
> -
> -/* Start an inferior Unix child process and sets inferior_ptid to its
> -   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> -   the arguments to the program.  ENV is the environment vector to
> -   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> -   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> -   one.  */
> -
> -/* This function is NOT reentrant.  Some of the variables have been
> -   made static to ensure that they survive the vfork call.  */
> -
> -int
> -fork_inferior (char *exec_file_arg, char *allargs, char **env,
> -	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> -	       void (*pre_trace_fun) (void), char *shell_file_arg,
> -               void (*exec_fun)(const char *file, char * const *argv,
> -                                char * const *env))
> -{
> -  int pid;
> -  static char default_shell_file[] = SHELL_FILE;
> -  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
> -  static int debug_fork = 0;
> -  /* This is set to the result of setpgrp, which if vforked, will be visible
> -     to you in the parent process.  It's only used by humans for debugging.  */
> -  static int debug_setpgrp = 657473;
> -  static char *shell_file;
> -  static char *exec_file;
> -  char **save_our_env;
> -  int shell = 0;
> -  static char **argv;
> -  const char *inferior_io_terminal = get_inferior_io_terminal ();
> -  struct inferior *inf;
> -  int i;
> -  int save_errno;
> -  struct ui *save_ui;
> -
> -  /* If no exec file handed to us, get it from the exec-file command
> -     -- with a good, common error message if none is specified.  */
> -  exec_file = exec_file_arg;
> -  if (exec_file == 0)
> -    exec_file = get_exec_file (1);
> -
> -  /* 'startup_with_shell' is declared in inferior.h and bound to the
> -     "set startup-with-shell" option.  If 0, we'll just do a
> -     fork/exec, no shell, so don't bother figuring out what shell.  */
> -  shell_file = shell_file_arg;
> -  if (startup_with_shell)
> -    {
> -      /* Figure out what shell to start up the user program under.  */
> -      if (shell_file == NULL)
> -	shell_file = getenv ("SHELL");
> -      if (shell_file == NULL)
> -	shell_file = default_shell_file;
> -      shell = 1;
> -    }
> -
> -  if (!shell)
> -    {
> -      /* We're going to call execvp.  Create argument vector.
> -	 Calculate an upper bound on the length of the vector by
> -	 assuming that every other character is a separate
> -	 argument.  */
> -      int argc = (strlen (allargs) + 1) / 2 + 2;
> -
> -      argv = XALLOCAVEC (char *, argc);
> -      argv[0] = exec_file;
> -      breakup_args (allargs, &argv[1]);
> -    }
> -  else
> -    {
> -      /* We're going to call a shell.  */
> -      char *shell_command;
> -      int len;
> -      char *p;
> -      int need_to_quote;
> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> -
> -      /* Multiplying the length of exec_file by 4 is to account for the
> -         fact that it may expand when quoted; it is a worst-case number
> -         based on every character being '.  */
> -      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
> -      if (exec_wrapper)
> -        len += strlen (exec_wrapper) + 1;
> -
> -      shell_command = (char *) alloca (len);
> -      shell_command[0] = '\0';
> -
> -      strcat (shell_command, "exec ");
> -
> -      /* Add any exec wrapper.  That may be a program name with arguments, so
> -	 the user must handle quoting.  */
> -      if (exec_wrapper)
> -	{
> -	  strcat (shell_command, exec_wrapper);
> -	  strcat (shell_command, " ");
> -	}
> -
> -      /* Now add exec_file, quoting as necessary.  */
> -
> -      /* Quoting in this style is said to work with all shells.  But
> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> -         we need to.  */
> -      p = exec_file;
> -      while (1)
> -	{
> -	  switch (*p)
> -	    {
> -	    case '\'':
> -	    case '!':
> -	    case '"':
> -	    case '(':
> -	    case ')':
> -	    case '$':
> -	    case '&':
> -	    case ';':
> -	    case '<':
> -	    case '>':
> -	    case ' ':
> -	    case '\n':
> -	    case '\t':
> -	      need_to_quote = 1;
> -	      goto end_scan;
> -
> -	    case '\0':
> -	      need_to_quote = 0;
> -	      goto end_scan;
> -
> -	    default:
> -	      break;
> -	    }
> -	  ++p;
> -	}
> -    end_scan:
> -      if (need_to_quote)
> -	{
> -	  strcat (shell_command, "'");
> -	  for (p = exec_file; *p != '\0'; ++p)
> -	    {
> -	      if (*p == '\'')
> -		strcat (shell_command, "'\\''");
> -	      else if (*p == '!' && escape_bang)
> -		strcat (shell_command, "\\!");
> -	      else
> -		strncat (shell_command, p, 1);
> -	    }
> -	  strcat (shell_command, "'");
> -	}
> -      else
> -	strcat (shell_command, exec_file);
> -
> -      strcat (shell_command, " ");
> -      strcat (shell_command, allargs);
> -
> -      /* If we decided above to start up with a shell, we exec the
> -	 shell, "-c" says to interpret the next arg as a shell command
> -	 to execute, and this command is "exec <target-program>
> -	 <args>".  */
> -      argv = (char **) alloca (4 * sizeof (char *));
> -      argv[0] = shell_file;
> -      argv[1] = "-c";
> -      argv[2] = shell_command;
> -      argv[3] = (char *) 0;
> -    }
> -
> -  /* Retain a copy of our environment variables, since the child will
> -     replace the value of environ and if we're vforked, we have to
> -     restore it.  */
> -  save_our_env = environ;
> -
> -  /* Likewise the current UI.  */
> -  save_ui = current_ui;
> -
> -  /* Tell the terminal handling subsystem what tty we plan to run on;
> -     it will just record the information for later.  */
> -  new_tty_prefork (inferior_io_terminal);
> -
> -  /* It is generally good practice to flush any possible pending stdio
> -     output prior to doing a fork, to avoid the possibility of both
> -     the parent and child flushing the same data after the fork.  */
> -  gdb_flush (main_ui->m_gdb_stdout);
> -  gdb_flush (main_ui->m_gdb_stderr);
> -
> -  /* If there's any initialization of the target layers that must
> -     happen to prepare to handle the child we're about fork, do it
> -     now...  */
> -  if (pre_trace_fun != NULL)
> -    (*pre_trace_fun) ();
> -
> -  /* Create the child process.  Since the child process is going to
> -     exec(3) shortly afterwards, try to reduce the overhead by
> -     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
> -     likely that this optimization won't work since there's too much
> -     work to do between the vfork(2) and the exec(3).  This is known
> -     to be the case on ttrace(2)-based HP-UX, where some handshaking
> -     between parent and child needs to happen between fork(2) and
> -     exec(2).  However, since the parent is suspended in the vforked
> -     state, this doesn't work.  Also note that the vfork(2) call might
> -     actually be a call to fork(2) due to the fact that autoconf will
> -     ``#define vfork fork'' on certain platforms.  */
> -  if (pre_trace_fun || debug_fork)
> -    pid = fork ();
> -  else
> -    pid = vfork ();
> -
> -  if (pid < 0)
> -    perror_with_name (("vfork"));
> -
> -  if (pid == 0)
> -    {
> -      /* Switch to the main UI, so that gdb_std{in/out/err} in the
> -	 child are mapped to std{in/out/err}.  This makes it possible
> -	 to use fprintf_unfiltered/warning/error/etc. in the child
> -	 from here on.  */
> -      current_ui = main_ui;
> -
> -      /* Close all file descriptors except those that gdb inherited
> -	 (usually 0/1/2), so they don't leak to the inferior.  Note
> -	 that this closes the file descriptors of all secondary
> -	 UIs.  */
> -      close_most_fds ();
> -
> -      if (debug_fork)
> -	sleep (debug_fork);
> -
> -      /* Create a new session for the inferior process, if necessary.
> -         It will also place the inferior in a separate process group.  */
> -      if (create_tty_session () <= 0)
> -	{
> -	  /* No session was created, but we still want to run the inferior
> -	     in a separate process group.  */
> -	  debug_setpgrp = gdb_setpgid ();
> -	  if (debug_setpgrp == -1)
> -	    perror (_("setpgrp failed in child"));
> -	}
> -
> -      /* Ask the tty subsystem to switch to the one we specified
> -         earlier (or to share the current terminal, if none was
> -         specified).  */
> -      new_tty ();
> -
> -      /* Changing the signal handlers for the inferior after
> -         a vfork can also change them for the superior, so we don't mess
> -         with signals here.  See comments in
> -         initialize_signals for how we get the right signal handlers
> -         for the inferior.  */
> -
> -      /* "Trace me, Dr. Memory!"  */
> -      (*traceme_fun) ();
> -
> -      /* The call above set this process (the "child") as debuggable
> -        by the original gdb process (the "parent").  Since processes
> -        (unlike people) can have only one parent, if you are debugging
> -        gdb itself (and your debugger is thus _already_ the
> -        controller/parent for this child), code from here on out is
> -        undebuggable.  Indeed, you probably got an error message
> -        saying "not parent".  Sorry; you'll have to use print
> -        statements!  */
> -
> -      restore_original_signals_state ();
> -
> -      /* There is no execlpe call, so we have to set the environment
> -         for our child in the global variable.  If we've vforked, this
> -         clobbers the parent, but environ is restored a few lines down
> -         in the parent.  By the way, yes we do need to look down the
> -         path to find $SHELL.  Rich Pixley says so, and I agree.  */
> -      environ = env;
> -
> -      if (exec_fun != NULL)
> -        (*exec_fun) (argv[0], argv, env);
> -      else
> -        execvp (argv[0], argv);
> -
> -      /* If we get here, it's an error.  */
> -      save_errno = errno;
> -      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
> -      for (i = 1; argv[i] != NULL; i++)
> -	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
> -      fprintf_unfiltered (gdb_stderr, ".\n");
> -      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
> -			  safe_strerror (save_errno));
> -      gdb_flush (gdb_stderr);
> -      _exit (0177);
> -    }
> -
> -  /* Restore our environment in case a vforked child clob'd it.  */
> -  environ = save_our_env;
> -
> -  /* Likewise the current UI.  */
> -  current_ui = save_ui;
> -
> -  if (!have_inferiors ())
> -    init_thread_list ();
> -
> -  inf = current_inferior ();
> -
> -  inferior_appeared (inf, pid);
> -
> -  /* Needed for wait_for_inferior stuff below.  */
> -  inferior_ptid = pid_to_ptid (pid);
> -
> -  new_tty_postfork ();
> -
> -  /* We have something that executes now.  We'll be running through
> -     the shell at this point, but the pid shouldn't change.  Targets
> -     supporting MT should fill this task's ptid with more data as soon
> -     as they can.  */
> -  add_thread_silent (inferior_ptid);
> -
> -  /* Now that we have a child process, make it our target, and
> -     initialize anything target-vector-specific that needs
> -     initializing.  */
> -  if (init_trace_fun)
> -    (*init_trace_fun) (pid);
> -
> -  /* We are now in the child process of interest, having exec'd the
> -     correct program, and are poised at the first instruction of the
> -     new program.  */
> -  return pid;
> -}
> -
> -/* Accept NTRAPS traps from the inferior.  */
> -
> -void
> -startup_inferior (int ntraps)
> -{
> -  int pending_execs = ntraps;
> -  int terminal_initted = 0;
> -  ptid_t resume_ptid;
> -
> -  if (startup_with_shell)
> -    {
> -      /* One trap extra for exec'ing the shell.  */
> -      pending_execs++;
> -    }
> -
> -  if (target_supports_multi_process ())
> -    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
> -  else
> -    resume_ptid = minus_one_ptid;
> -
> -  /* The process was started by the fork that created it, but it will
> -     have stopped one instruction after execing the shell.  Here we
> -     must get it up to actual execution of the real program.  */
> -
> -  if (exec_wrapper)
> -    pending_execs++;
> -
> -  while (1)
> -    {
> -      enum gdb_signal resume_signal = GDB_SIGNAL_0;
> -      ptid_t event_ptid;
> -
> -      struct target_waitstatus ws;
> -      memset (&ws, 0, sizeof (ws));
> -      event_ptid = target_wait (resume_ptid, &ws, 0);
> -
> -      if (ws.kind == TARGET_WAITKIND_IGNORE)
> -	/* The inferior didn't really stop, keep waiting.  */
> -	continue;
> -
> -      switch (ws.kind)
> -	{
> -	  case TARGET_WAITKIND_SPURIOUS:
> -	  case TARGET_WAITKIND_LOADED:
> -	  case TARGET_WAITKIND_FORKED:
> -	  case TARGET_WAITKIND_VFORKED:
> -	  case TARGET_WAITKIND_SYSCALL_ENTRY:
> -	  case TARGET_WAITKIND_SYSCALL_RETURN:
> -	    /* Ignore gracefully during startup of the inferior.  */
> -	    switch_to_thread (event_ptid);
> -	    break;
> -
> -	  case TARGET_WAITKIND_SIGNALLED:
> -	    target_terminal_ours ();
> -	    target_mourn_inferior (event_ptid);
> -	    error (_("During startup program terminated with signal %s, %s."),
> -		   gdb_signal_to_name (ws.value.sig),
> -		   gdb_signal_to_string (ws.value.sig));
> -	    return;
> -
> -	  case TARGET_WAITKIND_EXITED:
> -	    target_terminal_ours ();
> -	    target_mourn_inferior (event_ptid);
> -	    if (ws.value.integer)
> -	      error (_("During startup program exited with code %d."),
> -		     ws.value.integer);
> -	    else
> -	      error (_("During startup program exited normally."));
> -	    return;
> -
> -	  case TARGET_WAITKIND_EXECD:
> -	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
> -	    xfree (ws.value.execd_pathname);
> -	    resume_signal = GDB_SIGNAL_TRAP;
> -	    switch_to_thread (event_ptid);
> -	    break;
> -
> -	  case TARGET_WAITKIND_STOPPED:
> -	    resume_signal = ws.value.sig;
> -	    switch_to_thread (event_ptid);
> -	    break;
> -	}
> -
> -      if (resume_signal != GDB_SIGNAL_TRAP)
> -	{
> -	  /* Let shell child handle its own signals in its own way.  */
> -	  target_continue (resume_ptid, resume_signal);
> -	}
> -      else
> -	{
> -	  /* We handle SIGTRAP, however; it means child did an exec.  */
> -	  if (!terminal_initted)
> -	    {
> -	      /* Now that the child has exec'd we know it has already
> -	         set its process group.  On POSIX systems, tcsetpgrp
> -	         will fail with EPERM if we try it before the child's
> -	         setpgid.  */
> -
> -	      /* Set up the "saved terminal modes" of the inferior
> -	         based on what modes we are starting it with.  */
> -	      target_terminal_init ();
> -
> -	      /* Install inferior's terminal modes.  */
> -	      target_terminal_inferior ();
> -
> -	      terminal_initted = 1;
> -	    }
> -
> -	  if (--pending_execs == 0)
> -	    break;
> -
> -	  /* Just make it go on.  */
> -	  target_continue_no_signal (resume_ptid);
> -	}
> -    }
> -
> -  /* Mark all threads non-executing.  */
> -  set_executing (resume_ptid, 0, NULL);
> +  return exec_wrapper;
>  }
>
>  /* Implement the "unset exec-wrapper" command.  */
> @@ -586,7 +74,9 @@ Show the wrapper for running programs."), NULL,
>
>    add_setshow_boolean_cmd ("startup-with-shell", class_support,
>  			   &startup_with_shell, _("\
> -Set use of shell to start subprocesses.  The default is on."), _("\
> +Set use of shell to start subprocesses.  The default is on.\n\
> +This is also used to determine whether gdbserver will start the remote\n\
> +inferior using the shell."), _("\
>  Show use of shell to start subprocesses."), NULL,
>  			   NULL,
>  			   show_startup_with_shell,
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index 2add910..2ddcfd6 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -185,6 +185,7 @@ SFILES = \
>  	$(srcdir)/target.c \
>  	$(srcdir)/thread-db.c \
>  	$(srcdir)/utils.c \
> +	$(srcdir)/terminal.c \
>  	$(srcdir)/win32-arm-low.c \
>  	$(srcdir)/win32-i386-low.c \
>  	$(srcdir)/win32-low.c \
> @@ -204,6 +205,7 @@ SFILES = \
>  	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
> +	$(srcdir)/common/common-fork-child.c \
>  	$(srcdir)/common/common-inflow.c \
>  	$(srcdir)/common/gdb_vecs.c \
>  	$(srcdir)/common/new-op.c \
> @@ -235,6 +237,7 @@ OBS = \
>  	cleanups.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-fork-child.o \
>  	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
> @@ -269,6 +272,7 @@ OBS = \
>  	version.o \
>  	waitstatus.o \
>  	xml-utils.o \
> +	terminal.o \
>  	$(DEPFILES) \
>  	$(LIBOBJS) \
>  	$(XML_BUILTIN)
> @@ -772,6 +776,9 @@ format.o: ../common/format.c
>  filestuff.o: ../common/filestuff.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +common-fork-child.o: ../common/common-fork-child.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  common-inflow.o: ../common/common-inflow.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index 6b981d0..5f65e99 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>
>  #define get_thread(inf) ((struct thread_info *)(inf))
>
> +ptid_t inferior_ptid;
> +
>  void
>  add_inferior_to_list (struct inferior_list *list,
>  		      struct inferior_list_entry *new_inferior)
> @@ -469,6 +471,23 @@ make_cleanup_restore_current_thread (void)
>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>  }
>
> +/* See common/common-inferior.h.  */
> +
> +void
> +inferior_appeared (struct inferior *inf, int pid)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +struct inferior *
> +current_inferior (void)
> +{
> +  /* To be implemented.  */
> +  return NULL;
> +}
> +
>  /* See common/common-gdbthread.h.  */
>
>  void
> @@ -510,3 +529,11 @@ add_thread_silent (ptid_t ptid)
>
>    return add_thread (ptid_build (pid, pid, 0), NULL);
>  }
> +
> +/* See common/common-inferior.h.  */
> +
> +int
> +have_inferiors (void)
> +{
> +  return get_first_process () != NULL;
> +}
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index e3e372c..ea35796 100644
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -47,6 +47,8 @@
>  #include "tracepoint.h"
>  #include "hostio.h"
>  #include <inttypes.h>
> +#include "common-inferior.h"
> +#include "environ.h"
>  #ifndef ELFMAG0
>  /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
>     then ELFMAG0 will have been defined.  If it didn't get included by
> @@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
>    free (lwp);
>  }
>
> -/* Add a process to the common process list, and set its private
> -   data.  */
> +/* Update process represented by PID with necessary info.  */
>
>  static struct process_info *
> -linux_add_process (int pid, int attached)
> +linux_update_process (int pid)
>  {
> -  struct process_info *proc;
> +  struct process_info *proc = find_process_pid (pid);
>
> -  proc = add_process (pid, attached);
> +  gdb_assert (proc != NULL);
>    proc->priv = XCNEW (struct process_info_private);
>
>    if (the_low_target.new_process != NULL)
> @@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
>    return proc;
>  }
>
> +/* Add a process to the common process list, and set its private
> +   data.  */
> +
> +static struct process_info *
> +linux_add_process (int pid, int attached)
> +{
> +  add_process (pid, attached);
> +  return linux_update_process (pid);
> +}
> +
>  static CORE_ADDR get_pc (struct lwp_info *lwp);
>
>  /* Call the target arch_setup function on the current thread.  */
> @@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
>    return 1;
>  }
>
> +/* Update the lwp associated to thread represented by PTID.  */
> +
> +static struct lwp_info *
> +update_thread_lwp (ptid_t ptid)
> +{
> +  struct lwp_info *lwp;
> +  struct thread_info *thread;
> +
> +  lwp = XCNEW (struct lwp_info);
> +
> +  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
> +
> +  if (the_low_target.new_thread != NULL)
> +    the_low_target.new_thread (lwp);
> +
> +  thread = find_thread_ptid (ptid);
> +  gdb_assert (thread != NULL);
> +  thread->target_data = lwp;
> +  lwp->thread = thread;
> +
> +  return lwp;
> +}
> +
>  static struct lwp_info *
>  add_lwp (ptid_t ptid)
>  {
> @@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
>    return lwp;
>  }
>
> +/* Callback to be used when calling fork_inferior, responsible for
> +   actually initiating the tracing of the inferior.  */
> +
> +static void
> +linux_ptrace_fun (void)
> +{
> +  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> +
> +  setpgid (0, 0);
> +
> +  /* If gdbserver is connected to gdb via stdio, redirect the inferior's
> +     stdout to stderr so that inferior i/o doesn't corrupt the connection.
> +     Also, redirect stdin to /dev/null.  */
> +  if (remote_connection_is_stdio ())
> +    {
> +      close (0);
> +      open ("/dev/null", O_RDONLY);
> +      dup2 (2, 1);
> +      if (write (2, "stdin/stdout redirected\n",
> +		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
> +	{
> +	  /* Errors ignored.  */;
> +	}
> +    }
> +}
> +
>  /* Start an inferior process and returns its pid.
>     ALLARGS is a vector of program-name and args. */
>
>  static int
> -linux_create_inferior (char *program, char **allargs)
> +linux_create_inferior (std::vector<char *> &program_argv)
>  {
>    struct lwp_info *new_lwp;
>    int pid;
>    ptid_t ptid;
>    struct cleanup *restore_personality
>      = maybe_disable_address_space_randomization (disable_randomization);
> +  std::string program_args = stringify_argv (program_argv);
>
> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
> -  pid = vfork ();
> -#else
> -  pid = fork ();
> -#endif
> -  if (pid < 0)
> -    perror_with_name ("fork");
> +  pre_fork_inferior (program_argv);
>
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> -
> -      setpgid (0, 0);
> -
> -      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
> -	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
> -	 Also, redirect stdin to /dev/null.  */
> -      if (remote_connection_is_stdio ())
> -	{
> -	  close (0);
> -	  open ("/dev/null", O_RDONLY);
> -	  dup2 (2, 1);
> -	  if (write (2, "stdin/stdout redirected\n",
> -		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
> -	    {
> -	      /* Errors ignored.  */;
> -	    }
> -	}
> -
> -      restore_original_signals_state ();
> -
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> -
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), linux_ptrace_fun,
> +		       NULL, NULL, startup_shell, NULL);
>
>    do_cleanups (restore_personality);
>
> -  linux_add_process (pid, 0);
> +  linux_update_process (pid);
>
>    ptid = ptid_build (pid, pid, 0);
> -  new_lwp = add_lwp (ptid);
> +  new_lwp = update_thread_lwp (ptid);
>    new_lwp->must_set_ptrace_flags = 1;
>
> +  post_fork_inferior (pid, program_argv);
> +
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
> index 28a9757..1abf8e3 100644
> --- a/gdb/gdbserver/lynx-low.c
> +++ b/gdb/gdbserver/lynx-low.c
> @@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
>    return result;
>  }
>
> -/* Call add_process with the given parameters, and initializes
> -   the process' private data.  */
> +/* Update existing process represented by PID with necessary info.  */
>
>  static struct process_info *
> -lynx_add_process (int pid, int attached)
> +lynx_update_process (int pid)
>  {
> -  struct process_info *proc;
> +  struct process_info *proc = find_process_pid (pid);
> +
> +  gdb_assert (proc != NULL);
>
> -  proc = add_process (pid, attached);
>    proc->tdesc = lynx_tdesc;
>    proc->priv = XCNEW (struct process_info_private);
>    proc->priv->last_wait_event_ptid = null_ptid;
> @@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
>    return proc;
>  }
>
> +/* Call add_process with the given parameters, and initializes
> +   the process' private data.  */
> +
> +static struct process_info *
> +lynx_add_process (int pid, int attached)
> +{
> +  add_process (pid, attached);
> +  return lynx_update_process (pid);
> +}
> +
> +static void
> +lynx_ptrace_fun (void)
> +{
> +  int pgrp;
> +
> +  /* Switch child to its own process group so that signals won't
> +     directly affect gdbserver. */
> +  pgrp = getpid();
> +  setpgid (0, pgrp);
> +  ioctl (0, TIOCSPGRP, &pgrp);
> +  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
> +}
> +
>  /* Implement the create_inferior method of the target_ops vector.  */
>
>  static int
> -lynx_create_inferior (char *program, char **allargs)
> +lynx_create_inferior (std::vector<char *> &program_argv)
>  {
>    int pid;
>
>    lynx_debug ("lynx_create_inferior ()");
>
> -  pid = fork ();
> -  if (pid < 0)
> -    perror_with_name ("fork");
> +  pre_fork_inferior (program_argv);
>
> -  if (pid == 0)
> -    {
> -      int pgrp;
> -
> -      close_most_fds ();
> -
> -      /* Switch child to its own process group so that signals won't
> -         directly affect gdbserver. */
> -      pgrp = getpid();
> -      setpgid (0, pgrp);
> -      ioctl (0, TIOCSPGRP, &pgrp);
> -      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
> -      execv (program, allargs);
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), lynx_ptrace_fun,
> +		       NULL, NULL, startup_shell, NULL);
>
> -  lynx_add_process (pid, 0);
> +  post_fork_inferior (pid, program_argv);
> +
> +  lynx_update_process (pid, 0);
>    /* Do not add the process thread just yet, as we do not know its tid.
>       We will add it later, during the wait for the STOP event corresponding
>       to the lynx_ptrace (PTRACE_TRACEME) call above.  */
> +  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
> +
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
> index ce3b8e4..17d3dc9 100644
> --- a/gdb/gdbserver/nto-low.c
> +++ b/gdb/gdbserver/nto-low.c
> @@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
>    return len_read;
>  }
>
> -/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
> +/* Start inferior specified by PROGRAM_ARGV.  */
>
>  static int
> -nto_create_inferior (char *program, char **allargs)
> +nto_create_inferior (std::vector<char *> &program_argv)
>  {
>    struct inheritance inherit;
>    pid_t pid;
>    sigset_t set;
> +  std::string program_args = stringify_argv (program_argv);
>
> -  TRACE ("%s %s\n", __func__, program);
> +  TRACE ("%s %s\n", __func__, program_argv[0]);
>    /* Clear any pending SIGUSR1's but keep the behavior the same.  */
>    signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
>
> @@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
>    memset (&inherit, 0, sizeof (inherit));
>    inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
>    inherit.pgroup = SPAWN_NEWPGROUP;
> -  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
> +  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
>    sigprocmask (SIG_BLOCK, &set, NULL);
>
>    if (pid == -1)
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index ef8dd03..55eebd9 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -35,6 +35,31 @@
>  #include "tracepoint.h"
>  #include "dll.h"
>  #include "hostio.h"
> +#include "common-inferior.h"
> +#include "common-terminal.h"
> +#include "common-top.h"
> +#include "environ.h"
> +
> +/* We don't have a concept of a UI yet.  Therefore, we just set these
> +   to NULL.  */
> +
> +struct ui *main_ui = NULL;
> +struct ui *current_ui = NULL;
> +
> +/* The environment to pass to the inferior when creating it.  */
> +
> +struct gdb_environ *our_environ = NULL;
> +
> +/* Start the inferior using a shell.  */
> +
> +/* We always try to start the inferior using a shell.  */
> +
> +int startup_with_shell = 1;
> +
> +/* The shell that will be used to start the inferior will be
> +   determined later.  */
> +
> +char *startup_shell = NULL;
>
>  /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
>     `vCont'.  Note the multi-process extensions made `vCont' a
> @@ -78,7 +103,8 @@ static int vCont_supported;
>     space randomization feature before starting an inferior.  */
>  int disable_randomization = 1;
>
> -static char **program_argv, **wrapper_argv;
> +static std::vector<char *> program_argv;
> +static std::vector<char *> wrapper_argv;
>
>  int pass_signals[GDB_SIGNAL_LAST];
>  int program_signals[GDB_SIGNAL_LAST];
> @@ -236,33 +262,64 @@ target_running (void)
>    return get_first_thread () != NULL;
>  }
>
> -static int
> -start_inferior (char **argv)
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_wrapper (void)
>  {
> -  char **new_argv = argv;
> +  static std::string ret;
> +  static int initialized_p = 0;
> +
> +  if (wrapper_argv.empty ())
> +    return NULL;
>
> -  if (wrapper_argv != NULL)
> +  if (!initialized_p)
>      {
> -      int i, count = 1;
> -
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	count++;
> -      for (i = 0; argv[i] != NULL; i++)
> -	count++;
> -      new_argv = XALLOCAVEC (char *, count);
> -      count = 0;
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	new_argv[count++] = wrapper_argv[i];
> -      for (i = 0; argv[i] != NULL; i++)
> -	new_argv[count++] = argv[i];
> -      new_argv[count] = NULL;
> +      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
> +	   i != wrapper_argv.end ();
> +	   ++i)
> +	ret += *i + std::string (" ");
> +
> +      /* Erasing the last whitespace.  */
> +      ret.erase (ret.end () - 1);
> +
> +      initialized_p = 1;
>      }
>
> +  return (char *) ret.c_str ();
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_file (int err)
> +{
> +  if (err && program_argv.empty ())
> +    error (_("Could not get the exec file."));
> +  return program_argv[0];
> +}
> +
> +/* See server.h.  */
> +
> +struct gdb_environ *
> +get_environ (void)
> +{
> +  return our_environ;
> +}
> +
> +/* See server.h.  */
> +
> +void
> +pre_fork_inferior (std::vector<char *> &argv)
> +{
>    if (debug_threads)
>      {
> -      int i;
> -      for (i = 0; new_argv[i]; ++i)
> -	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
> +      int idx = 0;
> +
> +      for (std::vector<char *>::iterator i = argv.begin ();
> +	   i != argv.end ();
> +	   ++i, ++idx)
> +	debug_printf ("new_argv[%d] = \"%s\"\n", idx, *i);
>        debug_flush ();
>      }
>
> @@ -271,67 +328,35 @@ start_inferior (char **argv)
>    signal (SIGTTIN, SIG_DFL);
>  #endif
>
> -  signal_pid = create_inferior (new_argv[0], new_argv);
> +  /* Clear this so the backend doesn't get confused, thinking
> +     CONT_THREAD died, and it needs to resume all threads.  */
> +  cont_thread = null_ptid;
> +}
>
> -  /* FIXME: we don't actually know at this point that the create
> -     actually succeeded.  We won't know that until we wait.  */
> -  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
> -	   signal_pid);
> -  fflush (stderr);
> +/* See server.h.  */
> +
> +void
> +post_fork_inferior (int pid,
> +		    std::vector<char *> &argv)
> +{
> +  /* Number of traps to be expected by startup_inferior.  We always
> +     expect at least one trap for the main executable.  */
> +  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
>
>  #ifdef SIGTTOU
>    signal (SIGTTOU, SIG_IGN);
>    signal (SIGTTIN, SIG_IGN);
>    terminal_fd = fileno (stderr);
>    old_foreground_pgrp = tcgetpgrp (terminal_fd);
> -  tcsetpgrp (terminal_fd, signal_pid);
> +  tcsetpgrp (terminal_fd, pid);
>    atexit (restore_old_foreground_pgrp);
>  #endif
>
> -  if (wrapper_argv != NULL)
> -    {
> -      ptid_t ptid = pid_to_ptid (signal_pid);
> -
> -      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -
> -      if (last_status.kind == TARGET_WAITKIND_STOPPED)
> -	{
> -	  do
> -	    {
> -	      target_continue_no_signal (ptid);
> -
> -	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
> -		break;
> -
> -	      current_thread->last_resume_kind = resume_stop;
> -	      current_thread->last_status = last_status;
> -	    }
> -	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
> -	}
> -      target_post_create_inferior ();
> -      return signal_pid;
> -    }
> -
> -  /* Wait till we are at 1st instruction in program, return new pid
> -     (assuming success).  */
> -  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -
> -  /* At this point, the target process, if it exits, is stopped.  Do not call
> -     the function target_post_create_inferior if the process has already
> -     exited, as the target implementation of the routine may rely on the
> -     process being live. */
> -  if (last_status.kind != TARGET_WAITKIND_EXITED
> -      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
> -    {
> -      target_post_create_inferior ();
> -      current_thread->last_resume_kind = resume_stop;
> -      current_thread->last_status = last_status;
> -    }
> -  else
> -    target_mourn_inferior (last_ptid);
> -
> -  return signal_pid;
> +  startup_inferior (num_traps, &last_status, &last_ptid);
> +  signal_pid = pid;
> +  target_post_create_inferior ();
> +  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
> +  fflush (stderr);
>  }
>
>  static int
> @@ -2852,8 +2877,10 @@ handle_v_attach (char *own_buf)
>  static int
>  handle_v_run (char *own_buf)
>  {
> -  char *p, *next_p, **new_argv;
> -  int i, new_argc;
> +  char *p, *next_p;
> +  std::vector<char *> new_argv;
> +  int new_argc;
> +  int i;
>
>    new_argc = 0;
>    for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
> @@ -2862,62 +2889,91 @@ handle_v_run (char *own_buf)
>        new_argc++;
>      }
>
> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
> -  if (new_argv == NULL)
> -    {
> -      write_enn (own_buf);
> -      return 0;
> -    }
> -
> -  i = 0;
> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>      {
>        next_p = strchr (p, ';');
>        if (next_p == NULL)
>  	next_p = p + strlen (p);
>
> -      if (i == 0 && p == next_p)
> -	new_argv[i] = NULL;
> +      if (p == next_p)
> +	new_argv.push_back ("''");
>        else
>  	{
>  	  /* FIXME: Fail request if out of memory instead of dying.  */
> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
> -	  new_argv[i][(next_p - p) / 2] = '\0';
> +	  size_t len = 1 + (next_p - p) / 2;
> +	  char *s = (char *) xmalloc (len);
> +	  char *ss = (char *) xmalloc (len * 2);
> +	  char *tmp_s, *tmp_ss;
> +	  int need_quote;
> +
> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
> +	  s[(next_p - p) / 2] = '\0';
> +
> +	  tmp_s = s;
> +	  tmp_ss = ss;
> +	  need_quote = 0;
> +	  while (*tmp_s != '\0')
> +	    {
> +	      switch (*tmp_s)
> +		{
> +		case '\n':
> +		  *tmp_ss = '\'';
> +		  ++tmp_ss;
> +		  need_quote = 1;
> +		  break;
> +
> +		case '\'':
> +		  *tmp_ss = '\\';
> +		  ++tmp_ss;
> +		  break;
> +
> +		default:
> +		  break;
> +		}
> +
> +	      *tmp_ss = *tmp_s;
> +	      ++tmp_ss;
> +	      ++tmp_s;
> +	    }
> +
> +	  if (need_quote)
> +	    *tmp_ss++ = '\'';
> +
> +	  *tmp_ss = '\0';
> +	  new_argv.push_back (ss);
> +	  xfree (s);
>  	}
>
>        if (*next_p)
>  	next_p++;
> -      i++;
>      }
> -  new_argv[i] = NULL;
>
> -  if (new_argv[0] == NULL)
> +  if (new_argv.empty () || new_argv[0] == NULL)
>      {
>        /* GDB didn't specify a program to run.  Use the program from the
>  	 last run with the new argument list.  */
>
> -      if (program_argv == NULL)
> +      if (program_argv.empty ())
>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>
> -      new_argv[0] = strdup (program_argv[0]);
> -      if (new_argv[0] == NULL)
> +      new_argv.push_back (strdup (program_argv[0]));
> +      if (new_argv.empty () || new_argv[0] == NULL)
>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>      }
>
>    /* Free the old argv and install the new one.  */
> -  freeargv (program_argv);
> +  free_vector_argv (program_argv);
>    program_argv = new_argv;
>
> -  start_inferior (program_argv);
> +  create_inferior (program_argv);
>    if (last_status.kind == TARGET_WAITKIND_STOPPED)
>      {
>        prepare_resume_reply (own_buf, last_ptid, &last_status);
> @@ -3535,13 +3591,18 @@ captured_main (int argc, char *argv[])
>  	multi_mode = 1;
>        else if (strcmp (*next_arg, "--wrapper") == 0)
>  	{
> +	  char **tmp;
> +
>  	  next_arg++;
>
> -	  wrapper_argv = next_arg;
> +	  tmp = next_arg;
>  	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
> -	    next_arg++;
> +	    {
> +	      wrapper_argv.push_back (*next_arg);
> +	      next_arg++;
> +	    }
>
> -	  if (next_arg == wrapper_argv || *next_arg == NULL)
> +	  if (next_arg == tmp || *next_arg == NULL)
>  	    {
>  	      gdbserver_usage (stderr);
>  	      exit (1);
> @@ -3672,8 +3733,14 @@ captured_main (int argc, char *argv[])
>        exit (1);
>      }
>
> +  /* Gather information about the environment.  */
> +  our_environ = make_environ ();
> +  init_environ (our_environ);
> +
>    initialize_async_io ();
>    initialize_low ();
> +  /* This is called when initializing inflow on GDB.  */
> +  have_job_control ();
>    initialize_event_loop ();
>    if (target_supports_tracepoints ())
>      initialize_tracepoint ();
> @@ -3687,13 +3754,11 @@ captured_main (int argc, char *argv[])
>        int i, n;
>
>        n = argc - (next_arg - argv);
> -      program_argv = XNEWVEC (char *, n + 1);
>        for (i = 0; i < n; i++)
> -	program_argv[i] = xstrdup (next_arg[i]);
> -      program_argv[i] = NULL;
> +	program_argv.push_back (xstrdup (next_arg[i]));
>
>        /* Wait till we are at first instruction in program.  */
> -      start_inferior (program_argv);
> +      create_inferior (program_argv);
>
>        /* We are now (hopefully) stopped at the first instruction of
>  	 the target process.  This assumes that the target process was
> @@ -4308,9 +4373,9 @@ process_serial_event (void)
>  	  fprintf (stderr, "GDBserver restarting\n");
>
>  	  /* Wait till we are at 1st instruction in prog.  */
> -	  if (program_argv != NULL)
> +	  if (!program_argv.empty ())
>  	    {
> -	      start_inferior (program_argv);
> +	      create_inferior (program_argv);
>  	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>  		{
>  		  /* Stopped at the first instruction of the target
> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index f56c0f5..6b3d668 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -103,6 +103,8 @@ extern int swbreak_feature;
>     Only enabled if the target supports it.  */
>  extern int hwbreak_feature;
>
> +extern char *startup_shell;
> +
>  extern int disable_randomization;
>
>  #if USE_WIN32API
> @@ -132,6 +134,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  #include "utils.h"
>  #include "debug.h"
>  #include "gdb_vecs.h"
> +#include <vector>
>
>  /* Maximum number of bytes to read/write at once.  The value here
>     is chosen to fill up a packet (the headers account for the 32).  */
> @@ -148,4 +151,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  /* Definition for any syscall, used for unfiltered syscall reporting.  */
>  #define ANY_SYSCALL (-2)
>
> +/* Any pre-processing needed to be done before calling fork_inferior
> +   shall be implemented here.  ARGV is a vector containing the full
> +   argv of the inferior.  */
> +
> +extern void pre_fork_inferior (std::vector<char *> &argv);
> +
> +/* After fork_inferior has been called, we need to adjust a few
> +   signals and call startup_inferior.  This is done here.  PID is the
> +   pid of the new inferior, and ARGV is the vector containing the full
> +   argv of the inferior.  */
> +
> +extern void post_fork_inferior (int pid,
> +				std::vector<char *> &argv);
> +
> +extern struct gdb_environ *get_environ (void);
> +
>  #endif /* SERVER_H */
> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
> index 32e7c72..ccf736f 100644
> --- a/gdb/gdbserver/spu-low.c
> +++ b/gdb/gdbserver/spu-low.c
> @@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
>    return ret;
>  }
>
> +/* Callback to be used when calling fork_inferior, responsible for
> +   actually initiating the tracing of the inferior.  */
> +
> +static void
> +spu_ptrace_fun (void)
> +{
> +  ptrace (PTRACE_TRACEME, 0, 0, 0);
> +  setpgid (0, 0);
> +}
>
>  /* Start an inferior process and returns its pid.
> -   ALLARGS is a vector of program-name and args. */
> +   PROGRAM_ARGV is a vector of program-name and args. */
>  static int
> -spu_create_inferior (char *program, char **allargs)
> +spu_create_inferior (std::vector<char *> &program_argv)
>  {
>    int pid;
>    ptid_t ptid;
>    struct process_info *proc;
> +  std::string program_args = stringify_argv (program_argv);
>
> -  pid = fork ();
> -  if (pid < 0)
> -    perror_with_name ("fork");
> -
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, 0, 0);
> -
> -      setpgid (0, 0);
> +  pre_fork_inferior (program_argv);
>
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), spu_ptrace_fun,
> +		       NULL, NULL, startup_shell, NULL);
>
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  post_fork_inferior (pid, program_argv);
>
> -  proc = add_process (pid, 0);
> +  proc = find_process_pid (pid);
> +  gdb_assert (proc != NULL);
>    proc->tdesc = tdesc_spu;
>
> -  ptid = ptid_build (pid, pid, 0);
> -  add_thread (ptid, NULL);
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
> index 249a063..56c734c 100644
> --- a/gdb/gdbserver/target.c
> +++ b/gdb/gdbserver/target.c
> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>    return size;
>  }
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_init (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_inferior (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_ours (void)
> +{
> +  /* To be implemented.  */
> +}

Same suggestion as the other patch regarding either putting something in 
place now or adding more documentation about what these need to do in 
the future.

> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
> index d098a92..3e74b86 100644
> --- a/gdb/gdbserver/target.h
> +++ b/gdb/gdbserver/target.h
> @@ -28,6 +28,7 @@
>  #include "target/waitstatus.h"
>  #include "mem-break.h"
>  #include "btrace-common.h"
> +#include <vector>
>
>  struct emit_ops;
>  struct buffer;
> @@ -73,7 +74,7 @@ struct target_ops
>       Returns the new PID on success, -1 on failure.  Registers the new
>       process with the process list.  */
>
> -  int (*create_inferior) (char *program, char **args);
> +  int (*create_inferior) (std::vector<char *> &program_argv);
>
>    /* Do additional setup after a new process is created, including
>       exec-wrapper completion.  */
> @@ -480,8 +481,8 @@ extern struct target_ops *the_target;
>
>  void set_target_ops (struct target_ops *);
>
> -#define create_inferior(program, args) \
> -  (*the_target->create_inferior) (program, args)
> +#define create_inferior(program) \
> +  (*the_target->create_inferior) (program)
>
>  #define target_post_create_inferior()			 \
>    do							 \
> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
> index 37b9c89..8fa3ce5 100644
> --- a/gdb/gdbserver/utils.c
> +++ b/gdb/gdbserver/utils.c
> @@ -137,3 +137,40 @@ pfildes (gdb_fildes_t fd)
>    return plongest (fd);
>  #endif
>  }
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +gdb_flush_out_err (void)
> +{
> +  fflush (stdout);
> +  fflush (stderr);
> +}
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +free_vector_argv (std::vector<char *> &v)
> +{
> +  for (std::vector<char *>::iterator i = v.begin ();
> +       i != v.end ();
> +       ++i)
> +    xfree (*i);
> +
> +  v.clear ();
> +}

Nothing wrong with the above, but with the decision to use C++ 11, maybe 
this could be further simplified with range for if you think it's worth it?

{
   for (char* arg : v)
     xfree (arg);

   v.clear ();
}

Or maybe it is a bit too fancy for our own good, though we will 
eventually need to get used to it.

Another thought is to make the elements std::string themselves, in which 
case std::vector::clear () will call each elements' destructor. Again, 
maybe too fancy.

> +
> +/* See common/common-utils.h.  */
> +
> +std::string
> +stringify_argv (std::vector<char *> &argv)
> +{
> +  std::string ret ("");
> +
> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
> +       i != argv.end ();
> +       ++i)
> +    ret += *i + std::string (" ");
> +
> +  return ret;
> +}

Same suggestion as above for the range for.

{
   for (char* arg : argv)
     ret += arg + std::string (" ");

   return ret;
}

> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
> index 5e0cead..20c8dcd 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/gdbserver/utils.h
> @@ -19,7 +19,19 @@
>  #ifndef UTILS_H
>  #define UTILS_H
>
> +#include <vector>
> +
>  char *paddress (CORE_ADDR addr);
>  char *pfildes (gdb_fildes_t fd);
>
> +/* Works like FREEARGV, but with std::vector.  */
> +
> +extern void free_vector_argv (std::vector<char *> &v);
> +
> +/* Given a vector of arguments ARGV, return a string equivalent to
> +   joining all the arguments (starting from ARGV + 1) with a
> +   whitespace separating them.  */
> +
> +extern std::string stringify_argv (std::vector<char *> &argv);
> +
>  #endif /* UTILS_H */
> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
> index 70abfcd..1f7f538 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>  }
>
>  /* Start a new process.
> -   PROGRAM is a path to the program to execute.
> -   ARGS is a standard NULL-terminated array of arguments,
> -   to be passed to the inferior as ``argv''.
> +   PROGRAM_ARGV is the vector containing the inferior's argv.
>     Returns the new PID on success, -1 on failure.  Registers the new
>     process with the process list.  */
>  static int
> -win32_create_inferior (char *program, char **program_args)
> +win32_create_inferior (std::vector<char *> &program_argv)
>  {
>  #ifndef USE_WIN32API
>    char real_path[PATH_MAX];
> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>    int argc;
>    PROCESS_INFORMATION pi;
>    DWORD err;
> +  char *program = program_argv[0];
> +  std::string program_args = stringify_argv (program_argv);
> +  char *args = (char *) program_args.c_str ();
>
>    /* win32_wait needs to know we're not attaching.  */
>    attaching = 0;
> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>
>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>
> +  pre_fork_inferior (program, argv);
> +
>  #ifndef USE_WIN32API
>    orig_path = NULL;
>    path_ptr = getenv ("PATH");
> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>    program = real_path;
>  #endif
>
> -  argslen = 1;
> -  for (argc = 1; program_args[argc]; argc++)
> -    argslen += strlen (program_args[argc]) + 1;
> -  args = (char *) alloca (argslen);
> -  args[0] = '\0';
> -  for (argc = 1; program_args[argc]; argc++)
> -    {
> -      /* FIXME: Can we do better about quoting?  How does Cygwin
> -	 handle this?  */
> -      strcat (args, " ");
> -      strcat (args, program_args[argc]);
> -    }
>    OUTMSG2 (("Command line is \"%s\"\n", args));
>
>  #ifdef CREATE_NEW_PROCESS_GROUP
> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>
>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>
> +  post_fork_inferior (current_process_id, program_argv);
> +
>    return current_process_id;
>  }
>
> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index 85a53b8..3e2e226 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
>    thread_change_ptid (inferior_ptid,
>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>    inf->pending_execs = 0;
>    /* Get rid of the old shell threads.  */
>    prune_threads ();
> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
> index 64aaabe..ceb1422 100644
> --- a/gdb/inf-ptrace.c
> +++ b/gdb/inf-ptrace.c
> @@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>
>    discard_cleanups (back_to);
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>
>    /* On some targets, there must be some explicit actions taken after
>       the inferior has been started up.  */
> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index 403c096..6dae6b2 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -42,6 +42,7 @@ struct target_desc_info;
>
>  #include "progspace.h"
>  #include "registry.h"
> +#include "common-inferior.h"
>
>  #include "symfile-add-flags.h"
>
> @@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
>
>  extern void child_terminal_init_with_pgrp (int pgrp);
>
> -/* From fork-child.c */
> -
> -extern int fork_inferior (char *, char *, char **,
> -			  void (*)(void),
> -			  void (*)(int), void (*)(void), char *,
> -                          void (*)(const char *,
> -                                   char * const *, char * const *));
> -
> -
> -extern void startup_inferior (int);
> -
>  extern char *construct_inferior_arguments (int, char **);
>
>  /* From infcmd.c */
> diff --git a/gdb/procfs.c b/gdb/procfs.c
> index ff814ba..5b64618 100644
> --- a/gdb/procfs.c
> +++ b/gdb/procfs.c
> @@ -4380,7 +4380,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
>    thread_change_ptid (pid_to_ptid (pid),
>  		      ptid_build (pid, lwpid, 0));
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>
>  #ifdef SYS_syssgi
>    /* On mips-irix, we need to stop the inferior early enough during
> diff --git a/gdb/target.h b/gdb/target.h
> index a54b3db..adec5f2 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
>
>  extern int target_terminal_is_ours (void);
>
> -/* Initialize the terminal settings we record for the inferior,
> -   before we actually run the inferior.  */
> -
> -extern void target_terminal_init (void);
> -
> -/* Put the inferior's terminal settings into effect.  This is
> -   preparation for starting or resuming the inferior.  This is a no-op
> -   unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_inferior (void);
> -
>  /* Put some of our terminal settings into effect, enough to get proper
>     results from our output, but do not change into or out of RAW mode
>     so that no input is discarded.  This is a no-op if terminal_ours
> @@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
>
>  extern void target_terminal_ours_for_output (void);
>
> -/* Put our terminal settings into effect.  First record the inferior's
> -   terminal settings so they can be restored properly later.  This is
> -   a no-op unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_ours (void);
> -
>  /* Return true if the target stack has a non-default
>    "to_terminal_ours" method.  */
>
> diff --git a/gdb/target/target.h b/gdb/target/target.h
> index 2f4c716..2f0d8ba 100644
> --- a/gdb/target/target.h
> +++ b/gdb/target/target.h
> @@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
>
>  extern int target_supports_multi_process (void);
>
> +/* Initialize the terminal settings we record for the inferior,
> +   before we actually run the inferior.  */
> +

Spurious newline due to the following?

 
https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation

   "Note that this only applies to the case where the comment is placed
   besides the subprogram implementation (typically in a .c file). In the
   case of the documentation being placed next to the subprogram
   declaration, then the comment should be placed immediately before the
   declaration."

> +extern void target_terminal_init (void);
> +
> +/* Put the inferior's terminal settings into effect.  This is
> +   preparation for starting or resuming the inferior.  This is a no-op
> +   unless called with the main UI as current UI.  */
> +
> +extern void target_terminal_inferior (void);
> +
> +/* Put our terminal settings into effect.  First record the inferior's
> +   terminal settings so they can be restored properly later.  This is
> +   a no-op unless called with the main UI as current UI.  */
> +
> +extern void target_terminal_ours (void);
> +
>  #endif /* TARGET_COMMON_H */
> diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
> index f68029d..efdfb58 100644
> --- a/gdb/testsuite/gdb.server/non-existing-program.exp
> +++ b/gdb/testsuite/gdb.server/non-existing-program.exp
> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>  set msg "gdbserver exits cleanly"
>  set saw_exiting 0
>  expect {
> -    # This is what we get on ptrace-based targets.
> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
> +    # This is what we get on ptrace-based targets with
> +    # startup-with-shell disabled.
> +    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
> +	set saw_exiting 1
> +	exp_continue
> +    }
> +    # Likewise, but with startup-with-shell enabled.
> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>  	set saw_exiting 1
>  	exp_continue
>      }
> diff --git a/gdb/top.h b/gdb/top.h
> index 482ed3e..0c057d7 100644
> --- a/gdb/top.h
> +++ b/gdb/top.h
> @@ -22,6 +22,7 @@
>
>  #include "buffer.h"
>  #include "event-loop.h"
> +#include "common-top.h"
>
>  struct tl_interp_info;
>
> @@ -144,14 +145,6 @@ struct ui
>    struct ui_out *m_current_uiout;
>  };
>
> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> -   It always exists and is created automatically when GDB starts
> -   up.  */
> -extern struct ui *main_ui;
> -
> -/* The current UI.  */
> -extern struct ui *current_ui;
> -
>  /* The list of all UIs.  */
>  extern struct ui *ui_list;
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 6bf3716..026e9d7 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -3435,6 +3435,15 @@ strip_leading_path_elements (const char *path, int n)
>    return p;
>  }
>
> +/* See common/common-utils.h.  */
> +
> +void
> +gdb_flush_out_err (void)
> +{
> +  gdb_flush (main_ui->m_gdb_stdout);
> +  gdb_flush (main_ui->m_gdb_stderr);
> +}
> +
>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>  extern initialize_file_ftype _initialize_utils;
>
>

The patch looks reasonable to me, though it would be nice to do a second 
pass on a version without the git-copy in place. That way we can see the 
real changes for the code that was moved.

Thanks,
Luis

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-01-03 20:48     ` Sergio Durigan Junior
@ 2017-01-04 16:08       ` Eli Zaretskii
  2017-01-05 20:12         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Eli Zaretskii @ 2017-01-04 16:08 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: gdb-patches@sourceware.org, palves@redhat.com
> Date: Tue, 03 Jan 2017 15:48:26 -0500
> 
> >     Also, is it possible that a user will want
> >     remote targets to use a shell, while avoiding that for native
> >     debugging, in the same session?
> 
> Yeah, I thought about that.  My first thought was to add a 'set/show
> remote startup-with-shell' option, but I thought this was going to be
> too much for the user.  Maybe not.
> 
> With this new setting, we'd have:
> 
> - startup-with-shell: Used only locally, default on.  Instructs GDB to
>   start the inferior using the shell.
> 
> - remote startup-with-shell: Used only remotely, default on.  Instructs
>   gdbserver to start the inferior using the shell.
> 
> - remote startup-shell: Used only remotely (if remote startup-with-shell
>   is on), default "" (empty).  Tells which shell to be used by gdbserver
>   to start the inferior.  If empty, use $SHELL.
> 
> WDYT?

Makes sense to me, thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 5/6] Share fork_inferior et al with gdbserver
  2017-01-03 23:32   ` Luis Machado
@ 2017-01-05 20:11     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-05 20:11 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, palves

Hey Luis,

Thanks for the review.

As usual, comments below.

On Tuesday, January 03 2017, Luis Machado wrote:

> Not a lot of comments at this point, but a few.
>
>> [...]
>> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
>> new file mode 100644
>> index 0000000..fb78109
>> --- /dev/null
>> +++ b/gdb/common/common-inferior.h
>> @@ -0,0 +1,113 @@
>> +/* Variables that describe the inferior process running under GDB:
>> +   Where it is, why it stopped, and how to step it.
>
> Common code that describes the inferior process under GDB/GDBserver ...?
>
> I'd check the other files that were created in common/ to make sure
> their descriptions in the copyright block aren't unchanged from their
> original files.

Yeah, I was going to do that already after your last comments on other
patches, but thanks for the heads up.

>> [...]
>> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
>> index 249a063..56c734c 100644
>> --- a/gdb/gdbserver/target.c
>> +++ b/gdb/gdbserver/target.c
>> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>>    return size;
>>  }
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_init (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_inferior (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_ours (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>
> Same suggestion as the other patch regarding either putting something
> in place now or adding more documentation about what these need to do
> in the future.

Yep, they're on my list, thanks.

>> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
>> index d098a92..3e74b86 100644
>> --- a/gdb/gdbserver/target.h
>> +++ b/gdb/gdbserver/target.h
>> @@ -28,6 +28,7 @@
>>  #include "target/waitstatus.h"
>>  #include "mem-break.h"
>>  #include "btrace-common.h"
>> +#include <vector>
>>
>>  struct emit_ops;
>>  struct buffer;
>> @@ -73,7 +74,7 @@ struct target_ops
>>       Returns the new PID on success, -1 on failure.  Registers the new
>>       process with the process list.  */
>>
>> -  int (*create_inferior) (char *program, char **args);
>> +  int (*create_inferior) (std::vector<char *> &program_argv);
>>
>>    /* Do additional setup after a new process is created, including
>>       exec-wrapper completion.  */
>> @@ -480,8 +481,8 @@ extern struct target_ops *the_target;
>>
>>  void set_target_ops (struct target_ops *);
>>
>> -#define create_inferior(program, args) \
>> -  (*the_target->create_inferior) (program, args)
>> +#define create_inferior(program) \
>> +  (*the_target->create_inferior) (program)
>>
>>  #define target_post_create_inferior()			 \
>>    do							 \
>> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
>> index 37b9c89..8fa3ce5 100644
>> --- a/gdb/gdbserver/utils.c
>> +++ b/gdb/gdbserver/utils.c
>> @@ -137,3 +137,40 @@ pfildes (gdb_fildes_t fd)
>>    return plongest (fd);
>>  #endif
>>  }
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +gdb_flush_out_err (void)
>> +{
>> +  fflush (stdout);
>> +  fflush (stderr);
>> +}
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +free_vector_argv (std::vector<char *> &v)
>> +{
>> +  for (std::vector<char *>::iterator i = v.begin ();
>> +       i != v.end ();
>> +       ++i)
>> +    xfree (*i);
>> +
>> +  v.clear ();
>> +}
>
> Nothing wrong with the above, but with the decision to use C++ 11,
> maybe this could be further simplified with range for if you think
> it's worth it?
>
> {
>   for (char* arg : v)
>     xfree (arg);
>
>   v.clear ();
> }
>
> Or maybe it is a bit too fancy for our own good, though we will
> eventually need to get used to it.

Oh, I think I've lost some context then, because I thought we were still
waiting a bit before using C++11.

> Another thought is to make the elements std::string themselves, in
> which case std::vector::clear () will call each elements'
> destructor. Again, maybe too fancy.

Yeah, my initial plan was to make them std::string's, but there was some
reason (which I can't remember now, for the life of me) why I decided to
make them char *.  Anyway, I'll revisit this.

>> +
>> +/* See common/common-utils.h.  */
>> +
>> +std::string
>> +stringify_argv (std::vector<char *> &argv)
>> +{
>> +  std::string ret ("");
>> +
>> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
>> +       i != argv.end ();
>> +       ++i)
>> +    ret += *i + std::string (" ");
>> +
>> +  return ret;
>> +}
>
> Same suggestion as above for the range for.
>
> {
>   for (char* arg : argv)
>     ret += arg + std::string (" ");
>
>   return ret;
> }
>
>> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
>> index 5e0cead..20c8dcd 100644
>> --- a/gdb/gdbserver/utils.h
>> +++ b/gdb/gdbserver/utils.h
>> @@ -19,7 +19,19 @@
>>  #ifndef UTILS_H
>>  #define UTILS_H
>>
>> +#include <vector>
>> +
>>  char *paddress (CORE_ADDR addr);
>>  char *pfildes (gdb_fildes_t fd);
>>
>> +/* Works like FREEARGV, but with std::vector.  */
>> +
>> +extern void free_vector_argv (std::vector<char *> &v);
>> +
>> +/* Given a vector of arguments ARGV, return a string equivalent to
>> +   joining all the arguments (starting from ARGV + 1) with a
>> +   whitespace separating them.  */
>> +
>> +extern std::string stringify_argv (std::vector<char *> &argv);
>> +
>>  #endif /* UTILS_H */
>> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
>> index 70abfcd..1f7f538 100644
>> --- a/gdb/gdbserver/win32-low.c
>> +++ b/gdb/gdbserver/win32-low.c
>> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>>  }
>>
>>  /* Start a new process.
>> -   PROGRAM is a path to the program to execute.
>> -   ARGS is a standard NULL-terminated array of arguments,
>> -   to be passed to the inferior as ``argv''.
>> +   PROGRAM_ARGV is the vector containing the inferior's argv.
>>     Returns the new PID on success, -1 on failure.  Registers the new
>>     process with the process list.  */
>>  static int
>> -win32_create_inferior (char *program, char **program_args)
>> +win32_create_inferior (std::vector<char *> &program_argv)
>>  {
>>  #ifndef USE_WIN32API
>>    char real_path[PATH_MAX];
>> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>>    int argc;
>>    PROCESS_INFORMATION pi;
>>    DWORD err;
>> +  char *program = program_argv[0];
>> +  std::string program_args = stringify_argv (program_argv);
>> +  char *args = (char *) program_args.c_str ();
>>
>>    /* win32_wait needs to know we're not attaching.  */
>>    attaching = 0;
>> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>>
>>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>>
>> +  pre_fork_inferior (program, argv);
>> +
>>  #ifndef USE_WIN32API
>>    orig_path = NULL;
>>    path_ptr = getenv ("PATH");
>> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>>    program = real_path;
>>  #endif
>>
>> -  argslen = 1;
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    argslen += strlen (program_args[argc]) + 1;
>> -  args = (char *) alloca (argslen);
>> -  args[0] = '\0';
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    {
>> -      /* FIXME: Can we do better about quoting?  How does Cygwin
>> -	 handle this?  */
>> -      strcat (args, " ");
>> -      strcat (args, program_args[argc]);
>> -    }
>>    OUTMSG2 (("Command line is \"%s\"\n", args));
>>
>>  #ifdef CREATE_NEW_PROCESS_GROUP
>> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>>
>>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>>
>> +  post_fork_inferior (current_process_id, program_argv);
>> +
>>    return current_process_id;
>>  }
>>
>> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
>> index 85a53b8..3e2e226 100644
>> --- a/gdb/gnu-nat.c
>> +++ b/gdb/gnu-nat.c
>> @@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
>>    thread_change_ptid (inferior_ptid,
>>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>    inf->pending_execs = 0;
>>    /* Get rid of the old shell threads.  */
>>    prune_threads ();
>> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
>> index 64aaabe..ceb1422 100644
>> --- a/gdb/inf-ptrace.c
>> +++ b/gdb/inf-ptrace.c
>> @@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>>
>>    discard_cleanups (back_to);
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>
>>    /* On some targets, there must be some explicit actions taken after
>>       the inferior has been started up.  */
>> diff --git a/gdb/inferior.h b/gdb/inferior.h
>> index 403c096..6dae6b2 100644
>> --- a/gdb/inferior.h
>> +++ b/gdb/inferior.h
>> @@ -42,6 +42,7 @@ struct target_desc_info;
>>
>>  #include "progspace.h"
>>  #include "registry.h"
>> +#include "common-inferior.h"
>>
>>  #include "symfile-add-flags.h"
>>
>> @@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
>>
>>  extern void child_terminal_init_with_pgrp (int pgrp);
>>
>> -/* From fork-child.c */
>> -
>> -extern int fork_inferior (char *, char *, char **,
>> -			  void (*)(void),
>> -			  void (*)(int), void (*)(void), char *,
>> -                          void (*)(const char *,
>> -                                   char * const *, char * const *));
>> -
>> -
>> -extern void startup_inferior (int);
>> -
>>  extern char *construct_inferior_arguments (int, char **);
>>
>>  /* From infcmd.c */
>> diff --git a/gdb/procfs.c b/gdb/procfs.c
>> index ff814ba..5b64618 100644
>> --- a/gdb/procfs.c
>> +++ b/gdb/procfs.c
>> @@ -4380,7 +4380,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
>>    thread_change_ptid (pid_to_ptid (pid),
>>  		      ptid_build (pid, lwpid, 0));
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>
>>  #ifdef SYS_syssgi
>>    /* On mips-irix, we need to stop the inferior early enough during
>> diff --git a/gdb/target.h b/gdb/target.h
>> index a54b3db..adec5f2 100644
>> --- a/gdb/target.h
>> +++ b/gdb/target.h
>> @@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
>>
>>  extern int target_terminal_is_ours (void);
>>
>> -/* Initialize the terminal settings we record for the inferior,
>> -   before we actually run the inferior.  */
>> -
>> -extern void target_terminal_init (void);
>> -
>> -/* Put the inferior's terminal settings into effect.  This is
>> -   preparation for starting or resuming the inferior.  This is a no-op
>> -   unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_inferior (void);
>> -
>>  /* Put some of our terminal settings into effect, enough to get proper
>>     results from our output, but do not change into or out of RAW mode
>>     so that no input is discarded.  This is a no-op if terminal_ours
>> @@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
>>
>>  extern void target_terminal_ours_for_output (void);
>>
>> -/* Put our terminal settings into effect.  First record the inferior's
>> -   terminal settings so they can be restored properly later.  This is
>> -   a no-op unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_ours (void);
>> -
>>  /* Return true if the target stack has a non-default
>>    "to_terminal_ours" method.  */
>>
>> diff --git a/gdb/target/target.h b/gdb/target/target.h
>> index 2f4c716..2f0d8ba 100644
>> --- a/gdb/target/target.h
>> +++ b/gdb/target/target.h
>> @@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
>>
>>  extern int target_supports_multi_process (void);
>>
>> +/* Initialize the terminal settings we record for the inferior,
>> +   before we actually run the inferior.  */
>> +
>
> Spurious newline due to the following?
>
>
> https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation
>
>   "Note that this only applies to the case where the comment is placed
>   besides the subprogram implementation (typically in a .c file). In the
>   case of the documentation being placed next to the subprogram
>   declaration, then the comment should be placed immediately before the
>   declaration."

Yeah.

>> +extern void target_terminal_init (void);
>> +
>> +/* Put the inferior's terminal settings into effect.  This is
>> +   preparation for starting or resuming the inferior.  This is a no-op
>> +   unless called with the main UI as current UI.  */
>> +
>> +extern void target_terminal_inferior (void);
>> +
>> +/* Put our terminal settings into effect.  First record the inferior's
>> +   terminal settings so they can be restored properly later.  This is
>> +   a no-op unless called with the main UI as current UI.  */
>> +
>> +extern void target_terminal_ours (void);
>> +
>>  #endif /* TARGET_COMMON_H */
>> diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
>> index f68029d..efdfb58 100644
>> --- a/gdb/testsuite/gdb.server/non-existing-program.exp
>> +++ b/gdb/testsuite/gdb.server/non-existing-program.exp
>> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>>  set msg "gdbserver exits cleanly"
>>  set saw_exiting 0
>>  expect {
>> -    # This is what we get on ptrace-based targets.
>> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
>> +    # This is what we get on ptrace-based targets with
>> +    # startup-with-shell disabled.
>> +    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>> +	set saw_exiting 1
>> +	exp_continue
>> +    }
>> +    # Likewise, but with startup-with-shell enabled.
>> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>>  	set saw_exiting 1
>>  	exp_continue
>>      }
>> diff --git a/gdb/top.h b/gdb/top.h
>> index 482ed3e..0c057d7 100644
>> --- a/gdb/top.h
>> +++ b/gdb/top.h
>> @@ -22,6 +22,7 @@
>>
>>  #include "buffer.h"
>>  #include "event-loop.h"
>> +#include "common-top.h"
>>
>>  struct tl_interp_info;
>>
>> @@ -144,14 +145,6 @@ struct ui
>>    struct ui_out *m_current_uiout;
>>  };
>>
>> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>> -   It always exists and is created automatically when GDB starts
>> -   up.  */
>> -extern struct ui *main_ui;
>> -
>> -/* The current UI.  */
>> -extern struct ui *current_ui;
>> -
>>  /* The list of all UIs.  */
>>  extern struct ui *ui_list;
>>
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index 6bf3716..026e9d7 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -3435,6 +3435,15 @@ strip_leading_path_elements (const char *path, int n)
>>    return p;
>>  }
>>
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +gdb_flush_out_err (void)
>> +{
>> +  gdb_flush (main_ui->m_gdb_stdout);
>> +  gdb_flush (main_ui->m_gdb_stderr);
>> +}
>> +
>>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>>  extern initialize_file_ftype _initialize_utils;
>>
>>
>
> The patch looks reasonable to me, though it would be nice to do a
> second pass on a version without the git-copy in place. That way we
> can see the real changes for the code that was moved.

Yeah, agreed.  I'll take care to include the full diff next time.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-01-04 16:08       ` Eli Zaretskii
@ 2017-01-05 20:12         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-05 20:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, palves

On Wednesday, January 04 2017, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: gdb-patches@sourceware.org, palves@redhat.com
>> Date: Tue, 03 Jan 2017 15:48:26 -0500
>> 
>> >     Also, is it possible that a user will want
>> >     remote targets to use a shell, while avoiding that for native
>> >     debugging, in the same session?
>> 
>> Yeah, I thought about that.  My first thought was to add a 'set/show
>> remote startup-with-shell' option, but I thought this was going to be
>> too much for the user.  Maybe not.
>> 
>> With this new setting, we'd have:
>> 
>> - startup-with-shell: Used only locally, default on.  Instructs GDB to
>>   start the inferior using the shell.
>> 
>> - remote startup-with-shell: Used only remotely, default on.  Instructs
>>   gdbserver to start the inferior using the shell.
>> 
>> - remote startup-shell: Used only remotely (if remote startup-with-shell
>>   is on), default "" (empty).  Tells which shell to be used by gdbserver
>>   to start the inferior.  If empty, use $SHELL.
>> 
>> WDYT?
>
> Makes sense to me, thanks.

Cool, thanks.  I'll go ahead and implement this idea, then.

Cheers,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 1/6] Share gdb/environ.[ch] with gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                     ` (2 preceding siblings ...)
  2017-01-18 15:36   ` [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
@ 2017-01-18 15:36   ` Sergio Durigan Junior
  2017-02-01 20:35     ` Luis Machado
  2017-01-18 15:42   ` [PATCH v2 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
                     ` (3 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:36 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

We will need access to the environment functions when we share
fork_inferior between GDB and gdbserver, therefore we simply make the
API on gdb/environ.[ch] available on common/.  No extra adjustments
are needed to make it compile on gdbserver.

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

	* Makefile.in (SFILES): Replace "environ.c" with
	"common/environ.c".
	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
	to...
	* common/environ.c: ... here.
	* environ.h: Moved to...
	* common/environ.h: ... here.

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

	* Makefile.in (SFILES): Add "common/environ.c".
	(OBJS): Add "common/environ.h".
---
 gdb/Makefile.in            | 4 ++--
 gdb/{ => common}/environ.c | 2 +-
 gdb/{ => common}/environ.h | 0
 gdb/gdbserver/Makefile.in  | 5 +++++
 4 files changed, 8 insertions(+), 3 deletions(-)
 rename gdb/{ => common}/environ.c (99%)
 rename gdb/{ => common}/environ.h (100%)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3ce7d69..3f19818 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1048,7 +1048,6 @@ SFILES = \
 	dwarf2loc.c \
 	dwarf2read.c \
 	elfread.c \
-	environ.c \
 	eval.c \
 	event-loop.c \
 	event-top.c \
@@ -1193,6 +1192,7 @@ SFILES = \
 	common/common-regcache.c \
 	common/common-utils.c \
 	common/errors.c \
+	common/environ.c \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
@@ -1271,7 +1271,6 @@ HFILES_NO_SRCDIR = \
 	dwarf2-frame-tailcall.h \
 	dwarf2expr.h \
 	dwarf2loc.h \
-	environ.h \
 	event-loop.h \
 	event-top.h \
 	exceptions.h \
@@ -1471,6 +1470,7 @@ HFILES_NO_SRCDIR = \
 	common/common-types.h \
 	common/common-utils.h \
 	common/errors.h \
+	common/environ.h \
 	common/fileio.h \
 	common/format.h \
 	common/gdb_assert.h \
diff --git a/gdb/environ.c b/gdb/common/environ.c
similarity index 99%
rename from gdb/environ.c
rename to gdb/common/environ.c
index bfeabec..3145d01 100644
--- a/gdb/environ.c
+++ b/gdb/common/environ.c
@@ -15,7 +15,7 @@
    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 "defs.h"
+#include "common-defs.h"
 #include "environ.h"
 #include <algorithm>
 \f
diff --git a/gdb/environ.h b/gdb/common/environ.h
similarity index 100%
rename from gdb/environ.h
rename to gdb/common/environ.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 75736b6..ef0dc99 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -201,6 +201,7 @@ SFILES = \
 	$(srcdir)/common/common-regcache.c \
 	$(srcdir)/common/common-utils.c \
 	$(srcdir)/common/errors.c \
+	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
 	$(srcdir)/common/gdb_vecs.c \
@@ -238,6 +239,7 @@ OBS = \
 	debug.o \
 	dll.o \
 	errors.o \
+	environ.o \
 	event-loop.o \
 	fileio.o \
 	filestuff.o \
@@ -774,6 +776,9 @@ agent.o: ../common/agent.c
 errors.o: ../common/errors.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+environ.o: ../common/environ.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-debug.o: ../common/common-debug.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
  2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
@ 2017-01-18 15:36   ` Sergio Durigan Junior
  2017-01-18 16:43     ` Eli Zaretskii
  2017-02-01 19:07     ` Luis Machado
  2017-01-18 15:36   ` [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
                     ` (5 subsequent siblings)
  7 siblings, 2 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:36 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

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-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS (Changes since GDB 7.12): Announce that GDBserver is now
	able to start inferiors	using a shell.
	(New remote packets): Announce new packet "QStartupWithShell".
	* remote.c: Add PACKET_QStartupWithShell.
	(remote_start_remote): 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-01-17  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-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
2017-01-17  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/NEWS                                        | 10 +++
 gdb/doc/gdb.texinfo                             | 26 ++++++++
 gdb/gdbserver/server.c                          | 36 ++++++++++-
 gdb/remote.c                                    | 20 ++++++
 gdb/testsuite/gdb.server/startup-with-shell.c   | 29 +++++++++
 gdb/testsuite/gdb.server/startup-with-shell.exp | 83 +++++++++++++++++++++++++
 6 files changed, 203 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index b976815..9bf8df4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
 
 *** Changes since GDB 7.12
 
+* GDBserver is now able to start inferiors using a shell.  When using
+  "target extended-remote", the host GDB honors the value of "set
+  startup-with-shell" in order to inform GDBserver whether the remote
+  inferior should be started with a shell or not.  When using "target
+  remote", it is possible to disable the startup with shell by using
+  the new parameter "--no-startup-with-shell" when starting GDBserver.
+
 * Building GDB and GDBserver now requires a C++11 compiler.
 
   For example, GCC 4.8 or later.
@@ -356,6 +363,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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2b6b654..bfe11de 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
@@ -20772,6 +20773,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}
@@ -36330,6 +36335,27 @@ 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.
+
+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 give as hex digits.
+@end table
+
 @item qfThreadInfo
 @itemx qsThreadInfo
 @cindex list active threads, remote request
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index a26ad52..56bd613 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -866,6 +866,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      char *value = own_buf + strlen ("QStartupWithShell:");
+
+      if (strcmp (value, "1") == 0)
+	startup_with_shell = 1;
+      else if (strcmp (value, "0") == 0)
+	startup_with_shell = 0;
+      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;
@@ -2302,7 +2327,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 ())
@@ -3396,6 +3421,11 @@ 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.\n"
+	   "  --no-startup-with-shell\n"
+	   "                        Don't start PROG using a shell (i.e., use the exec*\n"
+	   "                        family of functions).\n"
 	   "\n"
 	   "Debug options:\n"
 	   "\n"
@@ -3679,6 +3709,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 = 1;
+      else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
+	startup_with_shell = 0;
       else if (strcmp (*next_arg, "--once") == 0)
 	run_once = 1;
       else
diff --git a/gdb/remote.c b/gdb/remote.c
index 2f7954a..67319f6 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1428,6 +1428,7 @@ enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QStartupWithShell,
   PACKET_qCRC,
   PACKET_qSearch_memory,
   PACKET_vAttach,
@@ -4079,6 +4080,20 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     remote_set_permissions (target);
 
+  /* 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);
+    }
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an
@@ -4633,6 +4648,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,
@@ -14110,6 +14127,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);
 
diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.c
@@ -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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
new file mode 100644
index 0000000..8992593
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
@@ -0,0 +1,83 @@
+# 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/>.
+
+# Test startup-with-shell support using extended-remote.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+if { [skip_gdbserver_tests] } {
+    return 0
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+# Initial setup for simple test (wildcard expansion, variable substitution).
+
+proc initial_setup_simple { startup_with_shell run_args } {
+    global hex decimal binfile
+
+    clean_restart $binfile
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+
+    gdb_test_no_output "set startup-with-shell $startup_with_shell"
+
+    set target_exec [gdbserver_download_current_prog]
+    gdbserver_start_extended
+    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+
+    gdb_breakpoint main
+
+    gdb_test "run $run_args" \
+	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
+	"run to main"
+}
+
+## Doing the actual tests
+
+with_test_prefix "startup_with_shell = on; run_args = *.log" {
+    initial_setup_simple "on" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
+	"testing first argument"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.log" {
+    initial_setup_simple "off" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
+	"testing first argument"
+}
+
+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)
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
@ 2017-01-18 15:36   ` Sergio Durigan Junior
  2017-02-01 18:37     ` Luis Machado
  2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:36 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

As part of the bigger work of sharing fork_inferior with gdbserver,
some parts of gdb/terminal.h also needed to be moved to a common
place.  These parts are:

- The code responsible for determining some terminal-based define's
  based on available features;

- job control;

- terminal-related functions needed by fork_inferior;

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

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
	* common/common-terminal.h: New file, with parts of "terminal.h".
	* terminal.h: Move terminal-related defines to
	"common/common-terminal.h".  Include "common/common-terminal.h".
	(new_tty_prefork): Move to "common/common-terminal.h".
	(new_tty): Likewise.
	(new_tty_postfork): Likewise.
	(job_control): Likewise.
	(create_tty_session): Likewise.
	(gdb_setpgid): Likewise.
	* utils.c: Include "terminal.h".

gdb/gdbserver/ChangeLog:
2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>

	* terminal.c: New file.
---
 gdb/Makefile.in              |   1 +
 gdb/common/common-terminal.h | 119 +++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/terminal.c     |  88 ++++++++++++++++++++++++++++++++
 gdb/terminal.h               |  73 +-------------------------
 gdb/utils.c                  |   1 +
 5 files changed, 210 insertions(+), 72 deletions(-)
 create mode 100644 gdb/common/common-terminal.h
 create mode 100644 gdb/gdbserver/terminal.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3f19818..c05d456 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/common-terminal.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
new file mode 100644
index 0000000..f7ab96a
--- /dev/null
+++ b/gdb/common/common-terminal.h
@@ -0,0 +1,119 @@
+/* Common terminal interface definitions for GDB and gdbserver.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TERMINAL_H
+#define COMMON_TERMINAL_H
+
+/* If we're using autoconf, it will define HAVE_TERMIOS_H,
+   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
+   ser-unix.c and inflow.c to inspect those names instead of
+   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
+   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
+   nothing has already defined the one of the names, and do the right
+   thing.  */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
+	  !defined (HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  FIXME: serial.h and
+   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+   is converted to use them, can get rid of this crap.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+#include <sys/types.h>
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
+extern void new_tty (void);
+
+/* NEW_TTY_PREFORK is called before forking a new child process,
+   so we can record the state of ttys in the child to be formed.
+   TTYNAME is null if we are to share the terminal with gdb;
+   or points to a string containing the name of the desired tty.
+
+   NEW_TTY is called in new child processes under Unix, which will
+   become debugger target processes.  This actually switches to
+   the terminal specified in the NEW_TTY_PREFORK call.  */
+extern void new_tty_prefork (const char *ttyname);
+
+/* NEW_TTY_POSTFORK is called after forking a new child process, and
+   adding it to the inferior table, to store the TTYNAME being used by
+   the child, or null if it sharing the terminal with gdb.  */
+extern void new_tty_postfork (void);
+
+/* Create a new session if the inferior will run in a different tty.
+   A session is UNIX's way of grouping processes that share a controlling
+   terminal, so a new one is needed if the inferior terminal will be
+   different from GDB's.
+
+   Returns the session id of the new session, 0 if no session was created
+   or -1 if an error occurred.  */
+extern pid_t create_tty_session (void);
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid (void);
+
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  */
+extern void have_job_control (void);
+
+#endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
new file mode 100644
index 0000000..42ac651
--- /dev/null
+++ b/gdb/gdbserver/terminal.c
@@ -0,0 +1,88 @@
+/* Terminal interface definitions for the GDB remote server.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "common-terminal.h"
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_prefork (const char *ttyname)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_postfork (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+pid_t
+create_tty_session (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+  return (pid_t) 1;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+set_inferior_io_terminal (const char *terminal_name)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-inferior.h.  */
+
+const char *
+get_inferior_io_terminal (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+  return NULL;
+}
diff --git a/gdb/terminal.h b/gdb/terminal.h
index d8691b2..8139319 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,83 +19,12 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
+#include "common-terminal.h"
 
 struct inferior;
 
-extern void new_tty_prefork (const char *);
-
-extern void new_tty (void);
-
-extern void new_tty_postfork (void);
-
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
-extern pid_t create_tty_session (void);
-
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index f142ffe..4993145 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -53,6 +53,7 @@
 #include "top.h"
 #include "main.h"
 #include "solist.h"
+#include "terminal.h"
 
 #include "inferior.h"		/* for signed_pointer_to_address */
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (6 preceding siblings ...)
  2016-12-23  7:50 ` [PATCH 0/6] Implement the ability to start inferiors with a shell " Eli Zaretskii
@ 2017-01-18 15:36 ` Sergio Durigan Junior
  2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
                     ` (7 more replies)
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (2 subsequent siblings)
  10 siblings, 8 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:36 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Eli Zaretskii, Luis Machado

Hi again,

This is the second version of this patch series.  I addressed many
comments made by Luis, Eli, Tom and Pedro (private) on the first
version.  Thanks!

Here's what changed from v1:

 - Added NEWS entry

 - Mentioned that the feature is to be used on UNIX-like systems

 - Removed third argument from set_executing

 - Removed 'set remote startup-shell' command

 - Renamed the packet to QStartupWithShell.  Now, the packet has only
   a boolean argument: "1" (meaning that the remote target should use
   a shell to start the inferior), and "0" (the remote target should
   not use a shell to start the inferior).

 - Write documentation for this new packet

 - Fixed and rewrote ChangeLog entries

 - Fixed spurious newlines on comments.

 - Fix comments that only mentioned "GDB" on files that are now being
   shared with gdbserver.

 - Adjust copyright notices on files

 - Use "untested" where applicable on the testcase


This patch series implement the "startup-with-shell" feature on
gdbserver.  This means that it will be possible to start inferiors
using the shell (instead of calling execv*), which brings many
advantages.

First of all, it will be possible to use I/O redirection, variable
substitution and globbing expansion on gdbserver just like we do today
on GDB.  This is great because, among other things, it brings
gdbserver on a pair with GDB when considering the Feature Parity
project.

Secondly, a great deal of code had to be shared between GDB and
gdbserver, especially the fork_inferior function, which means that now
both programs are using virtually the same code to start inferiors.
I've also had to touch on other areas, like terminal.h, inflow.c and
gdbthread.h, and even though only the APIs were shared (i.e.,
gdbserver's version of a gdbthread.h function may differ from GDB's
version), this is also beneficial in the long run when we start to
unify the code more deeply.  But I'm "raining in the wet" here; all
this has been explained in better terms before.

I did my best to split the patches, but unfortunately the
fork_inferior patch is big and I couldn't see a better way to do that.
But it shouldn't be very hard to review them, because most of it is
just "code movement".


^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
  2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
  2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-01-18 15:36   ` Sergio Durigan Junior
  2017-02-01 18:41     ` Luis Machado
  2017-01-18 15:36   ` [PATCH v2 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
                     ` (4 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:36 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

After sharing parts of gdb/terminal.h, it is also needed to share the
two functions on gdb/inflow.c that are going to be needed by the
fork_inferior sharing.  They are 'gdb_setpgid' and the new
'have_job_control'.

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

	* Makefile.in (SFILES): Add "common/common-inflow.c".
	(COMMON_OBS): Add "common/common-inflow.o".
	* common/common-inflow.c: New file, with contents from
	"gdb/inflow.c".
	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* utils.c (job_control): Delete.

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

	* Makefile.in: Add rule for "common-inflow.o".
	(SFILE): Add "common/common-inflow.c".
	(OBS): Add "common-inflow.o".
---
 gdb/Makefile.in            |  2 +
 gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/Makefile.in  |  5 +++
 gdb/inflow.c               | 63 +-------------------------------
 gdb/utils.c                |  4 --
 5 files changed, 100 insertions(+), 65 deletions(-)
 create mode 100644 gdb/common/common-inflow.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c05d456..c0325d5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1196,6 +1196,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1623,6 +1624,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
new file mode 100644
index 0000000..9871b5e
--- /dev/null
+++ b/gdb/common/common-inflow.c
@@ -0,0 +1,91 @@
+/* Low level interface to ptrace, for GDB and gdbserver when running under Unix.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "common-terminal.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* This is here because this is where we figure out whether we (probably)
+   have job control.  Just using job_control only does part of it because
+   setpgid or setpgrp might not exist on a system without job control.
+   It might be considered misplaced (on the other hand, process groups and
+   job control are closely related to ttys).
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index ef0dc99..74e199b 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
@@ -770,6 +772,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-inflow.o: ../common/common-inflow.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 agent.o: ../common/agent.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 7ffa83a..271278d 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -803,43 +803,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -860,30 +823,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 4993145..119992e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                     ` (3 preceding siblings ...)
  2017-01-18 15:36   ` [PATCH v2 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2017-01-18 15:42   ` Sergio Durigan Junior
  2017-02-01 18:54     ` Luis Machado
  2017-01-18 15:44   ` [PATCH v2 5/6] Share fork_inferior et al " Sergio Durigan Junior
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:42 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

Again, it was necessary to share a few functions declared on
gdb/gdbthread.h with gdbserver, because they are needed by
fork_inferior.  I decided to implement them on
gdb/gdbserver/inferiors.c because that's where the thread functions
are also implemented on gdbserver.  Some of these functions do not
need to be implemented on gdbserver, or don't make sense there, so
they are left blank and commented properly.

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

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* fork-child.c (fork_inferior): Update call of "set_executing".
	* gdbthread.h: Include "common-gdbthread.h".
	(init_thread_list): Moved to "common/common-gdbthread.h".
	(add_thread_silent): Likewise.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	* thread.c (set_executing): Update function comment.

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

	* inferiors.c (init_thread_list): New function.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	(add_thread_silent): Likewise.
	* server.c (get_last_target_waitstatus): Likewise.
	* server.h (get_last_target_waitstatus): Likewise.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 45 +++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     | 41 +++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/server.c        |  8 ++++++++
 gdb/gdbserver/server.h        |  3 +++
 gdb/gdbthread.h               | 20 +------------------
 gdb/thread.c                  |  2 ++
 7 files changed, 101 insertions(+), 19 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c0325d5..3e49e6e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..eb66de9
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,45 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
+   
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_THREAD_H
+#define COMMON_THREAD_H
+
+struct target_waitstatus;
+
+/* Create an empty thread list, or empty the existing one.  */
+extern void init_thread_list (void);
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
+   marks all threads.
+
+   Note that this is different from the running state.  See the
+   description of state and executing fields of struct
+   thread_info.  */
+extern void set_executing (ptid_t ptid, int executing);
+
+/* Add a thread to the thread list and return the pointer to the new
+   thread.  Caller may use this pointer to initialize the private
+   thread data.  */
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+#endif /* ! COMMON_THREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..441ec2c 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,44 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+init_thread_list (void)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
+{
+  gdb_assert (current_thread != NULL);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = get_last_target_waitstatus ();
+}
+
+/* See common/common-gdbthread.h.  */
+
+struct thread_info *
+add_thread_silent (ptid_t ptid)
+{
+  pid_t pid = ptid_get_pid (ptid);
+
+  /* Check if there is a process already.  */
+  if (find_process_pid (pid) == NULL)
+    add_process (pid, 0);
+
+  return add_thread (ptid_build (pid, pid, 0), NULL);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 4bc7f71..43d9406 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -236,6 +236,14 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
+/* See server.h.  */
+
+struct target_waitstatus
+get_last_target_waitstatus (void)
+{
+  return last_status;
+}
+
 static int
 start_inferior (char **argv)
 {
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..71848f1 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -148,4 +148,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* Return the global variable LAST_STATUS from server.c.  */
+extern struct target_waitstatus get_last_target_waitstatus (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 455cfd8..b4d3499 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -31,6 +31,7 @@ struct symtab;
 #include "common/vec.h"
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -344,19 +345,12 @@ struct thread_info
   struct thread_info *step_over_next;
 };
 
-/* Create an empty thread list, or empty the existing one.  */
-extern void init_thread_list (void);
-
 /* Add a thread to the thread list, print a message
    that a new thread is found, and return the pointer to
    the new thread.  Caller my use this pointer to 
    initialize the private thread data.  */
 extern struct thread_info *add_thread (ptid_t ptid);
 
-/* Same as add_thread, but does not print a message
-   about new thread.  */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
-
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
 						 struct private_thread_info *);
@@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
@@ -518,14 +508,6 @@ extern int is_exited (ptid_t ptid);
 /* In the frontend's perpective, is this thread stopped?  */
 extern int is_stopped (ptid_t ptid);
 
-/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
-   marks all threads.
-
-   Note that this is different from the running state.  See the
-   description of state and executing fields of struct
-   thread_info.  */
-extern void set_executing (ptid_t ptid, int executing);
-
 /* Reports if thread PTID is executing.  */
 extern int is_executing (ptid_t ptid);
 
diff --git a/gdb/thread.c b/gdb/thread.c
index e45b257..d159855 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1011,6 +1011,8 @@ is_executing (ptid_t ptid)
   return tp->executing;
 }
 
+/* See common/common-gdbthread.h.  */
+
 void
 set_executing (ptid_t ptid, int executing)
 {
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v2 5/6] Share fork_inferior et al with gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                     ` (4 preceding siblings ...)
  2017-01-18 15:42   ` [PATCH v2 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2017-01-18 15:44   ` Sergio Durigan Junior
  2017-02-01 21:39     ` Luis Machado
  2017-01-26 22:47   ` [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-18 15:44 UTC (permalink / raw)
  To: GDB Patches
  Cc: Pedro Alves, Eli Zaretskii, Luis Machado, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.  For some
feature, like the target_terminal_* functions, I chose to just use
placeholders for the real functions on gdbserver, that should be
implemented in the future.  For now, we don't need them in order to
make things work.  Also, since we don't manipulate terminal modes on
gdbserver the way we do on GDB, they are not possible to implement
right now (unless I chose to properly implement terminal handling on
gdbserver, which is something we don't know if we want now).

Last, but not least, I did a major revamp on the way gdbserver
computes and stores the inferior's arguments.  It's now using a
std::vector<char *> and std::string where applicable, which makes
things much easier even to understand.  This simplification was also
interesting for the "create_inferior" method of gdbserver's target.c;
now, it only needs one argument (a vector containing the full inferior
argv) instead of two char * that were confusing to
manipulate/generate.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

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

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
	"common/common-top.h".
	(COMMON_OBS): Add "common-fork-child.o".
	* common-fork-child.c: New file, with the majority of
	"gdb/fork-child.c".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* common/common-top.h: New file.
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Update call of
	"startup_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(fork_inferior): Likewise.  Update function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Update call to
	"startup_inferior".
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* inferior.h: Include "common-inferior.h".
	(fork_inferior): Move prototype to "common-inferior.h".
	(startup_inferior): Likewise.
	* procfs.c (procfs_init_inferior): Update call to
	"startup_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* top.h: Include "common-top.h".
	(main_ui): Move
	(current_ui): Move
	* utils.c (gdb_flush_out_err): New function.

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

	* Makefile.in (SFILES): Add "terminal.c" and
	"common/common-fork-child.c".
	(OBS): Add common-fork-child.o and terminal.o.
	(common-fork-child.o): New rule.
	* inferiors (inferior_ptid): New variable.
	(inferior_appeared): New function.
	(current_inferior): Likewise.
	(have_inferiors): Likewise.
	* linux-low.c: Include "common-inferior.h" and "environ.h".
	(linux_update_process): New function.
	(linux_add_process): Update comment.  Adjust function to call
	"linux_update_process".
	(update_thread_lwp): New function.
	(linux_ptrace_fun): Likewise.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c (lynx_update_process): New function.
	(lynx_add_process): Update comment.  Adjust function to call
	"lynx_update_process".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".
	* server.c: Include "common-inferior.h", "common-terminal.h",
	"common-top.h", "environ.h".
	(main_ui): New variable.
	(current_ui): Likewise.
	(our_environ): Likewise.
	(startup_with_shell): Likewise.
	(program_argv): Convert to std::vector<char *>.
	(wrapper_argv): Likewise.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(pre_fork_inferior): New function, with parts of "start_inferior".
	(post_fork_inferior): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(pre_fork_inferior): New prototype.
	(post_fork_inferior): Likewise.
	(get_environ): Likewise.
	* spu-low.c (spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype
	to accept one std::vector<char *> representing the full program
	argv.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	(free_vector_argv): Likewise.
	(stringify_argv): Likewise.
	* utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	(stringify_argv): Likewise.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   4 +
 gdb/common/common-fork-child.c                    | 593 ++++++++++++++++++++++
 gdb/common/common-inferior.h                      | 104 ++++
 gdb/common/common-top.h                           |  31 ++
 gdb/common/common-utils.h                         |   4 +
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |   2 +-
 gdb/fork-child.c                                  | 526 +------------------
 gdb/gdbserver/Makefile.in                         |   7 +
 gdb/gdbserver/inferiors.c                         |  31 +-
 gdb/gdbserver/linux-low.c                         | 124 +++--
 gdb/gdbserver/lynx-low.c                          |  66 ++-
 gdb/gdbserver/nto-low.c                           |   9 +-
 gdb/gdbserver/server.c                            | 274 ++++++----
 gdb/gdbserver/server.h                            |  16 +
 gdb/gdbserver/spu-low.c                           |  43 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |   7 +-
 gdb/gdbserver/utils.c                             |  35 ++
 gdb/gdbserver/utils.h                             |  10 +
 gdb/gdbserver/win32-low.c                         |  25 +-
 gdb/gnu-nat.c                                     |   2 +-
 gdb/inf-ptrace.c                                  |   2 +-
 gdb/inferior.h                                    |  12 +-
 gdb/procfs.c                                      |   2 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  17 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
 gdb/top.h                                         |   9 +-
 gdb/utils.c                                       |   9 +
 30 files changed, 1226 insertions(+), 793 deletions(-)
 create mode 100644 gdb/common/common-fork-child.c
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/common/common-top.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3e49e6e..bf8b359 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1196,6 +1196,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-fork-child.c \
 	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
@@ -1483,6 +1484,8 @@ HFILES_NO_SRCDIR = \
 	common/gdb_sys_time.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
+	common/common-top.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1625,6 +1628,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
new file mode 100644
index 0000000..65ef374
--- /dev/null
+++ b/gdb/common/common-fork-child.c
@@ -0,0 +1,593 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and gdbserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   Contributed by Cygnus Support.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "target/waitstatus.h"
+#include "common-terminal.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "common-top.h"
+#include "signals-state-save-restore.h"
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Break up SCRATCH into an argument vector suitable for passing to
+   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
+   would get as input the string "a b c d", and as output it would
+   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+
+static void
+breakup_args_for_exec (char *scratch, char **argv)
+{
+  char *cp = scratch, *tmp;
+
+  for (;;)
+    {
+      /* Scan past leading separators */
+      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
+	cp++;
+
+      /* Break if at end of string.  */
+      if (*cp == '\0')
+	break;
+
+      /* Take an arg.  */
+      *argv++ = cp;
+
+      /* Scan for next arg separator.  */
+      tmp = strchr (cp, ' ');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\t');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\n');
+
+      /* No separators => end of string => break.  */
+      if (tmp == NULL)
+	break;
+      cp = tmp;
+
+      /* Replace the separator with a terminator.  */
+      *cp++ = '\0';
+    }
+
+  /* Null-terminate the vector.  */
+  *argv = NULL;
+}
+
+/* When executing a command under the given shell, return non-zero if
+   the '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  const int shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return 0;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return 1;
+
+  return 0;
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_startup_shell (void)
+{
+  static char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* Quote the shell command that will be executed.  This function is
+   called when the inferior is going to be executed under a shell
+   (i.e., when 'startup-with-shell' is set).
+
+   SHELL_FILE is the shell which will be used to execute the inferior
+   (e.g., /bin/sh).
+
+   EXEC_FILE is the inferior executable itself.
+
+   ALLARGS contains all the arguments that will be passed to the
+   inferior.
+
+   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
+   the inferior.
+
+   SHELL_CMD is a pointer to the resulting shell command that will be
+   executed.  The resulting shell command will be returned in it.  It
+   must be pre-allocated and have a reasonable size.  For an example
+   on how to determine its size, see 'fork_inferior' on
+   fork-child.c.  */
+
+static void
+quote_shell_command (const char *shell_file, const char *exec_file,
+		     const char *allargs, const char *exec_wrapper,
+		     char **shell_cmd)
+{
+  char *shell_command = *shell_cmd;
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  shell_command[0] = '\0';
+  strcat (shell_command, "exec ");
+
+  /* Add any exec wrapper.  That may be a program name with arguments, so
+     the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      strcat (shell_command, exec_wrapper);
+      strcat (shell_command, " ");
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But
+     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
+     we need to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      strcat (shell_command, "'");
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    strcat (shell_command, "'\\''");
+	  else if (*p == '!' && escape_bang)
+	    strcat (shell_command, "\\!");
+	  else
+	    strncat (shell_command, p, 1);
+	}
+      strcat (shell_command, "'");
+    }
+  else
+    strcat (shell_command, exec_file);
+
+  strcat (shell_command, " ");
+  strcat (shell_command, allargs);
+}
+
+/* See common/common-inferior.h.  */
+
+int
+fork_inferior (char *exec_file_arg, char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
+{
+  int pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  static int debug_fork = 0;
+  /* This is set to the result of setpgrp, which if vforked, will be visible
+     to you in the parent process.  It's only used by humans for debugging.  */
+  static int debug_setpgrp = 657473;
+  static char *shell_file;
+  static char *exec_file;
+  char **save_our_env;
+  int shell = 0;
+  static char **argv;
+  const char *inferior_io_terminal = get_inferior_io_terminal ();
+  struct inferior *inf;
+  int i;
+  int save_errno;
+  struct ui *save_ui;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  exec_file = exec_file_arg;
+  if (exec_file == 0)
+    exec_file = get_exec_file (1);
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  shell_file = shell_file_arg;
+  if (startup_with_shell)
+    {
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+      shell = 1;
+    }
+
+  if (!shell)
+    {
+      /* We're going to call execvp.  Create argument vector.
+	 Calculate an upper bound on the length of the vector by
+	 assuming that every other character is a separate
+	 argument.  */
+      int argc = (strlen (allargs) + 1) / 2 + 2;
+
+      argv = XALLOCAVEC (char *, argc);
+      argv[0] = exec_file;
+      breakup_args_for_exec (allargs, &argv[1]);
+    }
+  else
+    {
+      /* We're going to call a shell.  */
+      char *shell_command;
+      char *exec_wrapper = get_exec_wrapper ();
+      size_t len;
+
+      /* Multiplying the length of exec_file by 4 is to account for the
+         fact that it may expand when quoted; it is a worst-case number
+         based on every character being '.  */
+      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
+      if (exec_wrapper != NULL)
+        len += strlen (exec_wrapper) + 1;
+
+      shell_command = (char *) alloca (len);
+      shell_command[0] = '\0';
+
+      quote_shell_command (shell_file, exec_file,
+			   allargs,
+			   exec_wrapper, &shell_command);
+
+      /* If we decided above to start up with a shell, we exec the
+	 shell, "-c" says to interpret the next arg as a shell command
+	 to execute, and this command is "exec <target-program>
+	 <args>".  */
+      argv = (char **) alloca (4 * sizeof (char *));
+      argv[0] = shell_file;
+      argv[1] = "-c";
+      argv[2] = shell_command;
+      argv[3] = (char *) 0;
+    }
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Likewise the current UI.  */
+  save_ui = current_ui;
+
+  /* Tell the terminal handling subsystem what tty we plan to run on;
+     it will just record the information for later.  */
+  new_tty_prefork (inferior_io_terminal);
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Switch to the main UI, so that gdb_std{in/out/err} in the
+	 child are mapped to std{in/out/err}.  This makes it possible
+	 to use fprintf_unfiltered/warning/error/etc. in the child
+	 from here on.  */
+      current_ui = main_ui;
+
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
+      close_most_fds ();
+
+      if (debug_fork)
+	sleep (debug_fork);
+
+      /* Create a new session for the inferior process, if necessary.
+         It will also place the inferior in a separate process group.  */
+      if (create_tty_session () <= 0)
+	{
+	  /* No session was created, but we still want to run the inferior
+	     in a separate process group.  */
+	  debug_setpgrp = gdb_setpgid ();
+	  if (debug_setpgrp == -1)
+	    perror (_("setpgrp failed in child"));
+	}
+
+      /* Ask the tty subsystem to switch to the one we specified
+         earlier (or to share the current terminal, if none was
+         specified).  */
+      new_tty ();
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], argv, env);
+      else
+        execvp (argv[0], argv);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  /* Likewise the current UI.  */
+  current_ui = save_ui;
+
+  if (!have_inferiors ())
+    init_thread_list ();
+
+  inf = current_inferior ();
+
+  inferior_appeared (inf, pid);
+
+  /* Needed for wait_for_inferior stuff below.  */
+  inferior_ptid = pid_to_ptid (pid);
+
+  new_tty_postfork ();
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point, but the pid shouldn't change.  Targets
+     supporting MT should fill this task's ptid with more data as soon
+     as they can.  */
+  add_thread_silent (inferior_ptid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+startup_inferior (int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  /* Mark all threads non-executing.  */
+  set_executing (resume_ptid, 0);
+}
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..e8f163f
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,104 @@
+/* Variables that describe the inferior process running under GDB and
+   gdbserver: Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+struct inferior;
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Collected pid, tid, etc. of the debugged inferior.  When there's
+   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
+extern ptid_t inferior_ptid;
+
+/* Accept NTRAPS traps from the inferior.  */
+extern void startup_inferior (int ntraps,
+			      struct target_waitstatus *mystatus,
+			      ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+               void (*exec_fun) (const char *file, char * const *argv,
+				 char * const *env));
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+extern char *get_startup_shell (void);
+
+/* Set file name for default use for standard in/out in the inferior.  */
+extern void set_inferior_io_terminal (const char *terminal_name);
+
+/* Get file name for default use for standard in/out in the inferior.  */
+extern const char *get_inferior_io_terminal (void);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+/* Returns true if the inferior list is not empty.  */
+extern int have_inferiors (void);
+
+extern void inferior_appeared (struct inferior *inf, int pid);
+
+/* Return a pointer to the current inferior.  It is an error to call
+   this if there is no current inferior.  */
+extern struct inferior *current_inferior (void);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-top.h b/gdb/common/common-top.h
new file mode 100644
index 0000000..a2aa692
--- /dev/null
+++ b/gdb/common/common-top.h
@@ -0,0 +1,31 @@
+/* Common top level stuff for GDB and gdbserver.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TOP_H
+#define COMMON_TOP_H
+
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+extern struct ui *main_ui;
+
+/* The current UI.  */
+extern struct ui *current_ui;
+
+#endif /* ! COMMON_TOP_H */
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 618d266..59e85b1 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -103,4 +103,8 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and gdbserver.  */
+extern void gdb_flush_out_err (void);
+
 #endif
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 54cb789..d76fa1a 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 8c5e8a0..ef94d10 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 }
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index eaa8cb5..a6550c7 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,531 +21,19 @@
 
 #include "defs.h"
 #include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
 #include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
-#include "top.h"
-#include "signals-state-save-restore.h"
-#include <signal.h>
 
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-extern char **environ;
+static char *exec_wrapper = NULL;
 
-static char *exec_wrapper;
+/* See common/common-inferior.h.  */
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
-
-static void
-breakup_args (char *scratch, char **argv)
+char *
+get_exec_wrapper (void)
 {
-  char *cp = scratch, *tmp;
-
-  for (;;)
-    {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
-    }
-
-  /* Null-terminate the vector.  */
-  *argv = NULL;
-}
-
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static int
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  const int shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return 0;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return 1;
-
-  return 0;
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static char *exec_file;
-  char **save_our_env;
-  int shell = 0;
-  static char **argv;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
-    exec_file = get_exec_file (1);
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
-  if (startup_with_shell)
-    {
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  strcat (shell_command, "'");
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
-	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
-	      else
-		strncat (shell_command, p, 1);
-	    }
-	  strcat (shell_command, "'");
-	}
-      else
-	strcat (shell_command, exec_file);
-
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
-    }
-
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
-
-  /* Tell the terminal handling subsystem what tty we plan to run on;
-     it will just record the information for later.  */
-  new_tty_prefork (inferior_io_terminal);
-
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
-      else
-        execvp (argv[0], argv);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
-
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
-
-  if (!have_inferiors ())
-    init_thread_list ();
-
-  inf = current_inferior ();
-
-  inferior_appeared (inf, pid);
-
-  /* Needed for wait_for_inferior stuff below.  */
-  inferior_ptid = pid_to_ptid (pid);
-
-  new_tty_postfork ();
-
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
-}
-
-/* Accept NTRAPS traps from the inferior.  */
-
-void
-startup_inferior (int ntraps)
-{
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
-
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
-
-  if (exec_wrapper)
-    pending_execs++;
-
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
-
-  /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  return exec_wrapper;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 74e199b..9b6e96a 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,6 +185,7 @@ SFILES = \
 	$(srcdir)/target.c \
 	$(srcdir)/thread-db.c \
 	$(srcdir)/utils.c \
+	$(srcdir)/terminal.c \
 	$(srcdir)/win32-arm-low.c \
 	$(srcdir)/win32-i386-low.c \
 	$(srcdir)/win32-low.c \
@@ -204,6 +205,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-fork-child.c \
 	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
@@ -235,6 +237,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
@@ -269,6 +272,7 @@ OBS = \
 	version.o \
 	waitstatus.o \
 	xml-utils.o \
+	terminal.o \
 	$(DEPFILES) \
 	$(LIBOBJS) \
 	$(XML_BUILTIN)
@@ -772,6 +776,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-fork-child.o: ../common/common-fork-child.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-inflow.o: ../common/common-inflow.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 441ec2c..21346cb 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,8 @@ struct thread_info *current_thread;
 
 #define get_thread(inf) ((struct thread_info *)(inf))
 
+ptid_t inferior_ptid;
+
 void
 add_inferior_to_list (struct inferior_list *list,
 		      struct inferior_list_entry *new_inferior)
@@ -469,12 +471,31 @@ make_cleanup_restore_current_thread (void)
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
 
+/* See common/common-inferior.h.  */
+
+void
+inferior_appeared (struct inferior *inf, int pid)
+{
+  /* Placeholder needed for fork_inferior.  We do not have to do
+     anything in this case.  */
+}
+
+/* See common/common-inferior.h.  */
+
+struct inferior *
+current_inferior (void)
+{
+  /* Placeholder needed for fork_inferior.  gdbserver has other
+     functions that serve this purpose.  */
+  return NULL;
+}
+
 /* See common/common-gdbthread.h.  */
 
 void
 init_thread_list (void)
 {
-  /* To be implemented.  */
+  /* Placeholder needed for fork_inferior.  No action is needed.  */
 }
 
 /* See common/common-gdbthread.h.  */
@@ -509,3 +530,11 @@ add_thread_silent (ptid_t ptid)
 
   return add_thread (ptid_build (pid, pid, 0), NULL);
 }
+
+/* See common/common-inferior.h.  */
+
+int
+have_inferiors (void)
+{
+  return get_first_process () != NULL;
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e27cbf8..170e8f2 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
-/* Add a process to the common process list, and set its private
-   data.  */
+/* Update process represented by PID with necessary info.  */
 
 static struct process_info *
-linux_add_process (int pid, int attached)
+linux_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
 
-  proc = add_process (pid, attached);
+  gdb_assert (proc != NULL);
   proc->priv = XCNEW (struct process_info_private);
 
   if (the_low_target.new_process != NULL)
@@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return linux_update_process (pid);
+}
+
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
 /* Call the target arch_setup function on the current thread.  */
@@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
   return 1;
 }
 
+/* Update the lwp associated to thread represented by PTID.  */
+
+static struct lwp_info *
+update_thread_lwp (ptid_t ptid)
+{
+  struct lwp_info *lwp;
+  struct thread_info *thread;
+
+  lwp = XCNEW (struct lwp_info);
+
+  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
+  if (the_low_target.new_thread != NULL)
+    the_low_target.new_thread (lwp);
+
+  thread = find_thread_ptid (ptid);
+  gdb_assert (thread != NULL);
+  thread->target_data = lwp;
+  lwp->thread = thread;
+
+  return lwp;
+}
+
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 {
@@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
+
+  setpgid (0, 0);
+
+  /* If gdbserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      close (0);
+      open ("/dev/null", O_RDONLY);
+      dup2 (2, 1);
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args. */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (std::vector<char *> &program_argv)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string program_args = stringify_argv (program_argv);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
-  linux_add_process (pid, 0);
+  linux_update_process (pid);
 
   ptid = ptid_build (pid, pid, 0);
-  new_lwp = add_lwp (ptid);
+  new_lwp = update_thread_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program_argv);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..296fd6f 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
-/* Call add_process with the given parameters, and initializes
-   the process' private data.  */
+/* Update existing process represented by PID with necessary info.  */
 
 static struct process_info *
-lynx_add_process (int pid, int attached)
+lynx_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
+
+  gdb_assert (proc != NULL);
 
-  proc = add_process (pid, attached);
   proc->tdesc = lynx_tdesc;
   proc->priv = XCNEW (struct process_info_private);
   proc->priv->last_wait_event_ptid = null_ptid;
@@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return lynx_update_process (pid);
+}
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect gdbserver. */
+  pgrp = getpid();
+  setpgid (0, pgrp);
+  ioctl (0, TIOCSPGRP, &pgrp);
+  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  lynx_add_process (pid, 0);
+  post_fork_inferior (pid, program_argv);
+
+  lynx_update_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..ea2a3a4 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM_ARGV.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (std::vector<char *> &program_argv)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string program_args = stringify_argv (program_argv);
 
-  TRACE ("%s %s\n", __func__, program);
+  TRACE ("%s %s\n", __func__, program_argv[0]);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
   signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
 
@@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 43d9406..a26ad52 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,26 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "common-terminal.h"
+#include "common-top.h"
+#include "environ.h"
+
+/* We don't have a concept of a UI yet.  Therefore, we just set these
+   to NULL.  */
+
+struct ui *main_ui = NULL;
+struct ui *current_ui = NULL;
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +98,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -244,33 +265,64 @@ get_last_target_waitstatus (void)
   return last_status;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_wrapper (void)
 {
-  char **new_argv = argv;
+  static std::string ret;
+  static int initialized_p = 0;
+
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  if (wrapper_argv != NULL)
+  if (!initialized_p)
     {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
+      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
+	   i != wrapper_argv.end ();
+	   ++i)
+	ret += *i + std::string (" ");
+
+      /* Erasing the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = 1;
     }
 
+  return (char *) ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_argv.empty ())
+    error (_("Could not get the exec file."));
+  return program_argv[0];
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See server.h.  */
+
+void
+pre_fork_inferior (std::vector<char *> &argv)
+{
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      int idx = 0;
+
+      for (std::vector<char *>::iterator i = argv.begin ();
+	   i != argv.end ();
+	   ++i, ++idx)
+	debug_printf ("new_argv[%d] = \"%s\"\n", idx, *i);
       debug_flush ();
     }
 
@@ -279,67 +331,35 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid,
+		    std::vector<char *> &argv)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
-
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
-
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
-
-  return signal_pid;
+  startup_inferior (num_traps, &last_status, &last_ptid);
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
+  fflush (stderr);
 }
 
 static int
@@ -2860,8 +2880,10 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
-  int i, new_argc;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
+  int new_argc;
+  int i;
 
   new_argc = 0;
   for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
@@ -2870,62 +2892,91 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
-      if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+      if (p == next_p)
+	new_argv.push_back ("''");
       else
 	{
 	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = 1 + (next_p - p) / 2;
+	  char *s = (char *) xmalloc (len);
+	  char *ss = (char *) xmalloc (len * 2);
+	  char *tmp_s, *tmp_ss;
+	  int need_quote;
+
+	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
+	  s[(next_p - p) / 2] = '\0';
+
+	  tmp_s = s;
+	  tmp_ss = ss;
+	  need_quote = 0;
+	  while (*tmp_s != '\0')
+	    {
+	      switch (*tmp_s)
+		{
+		case '\n':
+		  *tmp_ss = '\'';
+		  ++tmp_ss;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  *tmp_ss = '\\';
+		  ++tmp_ss;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_ss = *tmp_s;
+	      ++tmp_ss;
+	      ++tmp_s;
+	    }
+
+	  if (need_quote)
+	    *tmp_ss++ = '\'';
+
+	  *tmp_ss = '\0';
+	  new_argv.push_back (ss);
+	  xfree (s);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
 
-  if (new_argv[0] == NULL)
+  if (new_argv.empty () || new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
 
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
+      new_argv.push_back (strdup (program_argv[0]));
+      if (new_argv.empty () || new_argv[0] == NULL)
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  create_inferior (program_argv);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3543,13 +3594,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3680,8 +3736,14 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  /* This is called when initializing inflow on GDB.  */
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3695,13 +3757,11 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      create_inferior (program_argv);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4316,9 +4376,9 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      create_inferior (program_argv);
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 71848f1..47e094a 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -151,4 +152,19 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Return the global variable LAST_STATUS from server.c.  */
 extern struct target_waitstatus get_last_target_waitstatus (void);
 
+/* Any pre-processing needed to be done before calling fork_inferior
+   shall be implemented here.  ARGV is a vector containing the full
+   argv of the inferior.  */
+extern void pre_fork_inferior (std::vector<char *> &argv);
+
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and ARGV is the vector containing the full
+   argv of the inferior.  */
+extern void post_fork_inferior (int pid, std::vector<char *> &argv);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..7f26331 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, 0, 0);
+  setpgid (0, 0);
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM_ARGV is a vector of program-name and args. */
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string program_args = stringify_argv (program_argv);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
+  pre_fork_inferior (program_argv);
 
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program_argv);
 
-  proc = add_process (pid, 0);
+  proc = find_process_pid (pid);
+  gdb_assert (proc != NULL);
   proc->tdesc = tdesc_spu;
 
-  ptid = ptid_build (pid, pid, 0);
-  add_thread (ptid, NULL);
   return pid;
 }
 
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..1e1d193 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..3f94115 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -73,7 +74,7 @@ struct target_ops
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
 
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (std::vector<char *> &program_argv);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program) \
+  (*the_target->create_inferior) (program)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..004a78e 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,38 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (char *&i : v)
+    xfree (i);
+
+  v.clear ();
+}
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (std::vector<char *> &argv)
+{
+  std::string ret ("");
+
+  for (std::vector<char *>::iterator i = argv.begin () + 1;
+       i != argv.end ();
+       ++i)
+    ret += *i + std::string (" ");
+
+  return ret;
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index b4ded31..a30d99a 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,7 +19,17 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
+/* Works like FREEARGV, but with std::vector.  */
+extern void free_vector_argv (std::vector<char *> &v);
+
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments (starting from ARGV + 1) with a
+   whitespace separating them.  */
+extern std::string stringify_argv (std::vector<char *> &argv);
+
 #endif /* UTILS_H */
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index d3ddbf5..c005a70 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,11 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM_ARGV is the vector containing the inferior's argv.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (std::vector<char *> &program_argv)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  char *program = program_argv[0];
+  std::string program_args = stringify_argv (program_argv);
+  char *args = (char *) program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
 
   flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
 
+  pre_fork_inferior (program, argv);
+
 #ifndef USE_WIN32API
   orig_path = NULL;
   path_ptr = getenv ("PATH");
@@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
@@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
 
   do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
+  post_fork_inferior (current_process_id, program_argv);
+
   return current_process_id;
 }
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 9935dcb..bccfd9c 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index f61bfe7..e9a7de2 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 258cc29..e56d4ba 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -42,6 +42,7 @@ struct target_desc_info;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 
@@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
 
 extern void child_terminal_init_with_pgrp (int pgrp);
 
-/* From fork-child.c */
-
-extern int fork_inferior (char *, char *, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
-
 extern char *construct_inferior_arguments (int, char **);
 
 /* From infcmd.c */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 2269016..ac76be6 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4375,7 +4375,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
diff --git a/gdb/target.h b/gdb/target.h
index f2b9181..99a1e9b 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..06b859c 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..fec138d 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled.
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/top.h b/gdb/top.h
index 2da92df..0c8d324 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -22,6 +22,7 @@
 
 #include "buffer.h"
 #include "event-loop.h"
+#include "common-top.h"
 
 struct tl_interp_info;
 
@@ -144,14 +145,6 @@ struct ui
   struct ui_out *m_current_uiout;
 };
 
-/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
-   It always exists and is created automatically when GDB starts
-   up.  */
-extern struct ui *main_ui;
-
-/* The current UI.  */
-extern struct ui *current_ui;
-
 /* The list of all UIs.  */
 extern struct ui *ui_list;
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 119992e..357ea4f 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3404,6 +3404,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-01-18 16:43     ` Eli Zaretskii
  2017-02-01 19:07     ` Luis Machado
  1 sibling, 0 replies; 157+ messages in thread
From: Eli Zaretskii @ 2017-01-18 16:43 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves, lgustavo

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>, Eli Zaretskii <eliz@gnu.org>,
>         Luis Machado <lgustavo@codesourcery.com>,
>         Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Wed, 18 Jan 2017 10:36:05 -0500
> 
> 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.

Thanks, the documentation parts are approved.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                     ` (5 preceding siblings ...)
  2017-01-18 15:44   ` [PATCH v2 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-01-26 22:47   ` Sergio Durigan Junior
  2017-01-27  7:45     ` Eli Zaretskii
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-26 22:47 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Eli Zaretskii, Luis Machado

On Wednesday, January 18 2017, I wrote:

> Hi again,

Ping.

> This is the second version of this patch series.  I addressed many
> comments made by Luis, Eli, Tom and Pedro (private) on the first
> version.  Thanks!
>
> Here's what changed from v1:
>
>  - Added NEWS entry
>
>  - Mentioned that the feature is to be used on UNIX-like systems
>
>  - Removed third argument from set_executing
>
>  - Removed 'set remote startup-shell' command
>
>  - Renamed the packet to QStartupWithShell.  Now, the packet has only
>    a boolean argument: "1" (meaning that the remote target should use
>    a shell to start the inferior), and "0" (the remote target should
>    not use a shell to start the inferior).
>
>  - Write documentation for this new packet
>
>  - Fixed and rewrote ChangeLog entries
>
>  - Fixed spurious newlines on comments.
>
>  - Fix comments that only mentioned "GDB" on files that are now being
>    shared with gdbserver.
>
>  - Adjust copyright notices on files
>
>  - Use "untested" where applicable on the testcase
>
>
> This patch series implement the "startup-with-shell" feature on
> gdbserver.  This means that it will be possible to start inferiors
> using the shell (instead of calling execv*), which brings many
> advantages.
>
> First of all, it will be possible to use I/O redirection, variable
> substitution and globbing expansion on gdbserver just like we do today
> on GDB.  This is great because, among other things, it brings
> gdbserver on a pair with GDB when considering the Feature Parity
> project.
>
> Secondly, a great deal of code had to be shared between GDB and
> gdbserver, especially the fork_inferior function, which means that now
> both programs are using virtually the same code to start inferiors.
> I've also had to touch on other areas, like terminal.h, inflow.c and
> gdbthread.h, and even though only the APIs were shared (i.e.,
> gdbserver's version of a gdbthread.h function may differ from GDB's
> version), this is also beneficial in the long run when we start to
> unify the code more deeply.  But I'm "raining in the wet" here; all
> this has been explained in better terms before.
>
> I did my best to split the patches, but unfortunately the
> fork_inferior patch is big and I couldn't see a better way to do that.
> But it shouldn't be very hard to review them, because most of it is
> just "code movement".

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver
  2017-01-26 22:47   ` [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
@ 2017-01-27  7:45     ` Eli Zaretskii
  2017-01-27 17:59       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Eli Zaretskii @ 2017-01-27  7:45 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves, lgustavo

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>, Eli Zaretskii <eliz@gnu.org>,        Luis Machado <lgustavo@codesourcery.com>
> Date: Thu, 26 Jan 2017 17:47:41 -0500
> 
> On Wednesday, January 18 2017, I wrote:
> 
> > Hi again,
> 
> Ping.
> 
> > This is the second version of this patch series.  I addressed many
> > comments made by Luis, Eli, Tom and Pedro (private) on the first
> > version.  Thanks!

I already approved the documentation parts, so you are not pinging me,
right?

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver
  2017-01-27  7:45     ` Eli Zaretskii
@ 2017-01-27 17:59       ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-01-27 17:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, palves, lgustavo

On Friday, January 27 2017, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: Pedro Alves <palves@redhat.com>, Eli Zaretskii <eliz@gnu.org>,        Luis Machado <lgustavo@codesourcery.com>
>> Date: Thu, 26 Jan 2017 17:47:41 -0500
>> 
>> On Wednesday, January 18 2017, I wrote:
>> 
>> > Hi again,
>> 
>> Ping.
>> 
>> > This is the second version of this patch series.  I addressed many
>> > comments made by Luis, Eli, Tom and Pedro (private) on the first
>> > version.  Thanks!
>
> I already approved the documentation parts, so you are not pinging me,
> right?

Yes, that's right, thanks for the approval and sorry for including you
in the ping.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
@ 2017-02-01 18:37     ` Luis Machado
  2017-02-07 22:39       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2017-02-01 18:37 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> As part of the bigger work of sharing fork_inferior with gdbserver,
> some parts of gdb/terminal.h also needed to be moved to a common
> place.  These parts are:
>
> - The code responsible for determining some terminal-based define's
>   based on available features;
>
> - job control;
>
> - terminal-related functions needed by fork_inferior;
>
> gdb/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
> 	* common/common-terminal.h: New file, with parts of "terminal.h".
> 	* terminal.h: Move terminal-related defines to
> 	"common/common-terminal.h".  Include "common/common-terminal.h".
> 	(new_tty_prefork): Move to "common/common-terminal.h".
> 	(new_tty): Likewise.
> 	(new_tty_postfork): Likewise.
> 	(job_control): Likewise.
> 	(create_tty_session): Likewise.
> 	(gdb_setpgid): Likewise.
> 	* utils.c: Include "terminal.h".
>
> gdb/gdbserver/ChangeLog:
> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* terminal.c: New file.
> ---
>  gdb/Makefile.in              |   1 +
>  gdb/common/common-terminal.h | 119 +++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/terminal.c     |  88 ++++++++++++++++++++++++++++++++
>  gdb/terminal.h               |  73 +-------------------------
>  gdb/utils.c                  |   1 +
>  5 files changed, 210 insertions(+), 72 deletions(-)
>  create mode 100644 gdb/common/common-terminal.h
>  create mode 100644 gdb/gdbserver/terminal.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3f19818..c05d456 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-regcache.h \
>  	common/common-types.h \
>  	common/common-utils.h \
> +	common/common-terminal.h \
>  	common/errors.h \
>  	common/environ.h \
>  	common/fileio.h \
> diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
> new file mode 100644
> index 0000000..f7ab96a
> --- /dev/null
> +++ b/gdb/common/common-terminal.h
> @@ -0,0 +1,119 @@
> +/* Common terminal interface definitions for GDB and gdbserver.
> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_TERMINAL_H
> +#define COMMON_TERMINAL_H
> +
> +/* If we're using autoconf, it will define HAVE_TERMIOS_H,
> +   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
> +   ser-unix.c and inflow.c to inspect those names instead of
> +   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
> +   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
> +   nothing has already defined the one of the names, and do the right
> +   thing.  */
> +
> +#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
> +#if defined(HAVE_TERMIOS_H)
> +#define HAVE_TERMIOS
> +#else /* ! defined (HAVE_TERMIOS_H) */
> +#if defined(HAVE_TERMIO_H)
> +#define HAVE_TERMIO
> +#else /* ! defined (HAVE_TERMIO_H) */
> +#if defined(HAVE_SGTTY_H)
> +#define HAVE_SGTTY
> +#endif /* ! defined (HAVE_SGTTY_H) */
> +#endif /* ! defined (HAVE_TERMIO_H) */
> +#endif /* ! defined (HAVE_TERMIOS_H) */
> +#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
> +	  !defined (HAVE_SGTTY) */
> +
> +#if defined(HAVE_TERMIOS)
> +#include <termios.h>
> +#endif
> +
> +#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
> +
> +/* Define a common set of macros -- BSD based -- and redefine whatever
> +   the system offers to make it look like that.  FIXME: serial.h and
> +   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
> +   is converted to use them, can get rid of this crap.  */
> +
> +#ifdef HAVE_TERMIO
> +
> +#include <termio.h>
> +
> +#undef TIOCGETP
> +#define TIOCGETP TCGETA
> +#undef TIOCSETN
> +#define TIOCSETN TCSETA
> +#undef TIOCSETP
> +#define TIOCSETP TCSETAF
> +#define TERMINAL struct termio
> +
> +#else /* sgtty */
> +
> +#include <fcntl.h>
> +#include <sgtty.h>
> +#include <sys/ioctl.h>
> +#define TERMINAL struct sgttyb
> +
> +#endif /* sgtty */
> +#endif
> +
> +#include <sys/types.h>
> +
> +/* Do we have job control?  Can be assumed to always be the same
> +   within a given run of GDB.  Use in gdb/inflow.c and
> +   common/common-inflow.c.  */
> +extern int job_control;
> +
> +extern void new_tty (void);
> +
> +/* NEW_TTY_PREFORK is called before forking a new child process,
> +   so we can record the state of ttys in the child to be formed.
> +   TTYNAME is null if we are to share the terminal with gdb;

This is still referencing only gdb, but the code is now shared with 
gdbserver as well.

> +   or points to a string containing the name of the desired tty.
> +
> +   NEW_TTY is called in new child processes under Unix, which will
> +   become debugger target processes.  This actually switches to
> +   the terminal specified in the NEW_TTY_PREFORK call.  */
> +extern void new_tty_prefork (const char *ttyname);
> +
> +/* NEW_TTY_POSTFORK is called after forking a new child process, and
> +   adding it to the inferior table, to store the TTYNAME being used by
> +   the child, or null if it sharing the terminal with gdb.  */

Here as well.

> +extern void new_tty_postfork (void);
> +
> +/* Create a new session if the inferior will run in a different tty.
> +   A session is UNIX's way of grouping processes that share a controlling
> +   terminal, so a new one is needed if the inferior terminal will be
> +   different from GDB's.

And here.

> +
> +   Returns the session id of the new session, 0 if no session was created
> +   or -1 if an error occurred.  */
> +extern pid_t create_tty_session (void);
> +
> +/* Set the process group of the caller to its own pid, or do nothing
> +   if we lack job control.  */
> +extern int gdb_setpgid (void);
> +
> +/* Determine whether we have job control, and set variable JOB_CONTROL
> +   accordingly.  */
> +extern void have_job_control (void);
> +
> +#endif /* ! COMMON_TERMINAL_H */
> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
> new file mode 100644
> index 0000000..42ac651
> --- /dev/null
> +++ b/gdb/gdbserver/terminal.c
> @@ -0,0 +1,88 @@
> +/* Terminal interface definitions for the GDB remote server.
> +   Copyright (C) 2016-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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 "server.h"
> +#include "common-terminal.h"
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty_prefork (const char *ttyname)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +new_tty_postfork (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +pid_t
> +create_tty_session (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +  return (pid_t) 1;
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +void
> +set_inferior_io_terminal (const char *terminal_name)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +const char *
> +get_inferior_io_terminal (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +  return NULL;
> +}
> diff --git a/gdb/terminal.h b/gdb/terminal.h
> index d8691b2..8139319 100644
> --- a/gdb/terminal.h
> +++ b/gdb/terminal.h
> @@ -19,83 +19,12 @@
>  #if !defined (TERMINAL_H)
>  #define TERMINAL_H 1
>
> -
> -/* If we're using autoconf, it will define HAVE_TERMIOS_H,
> -   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
> -   ser-unix.c and inflow.c to inspect those names instead of
> -   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
> -   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
> -   nothing has already defined the one of the names, and do the right
> -   thing.  */
> -
> -#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
> -#if defined(HAVE_TERMIOS_H)
> -#define HAVE_TERMIOS
> -#else /* ! defined (HAVE_TERMIOS_H) */
> -#if defined(HAVE_TERMIO_H)
> -#define HAVE_TERMIO
> -#else /* ! defined (HAVE_TERMIO_H) */
> -#if defined(HAVE_SGTTY_H)
> -#define HAVE_SGTTY
> -#endif /* ! defined (HAVE_SGTTY_H) */
> -#endif /* ! defined (HAVE_TERMIO_H) */
> -#endif /* ! defined (HAVE_TERMIOS_H) */
> -#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
> -	  !defined (HAVE_SGTTY) */
> -
> -#if defined(HAVE_TERMIOS)
> -#include <termios.h>
> -#endif
> -
> -#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
> -
> -/* Define a common set of macros -- BSD based -- and redefine whatever
> -   the system offers to make it look like that.  FIXME: serial.h and
> -   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
> -   is converted to use them, can get rid of this crap.  */
> -
> -#ifdef HAVE_TERMIO
> -
> -#include <termio.h>
> -
> -#undef TIOCGETP
> -#define TIOCGETP TCGETA
> -#undef TIOCSETN
> -#define TIOCSETN TCSETA
> -#undef TIOCSETP
> -#define TIOCSETP TCSETAF
> -#define TERMINAL struct termio
> -
> -#else /* sgtty */
> -
> -#include <fcntl.h>
> -#include <sgtty.h>
> -#include <sys/ioctl.h>
> -#define TERMINAL struct sgttyb
> -
> -#endif /* sgtty */
> -#endif
> +#include "common-terminal.h"
>
>  struct inferior;
>
> -extern void new_tty_prefork (const char *);
> -
> -extern void new_tty (void);
> -
> -extern void new_tty_postfork (void);
> -
>  extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>
> -/* Do we have job control?  Can be assumed to always be the same within
> -   a given run of GDB.  In inflow.c.  */
> -extern int job_control;
> -
> -extern pid_t create_tty_session (void);
> -
> -/* Set the process group of the caller to its own pid, or do nothing if
> -   we lack job control.  */
> -extern int gdb_setpgid (void);
> -
>  /* Set up a serial structure describing standard input.  In inflow.c.  */
>  extern void initialize_stdin_serial (void);
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index f142ffe..4993145 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -53,6 +53,7 @@
>  #include "top.h"
>  #include "main.h"
>  #include "solist.h"
> +#include "terminal.h"
>
>  #include "inferior.h"		/* for signed_pointer_to_address */
>
>

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver
  2017-01-18 15:36   ` [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
@ 2017-02-01 18:41     ` Luis Machado
  0 siblings, 0 replies; 157+ messages in thread
From: Luis Machado @ 2017-02-01 18:41 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> After sharing parts of gdb/terminal.h, it is also needed to share the
> two functions on gdb/inflow.c that are going to be needed by the
> fork_inferior sharing.  They are 'gdb_setpgid' and the new
> 'have_job_control'.
>
> gdb/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/common-inflow.c".
> 	(COMMON_OBS): Add "common/common-inflow.o".
> 	* common/common-inflow.c: New file, with contents from
> 	"gdb/inflow.c".
> 	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
> 	(_initialize_inflow): Move setting of "job_control" to
> 	"handle_job_control".
> 	* utils.c (job_control): Delete.
>
> gdb/gdbserver/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in: Add rule for "common-inflow.o".
> 	(SFILE): Add "common/common-inflow.c".
> 	(OBS): Add "common-inflow.o".
> ---
>  gdb/Makefile.in            |  2 +
>  gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/Makefile.in  |  5 +++
>  gdb/inflow.c               | 63 +-------------------------------
>  gdb/utils.c                |  4 --
>  5 files changed, 100 insertions(+), 65 deletions(-)
>  create mode 100644 gdb/common/common-inflow.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index c05d456..c0325d5 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1196,6 +1196,7 @@ SFILES = \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> +	common/common-inflow.c \
>  	common/gdb_vecs.c \
>  	common/new-op.c \
>  	common/print-utils.c \
> @@ -1623,6 +1624,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	common-agent.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
>  	complaints.o \
> diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
> new file mode 100644
> index 0000000..9871b5e
> --- /dev/null
> +++ b/gdb/common/common-inflow.c
> @@ -0,0 +1,91 @@
> +/* Low level interface to ptrace, for GDB and gdbserver when running under Unix.
> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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 "common-defs.h"
> +#include "common-terminal.h"
> +
> +/* Nonzero if we have job control.  */
> +int job_control;
> +
> +/* This is here because this is where we figure out whether we (probably)
> +   have job control.  Just using job_control only does part of it because
> +   setpgid or setpgrp might not exist on a system without job control.
> +   It might be considered misplaced (on the other hand, process groups and
> +   job control are closely related to ttys).
> +
> +   For a more clean implementation, in libiberty, put a setpgid which merely
> +   calls setpgrp and a setpgrp which does nothing (any system with job control
> +   will have one or the other).  */
> +
> +int
> +gdb_setpgid (void)
> +{
> +  int retval = 0;
> +
> +  if (job_control)
> +    {
> +#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
> +#ifdef HAVE_SETPGID
> +      /* The call setpgid (0, 0) is supposed to work and mean the same
> +         thing as this, but on Ultrix 4.2A it fails with EPERM (and
> +         setpgid (getpid (), getpid ()) succeeds).  */
> +      retval = setpgid (getpid (), getpid ());
> +#else
> +#ifdef HAVE_SETPGRP
> +#ifdef SETPGRP_VOID
> +      retval = setpgrp ();
> +#else
> +      retval = setpgrp (getpid (), getpid ());
> +#endif
> +#endif /* HAVE_SETPGRP */
> +#endif /* HAVE_SETPGID */
> +#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
> +    }
> +
> +  return retval;
> +}
> +
> +/* See common/common-terminal.h.  */
> +
> +void
> +have_job_control (void)
> +{
> +  /* OK, figure out whether we have job control.  If neither termios nor
> +     sgtty (i.e. termio or go32), leave job_control 0.  */
> +#if defined (HAVE_TERMIOS)
> +  /* Do all systems with termios have the POSIX way of identifying job
> +     control?  I hope so.  */
> +#ifdef _POSIX_JOB_CONTROL
> +  job_control = 1;
> +#else
> +#ifdef _SC_JOB_CONTROL
> +  job_control = sysconf (_SC_JOB_CONTROL);
> +#else
> +  job_control = 0;		/* Have to assume the worst.  */
> +#endif /* _SC_JOB_CONTROL */
> +#endif /* _POSIX_JOB_CONTROL */
> +#endif /* HAVE_TERMIOS */
> +
> +#ifdef HAVE_SGTTY
> +#ifdef TIOCGPGRP
> +  job_control = 1;
> +#else
> +  job_control = 0;
> +#endif /* TIOCGPGRP */
> +#endif /* sgtty */
> +}
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index ef0dc99..74e199b 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -204,6 +204,7 @@ SFILES = \
>  	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
> +	$(srcdir)/common/common-inflow.c \
>  	$(srcdir)/common/gdb_vecs.c \
>  	$(srcdir)/common/new-op.c \
>  	$(srcdir)/common/print-utils.c \
> @@ -234,6 +235,7 @@ OBS = \
>  	cleanups.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
>  	debug.o \
> @@ -770,6 +772,9 @@ format.o: ../common/format.c
>  filestuff.o: ../common/filestuff.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +common-inflow.o: ../common/common-inflow.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  agent.o: ../common/agent.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> diff --git a/gdb/inflow.c b/gdb/inflow.c
> index 7ffa83a..271278d 100644
> --- a/gdb/inflow.c
> +++ b/gdb/inflow.c
> @@ -803,43 +803,6 @@ create_tty_session (void)
>  #endif /* HAVE_SETSID */
>  }
>
> -/* This is here because this is where we figure out whether we (probably)
> -   have job control.  Just using job_control only does part of it because
> -   setpgid or setpgrp might not exist on a system without job control.
> -   It might be considered misplaced (on the other hand, process groups and
> -   job control are closely related to ttys).
> -
> -   For a more clean implementation, in libiberty, put a setpgid which merely
> -   calls setpgrp and a setpgrp which does nothing (any system with job control
> -   will have one or the other).  */
> -int
> -gdb_setpgid (void)
> -{
> -  int retval = 0;
> -
> -  if (job_control)
> -    {
> -#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
> -#ifdef HAVE_SETPGID
> -      /* The call setpgid (0, 0) is supposed to work and mean the same
> -         thing as this, but on Ultrix 4.2A it fails with EPERM (and
> -         setpgid (getpid (), getpid ()) succeeds).  */
> -      retval = setpgid (getpid (), getpid ());
> -#else
> -#ifdef HAVE_SETPGRP
> -#ifdef SETPGRP_VOID
> -      retval = setpgrp ();
> -#else
> -      retval = setpgrp (getpid (), getpid ());
> -#endif
> -#endif /* HAVE_SETPGRP */
> -#endif /* HAVE_SETPGID */
> -#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
> -    }
> -
> -  return retval;
> -}
> -
>  /* Get all the current tty settings (including whether we have a
>     tty at all!).  We can't do this in _initialize_inflow because
>     serial_fdopen() won't work until the serial_ops_list is
> @@ -860,30 +823,8 @@ _initialize_inflow (void)
>
>    terminal_is_ours = 1;
>
> -  /* OK, figure out whether we have job control.  If neither termios nor
> -     sgtty (i.e. termio or go32), leave job_control 0.  */
> -
> -#if defined (HAVE_TERMIOS)
> -  /* Do all systems with termios have the POSIX way of identifying job
> -     control?  I hope so.  */
> -#ifdef _POSIX_JOB_CONTROL
> -  job_control = 1;
> -#else
> -#ifdef _SC_JOB_CONTROL
> -  job_control = sysconf (_SC_JOB_CONTROL);
> -#else
> -  job_control = 0;		/* Have to assume the worst.  */
> -#endif /* _SC_JOB_CONTROL */
> -#endif /* _POSIX_JOB_CONTROL */
> -#endif /* HAVE_TERMIOS */
> -
> -#ifdef HAVE_SGTTY
> -#ifdef TIOCGPGRP
> -  job_control = 1;
> -#else
> -  job_control = 0;
> -#endif /* TIOCGPGRP */
> -#endif /* sgtty */
> +  /* OK, figure out whether we have job control.  */
> +  have_job_control ();
>
>    observer_attach_inferior_exit (inflow_inferior_exit);
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 4993145..119992e 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
>
>  static int debug_timestamp = 0;
>
> -/* Nonzero if we have job control.  */
> -
> -int job_control;
> -
>  /* Nonzero means that strings with character values >0x7F should be printed
>     as octal escapes.  Zero means just print the value (e.g. it's an
>     international character, and the terminal or window can cope.)  */
>

I have no further comments on this one.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-01-18 15:42   ` [PATCH v2 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2017-02-01 18:54     ` Luis Machado
  2017-02-07 22:42       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2017-02-01 18:54 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> Again, it was necessary to share a few functions declared on
> gdb/gdbthread.h with gdbserver, because they are needed by
> fork_inferior.  I decided to implement them on
> gdb/gdbserver/inferiors.c because that's where the thread functions
> are also implemented on gdbserver.  Some of these functions do not
> need to be implemented on gdbserver, or don't make sense there, so
> they are left blank and commented properly.
>
> gdb/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
> 	* common/common-gdbthread.h: New file, with parts from
> 	"gdb/gdbthread.h".
> 	* fork-child.c (fork_inferior): Update call of "set_executing".
> 	* gdbthread.h: Include "common-gdbthread.h".
> 	(init_thread_list): Moved to "common/common-gdbthread.h".
> 	(add_thread_silent): Likewise.
> 	(switch_to_thread): Likewise.
> 	(set_executing): Likewise.
> 	* thread.c (set_executing): Update function comment.
>
> gdb/gdbserver/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* inferiors.c (init_thread_list): New function.
> 	(switch_to_thread): Likewise.
> 	(set_executing): Likewise.
> 	(add_thread_silent): Likewise.
> 	* server.c (get_last_target_waitstatus): Likewise.
> 	* server.h (get_last_target_waitstatus): Likewise.
> ---
>  gdb/Makefile.in               |  1 +
>  gdb/common/common-gdbthread.h | 45 +++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/inferiors.c     | 41 +++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/server.c        |  8 ++++++++
>  gdb/gdbserver/server.h        |  3 +++
>  gdb/gdbthread.h               | 20 +------------------
>  gdb/thread.c                  |  2 ++
>  7 files changed, 101 insertions(+), 19 deletions(-)
>  create mode 100644 gdb/common/common-gdbthread.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index c0325d5..3e49e6e 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-debug.h \
>  	common/common-defs.h \
>  	common/common-exceptions.h \
> +	common/common-gdbthread.h \
>  	common/common-regcache.h \
>  	common/common-types.h \
>  	common/common-utils.h \
> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
> new file mode 100644
> index 0000000..eb66de9
> --- /dev/null
> +++ b/gdb/common/common-gdbthread.h
> @@ -0,0 +1,45 @@
> +/* Common multi-process/thread control defs for GDB and gdbserver.
> +   Copyright (C) 1987-2017 Free Software Foundation, Inc.
> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
> +
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_THREAD_H
> +#define COMMON_THREAD_H
> +
> +struct target_waitstatus;
> +
> +/* Create an empty thread list, or empty the existing one.  */
> +extern void init_thread_list (void);
> +
> +/* Switch from one thread to another.  */
> +extern void switch_to_thread (ptid_t ptid);
> +
> +/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
> +   marks all threads.
> +
> +   Note that this is different from the running state.  See the
> +   description of state and executing fields of struct
> +   thread_info.  */
> +extern void set_executing (ptid_t ptid, int executing);
> +
> +/* Add a thread to the thread list and return the pointer to the new
> +   thread.  Caller may use this pointer to initialize the private
> +   thread data.  */
> +extern struct thread_info *add_thread_silent (ptid_t ptid);
> +
> +#endif /* ! COMMON_THREAD_H */
> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index b65a726..441ec2c 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -468,3 +468,44 @@ make_cleanup_restore_current_thread (void)
>  {
>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>  }
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +init_thread_list (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +switch_to_thread (ptid_t ptid)
> +{
> +  if (!ptid_equal (ptid, minus_one_ptid))
> +    current_thread = find_thread_ptid (ptid);
> +}
> +
> +/* See common/common-gdbthread.h.  */
> +
> +void
> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
> +{
> +  gdb_assert (current_thread != NULL);
> +  current_thread->last_resume_kind = resume_stop;
> +  current_thread->last_status = get_last_target_waitstatus ();
> +}
> +


I'm still not sure about this particular function. But i'd like to hear 
what other think.

Otherwise i have no further comments on this one.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  2017-01-18 16:43     ` Eli Zaretskii
@ 2017-02-01 19:07     ` Luis Machado
  1 sibling, 0 replies; 157+ messages in thread
From: Luis Machado @ 2017-02-01 19:07 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> 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-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* NEWS (Changes since GDB 7.12): Announce that GDBserver is now
> 	able to start inferiors	using a shell.
> 	(New remote packets): Announce new packet "QStartupWithShell".
> 	* remote.c: Add PACKET_QStartupWithShell.
> 	(remote_start_remote): 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-01-17  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-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* gdb.server/startup-with-shell.c: New file.
> 	* gdb.server/startup-with-shell.exp: Likewise.
>
> gdb/doc/ChangeLog:
> 2017-01-17  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/NEWS                                        | 10 +++
>  gdb/doc/gdb.texinfo                             | 26 ++++++++
>  gdb/gdbserver/server.c                          | 36 ++++++++++-
>  gdb/remote.c                                    | 20 ++++++
>  gdb/testsuite/gdb.server/startup-with-shell.c   | 29 +++++++++
>  gdb/testsuite/gdb.server/startup-with-shell.exp | 83 +++++++++++++++++++++++++
>  6 files changed, 203 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index b976815..9bf8df4 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,13 @@
>
>  *** Changes since GDB 7.12
>
> +* GDBserver is now able to start inferiors using a shell.  When using
> +  "target extended-remote", the host GDB honors the value of "set
> +  startup-with-shell" in order to inform GDBserver whether the remote
> +  inferior should be started with a shell or not.  When using "target
> +  remote", it is possible to disable the startup with shell by using
> +  the new parameter "--no-startup-with-shell" when starting GDBserver.
> +
>  * Building GDB and GDBserver now requires a C++11 compiler.
>
>    For example, GCC 4.8 or later.
> @@ -356,6 +363,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.
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 2b6b654..bfe11de 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -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
> @@ -20772,6 +20773,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}
> @@ -36330,6 +36335,27 @@ 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.

Missing documentation aboue what VALUE should be and the range of values 
it may contain?

> +
> +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 give as hex digits.
> +@end table
> +
>  @item qfThreadInfo
>  @itemx qsThreadInfo
>  @cindex list active threads, remote request
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index a26ad52..56bd613 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -866,6 +866,31 @@ handle_general_set (char *own_buf)
>        return;
>      }
>
> +  if (startswith (own_buf, "QStartupWithShell:"))
> +    {
> +      char *value = own_buf + strlen ("QStartupWithShell:");
> +
> +      if (strcmp (value, "1") == 0)
> +	startup_with_shell = 1;
> +      else if (strcmp (value, "0") == 0)
> +	startup_with_shell = 0;
> +      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;
> @@ -2302,7 +2327,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 ())
> @@ -3396,6 +3421,11 @@ 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.\n"
> +	   "  --no-startup-with-shell\n"
> +	   "                        Don't start PROG using a shell (i.e., use the exec*\n"
> +	   "                        family of functions).\n"
>  	   "\n"
>  	   "Debug options:\n"
>  	   "\n"
> @@ -3679,6 +3709,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 = 1;
> +      else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
> +	startup_with_shell = 0;
>        else if (strcmp (*next_arg, "--once") == 0)
>  	run_once = 1;
>        else
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 2f7954a..67319f6 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -1428,6 +1428,7 @@ enum {
>    PACKET_QPassSignals,
>    PACKET_QCatchSyscalls,
>    PACKET_QProgramSignals,
> +  PACKET_QStartupWithShell,
>    PACKET_qCRC,
>    PACKET_qSearch_memory,
>    PACKET_vAttach,
> @@ -4079,6 +4080,20 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
>    if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
>      remote_set_permissions (target);
>
> +  /* 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);
> +    }
> +
>    /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
>       unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
>       as a reply to known packet.  For packet "vFile:setfs:" it is an
> @@ -4633,6 +4648,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,
> @@ -14110,6 +14127,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);
>
> diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
> new file mode 100644
> index 0000000..6278447
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.c
> @@ -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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
> new file mode 100644
> index 0000000..8992593
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
> @@ -0,0 +1,83 @@
> +# 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/>.
> +
> +# Test startup-with-shell support using extended-remote.
> +
> +load_lib gdbserver-support.exp
> +
> +standard_testfile
> +
> +if { [skip_gdbserver_tests] } {

untested "skipping gdbserver tests"

> +    return 0
> +}
> +
> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
> +    return -1
> +}
> +
> +# Initial setup for simple test (wildcard expansion, variable substitution).
> +
> +proc initial_setup_simple { startup_with_shell run_args } {
> +    global hex decimal binfile
> +
> +    clean_restart $binfile
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +
> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
> +
> +    set target_exec [gdbserver_download_current_prog]
> +    gdbserver_start_extended
> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
> +
> +    gdb_breakpoint main
> +
> +    gdb_test "run $run_args" \
> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
> +	"run to main"
> +}
> +
> +## Doing the actual tests
> +
> +with_test_prefix "startup_with_shell = on; run_args = *.log" {
> +    initial_setup_simple "on" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
> +	"testing first argument"
> +}
> +
> +with_test_prefix "startup_with_shell = off; run_args = *.log" {
> +    initial_setup_simple "off" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
> +	"testing first argument"
> +}
> +
> +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)
> +}
>

Otherwise i have no further comments.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 1/6] Share gdb/environ.[ch] with gdbserver
  2017-01-18 15:36   ` [PATCH v2 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2017-02-01 20:35     ` Luis Machado
  0 siblings, 0 replies; 157+ messages in thread
From: Luis Machado @ 2017-02-01 20:35 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> We will need access to the environment functions when we share
> fork_inferior between GDB and gdbserver, therefore we simply make the
> API on gdb/environ.[ch] available on common/.  No extra adjustments
> are needed to make it compile on gdbserver.
>
> gdb/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Replace "environ.c" with
> 	"common/environ.c".
> 	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
> 	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
> 	to...
> 	* common/environ.c: ... here.
> 	* environ.h: Moved to...
> 	* common/environ.h: ... here.
>
> gdb/gdbserver/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/environ.c".
> 	(OBJS): Add "common/environ.h".
> ---
>  gdb/Makefile.in            | 4 ++--
>  gdb/{ => common}/environ.c | 2 +-
>  gdb/{ => common}/environ.h | 0
>  gdb/gdbserver/Makefile.in  | 5 +++++
>  4 files changed, 8 insertions(+), 3 deletions(-)
>  rename gdb/{ => common}/environ.c (99%)
>  rename gdb/{ => common}/environ.h (100%)
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3ce7d69..3f19818 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1048,7 +1048,6 @@ SFILES = \
>  	dwarf2loc.c \
>  	dwarf2read.c \
>  	elfread.c \
> -	environ.c \
>  	eval.c \
>  	event-loop.c \
>  	event-top.c \
> @@ -1193,6 +1192,7 @@ SFILES = \
>  	common/common-regcache.c \
>  	common/common-utils.c \
>  	common/errors.c \
> +	common/environ.c \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> @@ -1271,7 +1271,6 @@ HFILES_NO_SRCDIR = \
>  	dwarf2-frame-tailcall.h \
>  	dwarf2expr.h \
>  	dwarf2loc.h \
> -	environ.h \
>  	event-loop.h \
>  	event-top.h \
>  	exceptions.h \
> @@ -1471,6 +1470,7 @@ HFILES_NO_SRCDIR = \
>  	common/common-types.h \
>  	common/common-utils.h \
>  	common/errors.h \
> +	common/environ.h \
>  	common/fileio.h \
>  	common/format.h \
>  	common/gdb_assert.h \
> diff --git a/gdb/environ.c b/gdb/common/environ.c
> similarity index 99%
> rename from gdb/environ.c
> rename to gdb/common/environ.c
> index bfeabec..3145d01 100644
> --- a/gdb/environ.c
> +++ b/gdb/common/environ.c
> @@ -15,7 +15,7 @@
>     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 "defs.h"
> +#include "common-defs.h"
>  #include "environ.h"
>  #include <algorithm>
>  \f
> diff --git a/gdb/environ.h b/gdb/common/environ.h
> similarity index 100%
> rename from gdb/environ.h
> rename to gdb/common/environ.h
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index 75736b6..ef0dc99 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -201,6 +201,7 @@ SFILES = \
>  	$(srcdir)/common/common-regcache.c \
>  	$(srcdir)/common/common-utils.c \
>  	$(srcdir)/common/errors.c \
> +	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
>  	$(srcdir)/common/gdb_vecs.c \
> @@ -238,6 +239,7 @@ OBS = \
>  	debug.o \
>  	dll.o \
>  	errors.o \
> +	environ.o \
>  	event-loop.o \
>  	fileio.o \
>  	filestuff.o \
> @@ -774,6 +776,9 @@ agent.o: ../common/agent.c
>  errors.o: ../common/errors.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +environ.o: ../common/environ.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  common-debug.o: ../common/common-debug.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
>

I have no further comments on this one.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 5/6] Share fork_inferior et al with gdbserver
  2017-01-18 15:44   ` [PATCH v2 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-02-01 21:39     ` Luis Machado
  2017-02-07 22:23       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Luis Machado @ 2017-02-01 21:39 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Pedro Alves, Eli Zaretskii

On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
> This is the most important (and the biggest, sorry) patch of the
> series.  It moves fork_inferior from gdb/fork-child.c to
> common/common-fork-child.c and makes all the necessary adjustments to
> both GDB and gdbserver to make sure everything works OK.
>
> There is no "most important change" with this patch; all changes are
> made in a progressive way, making sure that gdbserver had the
> necessary features while not breaking GDB at the same time.  For some
> feature, like the target_terminal_* functions, I chose to just use
> placeholders for the real functions on gdbserver, that should be
> implemented in the future.  For now, we don't need them in order to
> make things work.  Also, since we don't manipulate terminal modes on
> gdbserver the way we do on GDB, they are not possible to implement
> right now (unless I chose to properly implement terminal handling on
> gdbserver, which is something we don't know if we want now).
>
> Last, but not least, I did a major revamp on the way gdbserver
> computes and stores the inferior's arguments.  It's now using a
> std::vector<char *> and std::string where applicable, which makes
> things much easier even to understand.  This simplification was also
> interesting for the "create_inferior" method of gdbserver's target.c;
> now, it only needs one argument (a vector containing the full inferior
> argv) instead of two char * that were confusing to
> manipulate/generate.
>
> I decided to go ahead and implement a partial support for starting the
> inferior with a shell on gdbserver, although the full feature comes in
> the next patch.  The user won't have the option to disable the
> startup-with-shell, and also won't be able to change which shell
> gdbserver will use (other than setting the $SHELL environment
> variable, that is).
>
> Everything is working as expected, and no regressions were present
> during the tests.
>
> gdb/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "common/common-fork-child.c".
> 	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
> 	"common/common-top.h".
> 	(COMMON_OBS): Add "common-fork-child.o".
> 	* common-fork-child.c: New file, with the majority of
> 	"gdb/fork-child.c".
> 	* common/common-inferior.h: New file, with contents from
> 	"gdb/inferior.h".
> 	* common/common-top.h: New file.
> 	* common/common-utils.h (gdb_flush_out_err): New prototype.
> 	* corefile.c (get_exec_file): Update comment.
> 	* darwin-nat.c (darwin_ptrace_him): Update call of
> 	"startup_inferior".
> 	* fork-child.c: Cleanup unnecessary includes.
> 	(SHELL_FILE): Move to "common/common-fork-child.c".
> 	(environ): Likewise.
> 	(exec_wrapper): Initialize.
> 	(get_exec_wrapper): New function.
> 	(breakup_args): Move to "common/common-fork-child.c"; rename to
> 	"breakup_args_for_exec".
> 	(escape_bang_in_quoted_argument): Move to
> 	"common/common-fork-child.c".
> 	(fork_inferior): Likewise.  Update function to support gdbserver.
> 	(startup_inferior): Likewise.
> 	* gnu-nat.c (gnu_create_inferior): Update call to
> 	"startup_inferior".
> 	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
> 	* inferior.h: Include "common-inferior.h".
> 	(fork_inferior): Move prototype to "common-inferior.h".
> 	(startup_inferior): Likewise.
> 	* procfs.c (procfs_init_inferior): Update call to
> 	"startup_inferior".
> 	* target.h (target_terminal_init): Move prototype to
> 	"target/target.h".
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* target/target.h (target_terminal_init): New prototype, moved
> 	from "target.h".
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* top.h: Include "common-top.h".
> 	(main_ui): Move
> 	(current_ui): Move
> 	* utils.c (gdb_flush_out_err): New function.
>
> gdb/gdbserver/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* Makefile.in (SFILES): Add "terminal.c" and
> 	"common/common-fork-child.c".
> 	(OBS): Add common-fork-child.o and terminal.o.
> 	(common-fork-child.o): New rule.
> 	* inferiors (inferior_ptid): New variable.
> 	(inferior_appeared): New function.
> 	(current_inferior): Likewise.
> 	(have_inferiors): Likewise.
> 	* linux-low.c: Include "common-inferior.h" and "environ.h".
> 	(linux_update_process): New function.
> 	(linux_add_process): Update comment.  Adjust function to call
> 	"linux_update_process".
> 	(update_thread_lwp): New function.
> 	(linux_ptrace_fun): Likewise.
> 	(linux_create_inferior): Adjust function prototype to reflect
> 	change on "target.h".  Adjust function code to use
> 	"fork_inferior".
> 	* lynx-low.c (lynx_update_process): New function.
> 	(lynx_add_process): Update comment.  Adjust function to call
> 	"lynx_update_process".
> 	(lynx_ptrace_fun): New function.
> 	(lynx_create_inferior): Adjust function prototype to reflect
> 	change on "target.h".  Adjust function code to use
> 	"fork_inferior".
> 	* nto-low.c (nto_create_inferior): Adjust function prototype and
> 	code to reflect change on "target.h".
> 	* server.c: Include "common-inferior.h", "common-terminal.h",
> 	"common-top.h", "environ.h".
> 	(main_ui): New variable.
> 	(current_ui): Likewise.
> 	(our_environ): Likewise.
> 	(startup_with_shell): Likewise.
> 	(program_argv): Convert to std::vector<char *>.
> 	(wrapper_argv): Likewise.
> 	(start_inferior): Delete function.
> 	(get_exec_wrapper): New function.
> 	(get_exec_file): Likewise.
> 	(get_environ): Likewise.
> 	(pre_fork_inferior): New function, with parts of "start_inferior".
> 	(post_fork_inferior): Likewise.
> 	(handle_v_run): Update code to deal with arguments coming from the
> 	remote host.  Update calls from "start_inferior" to
> 	"create_inferior".
> 	(captured_main): Likewise.  Initialize environment variable.  Call
> 	"have_job_control".
> 	* server.h: Include <vector>.
> 	(pre_fork_inferior): New prototype.
> 	(post_fork_inferior): Likewise.
> 	(get_environ): Likewise.
> 	* spu-low.c (spu_ptrace_fun): New function.
> 	(spu_create_inferior): Adjust function prototype to reflect change
> 	on "target.h".  Adjust function code to use "fork_inferior".
> 	* target.c (target_terminal_init): New function.
> 	(target_terminal_inferior): Likewise.
> 	(target_terminal_ours): Likewise.
> 	* target.h: Include <vector>.
> 	(struct target_ops) <create_inferior>: Update prototype
> 	to accept one std::vector<char *> representing the full program
> 	argv.
> 	(create_inferior): Update macro.
> 	* utils.c (gdb_flush_out_err): New function.
> 	(free_vector_argv): Likewise.
> 	(stringify_argv): Likewise.
> 	* utils.h: Include <vector>.
> 	(free_vector_argv): New prototype.
> 	(stringify_argv): Likewise.
> 	* win32-low.c (win32_create_inferior): Adjust function prototype
> 	and code to reflect change on "target.h".
>
> gdb/testsuite/ChangeLog:
> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>
> 	* gdb.server/non-existing-program.exp: Update regex in order to
> 	reflect the fact that gdbserver is now using fork_inferior (with a
> 	shell) to startup the inferior.
> ---
>  gdb/Makefile.in                                   |   4 +
>  gdb/common/common-fork-child.c                    | 593 ++++++++++++++++++++++
>  gdb/common/common-inferior.h                      | 104 ++++
>  gdb/common/common-top.h                           |  31 ++
>  gdb/common/common-utils.h                         |   4 +
>  gdb/corefile.c                                    |   4 +-
>  gdb/darwin-nat.c                                  |   2 +-
>  gdb/fork-child.c                                  | 526 +------------------
>  gdb/gdbserver/Makefile.in                         |   7 +
>  gdb/gdbserver/inferiors.c                         |  31 +-
>  gdb/gdbserver/linux-low.c                         | 124 +++--
>  gdb/gdbserver/lynx-low.c                          |  66 ++-
>  gdb/gdbserver/nto-low.c                           |   9 +-
>  gdb/gdbserver/server.c                            | 274 ++++++----
>  gdb/gdbserver/server.h                            |  16 +
>  gdb/gdbserver/spu-low.c                           |  43 +-
>  gdb/gdbserver/target.c                            |  24 +
>  gdb/gdbserver/target.h                            |   7 +-
>  gdb/gdbserver/utils.c                             |  35 ++
>  gdb/gdbserver/utils.h                             |  10 +
>  gdb/gdbserver/win32-low.c                         |  25 +-
>  gdb/gnu-nat.c                                     |   2 +-
>  gdb/inf-ptrace.c                                  |   2 +-
>  gdb/inferior.h                                    |  12 +-
>  gdb/procfs.c                                      |   2 +-
>  gdb/target.h                                      |  17 -
>  gdb/target/target.h                               |  17 +
>  gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
>  gdb/top.h                                         |   9 +-
>  gdb/utils.c                                       |   9 +
>  30 files changed, 1226 insertions(+), 793 deletions(-)
>  create mode 100644 gdb/common/common-fork-child.c
>  create mode 100644 gdb/common/common-inferior.h
>  create mode 100644 gdb/common/common-top.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3e49e6e..bf8b359 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1196,6 +1196,7 @@ SFILES = \
>  	common/fileio.c \
>  	common/filestuff.c \
>  	common/format.c \
> +	common/common-fork-child.c \
>  	common/common-inflow.c \
>  	common/gdb_vecs.c \
>  	common/new-op.c \
> @@ -1483,6 +1484,8 @@ HFILES_NO_SRCDIR = \
>  	common/gdb_sys_time.h \
>  	common/gdb_vecs.h \
>  	common/gdb_wait.h \
> +	common/common-inferior.h \
> +	common/common-top.h \
>  	common/host-defs.h \
>  	common/print-utils.h \
>  	common/ptid.h \
> @@ -1625,6 +1628,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	common-agent.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-fork-child.o \
>  	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
> diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
> new file mode 100644
> index 0000000..65ef374
> --- /dev/null
> +++ b/gdb/common/common-fork-child.c
> @@ -0,0 +1,593 @@
> +/* Fork a Unix child process, and set up to debug it, for GDB and gdbserver.

ISTR that gdbserver is officially spelled GDBserver. Though we have a 
mix of different ways of spelling it. I don't think it is terribly 
important in the present state. But here's a suggestion anyway. Feel 
free to ignore it.

> +
> +   Copyright (C) 1990-2017 Free Software Foundation, Inc.
> +
> +   Contributed by Cygnus Support.

I'm wondering if this is still needed or if we can move/drop it.

> +
> +   This file is part of GDB.
> +
> +   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 "common-defs.h"
> +#include "target/waitstatus.h"
> +#include "common-terminal.h"
> +#include "filestuff.h"
> +#include "target/target.h"
> +#include "common-inferior.h"
> +#include "common-gdbthread.h"
> +#include "common-top.h"
> +#include "signals-state-save-restore.h"
> +
> +extern char **environ;
> +
> +/* Default shell file to be used if 'startup-with-shell' is set but
> +   $SHELL is not.  */
> +#define SHELL_FILE "/bin/sh"
> +
> +/* Break up SCRATCH into an argument vector suitable for passing to
> +   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> +   would get as input the string "a b c d", and as output it would
> +   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> +
> +static void
> +breakup_args_for_exec (char *scratch, char **argv)
> +{
> +  char *cp = scratch, *tmp;
> +
> +  for (;;)
> +    {
> +      /* Scan past leading separators */
> +      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
> +	cp++;
> +
> +      /* Break if at end of string.  */
> +      if (*cp == '\0')
> +	break;
> +
> +      /* Take an arg.  */
> +      *argv++ = cp;
> +
> +      /* Scan for next arg separator.  */
> +      tmp = strchr (cp, ' ');
> +      if (tmp == NULL)
> +	tmp = strchr (cp, '\t');
> +      if (tmp == NULL)
> +	tmp = strchr (cp, '\n');
> +
> +      /* No separators => end of string => break.  */
> +      if (tmp == NULL)
> +	break;
> +      cp = tmp;
> +
> +      /* Replace the separator with a terminator.  */
> +      *cp++ = '\0';
> +    }
> +
> +  /* Null-terminate the vector.  */
> +  *argv = NULL;
> +}
> +
> +/* When executing a command under the given shell, return non-zero if
> +   the '!' character should be escaped when embedded in a quoted
> +   command-line argument.  */
> +
> +static int
> +escape_bang_in_quoted_argument (const char *shell_file)
> +{
> +  const int shell_file_len = strlen (shell_file);
> +
> +  /* Bang should be escaped only in C Shells.  For now, simply check
> +     that the shell name ends with 'csh', which covers at least csh
> +     and tcsh.  This should be good enough for now.  */
> +
> +  if (shell_file_len < 3)
> +    return 0;
> +
> +  if (shell_file[shell_file_len - 3] == 'c'
> +      && shell_file[shell_file_len - 2] == 's'
> +      && shell_file[shell_file_len - 1] == 'h')
> +    return 1;
> +
> +  return 0;
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_startup_shell (void)
> +{
> +  static char *ret;
> +
> +  ret = getenv ("SHELL");
> +  if (ret == NULL)
> +    ret = SHELL_FILE;
> +
> +  return ret;
> +}
> +
> +/* Quote the shell command that will be executed.  This function is
> +   called when the inferior is going to be executed under a shell
> +   (i.e., when 'startup-with-shell' is set).
> +
> +   SHELL_FILE is the shell which will be used to execute the inferior
> +   (e.g., /bin/sh).
> +
> +   EXEC_FILE is the inferior executable itself.
> +
> +   ALLARGS contains all the arguments that will be passed to the
> +   inferior.
> +
> +   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
> +   the inferior.
> +
> +   SHELL_CMD is a pointer to the resulting shell command that will be
> +   executed.  The resulting shell command will be returned in it.  It
> +   must be pre-allocated and have a reasonable size.  For an example
> +   on how to determine its size, see 'fork_inferior' on
> +   fork-child.c.  */
> +
> +static void
> +quote_shell_command (const char *shell_file, const char *exec_file,
> +		     const char *allargs, const char *exec_wrapper,
> +		     char **shell_cmd)
> +{
> +  char *shell_command = *shell_cmd;
> +  const char *p;
> +  int need_to_quote;
> +  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> +
> +  shell_command[0] = '\0';
> +  strcat (shell_command, "exec ");
> +
> +  /* Add any exec wrapper.  That may be a program name with arguments, so
> +     the user must handle quoting.  */
> +  if (exec_wrapper != NULL)
> +    {
> +      strcat (shell_command, exec_wrapper);
> +      strcat (shell_command, " ");
> +    }
> +
> +  /* Now add exec_file, quoting as necessary.  */
> +
> +  /* Quoting in this style is said to work with all shells.  But
> +     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> +     we need to.  */
> +  p = exec_file;
> +  while (1)
> +    {
> +      switch (*p)
> +	{
> +	case '\'':
> +	case '!':
> +	case '"':
> +	case '(':
> +	case ')':
> +	case '$':
> +	case '&':
> +	case ';':
> +	case '<':
> +	case '>':
> +	case ' ':
> +	case '\n':
> +	case '\t':
> +	  need_to_quote = 1;
> +	  goto end_scan;
> +
> +	case '\0':
> +	  need_to_quote = 0;
> +	  goto end_scan;
> +
> +	default:
> +	  break;
> +	}
> +      ++p;
> +    }
> + end_scan:
> +  if (need_to_quote)
> +    {
> +      strcat (shell_command, "'");
> +      for (p = exec_file; *p != '\0'; ++p)
> +	{
> +	  if (*p == '\'')
> +	    strcat (shell_command, "'\\''");
> +	  else if (*p == '!' && escape_bang)
> +	    strcat (shell_command, "\\!");
> +	  else
> +	    strncat (shell_command, p, 1);
> +	}
> +      strcat (shell_command, "'");
> +    }
> +  else
> +    strcat (shell_command, exec_file);
> +
> +  strcat (shell_command, " ");
> +  strcat (shell_command, allargs);
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +int
> +fork_inferior (char *exec_file_arg, char *allargs, char **env,
> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
> +               void (*exec_fun)(const char *file, char * const *argv,
> +                                char * const *env))

Something off with the identation above?

> +{
> +  int pid;
> +  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
> +  static int debug_fork = 0;
> +  /* This is set to the result of setpgrp, which if vforked, will be visible
> +     to you in the parent process.  It's only used by humans for debugging.  */
> +  static int debug_setpgrp = 657473;
> +  static char *shell_file;
> +  static char *exec_file;
> +  char **save_our_env;
> +  int shell = 0;
> +  static char **argv;
> +  const char *inferior_io_terminal = get_inferior_io_terminal ();
> +  struct inferior *inf;
> +  int i;
> +  int save_errno;
> +  struct ui *save_ui;
> +
> +  /* If no exec file handed to us, get it from the exec-file command
> +     -- with a good, common error message if none is specified.  */
> +  exec_file = exec_file_arg;
> +  if (exec_file == 0)
> +    exec_file = get_exec_file (1);
> +
> +  /* 'startup_with_shell' is declared in inferior.h and bound to the
> +     "set startup-with-shell" option.  If 0, we'll just do a
> +     fork/exec, no shell, so don't bother figuring out what shell.  */
> +  shell_file = shell_file_arg;
> +  if (startup_with_shell)
> +    {
> +      /* Figure out what shell to start up the user program under.  */
> +      if (shell_file == NULL)
> +	shell_file = get_startup_shell ();
> +
> +      gdb_assert (shell_file != NULL);
> +      shell = 1;
> +    }
> +
> +  if (!shell)
> +    {
> +      /* We're going to call execvp.  Create argument vector.
> +	 Calculate an upper bound on the length of the vector by
> +	 assuming that every other character is a separate
> +	 argument.  */
> +      int argc = (strlen (allargs) + 1) / 2 + 2;
> +
> +      argv = XALLOCAVEC (char *, argc);
> +      argv[0] = exec_file;
> +      breakup_args_for_exec (allargs, &argv[1]);
> +    }
> +  else
> +    {
> +      /* We're going to call a shell.  */
> +      char *shell_command;
> +      char *exec_wrapper = get_exec_wrapper ();
> +      size_t len;
> +
> +      /* Multiplying the length of exec_file by 4 is to account for the
> +         fact that it may expand when quoted; it is a worst-case number
> +         based on every character being '.  */
> +      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
> +      if (exec_wrapper != NULL)
> +        len += strlen (exec_wrapper) + 1;
> +
> +      shell_command = (char *) alloca (len);
> +      shell_command[0] = '\0';
> +
> +      quote_shell_command (shell_file, exec_file,
> +			   allargs,
> +			   exec_wrapper, &shell_command);
> +
> +      /* If we decided above to start up with a shell, we exec the
> +	 shell, "-c" says to interpret the next arg as a shell command
> +	 to execute, and this command is "exec <target-program>
> +	 <args>".  */
> +      argv = (char **) alloca (4 * sizeof (char *));
> +      argv[0] = shell_file;
> +      argv[1] = "-c";
> +      argv[2] = shell_command;
> +      argv[3] = (char *) 0;
> +    }
> +
> +  /* Retain a copy of our environment variables, since the child will
> +     replace the value of environ and if we're vforked, we have to
> +     restore it.  */
> +  save_our_env = environ;
> +
> +  /* Likewise the current UI.  */
> +  save_ui = current_ui;
> +
> +  /* Tell the terminal handling subsystem what tty we plan to run on;
> +     it will just record the information for later.  */
> +  new_tty_prefork (inferior_io_terminal);
> +
> +  /* It is generally good practice to flush any possible pending stdio
> +     output prior to doing a fork, to avoid the possibility of both
> +     the parent and child flushing the same data after the fork.  */
> +  gdb_flush_out_err ();
> +
> +  /* If there's any initialization of the target layers that must
> +     happen to prepare to handle the child we're about fork, do it
> +     now...  */
> +  if (pre_trace_fun != NULL)
> +    (*pre_trace_fun) ();
> +
> +  /* Create the child process.  Since the child process is going to
> +     exec(3) shortly afterwards, try to reduce the overhead by
> +     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
> +     likely that this optimization won't work since there's too much
> +     work to do between the vfork(2) and the exec(3).  This is known
> +     to be the case on ttrace(2)-based HP-UX, where some handshaking
> +     between parent and child needs to happen between fork(2) and
> +     exec(2).  However, since the parent is suspended in the vforked
> +     state, this doesn't work.  Also note that the vfork(2) call might
> +     actually be a call to fork(2) due to the fact that autoconf will
> +     ``#define vfork fork'' on certain platforms.  */
> +  if (pre_trace_fun || debug_fork)
> +    pid = fork ();
> +  else
> +    pid = vfork ();
> +
> +  if (pid < 0)
> +    perror_with_name (("vfork"));
> +
> +  if (pid == 0)
> +    {
> +      /* Switch to the main UI, so that gdb_std{in/out/err} in the
> +	 child are mapped to std{in/out/err}.  This makes it possible
> +	 to use fprintf_unfiltered/warning/error/etc. in the child
> +	 from here on.  */
> +      current_ui = main_ui;
> +
> +      /* Close all file descriptors except those that gdb inherited
> +	 (usually 0/1/2), so they don't leak to the inferior.  Note
> +	 that this closes the file descriptors of all secondary
> +	 UIs.  */
> +      close_most_fds ();
> +
> +      if (debug_fork)
> +	sleep (debug_fork);
> +
> +      /* Create a new session for the inferior process, if necessary.
> +         It will also place the inferior in a separate process group.  */
> +      if (create_tty_session () <= 0)
> +	{
> +	  /* No session was created, but we still want to run the inferior
> +	     in a separate process group.  */
> +	  debug_setpgrp = gdb_setpgid ();
> +	  if (debug_setpgrp == -1)
> +	    perror (_("setpgrp failed in child"));
> +	}
> +
> +      /* Ask the tty subsystem to switch to the one we specified
> +         earlier (or to share the current terminal, if none was
> +         specified).  */
> +      new_tty ();
> +
> +      /* Changing the signal handlers for the inferior after
> +         a vfork can also change them for the superior, so we don't mess
> +         with signals here.  See comments in
> +         initialize_signals for how we get the right signal handlers
> +         for the inferior.  */
> +
> +      /* "Trace me, Dr. Memory!"  */
> +      (*traceme_fun) ();
> +
> +      /* The call above set this process (the "child") as debuggable
> +        by the original gdb process (the "parent").  Since processes
> +        (unlike people) can have only one parent, if you are debugging
> +        gdb itself (and your debugger is thus _already_ the
> +        controller/parent for this child), code from here on out is
> +        undebuggable.  Indeed, you probably got an error message
> +        saying "not parent".  Sorry; you'll have to use print
> +        statements!  */
> +
> +      restore_original_signals_state ();
> +
> +      /* There is no execlpe call, so we have to set the environment
> +         for our child in the global variable.  If we've vforked, this
> +         clobbers the parent, but environ is restored a few lines down
> +         in the parent.  By the way, yes we do need to look down the
> +         path to find $SHELL.  Rich Pixley says so, and I agree.  */
> +      environ = env;
> +
> +      if (exec_fun != NULL)
> +        (*exec_fun) (argv[0], argv, env);
> +      else
> +        execvp (argv[0], argv);
> +
> +      /* If we get here, it's an error.  */
> +      save_errno = errno;
> +      warning ("Cannot exec %s", argv[0]);
> +
> +      for (i = 1; argv[i] != NULL; i++)
> +	warning (" %s", argv[i]);
> +
> +      warning ("Error: %s\n", safe_strerror (save_errno));
> +
> +      _exit (0177);
> +    }
> +
> +  /* Restore our environment in case a vforked child clob'd it.  */
> +  environ = save_our_env;
> +
> +  /* Likewise the current UI.  */
> +  current_ui = save_ui;
> +
> +  if (!have_inferiors ())
> +    init_thread_list ();
> +
> +  inf = current_inferior ();
> +
> +  inferior_appeared (inf, pid);
> +
> +  /* Needed for wait_for_inferior stuff below.  */
> +  inferior_ptid = pid_to_ptid (pid);
> +
> +  new_tty_postfork ();
> +
> +  /* We have something that executes now.  We'll be running through
> +     the shell at this point, but the pid shouldn't change.  Targets
> +     supporting MT should fill this task's ptid with more data as soon
> +     as they can.  */
> +  add_thread_silent (inferior_ptid);
> +
> +  /* Now that we have a child process, make it our target, and
> +     initialize anything target-vector-specific that needs
> +     initializing.  */
> +  if (init_trace_fun)
> +    (*init_trace_fun) (pid);
> +
> +  /* We are now in the child process of interest, having exec'd the
> +     correct program, and are poised at the first instruction of the
> +     new program.  */
> +  return pid;
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +void
> +startup_inferior (int ntraps,
> +		  struct target_waitstatus *last_waitstatus,
> +		  ptid_t *last_ptid)
> +{
> +  int pending_execs = ntraps;
> +  int terminal_initted = 0;
> +  ptid_t resume_ptid;
> +
> +  if (startup_with_shell)
> +    {
> +      /* One trap extra for exec'ing the shell.  */
> +      pending_execs++;
> +    }
> +
> +  if (target_supports_multi_process ())
> +    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
> +  else
> +    resume_ptid = minus_one_ptid;
> +
> +  /* The process was started by the fork that created it, but it will
> +     have stopped one instruction after execing the shell.  Here we
> +     must get it up to actual execution of the real program.  */
> +  if (get_exec_wrapper () != NULL)
> +    pending_execs++;
> +
> +  while (1)
> +    {
> +      enum gdb_signal resume_signal = GDB_SIGNAL_0;
> +      ptid_t event_ptid;
> +
> +      struct target_waitstatus ws;
> +      memset (&ws, 0, sizeof (ws));
> +      event_ptid = target_wait (resume_ptid, &ws, 0);
> +
> +      if (last_waitstatus != NULL)
> +	*last_waitstatus = ws;
> +      if (last_ptid != NULL)
> +	*last_ptid = event_ptid;
> +
> +      if (ws.kind == TARGET_WAITKIND_IGNORE)
> +	/* The inferior didn't really stop, keep waiting.  */
> +	continue;
> +
> +      switch (ws.kind)
> +	{
> +	  case TARGET_WAITKIND_SPURIOUS:
> +	  case TARGET_WAITKIND_LOADED:
> +	  case TARGET_WAITKIND_FORKED:
> +	  case TARGET_WAITKIND_VFORKED:
> +	  case TARGET_WAITKIND_SYSCALL_ENTRY:
> +	  case TARGET_WAITKIND_SYSCALL_RETURN:
> +	  case TARGET_WAITKIND_VFORK_DONE:
> +	  case TARGET_WAITKIND_IGNORE:
> +	  case TARGET_WAITKIND_NO_HISTORY:
> +	  case TARGET_WAITKIND_NO_RESUMED:
> +	  case TARGET_WAITKIND_THREAD_CREATED:
> +	  case TARGET_WAITKIND_THREAD_EXITED:
> +	    /* Ignore gracefully during startup of the inferior.  */
> +	    switch_to_thread (event_ptid);
> +	    break;
> +
> +	  case TARGET_WAITKIND_SIGNALLED:
> +	    target_terminal_ours ();
> +	    target_mourn_inferior (event_ptid);
> +	    error (_("During startup program terminated with signal %s, %s."),
> +		   gdb_signal_to_name (ws.value.sig),
> +		   gdb_signal_to_string (ws.value.sig));
> +	    return;
> +
> +	  case TARGET_WAITKIND_EXITED:
> +	    target_terminal_ours ();
> +	    target_mourn_inferior (event_ptid);
> +	    if (ws.value.integer)
> +	      error (_("During startup program exited with code %d."),
> +		     ws.value.integer);
> +	    else
> +	      error (_("During startup program exited normally."));
> +	    return;
> +
> +	  case TARGET_WAITKIND_EXECD:
> +	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
> +	    xfree (ws.value.execd_pathname);
> +	    resume_signal = GDB_SIGNAL_TRAP;
> +	    switch_to_thread (event_ptid);
> +	    break;
> +
> +	  case TARGET_WAITKIND_STOPPED:
> +	    resume_signal = ws.value.sig;
> +	    switch_to_thread (event_ptid);
> +	    break;
> +	}
> +
> +      if (resume_signal != GDB_SIGNAL_TRAP)
> +	{
> +	  /* Let shell child handle its own signals in its own way.  */
> +	  target_continue (resume_ptid, resume_signal);
> +	}
> +      else
> +	{
> +	  /* We handle SIGTRAP, however; it means child did an exec.  */
> +	  if (!terminal_initted)
> +	    {
> +	      /* Now that the child has exec'd we know it has already
> +	         set its process group.  On POSIX systems, tcsetpgrp
> +	         will fail with EPERM if we try it before the child's
> +	         setpgid.  */
> +
> +	      /* Set up the "saved terminal modes" of the inferior
> +	         based on what modes we are starting it with.  */
> +	      target_terminal_init ();
> +
> +	      /* Install inferior's terminal modes.  */
> +	      target_terminal_inferior ();
> +
> +	      terminal_initted = 1;
> +	    }
> +
> +	  if (--pending_execs == 0)
> +	    break;
> +
> +	  /* Just make it go on.  */
> +	  target_continue_no_signal (resume_ptid);
> +	}
> +    }
> +
> +  /* Mark all threads non-executing.  */
> +  set_executing (resume_ptid, 0);
> +}
> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
> new file mode 100644
> index 0000000..e8f163f
> --- /dev/null
> +++ b/gdb/common/common-inferior.h
> @@ -0,0 +1,104 @@
> +/* Variables that describe the inferior process running under GDB and
> +   gdbserver: Where it is, why it stopped, and how to step it.
> +

GDBserver?

> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.


1986-2017

> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_INFERIOR_H
> +#define COMMON_INFERIOR_H
> +
> +/* Number of traps that happen between exec'ing the shell to run an
> +   inferior and when we finally get to the inferior code, not counting
> +   the exec for the shell.  This is 1 on all supported
> +   implementations.  */
> +#define START_INFERIOR_TRAPS_EXPECTED 1
> +
> +struct inferior;
> +
> +/* Whether to start up the debuggee under a shell.
> +
> +   If startup-with-shell is set, GDB's "run" will attempt to start up
> +   the debuggee under a shell.
> +

Is the behavior the same for GDBserver under extended remote mode? 
Should we mention GDBserver here as well or is there something slightly 
different?

> +   This is in order for argument-expansion to occur.  E.g.,
> +
> +   (gdb) run *
> +
> +   The "*" gets expanded by the shell into a list of files.
> +
> +   While this is a nice feature, it may be handy to bypass the shell
> +   in some cases.  To disable this feature, do "set startup-with-shell
> +   false".
> +
> +   The catch-exec traps expected during start-up will be one more if
> +   the target is started up with a shell.  */
> +extern int startup_with_shell;
> +
> +/* Collected pid, tid, etc. of the debugged inferior.  When there's
> +   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
> +extern ptid_t inferior_ptid;
> +
> +/* Accept NTRAPS traps from the inferior.  */
> +extern void startup_inferior (int ntraps,
> +			      struct target_waitstatus *mystatus,
> +			      ptid_t *myptid);
> +
> +/* Start an inferior Unix child process and sets inferior_ptid to its
> +   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> +   the arguments to the program.  ENV is the environment vector to
> +   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> +   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> +   one.  */
> +
> +/* This function is NOT reentrant.  Some of the variables have been
> +   made static to ensure that they survive the vfork call.  */
> +extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
> +               void (*exec_fun) (const char *file, char * const *argv,
> +				 char * const *env));

Something funny with the identation above.

> +
> +/* Return the shell that must be used to startup the inferior.  The
> +   first attempt is the environment variable SHELL; if it is not set,
> +   then we default to SHELL_FILE.  */
> +extern char *get_startup_shell (void);
> +
> +/* Set file name for default use for standard in/out in the inferior.  */
> +extern void set_inferior_io_terminal (const char *terminal_name);
> +
> +/* Get file name for default use for standard in/out in the inferior.  */
> +extern const char *get_inferior_io_terminal (void);
> +
> +/* Return the exec wrapper to be used when starting the inferior, or NULL
> +   otherwise.  */
> +extern char *get_exec_wrapper (void);
> +
> +/* Return the name of the executable file as a string.
> +   ERR nonzero means get error if there is none specified;
> +   otherwise return 0 in that case.  */
> +extern char *get_exec_file (int err);
> +
> +/* Returns true if the inferior list is not empty.  */
> +extern int have_inferiors (void);
> +
> +extern void inferior_appeared (struct inferior *inf, int pid);
> +
> +/* Return a pointer to the current inferior.  It is an error to call
> +   this if there is no current inferior.  */
> +extern struct inferior *current_inferior (void);
> +
> +#endif /* ! COMMON_INFERIOR_H */
> diff --git a/gdb/common/common-top.h b/gdb/common/common-top.h
> new file mode 100644
> index 0000000..a2aa692
> --- /dev/null
> +++ b/gdb/common/common-top.h
> @@ -0,0 +1,31 @@
> +/* Common top level stuff for GDB and gdbserver.
> +

GDBserver.

> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_TOP_H
> +#define COMMON_TOP_H
> +
> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> +   It always exists and is created automatically when GDB starts
> +   up.  */
> +extern struct ui *main_ui;
> +
> +/* The current UI.  */
> +extern struct ui *current_ui;
> +
> +#endif /* ! COMMON_TOP_H */
> diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
> index 618d266..59e85b1 100644
> --- a/gdb/common/common-utils.h
> +++ b/gdb/common/common-utils.h
> @@ -103,4 +103,8 @@ extern const char *skip_spaces_const (const char *inp);
>
>  extern const char *skip_to_space_const (const char *inp);
>
> +/* Flush both stdout and stderr.  This function needs to be
> +   implemented differently on GDB and gdbserver.  */

GDBserver.

> +extern void gdb_flush_out_err (void);
> +
>  #endif
> diff --git a/gdb/corefile.c b/gdb/corefile.c
> index 54cb789..d76fa1a 100644
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
> @@ -170,9 +170,7 @@ validate_files (void)
>      }
>  }
>
> -/* Return the name of the executable file as a string.
> -   ERR nonzero means get error if there is none specified;
> -   otherwise return 0 in that case.  */
> +/* See common/common-inferior.h.  */
>
>  char *
>  get_exec_file (int err)
> diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
> index 8c5e8a0..ef94d10 100644
> --- a/gdb/darwin-nat.c
> +++ b/gdb/darwin-nat.c
> @@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
>
>    darwin_init_thread_list (inf);
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>  }
>
>  static void
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index eaa8cb5..a6550c7 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -21,531 +21,19 @@
>
>  #include "defs.h"
>  #include "inferior.h"
> -#include "terminal.h"
> -#include "target.h"
> -#include "gdb_wait.h"
> -#include "gdb_vfork.h"
> -#include "gdbcore.h"
> -#include "gdbthread.h"
> -#include "command.h" /* for dont_repeat () */
>  #include "gdbcmd.h"
> -#include "solib.h"
> -#include "filestuff.h"
> -#include "top.h"
> -#include "signals-state-save-restore.h"
> -#include <signal.h>
>
> -/* This just gets used as a default if we can't find SHELL.  */
> -#define SHELL_FILE "/bin/sh"
> +/* The exec-wrapper, if any, that will be used when starting the
> +   inferior.  */
>
> -extern char **environ;
> +static char *exec_wrapper = NULL;
>
> -static char *exec_wrapper;
> +/* See common/common-inferior.h.  */
>
> -/* Break up SCRATCH into an argument vector suitable for passing to
> -   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> -   would get as input the string "a b c d", and as output it would
> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> -
> -static void
> -breakup_args (char *scratch, char **argv)
> +char *
> +get_exec_wrapper (void)
>  {
> -  char *cp = scratch, *tmp;
> -
> -  for (;;)
> -    {
> -      /* Scan past leading separators */
> -      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
> -	cp++;
> -
> -      /* Break if at end of string.  */
> -      if (*cp == '\0')
> -	break;
> -
> -      /* Take an arg.  */
> -      *argv++ = cp;
> -
> -      /* Scan for next arg separator.  */
> -      tmp = strchr (cp, ' ');
> -      if (tmp == NULL)
> -	tmp = strchr (cp, '\t');
> -      if (tmp == NULL)
> -	tmp = strchr (cp, '\n');
> -
> -      /* No separators => end of string => break.  */
> -      if (tmp == NULL)
> -	break;
> -      cp = tmp;
> -
> -      /* Replace the separator with a terminator.  */
> -      *cp++ = '\0';
> -    }
> -
> -  /* Null-terminate the vector.  */
> -  *argv = NULL;
> -}
> -
> -/* When executing a command under the given shell, return non-zero if
> -   the '!' character should be escaped when embedded in a quoted
> -   command-line argument.  */
> -
> -static int
> -escape_bang_in_quoted_argument (const char *shell_file)
> -{
> -  const int shell_file_len = strlen (shell_file);
> -
> -  /* Bang should be escaped only in C Shells.  For now, simply check
> -     that the shell name ends with 'csh', which covers at least csh
> -     and tcsh.  This should be good enough for now.  */
> -
> -  if (shell_file_len < 3)
> -    return 0;
> -
> -  if (shell_file[shell_file_len - 3] == 'c'
> -      && shell_file[shell_file_len - 2] == 's'
> -      && shell_file[shell_file_len - 1] == 'h')
> -    return 1;
> -
> -  return 0;
> -}
> -
> -/* Start an inferior Unix child process and sets inferior_ptid to its
> -   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> -   the arguments to the program.  ENV is the environment vector to
> -   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> -   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> -   one.  */
> -
> -/* This function is NOT reentrant.  Some of the variables have been
> -   made static to ensure that they survive the vfork call.  */
> -
> -int
> -fork_inferior (char *exec_file_arg, char *allargs, char **env,
> -	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> -	       void (*pre_trace_fun) (void), char *shell_file_arg,
> -               void (*exec_fun)(const char *file, char * const *argv,
> -                                char * const *env))
> -{
> -  int pid;
> -  static char default_shell_file[] = SHELL_FILE;
> -  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
> -  static int debug_fork = 0;
> -  /* This is set to the result of setpgrp, which if vforked, will be visible
> -     to you in the parent process.  It's only used by humans for debugging.  */
> -  static int debug_setpgrp = 657473;
> -  static char *shell_file;
> -  static char *exec_file;
> -  char **save_our_env;
> -  int shell = 0;
> -  static char **argv;
> -  const char *inferior_io_terminal = get_inferior_io_terminal ();
> -  struct inferior *inf;
> -  int i;
> -  int save_errno;
> -  struct ui *save_ui;
> -
> -  /* If no exec file handed to us, get it from the exec-file command
> -     -- with a good, common error message if none is specified.  */
> -  exec_file = exec_file_arg;
> -  if (exec_file == 0)
> -    exec_file = get_exec_file (1);
> -
> -  /* 'startup_with_shell' is declared in inferior.h and bound to the
> -     "set startup-with-shell" option.  If 0, we'll just do a
> -     fork/exec, no shell, so don't bother figuring out what shell.  */
> -  shell_file = shell_file_arg;
> -  if (startup_with_shell)
> -    {
> -      /* Figure out what shell to start up the user program under.  */
> -      if (shell_file == NULL)
> -	shell_file = getenv ("SHELL");
> -      if (shell_file == NULL)
> -	shell_file = default_shell_file;
> -      shell = 1;
> -    }
> -
> -  if (!shell)
> -    {
> -      /* We're going to call execvp.  Create argument vector.
> -	 Calculate an upper bound on the length of the vector by
> -	 assuming that every other character is a separate
> -	 argument.  */
> -      int argc = (strlen (allargs) + 1) / 2 + 2;
> -
> -      argv = XALLOCAVEC (char *, argc);
> -      argv[0] = exec_file;
> -      breakup_args (allargs, &argv[1]);
> -    }
> -  else
> -    {
> -      /* We're going to call a shell.  */
> -      char *shell_command;
> -      int len;
> -      char *p;
> -      int need_to_quote;
> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> -
> -      /* Multiplying the length of exec_file by 4 is to account for the
> -         fact that it may expand when quoted; it is a worst-case number
> -         based on every character being '.  */
> -      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
> -      if (exec_wrapper)
> -        len += strlen (exec_wrapper) + 1;
> -
> -      shell_command = (char *) alloca (len);
> -      shell_command[0] = '\0';
> -
> -      strcat (shell_command, "exec ");
> -
> -      /* Add any exec wrapper.  That may be a program name with arguments, so
> -	 the user must handle quoting.  */
> -      if (exec_wrapper)
> -	{
> -	  strcat (shell_command, exec_wrapper);
> -	  strcat (shell_command, " ");
> -	}
> -
> -      /* Now add exec_file, quoting as necessary.  */
> -
> -      /* Quoting in this style is said to work with all shells.  But
> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> -         we need to.  */
> -      p = exec_file;
> -      while (1)
> -	{
> -	  switch (*p)
> -	    {
> -	    case '\'':
> -	    case '!':
> -	    case '"':
> -	    case '(':
> -	    case ')':
> -	    case '$':
> -	    case '&':
> -	    case ';':
> -	    case '<':
> -	    case '>':
> -	    case ' ':
> -	    case '\n':
> -	    case '\t':
> -	      need_to_quote = 1;
> -	      goto end_scan;
> -
> -	    case '\0':
> -	      need_to_quote = 0;
> -	      goto end_scan;
> -
> -	    default:
> -	      break;
> -	    }
> -	  ++p;
> -	}
> -    end_scan:
> -      if (need_to_quote)
> -	{
> -	  strcat (shell_command, "'");
> -	  for (p = exec_file; *p != '\0'; ++p)
> -	    {
> -	      if (*p == '\'')
> -		strcat (shell_command, "'\\''");
> -	      else if (*p == '!' && escape_bang)
> -		strcat (shell_command, "\\!");
> -	      else
> -		strncat (shell_command, p, 1);
> -	    }
> -	  strcat (shell_command, "'");
> -	}
> -      else
> -	strcat (shell_command, exec_file);
> -
> -      strcat (shell_command, " ");
> -      strcat (shell_command, allargs);
> -
> -      /* If we decided above to start up with a shell, we exec the
> -	 shell, "-c" says to interpret the next arg as a shell command
> -	 to execute, and this command is "exec <target-program>
> -	 <args>".  */
> -      argv = (char **) alloca (4 * sizeof (char *));
> -      argv[0] = shell_file;
> -      argv[1] = "-c";
> -      argv[2] = shell_command;
> -      argv[3] = (char *) 0;
> -    }
> -
> -  /* Retain a copy of our environment variables, since the child will
> -     replace the value of environ and if we're vforked, we have to
> -     restore it.  */
> -  save_our_env = environ;
> -
> -  /* Likewise the current UI.  */
> -  save_ui = current_ui;
> -
> -  /* Tell the terminal handling subsystem what tty we plan to run on;
> -     it will just record the information for later.  */
> -  new_tty_prefork (inferior_io_terminal);
> -
> -  /* It is generally good practice to flush any possible pending stdio
> -     output prior to doing a fork, to avoid the possibility of both
> -     the parent and child flushing the same data after the fork.  */
> -  gdb_flush (main_ui->m_gdb_stdout);
> -  gdb_flush (main_ui->m_gdb_stderr);
> -
> -  /* If there's any initialization of the target layers that must
> -     happen to prepare to handle the child we're about fork, do it
> -     now...  */
> -  if (pre_trace_fun != NULL)
> -    (*pre_trace_fun) ();
> -
> -  /* Create the child process.  Since the child process is going to
> -     exec(3) shortly afterwards, try to reduce the overhead by
> -     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
> -     likely that this optimization won't work since there's too much
> -     work to do between the vfork(2) and the exec(3).  This is known
> -     to be the case on ttrace(2)-based HP-UX, where some handshaking
> -     between parent and child needs to happen between fork(2) and
> -     exec(2).  However, since the parent is suspended in the vforked
> -     state, this doesn't work.  Also note that the vfork(2) call might
> -     actually be a call to fork(2) due to the fact that autoconf will
> -     ``#define vfork fork'' on certain platforms.  */
> -  if (pre_trace_fun || debug_fork)
> -    pid = fork ();
> -  else
> -    pid = vfork ();
> -
> -  if (pid < 0)
> -    perror_with_name (("vfork"));
> -
> -  if (pid == 0)
> -    {
> -      /* Switch to the main UI, so that gdb_std{in/out/err} in the
> -	 child are mapped to std{in/out/err}.  This makes it possible
> -	 to use fprintf_unfiltered/warning/error/etc. in the child
> -	 from here on.  */
> -      current_ui = main_ui;
> -
> -      /* Close all file descriptors except those that gdb inherited
> -	 (usually 0/1/2), so they don't leak to the inferior.  Note
> -	 that this closes the file descriptors of all secondary
> -	 UIs.  */
> -      close_most_fds ();
> -
> -      if (debug_fork)
> -	sleep (debug_fork);
> -
> -      /* Create a new session for the inferior process, if necessary.
> -         It will also place the inferior in a separate process group.  */
> -      if (create_tty_session () <= 0)
> -	{
> -	  /* No session was created, but we still want to run the inferior
> -	     in a separate process group.  */
> -	  debug_setpgrp = gdb_setpgid ();
> -	  if (debug_setpgrp == -1)
> -	    perror (_("setpgrp failed in child"));
> -	}
> -
> -      /* Ask the tty subsystem to switch to the one we specified
> -         earlier (or to share the current terminal, if none was
> -         specified).  */
> -      new_tty ();
> -
> -      /* Changing the signal handlers for the inferior after
> -         a vfork can also change them for the superior, so we don't mess
> -         with signals here.  See comments in
> -         initialize_signals for how we get the right signal handlers
> -         for the inferior.  */
> -
> -      /* "Trace me, Dr. Memory!"  */
> -      (*traceme_fun) ();
> -
> -      /* The call above set this process (the "child") as debuggable
> -        by the original gdb process (the "parent").  Since processes
> -        (unlike people) can have only one parent, if you are debugging
> -        gdb itself (and your debugger is thus _already_ the
> -        controller/parent for this child), code from here on out is
> -        undebuggable.  Indeed, you probably got an error message
> -        saying "not parent".  Sorry; you'll have to use print
> -        statements!  */
> -
> -      restore_original_signals_state ();
> -
> -      /* There is no execlpe call, so we have to set the environment
> -         for our child in the global variable.  If we've vforked, this
> -         clobbers the parent, but environ is restored a few lines down
> -         in the parent.  By the way, yes we do need to look down the
> -         path to find $SHELL.  Rich Pixley says so, and I agree.  */
> -      environ = env;
> -
> -      if (exec_fun != NULL)
> -        (*exec_fun) (argv[0], argv, env);
> -      else
> -        execvp (argv[0], argv);
> -
> -      /* If we get here, it's an error.  */
> -      save_errno = errno;
> -      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
> -      for (i = 1; argv[i] != NULL; i++)
> -	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
> -      fprintf_unfiltered (gdb_stderr, ".\n");
> -      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
> -			  safe_strerror (save_errno));
> -      gdb_flush (gdb_stderr);
> -      _exit (0177);
> -    }
> -
> -  /* Restore our environment in case a vforked child clob'd it.  */
> -  environ = save_our_env;
> -
> -  /* Likewise the current UI.  */
> -  current_ui = save_ui;
> -
> -  if (!have_inferiors ())
> -    init_thread_list ();
> -
> -  inf = current_inferior ();
> -
> -  inferior_appeared (inf, pid);
> -
> -  /* Needed for wait_for_inferior stuff below.  */
> -  inferior_ptid = pid_to_ptid (pid);
> -
> -  new_tty_postfork ();
> -
> -  /* We have something that executes now.  We'll be running through
> -     the shell at this point, but the pid shouldn't change.  Targets
> -     supporting MT should fill this task's ptid with more data as soon
> -     as they can.  */
> -  add_thread_silent (inferior_ptid);
> -
> -  /* Now that we have a child process, make it our target, and
> -     initialize anything target-vector-specific that needs
> -     initializing.  */
> -  if (init_trace_fun)
> -    (*init_trace_fun) (pid);
> -
> -  /* We are now in the child process of interest, having exec'd the
> -     correct program, and are poised at the first instruction of the
> -     new program.  */
> -  return pid;
> -}
> -
> -/* Accept NTRAPS traps from the inferior.  */
> -
> -void
> -startup_inferior (int ntraps)
> -{
> -  int pending_execs = ntraps;
> -  int terminal_initted = 0;
> -  ptid_t resume_ptid;
> -
> -  if (startup_with_shell)
> -    {
> -      /* One trap extra for exec'ing the shell.  */
> -      pending_execs++;
> -    }
> -
> -  if (target_supports_multi_process ())
> -    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
> -  else
> -    resume_ptid = minus_one_ptid;
> -
> -  /* The process was started by the fork that created it, but it will
> -     have stopped one instruction after execing the shell.  Here we
> -     must get it up to actual execution of the real program.  */
> -
> -  if (exec_wrapper)
> -    pending_execs++;
> -
> -  while (1)
> -    {
> -      enum gdb_signal resume_signal = GDB_SIGNAL_0;
> -      ptid_t event_ptid;
> -
> -      struct target_waitstatus ws;
> -      memset (&ws, 0, sizeof (ws));
> -      event_ptid = target_wait (resume_ptid, &ws, 0);
> -
> -      if (ws.kind == TARGET_WAITKIND_IGNORE)
> -	/* The inferior didn't really stop, keep waiting.  */
> -	continue;
> -
> -      switch (ws.kind)
> -	{
> -	  case TARGET_WAITKIND_SPURIOUS:
> -	  case TARGET_WAITKIND_LOADED:
> -	  case TARGET_WAITKIND_FORKED:
> -	  case TARGET_WAITKIND_VFORKED:
> -	  case TARGET_WAITKIND_SYSCALL_ENTRY:
> -	  case TARGET_WAITKIND_SYSCALL_RETURN:
> -	    /* Ignore gracefully during startup of the inferior.  */
> -	    switch_to_thread (event_ptid);
> -	    break;
> -
> -	  case TARGET_WAITKIND_SIGNALLED:
> -	    target_terminal_ours ();
> -	    target_mourn_inferior (event_ptid);
> -	    error (_("During startup program terminated with signal %s, %s."),
> -		   gdb_signal_to_name (ws.value.sig),
> -		   gdb_signal_to_string (ws.value.sig));
> -	    return;
> -
> -	  case TARGET_WAITKIND_EXITED:
> -	    target_terminal_ours ();
> -	    target_mourn_inferior (event_ptid);
> -	    if (ws.value.integer)
> -	      error (_("During startup program exited with code %d."),
> -		     ws.value.integer);
> -	    else
> -	      error (_("During startup program exited normally."));
> -	    return;
> -
> -	  case TARGET_WAITKIND_EXECD:
> -	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
> -	    xfree (ws.value.execd_pathname);
> -	    resume_signal = GDB_SIGNAL_TRAP;
> -	    switch_to_thread (event_ptid);
> -	    break;
> -
> -	  case TARGET_WAITKIND_STOPPED:
> -	    resume_signal = ws.value.sig;
> -	    switch_to_thread (event_ptid);
> -	    break;
> -	}
> -
> -      if (resume_signal != GDB_SIGNAL_TRAP)
> -	{
> -	  /* Let shell child handle its own signals in its own way.  */
> -	  target_continue (resume_ptid, resume_signal);
> -	}
> -      else
> -	{
> -	  /* We handle SIGTRAP, however; it means child did an exec.  */
> -	  if (!terminal_initted)
> -	    {
> -	      /* Now that the child has exec'd we know it has already
> -	         set its process group.  On POSIX systems, tcsetpgrp
> -	         will fail with EPERM if we try it before the child's
> -	         setpgid.  */
> -
> -	      /* Set up the "saved terminal modes" of the inferior
> -	         based on what modes we are starting it with.  */
> -	      target_terminal_init ();
> -
> -	      /* Install inferior's terminal modes.  */
> -	      target_terminal_inferior ();
> -
> -	      terminal_initted = 1;
> -	    }
> -
> -	  if (--pending_execs == 0)
> -	    break;
> -
> -	  /* Just make it go on.  */
> -	  target_continue_no_signal (resume_ptid);
> -	}
> -    }
> -
> -  /* Mark all threads non-executing.  */
> -  set_executing (resume_ptid, 0);
> +  return exec_wrapper;
>  }
>
>  /* Implement the "unset exec-wrapper" command.  */
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index 74e199b..9b6e96a 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -185,6 +185,7 @@ SFILES = \
>  	$(srcdir)/target.c \
>  	$(srcdir)/thread-db.c \
>  	$(srcdir)/utils.c \
> +	$(srcdir)/terminal.c \
>  	$(srcdir)/win32-arm-low.c \
>  	$(srcdir)/win32-i386-low.c \
>  	$(srcdir)/win32-low.c \
> @@ -204,6 +205,7 @@ SFILES = \
>  	$(srcdir)/common/environ.c \
>  	$(srcdir)/common/fileio.c \
>  	$(srcdir)/common/filestuff.c \
> +	$(srcdir)/common/common-fork-child.c \
>  	$(srcdir)/common/common-inflow.c \
>  	$(srcdir)/common/gdb_vecs.c \
>  	$(srcdir)/common/new-op.c \
> @@ -235,6 +237,7 @@ OBS = \
>  	cleanups.o \
>  	common-debug.o \
>  	common-exceptions.o \
> +	common-fork-child.o \
>  	common-inflow.o \
>  	common-regcache.o \
>  	common-utils.o \
> @@ -269,6 +272,7 @@ OBS = \
>  	version.o \
>  	waitstatus.o \
>  	xml-utils.o \
> +	terminal.o \
>  	$(DEPFILES) \
>  	$(LIBOBJS) \
>  	$(XML_BUILTIN)
> @@ -772,6 +776,9 @@ format.o: ../common/format.c
>  filestuff.o: ../common/filestuff.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> +common-fork-child.o: ../common/common-fork-child.c
> +	$(COMPILE) $<
> +	$(POSTCOMPILE)
>  common-inflow.o: ../common/common-inflow.c
>  	$(COMPILE) $<
>  	$(POSTCOMPILE)
> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index 441ec2c..21346cb 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>
>  #define get_thread(inf) ((struct thread_info *)(inf))
>
> +ptid_t inferior_ptid;
> +
>  void
>  add_inferior_to_list (struct inferior_list *list,
>  		      struct inferior_list_entry *new_inferior)
> @@ -469,12 +471,31 @@ make_cleanup_restore_current_thread (void)
>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>  }
>
> +/* See common/common-inferior.h.  */
> +
> +void
> +inferior_appeared (struct inferior *inf, int pid)
> +{
> +  /* Placeholder needed for fork_inferior.  We do not have to do
> +     anything in this case.  */
> +}

I'm still slightly confused about the presence of these empty functions. 
This particular one is meant to notify observers, correct? How do you 
envision this particular function being used for gdbserver in the future?

> +
> +/* See common/common-inferior.h.  */
> +
> +struct inferior *
> +current_inferior (void)
> +{
> +  /* Placeholder needed for fork_inferior.  gdbserver has other

GDBserver

> +     functions that serve this purpose.  */
> +  return NULL;
> +}
> +
>  /* See common/common-gdbthread.h.  */
>
>  void
>  init_thread_list (void)
>  {
> -  /* To be implemented.  */
> +  /* Placeholder needed for fork_inferior.  No action is needed.  */
>  }

Same here. Do you have an idea how this is going to be used for gdbserver?

>
>  /* See common/common-gdbthread.h.  */
> @@ -509,3 +530,11 @@ add_thread_silent (ptid_t ptid)
>
>    return add_thread (ptid_build (pid, pid, 0), NULL);
>  }
> +
> +/* See common/common-inferior.h.  */
> +
> +int
> +have_inferiors (void)
> +{
> +  return get_first_process () != NULL;
> +}
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index e27cbf8..170e8f2 100644
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -47,6 +47,8 @@
>  #include "tracepoint.h"
>  #include "hostio.h"
>  #include <inttypes.h>
> +#include "common-inferior.h"
> +#include "environ.h"
>  #ifndef ELFMAG0
>  /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
>     then ELFMAG0 will have been defined.  If it didn't get included by
> @@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
>    free (lwp);
>  }
>
> -/* Add a process to the common process list, and set its private
> -   data.  */
> +/* Update process represented by PID with necessary info.  */
>
>  static struct process_info *
> -linux_add_process (int pid, int attached)
> +linux_update_process (int pid)
>  {
> -  struct process_info *proc;
> +  struct process_info *proc = find_process_pid (pid);
>
> -  proc = add_process (pid, attached);
> +  gdb_assert (proc != NULL);
>    proc->priv = XCNEW (struct process_info_private);
>
>    if (the_low_target.new_process != NULL)
> @@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
>    return proc;
>  }
>
> +/* Add a process to the common process list, and set its private
> +   data.  */
> +
> +static struct process_info *
> +linux_add_process (int pid, int attached)
> +{
> +  add_process (pid, attached);
> +  return linux_update_process (pid);
> +}
> +
>  static CORE_ADDR get_pc (struct lwp_info *lwp);
>
>  /* Call the target arch_setup function on the current thread.  */
> @@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
>    return 1;
>  }
>
> +/* Update the lwp associated to thread represented by PTID.  */
> +
> +static struct lwp_info *
> +update_thread_lwp (ptid_t ptid)
> +{
> +  struct lwp_info *lwp;
> +  struct thread_info *thread;
> +
> +  lwp = XCNEW (struct lwp_info);
> +
> +  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
> +
> +  if (the_low_target.new_thread != NULL)
> +    the_low_target.new_thread (lwp);
> +
> +  thread = find_thread_ptid (ptid);
> +  gdb_assert (thread != NULL);
> +  thread->target_data = lwp;
> +  lwp->thread = thread;
> +
> +  return lwp;
> +}
> +
>  static struct lwp_info *
>  add_lwp (ptid_t ptid)
>  {
> @@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
>    return lwp;
>  }
>
> +/* Callback to be used when calling fork_inferior, responsible for
> +   actually initiating the tracing of the inferior.  */
> +
> +static void
> +linux_ptrace_fun (void)
> +{
> +  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> +
> +  setpgid (0, 0);
> +
> +  /* If gdbserver is connected to gdb via stdio, redirect the inferior's

GDBserver.

> +     stdout to stderr so that inferior i/o doesn't corrupt the connection.
> +     Also, redirect stdin to /dev/null.  */
> +  if (remote_connection_is_stdio ())
> +    {
> +      close (0);
> +      open ("/dev/null", O_RDONLY);
> +      dup2 (2, 1);
> +      if (write (2, "stdin/stdout redirected\n",
> +		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
> +	{
> +	  /* Errors ignored.  */;
> +	}
> +    }
> +}
> +
>  /* Start an inferior process and returns its pid.
>     ALLARGS is a vector of program-name and args. */
>
>  static int
> -linux_create_inferior (char *program, char **allargs)
> +linux_create_inferior (std::vector<char *> &program_argv)
>  {
>    struct lwp_info *new_lwp;
>    int pid;
>    ptid_t ptid;
>    struct cleanup *restore_personality
>      = maybe_disable_address_space_randomization (disable_randomization);
> +  std::string program_args = stringify_argv (program_argv);
>
> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
> -  pid = vfork ();
> -#else
> -  pid = fork ();
> -#endif
> -  if (pid < 0)
> -    perror_with_name ("fork");
> +  pre_fork_inferior (program_argv);
>
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> -
> -      setpgid (0, 0);
> -
> -      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
> -	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
> -	 Also, redirect stdin to /dev/null.  */
> -      if (remote_connection_is_stdio ())
> -	{
> -	  close (0);
> -	  open ("/dev/null", O_RDONLY);
> -	  dup2 (2, 1);
> -	  if (write (2, "stdin/stdout redirected\n",
> -		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
> -	    {
> -	      /* Errors ignored.  */;
> -	    }
> -	}
> -
> -      restore_original_signals_state ();
> -
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> -
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), linux_ptrace_fun,
> +		       NULL, NULL, NULL, NULL);
>
>    do_cleanups (restore_personality);
>
> -  linux_add_process (pid, 0);
> +  linux_update_process (pid);
>
>    ptid = ptid_build (pid, pid, 0);
> -  new_lwp = add_lwp (ptid);
> +  new_lwp = update_thread_lwp (ptid);
>    new_lwp->must_set_ptrace_flags = 1;
>
> +  post_fork_inferior (pid, program_argv);
> +
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
> index d300aae..296fd6f 100644
> --- a/gdb/gdbserver/lynx-low.c
> +++ b/gdb/gdbserver/lynx-low.c
> @@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
>    return result;
>  }
>
> -/* Call add_process with the given parameters, and initializes
> -   the process' private data.  */
> +/* Update existing process represented by PID with necessary info.  */
>
>  static struct process_info *
> -lynx_add_process (int pid, int attached)
> +lynx_update_process (int pid)
>  {
> -  struct process_info *proc;
> +  struct process_info *proc = find_process_pid (pid);
> +
> +  gdb_assert (proc != NULL);
>
> -  proc = add_process (pid, attached);
>    proc->tdesc = lynx_tdesc;
>    proc->priv = XCNEW (struct process_info_private);
>    proc->priv->last_wait_event_ptid = null_ptid;
> @@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
>    return proc;
>  }
>
> +/* Call add_process with the given parameters, and initializes
> +   the process' private data.  */
> +
> +static struct process_info *
> +lynx_add_process (int pid, int attached)
> +{
> +  add_process (pid, attached);
> +  return lynx_update_process (pid);
> +}
> +
> +static void
> +lynx_ptrace_fun (void)
> +{
> +  int pgrp;
> +
> +  /* Switch child to its own process group so that signals won't
> +     directly affect gdbserver. */

GDBserver.

> +  pgrp = getpid();
> +  setpgid (0, pgrp);
> +  ioctl (0, TIOCSPGRP, &pgrp);
> +  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
> +}
> +
>  /* Implement the create_inferior method of the target_ops vector.  */
>
>  static int
> -lynx_create_inferior (char *program, char **allargs)
> +lynx_create_inferior (std::vector<char *> &program_argv)
>  {
>    int pid;
>
>    lynx_debug ("lynx_create_inferior ()");
>
> -  pid = fork ();
> -  if (pid < 0)
> -    perror_with_name ("fork");
> +  pre_fork_inferior (program_argv);
>
> -  if (pid == 0)
> -    {
> -      int pgrp;
> -
> -      close_most_fds ();
> -
> -      /* Switch child to its own process group so that signals won't
> -         directly affect gdbserver. */
> -      pgrp = getpid();
> -      setpgid (0, pgrp);
> -      ioctl (0, TIOCSPGRP, &pgrp);
> -      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
> -      execv (program, allargs);
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), lynx_ptrace_fun,
> +		       NULL, NULL, NULL, NULL);
>
> -  lynx_add_process (pid, 0);
> +  post_fork_inferior (pid, program_argv);
> +
> +  lynx_update_process (pid, 0);
>    /* Do not add the process thread just yet, as we do not know its tid.
>       We will add it later, during the wait for the STOP event corresponding
>       to the lynx_ptrace (PTRACE_TRACEME) call above.  */
> +  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
> +
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
> index 6229b4c..ea2a3a4 100644
> --- a/gdb/gdbserver/nto-low.c
> +++ b/gdb/gdbserver/nto-low.c
> @@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
>    return len_read;
>  }
>
> -/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
> +/* Start inferior specified by PROGRAM_ARGV.  */
>
>  static int
> -nto_create_inferior (char *program, char **allargs)
> +nto_create_inferior (std::vector<char *> &program_argv)
>  {
>    struct inheritance inherit;
>    pid_t pid;
>    sigset_t set;
> +  std::string program_args = stringify_argv (program_argv);

I'm thinking... Stringifying a vector of char * sounds like something 
that could be done outside of the target-specific create_inferior 
functions. Can't we pass the arguments already stringified to the 
target-specific create_inferior function?

>
> -  TRACE ("%s %s\n", __func__, program);
> +  TRACE ("%s %s\n", __func__, program_argv[0]);
>    /* Clear any pending SIGUSR1's but keep the behavior the same.  */
>    signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
>
> @@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
>    memset (&inherit, 0, sizeof (inherit));
>    inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
>    inherit.pgroup = SPAWN_NEWPGROUP;
> -  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
> +  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
>    sigprocmask (SIG_BLOCK, &set, NULL);
>
>    if (pid == -1)
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 43d9406..a26ad52 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -35,6 +35,26 @@
>  #include "tracepoint.h"
>  #include "dll.h"
>  #include "hostio.h"
> +#include "common-inferior.h"
> +#include "common-terminal.h"
> +#include "common-top.h"
> +#include "environ.h"
> +
> +/* We don't have a concept of a UI yet.  Therefore, we just set these
> +   to NULL.  */
> +
> +struct ui *main_ui = NULL;
> +struct ui *current_ui = NULL;
> +
> +/* The environment to pass to the inferior when creating it.  */
> +
> +struct gdb_environ *our_environ = NULL;
> +
> +/* Start the inferior using a shell.  */
> +
> +/* We always try to start the inferior using a shell.  */
> +
> +int startup_with_shell = 1;

Maybe turn startup_with_shell to bool now that we require C++? It will 
only be on/off, right?

>
>  /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
>     `vCont'.  Note the multi-process extensions made `vCont' a
> @@ -78,7 +98,8 @@ static int vCont_supported;
>     space randomization feature before starting an inferior.  */
>  int disable_randomization = 1;
>
> -static char **program_argv, **wrapper_argv;
> +static std::vector<char *> program_argv;
> +static std::vector<char *> wrapper_argv;
>
>  int pass_signals[GDB_SIGNAL_LAST];
>  int program_signals[GDB_SIGNAL_LAST];
> @@ -244,33 +265,64 @@ get_last_target_waitstatus (void)
>    return last_status;
>  }
>
> -static int
> -start_inferior (char **argv)
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_wrapper (void)
>  {
> -  char **new_argv = argv;
> +  static std::string ret;
> +  static int initialized_p = 0;
> +
> +  if (wrapper_argv.empty ())
> +    return NULL;
>
> -  if (wrapper_argv != NULL)
> +  if (!initialized_p)
>      {
> -      int i, count = 1;
> -
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	count++;
> -      for (i = 0; argv[i] != NULL; i++)
> -	count++;
> -      new_argv = XALLOCAVEC (char *, count);
> -      count = 0;
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	new_argv[count++] = wrapper_argv[i];
> -      for (i = 0; argv[i] != NULL; i++)
> -	new_argv[count++] = argv[i];
> -      new_argv[count] = NULL;
> +      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
> +	   i != wrapper_argv.end ();
> +	   ++i)
> +	ret += *i + std::string (" ");
> +
> +      /* Erasing the last whitespace.  */
> +      ret.erase (ret.end () - 1);
> +
> +      initialized_p = 1;
>      }
>
> +  return (char *) ret.c_str ();
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_file (int err)
> +{
> +  if (err && program_argv.empty ())
> +    error (_("Could not get the exec file."));
> +  return program_argv[0];
> +}
> +
> +/* See server.h.  */
> +
> +struct gdb_environ *
> +get_environ (void)
> +{
> +  return our_environ;
> +}
> +
> +/* See server.h.  */
> +
> +void
> +pre_fork_inferior (std::vector<char *> &argv)
> +{
>    if (debug_threads)
>      {
> -      int i;
> -      for (i = 0; new_argv[i]; ++i)
> -	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
> +      int idx = 0;
> +
> +      for (std::vector<char *>::iterator i = argv.begin ();
> +	   i != argv.end ();
> +	   ++i, ++idx)
> +	debug_printf ("new_argv[%d] = \"%s\"\n", idx, *i);

Candidate for a range for loop format. Only a suggestion.

>        debug_flush ();
>      }
>
> @@ -279,67 +331,35 @@ start_inferior (char **argv)
>    signal (SIGTTIN, SIG_DFL);
>  #endif
>
> -  signal_pid = create_inferior (new_argv[0], new_argv);
> +  /* Clear this so the backend doesn't get confused, thinking
> +     CONT_THREAD died, and it needs to resume all threads.  */
> +  cont_thread = null_ptid;
> +}
>
> -  /* FIXME: we don't actually know at this point that the create
> -     actually succeeded.  We won't know that until we wait.  */
> -  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
> -	   signal_pid);
> -  fflush (stderr);
> +/* See server.h.  */
> +
> +void
> +post_fork_inferior (int pid,
> +		    std::vector<char *> &argv)
> +{
> +  /* Number of traps to be expected by startup_inferior.  We always
> +     expect at least one trap for the main executable.  */
> +  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
>
>  #ifdef SIGTTOU
>    signal (SIGTTOU, SIG_IGN);
>    signal (SIGTTIN, SIG_IGN);
>    terminal_fd = fileno (stderr);
>    old_foreground_pgrp = tcgetpgrp (terminal_fd);
> -  tcsetpgrp (terminal_fd, signal_pid);
> +  tcsetpgrp (terminal_fd, pid);
>    atexit (restore_old_foreground_pgrp);
>  #endif
>
> -  if (wrapper_argv != NULL)
> -    {
> -      ptid_t ptid = pid_to_ptid (signal_pid);
> -
> -      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -
> -      if (last_status.kind == TARGET_WAITKIND_STOPPED)
> -	{
> -	  do
> -	    {
> -	      target_continue_no_signal (ptid);
> -
> -	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
> -		break;
> -
> -	      current_thread->last_resume_kind = resume_stop;
> -	      current_thread->last_status = last_status;
> -	    }
> -	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
> -	}
> -      target_post_create_inferior ();
> -      return signal_pid;
> -    }
> -
> -  /* Wait till we are at 1st instruction in program, return new pid
> -     (assuming success).  */
> -  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
> -
> -  /* At this point, the target process, if it exits, is stopped.  Do not call
> -     the function target_post_create_inferior if the process has already
> -     exited, as the target implementation of the routine may rely on the
> -     process being live. */
> -  if (last_status.kind != TARGET_WAITKIND_EXITED
> -      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
> -    {
> -      target_post_create_inferior ();
> -      current_thread->last_resume_kind = resume_stop;
> -      current_thread->last_status = last_status;
> -    }
> -  else
> -    target_mourn_inferior (last_ptid);
> -
> -  return signal_pid;
> +  startup_inferior (num_traps, &last_status, &last_ptid);
> +  signal_pid = pid;
> +  target_post_create_inferior ();
> +  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
> +  fflush (stderr);
>  }
>
>  static int
> @@ -2860,8 +2880,10 @@ handle_v_attach (char *own_buf)
>  static int
>  handle_v_run (char *own_buf)
>  {
> -  char *p, *next_p, **new_argv;
> -  int i, new_argc;
> +  char *p, *next_p;
> +  std::vector<char *> new_argv;
> +  int new_argc;
> +  int i;
>
>    new_argc = 0;
>    for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
> @@ -2870,62 +2892,91 @@ handle_v_run (char *own_buf)
>        new_argc++;
>      }
>
> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
> -  if (new_argv == NULL)
> -    {
> -      write_enn (own_buf);
> -      return 0;
> -    }
> -
> -  i = 0;
> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>      {
>        next_p = strchr (p, ';');
>        if (next_p == NULL)
>  	next_p = p + strlen (p);
>
> -      if (i == 0 && p == next_p)
> -	new_argv[i] = NULL;
> +      if (p == next_p)
> +	new_argv.push_back ("''");
>        else
>  	{
>  	  /* FIXME: Fail request if out of memory instead of dying.  */
> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
> -	  new_argv[i][(next_p - p) / 2] = '\0';
> +	  size_t len = 1 + (next_p - p) / 2;
> +	  char *s = (char *) xmalloc (len);
> +	  char *ss = (char *) xmalloc (len * 2);
> +	  char *tmp_s, *tmp_ss;
> +	  int need_quote;
> +
> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
> +	  s[(next_p - p) / 2] = '\0';
> +
> +	  tmp_s = s;
> +	  tmp_ss = ss;
> +	  need_quote = 0;
> +	  while (*tmp_s != '\0')
> +	    {
> +	      switch (*tmp_s)
> +		{
> +		case '\n':
> +		  *tmp_ss = '\'';
> +		  ++tmp_ss;
> +		  need_quote = 1;
> +		  break;
> +
> +		case '\'':
> +		  *tmp_ss = '\\';
> +		  ++tmp_ss;
> +		  break;
> +
> +		default:
> +		  break;
> +		}
> +
> +	      *tmp_ss = *tmp_s;
> +	      ++tmp_ss;
> +	      ++tmp_s;
> +	    }
> +
> +	  if (need_quote)
> +	    *tmp_ss++ = '\'';
> +
> +	  *tmp_ss = '\0';
> +	  new_argv.push_back (ss);
> +	  xfree (s);
>  	}
>
>        if (*next_p)
>  	next_p++;
> -      i++;
>      }
> -  new_argv[i] = NULL;
>
> -  if (new_argv[0] == NULL)
> +  if (new_argv.empty () || new_argv[0] == NULL)
>      {
>        /* GDB didn't specify a program to run.  Use the program from the
>  	 last run with the new argument list.  */
>
> -      if (program_argv == NULL)
> +      if (program_argv.empty ())
>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>
> -      new_argv[0] = strdup (program_argv[0]);
> -      if (new_argv[0] == NULL)
> +      new_argv.push_back (strdup (program_argv[0]));
> +      if (new_argv.empty () || new_argv[0] == NULL)
>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>      }
>
>    /* Free the old argv and install the new one.  */
> -  freeargv (program_argv);
> +  free_vector_argv (program_argv);
>    program_argv = new_argv;
>
> -  start_inferior (program_argv);
> +  create_inferior (program_argv);
>    if (last_status.kind == TARGET_WAITKIND_STOPPED)
>      {
>        prepare_resume_reply (own_buf, last_ptid, &last_status);
> @@ -3543,13 +3594,18 @@ captured_main (int argc, char *argv[])
>  	multi_mode = 1;
>        else if (strcmp (*next_arg, "--wrapper") == 0)
>  	{
> +	  char **tmp;
> +
>  	  next_arg++;
>
> -	  wrapper_argv = next_arg;
> +	  tmp = next_arg;
>  	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
> -	    next_arg++;
> +	    {
> +	      wrapper_argv.push_back (*next_arg);
> +	      next_arg++;
> +	    }
>
> -	  if (next_arg == wrapper_argv || *next_arg == NULL)
> +	  if (next_arg == tmp || *next_arg == NULL)
>  	    {
>  	      gdbserver_usage (stderr);
>  	      exit (1);
> @@ -3680,8 +3736,14 @@ captured_main (int argc, char *argv[])
>        exit (1);
>      }
>
> +  /* Gather information about the environment.  */
> +  our_environ = make_environ ();
> +  init_environ (our_environ);
> +
>    initialize_async_io ();
>    initialize_low ();
> +  /* This is called when initializing inflow on GDB.  */
> +  have_job_control ();
>    initialize_event_loop ();
>    if (target_supports_tracepoints ())
>      initialize_tracepoint ();
> @@ -3695,13 +3757,11 @@ captured_main (int argc, char *argv[])
>        int i, n;
>
>        n = argc - (next_arg - argv);
> -      program_argv = XNEWVEC (char *, n + 1);
>        for (i = 0; i < n; i++)
> -	program_argv[i] = xstrdup (next_arg[i]);
> -      program_argv[i] = NULL;
> +	program_argv.push_back (xstrdup (next_arg[i]));
>
>        /* Wait till we are at first instruction in program.  */
> -      start_inferior (program_argv);
> +      create_inferior (program_argv);
>
>        /* We are now (hopefully) stopped at the first instruction of
>  	 the target process.  This assumes that the target process was
> @@ -4316,9 +4376,9 @@ process_serial_event (void)
>  	  fprintf (stderr, "GDBserver restarting\n");
>
>  	  /* Wait till we are at 1st instruction in prog.  */
> -	  if (program_argv != NULL)
> +	  if (!program_argv.empty ())
>  	    {
> -	      start_inferior (program_argv);
> +	      create_inferior (program_argv);
>  	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>  		{
>  		  /* Stopped at the first instruction of the target
> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index 71848f1..47e094a 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  #include "utils.h"
>  #include "debug.h"
>  #include "gdb_vecs.h"
> +#include <vector>
>
>  /* Maximum number of bytes to read/write at once.  The value here
>     is chosen to fill up a packet (the headers account for the 32).  */
> @@ -151,4 +152,19 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  /* Return the global variable LAST_STATUS from server.c.  */
>  extern struct target_waitstatus get_last_target_waitstatus (void);
>
> +/* Any pre-processing needed to be done before calling fork_inferior
> +   shall be implemented here.  ARGV is a vector containing the full
> +   argv of the inferior.  */
> +extern void pre_fork_inferior (std::vector<char *> &argv);
> +
> +/* After fork_inferior has been called, we need to adjust a few
> +   signals and call startup_inferior.  This is done here.  PID is the
> +   pid of the new inferior, and ARGV is the vector containing the full
> +   argv of the inferior.  */
> +extern void post_fork_inferior (int pid, std::vector<char *> &argv);
> +
> +/* Get the 'struct gdb_environ *' being used in the current
> +   session.  */
> +extern struct gdb_environ *get_environ (void);
> +
>  #endif /* SERVER_H */
> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
> index 117b871..7f26331 100644
> --- a/gdb/gdbserver/spu-low.c
> +++ b/gdb/gdbserver/spu-low.c
> @@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
>    return ret;
>  }
>
> +/* Callback to be used when calling fork_inferior, responsible for
> +   actually initiating the tracing of the inferior.  */
> +
> +static void
> +spu_ptrace_fun (void)
> +{
> +  ptrace (PTRACE_TRACEME, 0, 0, 0);
> +  setpgid (0, 0);
> +}
>
>  /* Start an inferior process and returns its pid.
> -   ALLARGS is a vector of program-name and args. */
> +   PROGRAM_ARGV is a vector of program-name and args. */
>  static int
> -spu_create_inferior (char *program, char **allargs)
> +spu_create_inferior (std::vector<char *> &program_argv)
>  {
>    int pid;
>    ptid_t ptid;
>    struct process_info *proc;
> +  std::string program_args = stringify_argv (program_argv);
>
> -  pid = fork ();
> -  if (pid < 0)
> -    perror_with_name ("fork");
> -
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, 0, 0);
> -
> -      setpgid (0, 0);
> +  pre_fork_inferior (program_argv);
>
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),
> +		       environ_vector (get_environ ()), spu_ptrace_fun,
> +		       NULL, NULL, NULL, NULL);
>
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  post_fork_inferior (pid, program_argv);
>
> -  proc = add_process (pid, 0);
> +  proc = find_process_pid (pid);
> +  gdb_assert (proc != NULL);
>    proc->tdesc = tdesc_spu;
>
> -  ptid = ptid_build (pid, pid, 0);
> -  add_thread (ptid, NULL);
>    return pid;
>  }
>
> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
> index fda72e8..1e1d193 100644
> --- a/gdb/gdbserver/target.c
> +++ b/gdb/gdbserver/target.c
> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>    return size;
>  }
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_init (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_inferior (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_ours (void)
> +{
> +  /* To be implemented.  */
> +}

Same question as the other TODO functions. How do you envision these 
being used for gdbserver in the future?

> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
> index 3cc2bc4..3f94115 100644
> --- a/gdb/gdbserver/target.h
> +++ b/gdb/gdbserver/target.h
> @@ -28,6 +28,7 @@
>  #include "target/waitstatus.h"
>  #include "mem-break.h"
>  #include "btrace-common.h"
> +#include <vector>
>
>  struct emit_ops;
>  struct buffer;
> @@ -73,7 +74,7 @@ struct target_ops
>       Returns the new PID on success, -1 on failure.  Registers the new
>       process with the process list.  */
>
> -  int (*create_inferior) (char *program, char **args);
> +  int (*create_inferior) (std::vector<char *> &program_argv);
>
>    /* Do additional setup after a new process is created, including
>       exec-wrapper completion.  */
> @@ -480,8 +481,8 @@ extern struct target_ops *the_target;
>
>  void set_target_ops (struct target_ops *);
>
> -#define create_inferior(program, args) \
> -  (*the_target->create_inferior) (program, args)
> +#define create_inferior(program) \
> +  (*the_target->create_inferior) (program)
>
>  #define target_post_create_inferior()			 \
>    do							 \
> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
> index 307d15a..004a78e 100644
> --- a/gdb/gdbserver/utils.c
> +++ b/gdb/gdbserver/utils.c
> @@ -137,3 +137,38 @@ pfildes (gdb_fildes_t fd)
>    return plongest (fd);
>  #endif
>  }
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +gdb_flush_out_err (void)
> +{
> +  fflush (stdout);
> +  fflush (stderr);
> +}
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +free_vector_argv (std::vector<char *> &v)
> +{
> +  for (char *&i : v)
> +    xfree (i);
> +
> +  v.clear ();
> +}
> +
> +/* See common/common-utils.h.  */
> +
> +std::string
> +stringify_argv (std::vector<char *> &argv)
> +{
> +  std::string ret ("");
> +
> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
> +       i != argv.end ();
> +       ++i)
> +    ret += *i + std::string (" ");
> +
> +  return ret;
> +}

Did you want to C++11-ify the above function as well?

> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
> index b4ded31..a30d99a 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/gdbserver/utils.h
> @@ -19,7 +19,17 @@
>  #ifndef UTILS_H
>  #define UTILS_H
>
> +#include <vector>
> +
>  char *paddress (CORE_ADDR addr);
>  char *pfildes (gdb_fildes_t fd);
>
> +/* Works like FREEARGV, but with std::vector.  */
> +extern void free_vector_argv (std::vector<char *> &v);
> +
> +/* Given a vector of arguments ARGV, return a string equivalent to
> +   joining all the arguments (starting from ARGV + 1) with a
> +   whitespace separating them.  */
> +extern std::string stringify_argv (std::vector<char *> &argv);
> +
>  #endif /* UTILS_H */
> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
> index d3ddbf5..c005a70 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>  }
>
>  /* Start a new process.
> -   PROGRAM is a path to the program to execute.
> -   ARGS is a standard NULL-terminated array of arguments,
> -   to be passed to the inferior as ``argv''.
> +   PROGRAM_ARGV is the vector containing the inferior's argv.
>     Returns the new PID on success, -1 on failure.  Registers the new
>     process with the process list.  */
>  static int
> -win32_create_inferior (char *program, char **program_args)
> +win32_create_inferior (std::vector<char *> &program_argv)
>  {
>  #ifndef USE_WIN32API
>    char real_path[PATH_MAX];
> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>    int argc;
>    PROCESS_INFORMATION pi;
>    DWORD err;
> +  char *program = program_argv[0];
> +  std::string program_args = stringify_argv (program_argv);
> +  char *args = (char *) program_args.c_str ();
>
>    /* win32_wait needs to know we're not attaching.  */
>    attaching = 0;
> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>
>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>
> +  pre_fork_inferior (program, argv);
> +
>  #ifndef USE_WIN32API
>    orig_path = NULL;
>    path_ptr = getenv ("PATH");
> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>    program = real_path;
>  #endif
>
> -  argslen = 1;
> -  for (argc = 1; program_args[argc]; argc++)
> -    argslen += strlen (program_args[argc]) + 1;
> -  args = (char *) alloca (argslen);
> -  args[0] = '\0';
> -  for (argc = 1; program_args[argc]; argc++)
> -    {
> -      /* FIXME: Can we do better about quoting?  How does Cygwin
> -	 handle this?  */
> -      strcat (args, " ");
> -      strcat (args, program_args[argc]);
> -    }
>    OUTMSG2 (("Command line is \"%s\"\n", args));
>
>  #ifdef CREATE_NEW_PROCESS_GROUP
> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>
>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>
> +  post_fork_inferior (current_process_id, program_argv);
> +
>    return current_process_id;
>  }
>
> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index 9935dcb..bccfd9c 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
>    thread_change_ptid (inferior_ptid,
>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>    inf->pending_execs = 0;
>    /* Get rid of the old shell threads.  */
>    prune_threads ();
> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
> index f61bfe7..e9a7de2 100644
> --- a/gdb/inf-ptrace.c
> +++ b/gdb/inf-ptrace.c
> @@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>
>    discard_cleanups (back_to);
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>
>    /* On some targets, there must be some explicit actions taken after
>       the inferior has been started up.  */
> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index 258cc29..e56d4ba 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -42,6 +42,7 @@ struct target_desc_info;
>
>  #include "progspace.h"
>  #include "registry.h"
> +#include "common-inferior.h"
>
>  #include "symfile-add-flags.h"
>
> @@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
>
>  extern void child_terminal_init_with_pgrp (int pgrp);
>
> -/* From fork-child.c */
> -
> -extern int fork_inferior (char *, char *, char **,
> -			  void (*)(void),
> -			  void (*)(int), void (*)(void), char *,
> -                          void (*)(const char *,
> -                                   char * const *, char * const *));
> -
> -
> -extern void startup_inferior (int);
> -
>  extern char *construct_inferior_arguments (int, char **);
>
>  /* From infcmd.c */
> diff --git a/gdb/procfs.c b/gdb/procfs.c
> index 2269016..ac76be6 100644
> --- a/gdb/procfs.c
> +++ b/gdb/procfs.c
> @@ -4375,7 +4375,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
>    thread_change_ptid (pid_to_ptid (pid),
>  		      ptid_build (pid, lwpid, 0));
>
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>
>  #ifdef SYS_syssgi
>    /* On mips-irix, we need to stop the inferior early enough during
> diff --git a/gdb/target.h b/gdb/target.h
> index f2b9181..99a1e9b 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
>
>  extern int target_terminal_is_ours (void);
>
> -/* Initialize the terminal settings we record for the inferior,
> -   before we actually run the inferior.  */
> -
> -extern void target_terminal_init (void);
> -
> -/* Put the inferior's terminal settings into effect.  This is
> -   preparation for starting or resuming the inferior.  This is a no-op
> -   unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_inferior (void);
> -
>  /* Put some of our terminal settings into effect, enough to get proper
>     results from our output, but do not change into or out of RAW mode
>     so that no input is discarded.  This is a no-op if terminal_ours
> @@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
>
>  extern void target_terminal_ours_for_output (void);
>
> -/* Put our terminal settings into effect.  First record the inferior's
> -   terminal settings so they can be restored properly later.  This is
> -   a no-op unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_ours (void);
> -
>  /* Return true if the target stack has a non-default
>    "to_terminal_ours" method.  */
>
> diff --git a/gdb/target/target.h b/gdb/target/target.h
> index 582852c..06b859c 100644
> --- a/gdb/target/target.h
> +++ b/gdb/target/target.h
> @@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
>
>  extern int target_supports_multi_process (void);
>
> +/* Initialize the terminal settings we record for the inferior,
> +   before we actually run the inferior.  */
> +

Spurious newline.

> +extern void target_terminal_init (void);
> +
> +/* Put the inferior's terminal settings into effect.  This is
> +   preparation for starting or resuming the inferior.  This is a no-op
> +   unless called with the main UI as current UI.  */
> +

Spurious newline.

> +extern void target_terminal_inferior (void);
> +
> +/* Put our terminal settings into effect.  First record the inferior's
> +   terminal settings so they can be restored properly later.  This is
> +   a no-op unless called with the main UI as current UI.  */
> +

Spurious newline.

> +extern void target_terminal_ours (void);
> +
>  #endif /* TARGET_COMMON_H */
> diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
> index d404564..fec138d 100644
> --- a/gdb/testsuite/gdb.server/non-existing-program.exp
> +++ b/gdb/testsuite/gdb.server/non-existing-program.exp
> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>  set msg "gdbserver exits cleanly"
>  set saw_exiting 0
>  expect {
> -    # This is what we get on ptrace-based targets.
> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
> +    # This is what we get on ptrace-based targets with
> +    # startup-with-shell disabled.
> +    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
> +	set saw_exiting 1
> +	exp_continue
> +    }
> +    # Likewise, but with startup-with-shell enabled.
> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>  	set saw_exiting 1
>  	exp_continue
>      }
> diff --git a/gdb/top.h b/gdb/top.h
> index 2da92df..0c8d324 100644
> --- a/gdb/top.h
> +++ b/gdb/top.h
> @@ -22,6 +22,7 @@
>
>  #include "buffer.h"
>  #include "event-loop.h"
> +#include "common-top.h"
>
>  struct tl_interp_info;
>
> @@ -144,14 +145,6 @@ struct ui
>    struct ui_out *m_current_uiout;
>  };
>
> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> -   It always exists and is created automatically when GDB starts
> -   up.  */
> -extern struct ui *main_ui;
> -
> -/* The current UI.  */
> -extern struct ui *current_ui;
> -
>  /* The list of all UIs.  */
>  extern struct ui *ui_list;
>
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 119992e..357ea4f 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -3404,6 +3404,15 @@ strip_leading_path_elements (const char *path, int n)
>    return p;
>  }
>
> +/* See common/common-utils.h.  */
> +
> +void
> +gdb_flush_out_err (void)
> +{
> +  gdb_flush (main_ui->m_gdb_stdout);
> +  gdb_flush (main_ui->m_gdb_stderr);
> +}
> +
>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>  extern initialize_file_ftype _initialize_utils;
>
>

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 5/6] Share fork_inferior et al with gdbserver
  2017-02-01 21:39     ` Luis Machado
@ 2017-02-07 22:23       ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-07 22:23 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, Pedro Alves, Eli Zaretskii

Thanks for the review, Luis.

Comments below.

On Wednesday, February 01 2017, Luis Machado wrote:

> On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
>> This is the most important (and the biggest, sorry) patch of the
>> series.  It moves fork_inferior from gdb/fork-child.c to
>> common/common-fork-child.c and makes all the necessary adjustments to
>> both GDB and gdbserver to make sure everything works OK.
>>
>> There is no "most important change" with this patch; all changes are
>> made in a progressive way, making sure that gdbserver had the
>> necessary features while not breaking GDB at the same time.  For some
>> feature, like the target_terminal_* functions, I chose to just use
>> placeholders for the real functions on gdbserver, that should be
>> implemented in the future.  For now, we don't need them in order to
>> make things work.  Also, since we don't manipulate terminal modes on
>> gdbserver the way we do on GDB, they are not possible to implement
>> right now (unless I chose to properly implement terminal handling on
>> gdbserver, which is something we don't know if we want now).
>>
>> Last, but not least, I did a major revamp on the way gdbserver
>> computes and stores the inferior's arguments.  It's now using a
>> std::vector<char *> and std::string where applicable, which makes
>> things much easier even to understand.  This simplification was also
>> interesting for the "create_inferior" method of gdbserver's target.c;
>> now, it only needs one argument (a vector containing the full inferior
>> argv) instead of two char * that were confusing to
>> manipulate/generate.
>>
>> I decided to go ahead and implement a partial support for starting the
>> inferior with a shell on gdbserver, although the full feature comes in
>> the next patch.  The user won't have the option to disable the
>> startup-with-shell, and also won't be able to change which shell
>> gdbserver will use (other than setting the $SHELL environment
>> variable, that is).
>>
>> Everything is working as expected, and no regressions were present
>> during the tests.
>>
>> gdb/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (SFILES): Add "common/common-fork-child.c".
>> 	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
>> 	"common/common-top.h".
>> 	(COMMON_OBS): Add "common-fork-child.o".
>> 	* common-fork-child.c: New file, with the majority of
>> 	"gdb/fork-child.c".
>> 	* common/common-inferior.h: New file, with contents from
>> 	"gdb/inferior.h".
>> 	* common/common-top.h: New file.
>> 	* common/common-utils.h (gdb_flush_out_err): New prototype.
>> 	* corefile.c (get_exec_file): Update comment.
>> 	* darwin-nat.c (darwin_ptrace_him): Update call of
>> 	"startup_inferior".
>> 	* fork-child.c: Cleanup unnecessary includes.
>> 	(SHELL_FILE): Move to "common/common-fork-child.c".
>> 	(environ): Likewise.
>> 	(exec_wrapper): Initialize.
>> 	(get_exec_wrapper): New function.
>> 	(breakup_args): Move to "common/common-fork-child.c"; rename to
>> 	"breakup_args_for_exec".
>> 	(escape_bang_in_quoted_argument): Move to
>> 	"common/common-fork-child.c".
>> 	(fork_inferior): Likewise.  Update function to support gdbserver.
>> 	(startup_inferior): Likewise.
>> 	* gnu-nat.c (gnu_create_inferior): Update call to
>> 	"startup_inferior".
>> 	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
>> 	* inferior.h: Include "common-inferior.h".
>> 	(fork_inferior): Move prototype to "common-inferior.h".
>> 	(startup_inferior): Likewise.
>> 	* procfs.c (procfs_init_inferior): Update call to
>> 	"startup_inferior".
>> 	* target.h (target_terminal_init): Move prototype to
>> 	"target/target.h".
>> 	(target_terminal_inferior): Likewise.
>> 	(target_terminal_ours): Likewise.
>> 	* target/target.h (target_terminal_init): New prototype, moved
>> 	from "target.h".
>> 	(target_terminal_inferior): Likewise.
>> 	(target_terminal_ours): Likewise.
>> 	* top.h: Include "common-top.h".
>> 	(main_ui): Move
>> 	(current_ui): Move
>> 	* utils.c (gdb_flush_out_err): New function.
>>
>> gdb/gdbserver/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (SFILES): Add "terminal.c" and
>> 	"common/common-fork-child.c".
>> 	(OBS): Add common-fork-child.o and terminal.o.
>> 	(common-fork-child.o): New rule.
>> 	* inferiors (inferior_ptid): New variable.
>> 	(inferior_appeared): New function.
>> 	(current_inferior): Likewise.
>> 	(have_inferiors): Likewise.
>> 	* linux-low.c: Include "common-inferior.h" and "environ.h".
>> 	(linux_update_process): New function.
>> 	(linux_add_process): Update comment.  Adjust function to call
>> 	"linux_update_process".
>> 	(update_thread_lwp): New function.
>> 	(linux_ptrace_fun): Likewise.
>> 	(linux_create_inferior): Adjust function prototype to reflect
>> 	change on "target.h".  Adjust function code to use
>> 	"fork_inferior".
>> 	* lynx-low.c (lynx_update_process): New function.
>> 	(lynx_add_process): Update comment.  Adjust function to call
>> 	"lynx_update_process".
>> 	(lynx_ptrace_fun): New function.
>> 	(lynx_create_inferior): Adjust function prototype to reflect
>> 	change on "target.h".  Adjust function code to use
>> 	"fork_inferior".
>> 	* nto-low.c (nto_create_inferior): Adjust function prototype and
>> 	code to reflect change on "target.h".
>> 	* server.c: Include "common-inferior.h", "common-terminal.h",
>> 	"common-top.h", "environ.h".
>> 	(main_ui): New variable.
>> 	(current_ui): Likewise.
>> 	(our_environ): Likewise.
>> 	(startup_with_shell): Likewise.
>> 	(program_argv): Convert to std::vector<char *>.
>> 	(wrapper_argv): Likewise.
>> 	(start_inferior): Delete function.
>> 	(get_exec_wrapper): New function.
>> 	(get_exec_file): Likewise.
>> 	(get_environ): Likewise.
>> 	(pre_fork_inferior): New function, with parts of "start_inferior".
>> 	(post_fork_inferior): Likewise.
>> 	(handle_v_run): Update code to deal with arguments coming from the
>> 	remote host.  Update calls from "start_inferior" to
>> 	"create_inferior".
>> 	(captured_main): Likewise.  Initialize environment variable.  Call
>> 	"have_job_control".
>> 	* server.h: Include <vector>.
>> 	(pre_fork_inferior): New prototype.
>> 	(post_fork_inferior): Likewise.
>> 	(get_environ): Likewise.
>> 	* spu-low.c (spu_ptrace_fun): New function.
>> 	(spu_create_inferior): Adjust function prototype to reflect change
>> 	on "target.h".  Adjust function code to use "fork_inferior".
>> 	* target.c (target_terminal_init): New function.
>> 	(target_terminal_inferior): Likewise.
>> 	(target_terminal_ours): Likewise.
>> 	* target.h: Include <vector>.
>> 	(struct target_ops) <create_inferior>: Update prototype
>> 	to accept one std::vector<char *> representing the full program
>> 	argv.
>> 	(create_inferior): Update macro.
>> 	* utils.c (gdb_flush_out_err): New function.
>> 	(free_vector_argv): Likewise.
>> 	(stringify_argv): Likewise.
>> 	* utils.h: Include <vector>.
>> 	(free_vector_argv): New prototype.
>> 	(stringify_argv): Likewise.
>> 	* win32-low.c (win32_create_inferior): Adjust function prototype
>> 	and code to reflect change on "target.h".
>>
>> gdb/testsuite/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* gdb.server/non-existing-program.exp: Update regex in order to
>> 	reflect the fact that gdbserver is now using fork_inferior (with a
>> 	shell) to startup the inferior.
>> ---
>>  gdb/Makefile.in                                   |   4 +
>>  gdb/common/common-fork-child.c                    | 593 ++++++++++++++++++++++
>>  gdb/common/common-inferior.h                      | 104 ++++
>>  gdb/common/common-top.h                           |  31 ++
>>  gdb/common/common-utils.h                         |   4 +
>>  gdb/corefile.c                                    |   4 +-
>>  gdb/darwin-nat.c                                  |   2 +-
>>  gdb/fork-child.c                                  | 526 +------------------
>>  gdb/gdbserver/Makefile.in                         |   7 +
>>  gdb/gdbserver/inferiors.c                         |  31 +-
>>  gdb/gdbserver/linux-low.c                         | 124 +++--
>>  gdb/gdbserver/lynx-low.c                          |  66 ++-
>>  gdb/gdbserver/nto-low.c                           |   9 +-
>>  gdb/gdbserver/server.c                            | 274 ++++++----
>>  gdb/gdbserver/server.h                            |  16 +
>>  gdb/gdbserver/spu-low.c                           |  43 +-
>>  gdb/gdbserver/target.c                            |  24 +
>>  gdb/gdbserver/target.h                            |   7 +-
>>  gdb/gdbserver/utils.c                             |  35 ++
>>  gdb/gdbserver/utils.h                             |  10 +
>>  gdb/gdbserver/win32-low.c                         |  25 +-
>>  gdb/gnu-nat.c                                     |   2 +-
>>  gdb/inf-ptrace.c                                  |   2 +-
>>  gdb/inferior.h                                    |  12 +-
>>  gdb/procfs.c                                      |   2 +-
>>  gdb/target.h                                      |  17 -
>>  gdb/target/target.h                               |  17 +
>>  gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
>>  gdb/top.h                                         |   9 +-
>>  gdb/utils.c                                       |   9 +
>>  30 files changed, 1226 insertions(+), 793 deletions(-)
>>  create mode 100644 gdb/common/common-fork-child.c
>>  create mode 100644 gdb/common/common-inferior.h
>>  create mode 100644 gdb/common/common-top.h
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 3e49e6e..bf8b359 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1196,6 +1196,7 @@ SFILES = \
>>  	common/fileio.c \
>>  	common/filestuff.c \
>>  	common/format.c \
>> +	common/common-fork-child.c \
>>  	common/common-inflow.c \
>>  	common/gdb_vecs.c \
>>  	common/new-op.c \
>> @@ -1483,6 +1484,8 @@ HFILES_NO_SRCDIR = \
>>  	common/gdb_sys_time.h \
>>  	common/gdb_vecs.h \
>>  	common/gdb_wait.h \
>> +	common/common-inferior.h \
>> +	common/common-top.h \
>>  	common/host-defs.h \
>>  	common/print-utils.h \
>>  	common/ptid.h \
>> @@ -1625,6 +1628,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>>  	common-agent.o \
>>  	common-debug.o \
>>  	common-exceptions.o \
>> +	common-fork-child.o \
>>  	common-inflow.o \
>>  	common-regcache.o \
>>  	common-utils.o \
>> diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
>> new file mode 100644
>> index 0000000..65ef374
>> --- /dev/null
>> +++ b/gdb/common/common-fork-child.c
>> @@ -0,0 +1,593 @@
>> +/* Fork a Unix child process, and set up to debug it, for GDB and gdbserver.
>
> ISTR that gdbserver is officially spelled GDBserver. Though we have a
> mix of different ways of spelling it. I don't think it is terribly
> important in the present state. But here's a suggestion anyway. Feel
> free to ignore it.

I corrected the spelling on the places you mentioned.

>> +
>> +   Copyright (C) 1990-2017 Free Software Foundation, Inc.
>> +
>> +   Contributed by Cygnus Support.
>
> I'm wondering if this is still needed or if we can move/drop it.

I adjusted this to be:

  Originally contributed by Cygnus Support.

>> +
>> +   This file is part of GDB.
>> +
>> +   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 "common-defs.h"
>> +#include "target/waitstatus.h"
>> +#include "common-terminal.h"
>> +#include "filestuff.h"
>> +#include "target/target.h"
>> +#include "common-inferior.h"
>> +#include "common-gdbthread.h"
>> +#include "common-top.h"
>> +#include "signals-state-save-restore.h"
>> +
>> +extern char **environ;
>> +
>> +/* Default shell file to be used if 'startup-with-shell' is set but
>> +   $SHELL is not.  */
>> +#define SHELL_FILE "/bin/sh"
>> +
>> +/* Break up SCRATCH into an argument vector suitable for passing to
>> +   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
>> +   would get as input the string "a b c d", and as output it would
>> +   fill in ARGV with the four arguments "a", "b", "c", "d".  */
>> +
>> +static void
>> +breakup_args_for_exec (char *scratch, char **argv)
>> +{
>> +  char *cp = scratch, *tmp;
>> +
>> +  for (;;)
>> +    {
>> +      /* Scan past leading separators */
>> +      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
>> +	cp++;
>> +
>> +      /* Break if at end of string.  */
>> +      if (*cp == '\0')
>> +	break;
>> +
>> +      /* Take an arg.  */
>> +      *argv++ = cp;
>> +
>> +      /* Scan for next arg separator.  */
>> +      tmp = strchr (cp, ' ');
>> +      if (tmp == NULL)
>> +	tmp = strchr (cp, '\t');
>> +      if (tmp == NULL)
>> +	tmp = strchr (cp, '\n');
>> +
>> +      /* No separators => end of string => break.  */
>> +      if (tmp == NULL)
>> +	break;
>> +      cp = tmp;
>> +
>> +      /* Replace the separator with a terminator.  */
>> +      *cp++ = '\0';
>> +    }
>> +
>> +  /* Null-terminate the vector.  */
>> +  *argv = NULL;
>> +}
>> +
>> +/* When executing a command under the given shell, return non-zero if
>> +   the '!' character should be escaped when embedded in a quoted
>> +   command-line argument.  */
>> +
>> +static int
>> +escape_bang_in_quoted_argument (const char *shell_file)
>> +{
>> +  const int shell_file_len = strlen (shell_file);
>> +
>> +  /* Bang should be escaped only in C Shells.  For now, simply check
>> +     that the shell name ends with 'csh', which covers at least csh
>> +     and tcsh.  This should be good enough for now.  */
>> +
>> +  if (shell_file_len < 3)
>> +    return 0;
>> +
>> +  if (shell_file[shell_file_len - 3] == 'c'
>> +      && shell_file[shell_file_len - 2] == 's'
>> +      && shell_file[shell_file_len - 1] == 'h')
>> +    return 1;
>> +
>> +  return 0;
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +char *
>> +get_startup_shell (void)
>> +{
>> +  static char *ret;
>> +
>> +  ret = getenv ("SHELL");
>> +  if (ret == NULL)
>> +    ret = SHELL_FILE;
>> +
>> +  return ret;
>> +}
>> +
>> +/* Quote the shell command that will be executed.  This function is
>> +   called when the inferior is going to be executed under a shell
>> +   (i.e., when 'startup-with-shell' is set).
>> +
>> +   SHELL_FILE is the shell which will be used to execute the inferior
>> +   (e.g., /bin/sh).
>> +
>> +   EXEC_FILE is the inferior executable itself.
>> +
>> +   ALLARGS contains all the arguments that will be passed to the
>> +   inferior.
>> +
>> +   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
>> +   the inferior.
>> +
>> +   SHELL_CMD is a pointer to the resulting shell command that will be
>> +   executed.  The resulting shell command will be returned in it.  It
>> +   must be pre-allocated and have a reasonable size.  For an example
>> +   on how to determine its size, see 'fork_inferior' on
>> +   fork-child.c.  */
>> +
>> +static void
>> +quote_shell_command (const char *shell_file, const char *exec_file,
>> +		     const char *allargs, const char *exec_wrapper,
>> +		     char **shell_cmd)
>> +{
>> +  char *shell_command = *shell_cmd;
>> +  const char *p;
>> +  int need_to_quote;
>> +  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
>> +
>> +  shell_command[0] = '\0';
>> +  strcat (shell_command, "exec ");
>> +
>> +  /* Add any exec wrapper.  That may be a program name with arguments, so
>> +     the user must handle quoting.  */
>> +  if (exec_wrapper != NULL)
>> +    {
>> +      strcat (shell_command, exec_wrapper);
>> +      strcat (shell_command, " ");
>> +    }
>> +
>> +  /* Now add exec_file, quoting as necessary.  */
>> +
>> +  /* Quoting in this style is said to work with all shells.  But
>> +     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
>> +     we need to.  */
>> +  p = exec_file;
>> +  while (1)
>> +    {
>> +      switch (*p)
>> +	{
>> +	case '\'':
>> +	case '!':
>> +	case '"':
>> +	case '(':
>> +	case ')':
>> +	case '$':
>> +	case '&':
>> +	case ';':
>> +	case '<':
>> +	case '>':
>> +	case ' ':
>> +	case '\n':
>> +	case '\t':
>> +	  need_to_quote = 1;
>> +	  goto end_scan;
>> +
>> +	case '\0':
>> +	  need_to_quote = 0;
>> +	  goto end_scan;
>> +
>> +	default:
>> +	  break;
>> +	}
>> +      ++p;
>> +    }
>> + end_scan:
>> +  if (need_to_quote)
>> +    {
>> +      strcat (shell_command, "'");
>> +      for (p = exec_file; *p != '\0'; ++p)
>> +	{
>> +	  if (*p == '\'')
>> +	    strcat (shell_command, "'\\''");
>> +	  else if (*p == '!' && escape_bang)
>> +	    strcat (shell_command, "\\!");
>> +	  else
>> +	    strncat (shell_command, p, 1);
>> +	}
>> +      strcat (shell_command, "'");
>> +    }
>> +  else
>> +    strcat (shell_command, exec_file);
>> +
>> +  strcat (shell_command, " ");
>> +  strcat (shell_command, allargs);
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +int
>> +fork_inferior (char *exec_file_arg, char *allargs, char **env,
>> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
>> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
>> +               void (*exec_fun)(const char *file, char * const *argv,
>> +                                char * const *env))
>
> Something off with the identation above?

Yeah, indeed.  I don't know why, though.  Something I have to check on
my Emacs config.  Anyway, fixed, thanks.

>> +{
>> +  int pid;
>> +  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
>> +  static int debug_fork = 0;
>> +  /* This is set to the result of setpgrp, which if vforked, will be visible
>> +     to you in the parent process.  It's only used by humans for debugging.  */
>> +  static int debug_setpgrp = 657473;
>> +  static char *shell_file;
>> +  static char *exec_file;
>> +  char **save_our_env;
>> +  int shell = 0;
>> +  static char **argv;
>> +  const char *inferior_io_terminal = get_inferior_io_terminal ();
>> +  struct inferior *inf;
>> +  int i;
>> +  int save_errno;
>> +  struct ui *save_ui;
>> +
>> +  /* If no exec file handed to us, get it from the exec-file command
>> +     -- with a good, common error message if none is specified.  */
>> +  exec_file = exec_file_arg;
>> +  if (exec_file == 0)
>> +    exec_file = get_exec_file (1);
>> +
>> +  /* 'startup_with_shell' is declared in inferior.h and bound to the
>> +     "set startup-with-shell" option.  If 0, we'll just do a
>> +     fork/exec, no shell, so don't bother figuring out what shell.  */
>> +  shell_file = shell_file_arg;
>> +  if (startup_with_shell)
>> +    {
>> +      /* Figure out what shell to start up the user program under.  */
>> +      if (shell_file == NULL)
>> +	shell_file = get_startup_shell ();
>> +
>> +      gdb_assert (shell_file != NULL);
>> +      shell = 1;
>> +    }
>> +
>> +  if (!shell)
>> +    {
>> +      /* We're going to call execvp.  Create argument vector.
>> +	 Calculate an upper bound on the length of the vector by
>> +	 assuming that every other character is a separate
>> +	 argument.  */
>> +      int argc = (strlen (allargs) + 1) / 2 + 2;
>> +
>> +      argv = XALLOCAVEC (char *, argc);
>> +      argv[0] = exec_file;
>> +      breakup_args_for_exec (allargs, &argv[1]);
>> +    }
>> +  else
>> +    {
>> +      /* We're going to call a shell.  */
>> +      char *shell_command;
>> +      char *exec_wrapper = get_exec_wrapper ();
>> +      size_t len;
>> +
>> +      /* Multiplying the length of exec_file by 4 is to account for the
>> +         fact that it may expand when quoted; it is a worst-case number
>> +         based on every character being '.  */
>> +      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
>> +      if (exec_wrapper != NULL)
>> +        len += strlen (exec_wrapper) + 1;
>> +
>> +      shell_command = (char *) alloca (len);
>> +      shell_command[0] = '\0';
>> +
>> +      quote_shell_command (shell_file, exec_file,
>> +			   allargs,
>> +			   exec_wrapper, &shell_command);
>> +
>> +      /* If we decided above to start up with a shell, we exec the
>> +	 shell, "-c" says to interpret the next arg as a shell command
>> +	 to execute, and this command is "exec <target-program>
>> +	 <args>".  */
>> +      argv = (char **) alloca (4 * sizeof (char *));
>> +      argv[0] = shell_file;
>> +      argv[1] = "-c";
>> +      argv[2] = shell_command;
>> +      argv[3] = (char *) 0;
>> +    }
>> +
>> +  /* Retain a copy of our environment variables, since the child will
>> +     replace the value of environ and if we're vforked, we have to
>> +     restore it.  */
>> +  save_our_env = environ;
>> +
>> +  /* Likewise the current UI.  */
>> +  save_ui = current_ui;
>> +
>> +  /* Tell the terminal handling subsystem what tty we plan to run on;
>> +     it will just record the information for later.  */
>> +  new_tty_prefork (inferior_io_terminal);
>> +
>> +  /* It is generally good practice to flush any possible pending stdio
>> +     output prior to doing a fork, to avoid the possibility of both
>> +     the parent and child flushing the same data after the fork.  */
>> +  gdb_flush_out_err ();
>> +
>> +  /* If there's any initialization of the target layers that must
>> +     happen to prepare to handle the child we're about fork, do it
>> +     now...  */
>> +  if (pre_trace_fun != NULL)
>> +    (*pre_trace_fun) ();
>> +
>> +  /* Create the child process.  Since the child process is going to
>> +     exec(3) shortly afterwards, try to reduce the overhead by
>> +     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
>> +     likely that this optimization won't work since there's too much
>> +     work to do between the vfork(2) and the exec(3).  This is known
>> +     to be the case on ttrace(2)-based HP-UX, where some handshaking
>> +     between parent and child needs to happen between fork(2) and
>> +     exec(2).  However, since the parent is suspended in the vforked
>> +     state, this doesn't work.  Also note that the vfork(2) call might
>> +     actually be a call to fork(2) due to the fact that autoconf will
>> +     ``#define vfork fork'' on certain platforms.  */
>> +  if (pre_trace_fun || debug_fork)
>> +    pid = fork ();
>> +  else
>> +    pid = vfork ();
>> +
>> +  if (pid < 0)
>> +    perror_with_name (("vfork"));
>> +
>> +  if (pid == 0)
>> +    {
>> +      /* Switch to the main UI, so that gdb_std{in/out/err} in the
>> +	 child are mapped to std{in/out/err}.  This makes it possible
>> +	 to use fprintf_unfiltered/warning/error/etc. in the child
>> +	 from here on.  */
>> +      current_ui = main_ui;
>> +
>> +      /* Close all file descriptors except those that gdb inherited
>> +	 (usually 0/1/2), so they don't leak to the inferior.  Note
>> +	 that this closes the file descriptors of all secondary
>> +	 UIs.  */
>> +      close_most_fds ();
>> +
>> +      if (debug_fork)
>> +	sleep (debug_fork);
>> +
>> +      /* Create a new session for the inferior process, if necessary.
>> +         It will also place the inferior in a separate process group.  */
>> +      if (create_tty_session () <= 0)
>> +	{
>> +	  /* No session was created, but we still want to run the inferior
>> +	     in a separate process group.  */
>> +	  debug_setpgrp = gdb_setpgid ();
>> +	  if (debug_setpgrp == -1)
>> +	    perror (_("setpgrp failed in child"));
>> +	}
>> +
>> +      /* Ask the tty subsystem to switch to the one we specified
>> +         earlier (or to share the current terminal, if none was
>> +         specified).  */
>> +      new_tty ();
>> +
>> +      /* Changing the signal handlers for the inferior after
>> +         a vfork can also change them for the superior, so we don't mess
>> +         with signals here.  See comments in
>> +         initialize_signals for how we get the right signal handlers
>> +         for the inferior.  */
>> +
>> +      /* "Trace me, Dr. Memory!"  */
>> +      (*traceme_fun) ();
>> +
>> +      /* The call above set this process (the "child") as debuggable
>> +        by the original gdb process (the "parent").  Since processes
>> +        (unlike people) can have only one parent, if you are debugging
>> +        gdb itself (and your debugger is thus _already_ the
>> +        controller/parent for this child), code from here on out is
>> +        undebuggable.  Indeed, you probably got an error message
>> +        saying "not parent".  Sorry; you'll have to use print
>> +        statements!  */
>> +
>> +      restore_original_signals_state ();
>> +
>> +      /* There is no execlpe call, so we have to set the environment
>> +         for our child in the global variable.  If we've vforked, this
>> +         clobbers the parent, but environ is restored a few lines down
>> +         in the parent.  By the way, yes we do need to look down the
>> +         path to find $SHELL.  Rich Pixley says so, and I agree.  */
>> +      environ = env;
>> +
>> +      if (exec_fun != NULL)
>> +        (*exec_fun) (argv[0], argv, env);
>> +      else
>> +        execvp (argv[0], argv);
>> +
>> +      /* If we get here, it's an error.  */
>> +      save_errno = errno;
>> +      warning ("Cannot exec %s", argv[0]);
>> +
>> +      for (i = 1; argv[i] != NULL; i++)
>> +	warning (" %s", argv[i]);
>> +
>> +      warning ("Error: %s\n", safe_strerror (save_errno));
>> +
>> +      _exit (0177);
>> +    }
>> +
>> +  /* Restore our environment in case a vforked child clob'd it.  */
>> +  environ = save_our_env;
>> +
>> +  /* Likewise the current UI.  */
>> +  current_ui = save_ui;
>> +
>> +  if (!have_inferiors ())
>> +    init_thread_list ();
>> +
>> +  inf = current_inferior ();
>> +
>> +  inferior_appeared (inf, pid);
>> +
>> +  /* Needed for wait_for_inferior stuff below.  */
>> +  inferior_ptid = pid_to_ptid (pid);
>> +
>> +  new_tty_postfork ();
>> +
>> +  /* We have something that executes now.  We'll be running through
>> +     the shell at this point, but the pid shouldn't change.  Targets
>> +     supporting MT should fill this task's ptid with more data as soon
>> +     as they can.  */
>> +  add_thread_silent (inferior_ptid);
>> +
>> +  /* Now that we have a child process, make it our target, and
>> +     initialize anything target-vector-specific that needs
>> +     initializing.  */
>> +  if (init_trace_fun)
>> +    (*init_trace_fun) (pid);
>> +
>> +  /* We are now in the child process of interest, having exec'd the
>> +     correct program, and are poised at the first instruction of the
>> +     new program.  */
>> +  return pid;
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +startup_inferior (int ntraps,
>> +		  struct target_waitstatus *last_waitstatus,
>> +		  ptid_t *last_ptid)
>> +{
>> +  int pending_execs = ntraps;
>> +  int terminal_initted = 0;
>> +  ptid_t resume_ptid;
>> +
>> +  if (startup_with_shell)
>> +    {
>> +      /* One trap extra for exec'ing the shell.  */
>> +      pending_execs++;
>> +    }
>> +
>> +  if (target_supports_multi_process ())
>> +    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
>> +  else
>> +    resume_ptid = minus_one_ptid;
>> +
>> +  /* The process was started by the fork that created it, but it will
>> +     have stopped one instruction after execing the shell.  Here we
>> +     must get it up to actual execution of the real program.  */
>> +  if (get_exec_wrapper () != NULL)
>> +    pending_execs++;
>> +
>> +  while (1)
>> +    {
>> +      enum gdb_signal resume_signal = GDB_SIGNAL_0;
>> +      ptid_t event_ptid;
>> +
>> +      struct target_waitstatus ws;
>> +      memset (&ws, 0, sizeof (ws));
>> +      event_ptid = target_wait (resume_ptid, &ws, 0);
>> +
>> +      if (last_waitstatus != NULL)
>> +	*last_waitstatus = ws;
>> +      if (last_ptid != NULL)
>> +	*last_ptid = event_ptid;
>> +
>> +      if (ws.kind == TARGET_WAITKIND_IGNORE)
>> +	/* The inferior didn't really stop, keep waiting.  */
>> +	continue;
>> +
>> +      switch (ws.kind)
>> +	{
>> +	  case TARGET_WAITKIND_SPURIOUS:
>> +	  case TARGET_WAITKIND_LOADED:
>> +	  case TARGET_WAITKIND_FORKED:
>> +	  case TARGET_WAITKIND_VFORKED:
>> +	  case TARGET_WAITKIND_SYSCALL_ENTRY:
>> +	  case TARGET_WAITKIND_SYSCALL_RETURN:
>> +	  case TARGET_WAITKIND_VFORK_DONE:
>> +	  case TARGET_WAITKIND_IGNORE:
>> +	  case TARGET_WAITKIND_NO_HISTORY:
>> +	  case TARGET_WAITKIND_NO_RESUMED:
>> +	  case TARGET_WAITKIND_THREAD_CREATED:
>> +	  case TARGET_WAITKIND_THREAD_EXITED:
>> +	    /* Ignore gracefully during startup of the inferior.  */
>> +	    switch_to_thread (event_ptid);
>> +	    break;
>> +
>> +	  case TARGET_WAITKIND_SIGNALLED:
>> +	    target_terminal_ours ();
>> +	    target_mourn_inferior (event_ptid);
>> +	    error (_("During startup program terminated with signal %s, %s."),
>> +		   gdb_signal_to_name (ws.value.sig),
>> +		   gdb_signal_to_string (ws.value.sig));
>> +	    return;
>> +
>> +	  case TARGET_WAITKIND_EXITED:
>> +	    target_terminal_ours ();
>> +	    target_mourn_inferior (event_ptid);
>> +	    if (ws.value.integer)
>> +	      error (_("During startup program exited with code %d."),
>> +		     ws.value.integer);
>> +	    else
>> +	      error (_("During startup program exited normally."));
>> +	    return;
>> +
>> +	  case TARGET_WAITKIND_EXECD:
>> +	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
>> +	    xfree (ws.value.execd_pathname);
>> +	    resume_signal = GDB_SIGNAL_TRAP;
>> +	    switch_to_thread (event_ptid);
>> +	    break;
>> +
>> +	  case TARGET_WAITKIND_STOPPED:
>> +	    resume_signal = ws.value.sig;
>> +	    switch_to_thread (event_ptid);
>> +	    break;
>> +	}
>> +
>> +      if (resume_signal != GDB_SIGNAL_TRAP)
>> +	{
>> +	  /* Let shell child handle its own signals in its own way.  */
>> +	  target_continue (resume_ptid, resume_signal);
>> +	}
>> +      else
>> +	{
>> +	  /* We handle SIGTRAP, however; it means child did an exec.  */
>> +	  if (!terminal_initted)
>> +	    {
>> +	      /* Now that the child has exec'd we know it has already
>> +	         set its process group.  On POSIX systems, tcsetpgrp
>> +	         will fail with EPERM if we try it before the child's
>> +	         setpgid.  */
>> +
>> +	      /* Set up the "saved terminal modes" of the inferior
>> +	         based on what modes we are starting it with.  */
>> +	      target_terminal_init ();
>> +
>> +	      /* Install inferior's terminal modes.  */
>> +	      target_terminal_inferior ();
>> +
>> +	      terminal_initted = 1;
>> +	    }
>> +
>> +	  if (--pending_execs == 0)
>> +	    break;
>> +
>> +	  /* Just make it go on.  */
>> +	  target_continue_no_signal (resume_ptid);
>> +	}
>> +    }
>> +
>> +  /* Mark all threads non-executing.  */
>> +  set_executing (resume_ptid, 0);
>> +}
>> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
>> new file mode 100644
>> index 0000000..e8f163f
>> --- /dev/null
>> +++ b/gdb/common/common-inferior.h
>> @@ -0,0 +1,104 @@
>> +/* Variables that describe the inferior process running under GDB and
>> +   gdbserver: Where it is, why it stopped, and how to step it.
>> +
>
> GDBserver?

Fixed.

>> +   Copyright (C) 1986-2016 Free Software Foundation, Inc.
>
>
> 1986-2017

Fixed.

>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_INFERIOR_H
>> +#define COMMON_INFERIOR_H
>> +
>> +/* Number of traps that happen between exec'ing the shell to run an
>> +   inferior and when we finally get to the inferior code, not counting
>> +   the exec for the shell.  This is 1 on all supported
>> +   implementations.  */
>> +#define START_INFERIOR_TRAPS_EXPECTED 1
>> +
>> +struct inferior;
>> +
>> +/* Whether to start up the debuggee under a shell.
>> +
>> +   If startup-with-shell is set, GDB's "run" will attempt to start up
>> +   the debuggee under a shell.
>> +
>
> Is the behavior the same for GDBserver under extended remote mode?
> Should we mention GDBserver here as well or is there something
> slightly different?

No, the behaviour should be exactly the same.  I mentioned GDBserver on
the sentence to make this clear.

>> +   This is in order for argument-expansion to occur.  E.g.,
>> +
>> +   (gdb) run *
>> +
>> +   The "*" gets expanded by the shell into a list of files.
>> +
>> +   While this is a nice feature, it may be handy to bypass the shell
>> +   in some cases.  To disable this feature, do "set startup-with-shell
>> +   false".
>> +
>> +   The catch-exec traps expected during start-up will be one more if
>> +   the target is started up with a shell.  */
>> +extern int startup_with_shell;
>> +
>> +/* Collected pid, tid, etc. of the debugged inferior.  When there's
>> +   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
>> +extern ptid_t inferior_ptid;
>> +
>> +/* Accept NTRAPS traps from the inferior.  */
>> +extern void startup_inferior (int ntraps,
>> +			      struct target_waitstatus *mystatus,
>> +			      ptid_t *myptid);
>> +
>> +/* Start an inferior Unix child process and sets inferior_ptid to its
>> +   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
>> +   the arguments to the program.  ENV is the environment vector to
>> +   pass.  SHELL_FILE is the shell file, or NULL if we should pick
>> +   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
>> +   one.  */
>> +
>> +/* This function is NOT reentrant.  Some of the variables have been
>> +   made static to ensure that they survive the vfork call.  */
>> +extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
>> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
>> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
>> +               void (*exec_fun) (const char *file, char * const *argv,
>> +				 char * const *env));
>
> Something funny with the identation above.

Fixed.

>> +
>> +/* Return the shell that must be used to startup the inferior.  The
>> +   first attempt is the environment variable SHELL; if it is not set,
>> +   then we default to SHELL_FILE.  */
>> +extern char *get_startup_shell (void);
>> +
>> +/* Set file name for default use for standard in/out in the inferior.  */
>> +extern void set_inferior_io_terminal (const char *terminal_name);
>> +
>> +/* Get file name for default use for standard in/out in the inferior.  */
>> +extern const char *get_inferior_io_terminal (void);
>> +
>> +/* Return the exec wrapper to be used when starting the inferior, or NULL
>> +   otherwise.  */
>> +extern char *get_exec_wrapper (void);
>> +
>> +/* Return the name of the executable file as a string.
>> +   ERR nonzero means get error if there is none specified;
>> +   otherwise return 0 in that case.  */
>> +extern char *get_exec_file (int err);
>> +
>> +/* Returns true if the inferior list is not empty.  */
>> +extern int have_inferiors (void);
>> +
>> +extern void inferior_appeared (struct inferior *inf, int pid);
>> +
>> +/* Return a pointer to the current inferior.  It is an error to call
>> +   this if there is no current inferior.  */
>> +extern struct inferior *current_inferior (void);
>> +
>> +#endif /* ! COMMON_INFERIOR_H */
>> diff --git a/gdb/common/common-top.h b/gdb/common/common-top.h
>> new file mode 100644
>> index 0000000..a2aa692
>> --- /dev/null
>> +++ b/gdb/common/common-top.h
>> @@ -0,0 +1,31 @@
>> +/* Common top level stuff for GDB and gdbserver.
>> +
>
> GDBserver.

Fixed.

>> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_TOP_H
>> +#define COMMON_TOP_H
>> +
>> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>> +   It always exists and is created automatically when GDB starts
>> +   up.  */
>> +extern struct ui *main_ui;
>> +
>> +/* The current UI.  */
>> +extern struct ui *current_ui;
>> +
>> +#endif /* ! COMMON_TOP_H */
>> diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
>> index 618d266..59e85b1 100644
>> --- a/gdb/common/common-utils.h
>> +++ b/gdb/common/common-utils.h
>> @@ -103,4 +103,8 @@ extern const char *skip_spaces_const (const char *inp);
>>
>>  extern const char *skip_to_space_const (const char *inp);
>>
>> +/* Flush both stdout and stderr.  This function needs to be
>> +   implemented differently on GDB and gdbserver.  */
>
> GDBserver.

Fixed.

>> +extern void gdb_flush_out_err (void);
>> +
>>  #endif
>> diff --git a/gdb/corefile.c b/gdb/corefile.c
>> index 54cb789..d76fa1a 100644
>> --- a/gdb/corefile.c
>> +++ b/gdb/corefile.c
>> @@ -170,9 +170,7 @@ validate_files (void)
>>      }
>>  }
>>
>> -/* Return the name of the executable file as a string.
>> -   ERR nonzero means get error if there is none specified;
>> -   otherwise return 0 in that case.  */
>> +/* See common/common-inferior.h.  */
>>
>>  char *
>>  get_exec_file (int err)
>> diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
>> index 8c5e8a0..ef94d10 100644
>> --- a/gdb/darwin-nat.c
>> +++ b/gdb/darwin-nat.c
>> @@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
>>
>>    darwin_init_thread_list (inf);
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>  }
>>
>>  static void
>> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
>> index eaa8cb5..a6550c7 100644
>> --- a/gdb/fork-child.c
>> +++ b/gdb/fork-child.c
>> @@ -21,531 +21,19 @@
>>
>>  #include "defs.h"
>>  #include "inferior.h"
>> -#include "terminal.h"
>> -#include "target.h"
>> -#include "gdb_wait.h"
>> -#include "gdb_vfork.h"
>> -#include "gdbcore.h"
>> -#include "gdbthread.h"
>> -#include "command.h" /* for dont_repeat () */
>>  #include "gdbcmd.h"
>> -#include "solib.h"
>> -#include "filestuff.h"
>> -#include "top.h"
>> -#include "signals-state-save-restore.h"
>> -#include <signal.h>
>>
>> -/* This just gets used as a default if we can't find SHELL.  */
>> -#define SHELL_FILE "/bin/sh"
>> +/* The exec-wrapper, if any, that will be used when starting the
>> +   inferior.  */
>>
>> -extern char **environ;
>> +static char *exec_wrapper = NULL;
>>
>> -static char *exec_wrapper;
>> +/* See common/common-inferior.h.  */
>>
>> -/* Break up SCRATCH into an argument vector suitable for passing to
>> -   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
>> -   would get as input the string "a b c d", and as output it would
>> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
>> -
>> -static void
>> -breakup_args (char *scratch, char **argv)
>> +char *
>> +get_exec_wrapper (void)
>>  {
>> -  char *cp = scratch, *tmp;
>> -
>> -  for (;;)
>> -    {
>> -      /* Scan past leading separators */
>> -      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
>> -	cp++;
>> -
>> -      /* Break if at end of string.  */
>> -      if (*cp == '\0')
>> -	break;
>> -
>> -      /* Take an arg.  */
>> -      *argv++ = cp;
>> -
>> -      /* Scan for next arg separator.  */
>> -      tmp = strchr (cp, ' ');
>> -      if (tmp == NULL)
>> -	tmp = strchr (cp, '\t');
>> -      if (tmp == NULL)
>> -	tmp = strchr (cp, '\n');
>> -
>> -      /* No separators => end of string => break.  */
>> -      if (tmp == NULL)
>> -	break;
>> -      cp = tmp;
>> -
>> -      /* Replace the separator with a terminator.  */
>> -      *cp++ = '\0';
>> -    }
>> -
>> -  /* Null-terminate the vector.  */
>> -  *argv = NULL;
>> -}
>> -
>> -/* When executing a command under the given shell, return non-zero if
>> -   the '!' character should be escaped when embedded in a quoted
>> -   command-line argument.  */
>> -
>> -static int
>> -escape_bang_in_quoted_argument (const char *shell_file)
>> -{
>> -  const int shell_file_len = strlen (shell_file);
>> -
>> -  /* Bang should be escaped only in C Shells.  For now, simply check
>> -     that the shell name ends with 'csh', which covers at least csh
>> -     and tcsh.  This should be good enough for now.  */
>> -
>> -  if (shell_file_len < 3)
>> -    return 0;
>> -
>> -  if (shell_file[shell_file_len - 3] == 'c'
>> -      && shell_file[shell_file_len - 2] == 's'
>> -      && shell_file[shell_file_len - 1] == 'h')
>> -    return 1;
>> -
>> -  return 0;
>> -}
>> -
>> -/* Start an inferior Unix child process and sets inferior_ptid to its
>> -   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
>> -   the arguments to the program.  ENV is the environment vector to
>> -   pass.  SHELL_FILE is the shell file, or NULL if we should pick
>> -   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
>> -   one.  */
>> -
>> -/* This function is NOT reentrant.  Some of the variables have been
>> -   made static to ensure that they survive the vfork call.  */
>> -
>> -int
>> -fork_inferior (char *exec_file_arg, char *allargs, char **env,
>> -	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
>> -	       void (*pre_trace_fun) (void), char *shell_file_arg,
>> -               void (*exec_fun)(const char *file, char * const *argv,
>> -                                char * const *env))
>> -{
>> -  int pid;
>> -  static char default_shell_file[] = SHELL_FILE;
>> -  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
>> -  static int debug_fork = 0;
>> -  /* This is set to the result of setpgrp, which if vforked, will be visible
>> -     to you in the parent process.  It's only used by humans for debugging.  */
>> -  static int debug_setpgrp = 657473;
>> -  static char *shell_file;
>> -  static char *exec_file;
>> -  char **save_our_env;
>> -  int shell = 0;
>> -  static char **argv;
>> -  const char *inferior_io_terminal = get_inferior_io_terminal ();
>> -  struct inferior *inf;
>> -  int i;
>> -  int save_errno;
>> -  struct ui *save_ui;
>> -
>> -  /* If no exec file handed to us, get it from the exec-file command
>> -     -- with a good, common error message if none is specified.  */
>> -  exec_file = exec_file_arg;
>> -  if (exec_file == 0)
>> -    exec_file = get_exec_file (1);
>> -
>> -  /* 'startup_with_shell' is declared in inferior.h and bound to the
>> -     "set startup-with-shell" option.  If 0, we'll just do a
>> -     fork/exec, no shell, so don't bother figuring out what shell.  */
>> -  shell_file = shell_file_arg;
>> -  if (startup_with_shell)
>> -    {
>> -      /* Figure out what shell to start up the user program under.  */
>> -      if (shell_file == NULL)
>> -	shell_file = getenv ("SHELL");
>> -      if (shell_file == NULL)
>> -	shell_file = default_shell_file;
>> -      shell = 1;
>> -    }
>> -
>> -  if (!shell)
>> -    {
>> -      /* We're going to call execvp.  Create argument vector.
>> -	 Calculate an upper bound on the length of the vector by
>> -	 assuming that every other character is a separate
>> -	 argument.  */
>> -      int argc = (strlen (allargs) + 1) / 2 + 2;
>> -
>> -      argv = XALLOCAVEC (char *, argc);
>> -      argv[0] = exec_file;
>> -      breakup_args (allargs, &argv[1]);
>> -    }
>> -  else
>> -    {
>> -      /* We're going to call a shell.  */
>> -      char *shell_command;
>> -      int len;
>> -      char *p;
>> -      int need_to_quote;
>> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
>> -
>> -      /* Multiplying the length of exec_file by 4 is to account for the
>> -         fact that it may expand when quoted; it is a worst-case number
>> -         based on every character being '.  */
>> -      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
>> -      if (exec_wrapper)
>> -        len += strlen (exec_wrapper) + 1;
>> -
>> -      shell_command = (char *) alloca (len);
>> -      shell_command[0] = '\0';
>> -
>> -      strcat (shell_command, "exec ");
>> -
>> -      /* Add any exec wrapper.  That may be a program name with arguments, so
>> -	 the user must handle quoting.  */
>> -      if (exec_wrapper)
>> -	{
>> -	  strcat (shell_command, exec_wrapper);
>> -	  strcat (shell_command, " ");
>> -	}
>> -
>> -      /* Now add exec_file, quoting as necessary.  */
>> -
>> -      /* Quoting in this style is said to work with all shells.  But
>> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
>> -         we need to.  */
>> -      p = exec_file;
>> -      while (1)
>> -	{
>> -	  switch (*p)
>> -	    {
>> -	    case '\'':
>> -	    case '!':
>> -	    case '"':
>> -	    case '(':
>> -	    case ')':
>> -	    case '$':
>> -	    case '&':
>> -	    case ';':
>> -	    case '<':
>> -	    case '>':
>> -	    case ' ':
>> -	    case '\n':
>> -	    case '\t':
>> -	      need_to_quote = 1;
>> -	      goto end_scan;
>> -
>> -	    case '\0':
>> -	      need_to_quote = 0;
>> -	      goto end_scan;
>> -
>> -	    default:
>> -	      break;
>> -	    }
>> -	  ++p;
>> -	}
>> -    end_scan:
>> -      if (need_to_quote)
>> -	{
>> -	  strcat (shell_command, "'");
>> -	  for (p = exec_file; *p != '\0'; ++p)
>> -	    {
>> -	      if (*p == '\'')
>> -		strcat (shell_command, "'\\''");
>> -	      else if (*p == '!' && escape_bang)
>> -		strcat (shell_command, "\\!");
>> -	      else
>> -		strncat (shell_command, p, 1);
>> -	    }
>> -	  strcat (shell_command, "'");
>> -	}
>> -      else
>> -	strcat (shell_command, exec_file);
>> -
>> -      strcat (shell_command, " ");
>> -      strcat (shell_command, allargs);
>> -
>> -      /* If we decided above to start up with a shell, we exec the
>> -	 shell, "-c" says to interpret the next arg as a shell command
>> -	 to execute, and this command is "exec <target-program>
>> -	 <args>".  */
>> -      argv = (char **) alloca (4 * sizeof (char *));
>> -      argv[0] = shell_file;
>> -      argv[1] = "-c";
>> -      argv[2] = shell_command;
>> -      argv[3] = (char *) 0;
>> -    }
>> -
>> -  /* Retain a copy of our environment variables, since the child will
>> -     replace the value of environ and if we're vforked, we have to
>> -     restore it.  */
>> -  save_our_env = environ;
>> -
>> -  /* Likewise the current UI.  */
>> -  save_ui = current_ui;
>> -
>> -  /* Tell the terminal handling subsystem what tty we plan to run on;
>> -     it will just record the information for later.  */
>> -  new_tty_prefork (inferior_io_terminal);
>> -
>> -  /* It is generally good practice to flush any possible pending stdio
>> -     output prior to doing a fork, to avoid the possibility of both
>> -     the parent and child flushing the same data after the fork.  */
>> -  gdb_flush (main_ui->m_gdb_stdout);
>> -  gdb_flush (main_ui->m_gdb_stderr);
>> -
>> -  /* If there's any initialization of the target layers that must
>> -     happen to prepare to handle the child we're about fork, do it
>> -     now...  */
>> -  if (pre_trace_fun != NULL)
>> -    (*pre_trace_fun) ();
>> -
>> -  /* Create the child process.  Since the child process is going to
>> -     exec(3) shortly afterwards, try to reduce the overhead by
>> -     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
>> -     likely that this optimization won't work since there's too much
>> -     work to do between the vfork(2) and the exec(3).  This is known
>> -     to be the case on ttrace(2)-based HP-UX, where some handshaking
>> -     between parent and child needs to happen between fork(2) and
>> -     exec(2).  However, since the parent is suspended in the vforked
>> -     state, this doesn't work.  Also note that the vfork(2) call might
>> -     actually be a call to fork(2) due to the fact that autoconf will
>> -     ``#define vfork fork'' on certain platforms.  */
>> -  if (pre_trace_fun || debug_fork)
>> -    pid = fork ();
>> -  else
>> -    pid = vfork ();
>> -
>> -  if (pid < 0)
>> -    perror_with_name (("vfork"));
>> -
>> -  if (pid == 0)
>> -    {
>> -      /* Switch to the main UI, so that gdb_std{in/out/err} in the
>> -	 child are mapped to std{in/out/err}.  This makes it possible
>> -	 to use fprintf_unfiltered/warning/error/etc. in the child
>> -	 from here on.  */
>> -      current_ui = main_ui;
>> -
>> -      /* Close all file descriptors except those that gdb inherited
>> -	 (usually 0/1/2), so they don't leak to the inferior.  Note
>> -	 that this closes the file descriptors of all secondary
>> -	 UIs.  */
>> -      close_most_fds ();
>> -
>> -      if (debug_fork)
>> -	sleep (debug_fork);
>> -
>> -      /* Create a new session for the inferior process, if necessary.
>> -         It will also place the inferior in a separate process group.  */
>> -      if (create_tty_session () <= 0)
>> -	{
>> -	  /* No session was created, but we still want to run the inferior
>> -	     in a separate process group.  */
>> -	  debug_setpgrp = gdb_setpgid ();
>> -	  if (debug_setpgrp == -1)
>> -	    perror (_("setpgrp failed in child"));
>> -	}
>> -
>> -      /* Ask the tty subsystem to switch to the one we specified
>> -         earlier (or to share the current terminal, if none was
>> -         specified).  */
>> -      new_tty ();
>> -
>> -      /* Changing the signal handlers for the inferior after
>> -         a vfork can also change them for the superior, so we don't mess
>> -         with signals here.  See comments in
>> -         initialize_signals for how we get the right signal handlers
>> -         for the inferior.  */
>> -
>> -      /* "Trace me, Dr. Memory!"  */
>> -      (*traceme_fun) ();
>> -
>> -      /* The call above set this process (the "child") as debuggable
>> -        by the original gdb process (the "parent").  Since processes
>> -        (unlike people) can have only one parent, if you are debugging
>> -        gdb itself (and your debugger is thus _already_ the
>> -        controller/parent for this child), code from here on out is
>> -        undebuggable.  Indeed, you probably got an error message
>> -        saying "not parent".  Sorry; you'll have to use print
>> -        statements!  */
>> -
>> -      restore_original_signals_state ();
>> -
>> -      /* There is no execlpe call, so we have to set the environment
>> -         for our child in the global variable.  If we've vforked, this
>> -         clobbers the parent, but environ is restored a few lines down
>> -         in the parent.  By the way, yes we do need to look down the
>> -         path to find $SHELL.  Rich Pixley says so, and I agree.  */
>> -      environ = env;
>> -
>> -      if (exec_fun != NULL)
>> -        (*exec_fun) (argv[0], argv, env);
>> -      else
>> -        execvp (argv[0], argv);
>> -
>> -      /* If we get here, it's an error.  */
>> -      save_errno = errno;
>> -      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
>> -      for (i = 1; argv[i] != NULL; i++)
>> -	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
>> -      fprintf_unfiltered (gdb_stderr, ".\n");
>> -      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
>> -			  safe_strerror (save_errno));
>> -      gdb_flush (gdb_stderr);
>> -      _exit (0177);
>> -    }
>> -
>> -  /* Restore our environment in case a vforked child clob'd it.  */
>> -  environ = save_our_env;
>> -
>> -  /* Likewise the current UI.  */
>> -  current_ui = save_ui;
>> -
>> -  if (!have_inferiors ())
>> -    init_thread_list ();
>> -
>> -  inf = current_inferior ();
>> -
>> -  inferior_appeared (inf, pid);
>> -
>> -  /* Needed for wait_for_inferior stuff below.  */
>> -  inferior_ptid = pid_to_ptid (pid);
>> -
>> -  new_tty_postfork ();
>> -
>> -  /* We have something that executes now.  We'll be running through
>> -     the shell at this point, but the pid shouldn't change.  Targets
>> -     supporting MT should fill this task's ptid with more data as soon
>> -     as they can.  */
>> -  add_thread_silent (inferior_ptid);
>> -
>> -  /* Now that we have a child process, make it our target, and
>> -     initialize anything target-vector-specific that needs
>> -     initializing.  */
>> -  if (init_trace_fun)
>> -    (*init_trace_fun) (pid);
>> -
>> -  /* We are now in the child process of interest, having exec'd the
>> -     correct program, and are poised at the first instruction of the
>> -     new program.  */
>> -  return pid;
>> -}
>> -
>> -/* Accept NTRAPS traps from the inferior.  */
>> -
>> -void
>> -startup_inferior (int ntraps)
>> -{
>> -  int pending_execs = ntraps;
>> -  int terminal_initted = 0;
>> -  ptid_t resume_ptid;
>> -
>> -  if (startup_with_shell)
>> -    {
>> -      /* One trap extra for exec'ing the shell.  */
>> -      pending_execs++;
>> -    }
>> -
>> -  if (target_supports_multi_process ())
>> -    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
>> -  else
>> -    resume_ptid = minus_one_ptid;
>> -
>> -  /* The process was started by the fork that created it, but it will
>> -     have stopped one instruction after execing the shell.  Here we
>> -     must get it up to actual execution of the real program.  */
>> -
>> -  if (exec_wrapper)
>> -    pending_execs++;
>> -
>> -  while (1)
>> -    {
>> -      enum gdb_signal resume_signal = GDB_SIGNAL_0;
>> -      ptid_t event_ptid;
>> -
>> -      struct target_waitstatus ws;
>> -      memset (&ws, 0, sizeof (ws));
>> -      event_ptid = target_wait (resume_ptid, &ws, 0);
>> -
>> -      if (ws.kind == TARGET_WAITKIND_IGNORE)
>> -	/* The inferior didn't really stop, keep waiting.  */
>> -	continue;
>> -
>> -      switch (ws.kind)
>> -	{
>> -	  case TARGET_WAITKIND_SPURIOUS:
>> -	  case TARGET_WAITKIND_LOADED:
>> -	  case TARGET_WAITKIND_FORKED:
>> -	  case TARGET_WAITKIND_VFORKED:
>> -	  case TARGET_WAITKIND_SYSCALL_ENTRY:
>> -	  case TARGET_WAITKIND_SYSCALL_RETURN:
>> -	    /* Ignore gracefully during startup of the inferior.  */
>> -	    switch_to_thread (event_ptid);
>> -	    break;
>> -
>> -	  case TARGET_WAITKIND_SIGNALLED:
>> -	    target_terminal_ours ();
>> -	    target_mourn_inferior (event_ptid);
>> -	    error (_("During startup program terminated with signal %s, %s."),
>> -		   gdb_signal_to_name (ws.value.sig),
>> -		   gdb_signal_to_string (ws.value.sig));
>> -	    return;
>> -
>> -	  case TARGET_WAITKIND_EXITED:
>> -	    target_terminal_ours ();
>> -	    target_mourn_inferior (event_ptid);
>> -	    if (ws.value.integer)
>> -	      error (_("During startup program exited with code %d."),
>> -		     ws.value.integer);
>> -	    else
>> -	      error (_("During startup program exited normally."));
>> -	    return;
>> -
>> -	  case TARGET_WAITKIND_EXECD:
>> -	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
>> -	    xfree (ws.value.execd_pathname);
>> -	    resume_signal = GDB_SIGNAL_TRAP;
>> -	    switch_to_thread (event_ptid);
>> -	    break;
>> -
>> -	  case TARGET_WAITKIND_STOPPED:
>> -	    resume_signal = ws.value.sig;
>> -	    switch_to_thread (event_ptid);
>> -	    break;
>> -	}
>> -
>> -      if (resume_signal != GDB_SIGNAL_TRAP)
>> -	{
>> -	  /* Let shell child handle its own signals in its own way.  */
>> -	  target_continue (resume_ptid, resume_signal);
>> -	}
>> -      else
>> -	{
>> -	  /* We handle SIGTRAP, however; it means child did an exec.  */
>> -	  if (!terminal_initted)
>> -	    {
>> -	      /* Now that the child has exec'd we know it has already
>> -	         set its process group.  On POSIX systems, tcsetpgrp
>> -	         will fail with EPERM if we try it before the child's
>> -	         setpgid.  */
>> -
>> -	      /* Set up the "saved terminal modes" of the inferior
>> -	         based on what modes we are starting it with.  */
>> -	      target_terminal_init ();
>> -
>> -	      /* Install inferior's terminal modes.  */
>> -	      target_terminal_inferior ();
>> -
>> -	      terminal_initted = 1;
>> -	    }
>> -
>> -	  if (--pending_execs == 0)
>> -	    break;
>> -
>> -	  /* Just make it go on.  */
>> -	  target_continue_no_signal (resume_ptid);
>> -	}
>> -    }
>> -
>> -  /* Mark all threads non-executing.  */
>> -  set_executing (resume_ptid, 0);
>> +  return exec_wrapper;
>>  }
>>
>>  /* Implement the "unset exec-wrapper" command.  */
>> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
>> index 74e199b..9b6e96a 100644
>> --- a/gdb/gdbserver/Makefile.in
>> +++ b/gdb/gdbserver/Makefile.in
>> @@ -185,6 +185,7 @@ SFILES = \
>>  	$(srcdir)/target.c \
>>  	$(srcdir)/thread-db.c \
>>  	$(srcdir)/utils.c \
>> +	$(srcdir)/terminal.c \
>>  	$(srcdir)/win32-arm-low.c \
>>  	$(srcdir)/win32-i386-low.c \
>>  	$(srcdir)/win32-low.c \
>> @@ -204,6 +205,7 @@ SFILES = \
>>  	$(srcdir)/common/environ.c \
>>  	$(srcdir)/common/fileio.c \
>>  	$(srcdir)/common/filestuff.c \
>> +	$(srcdir)/common/common-fork-child.c \
>>  	$(srcdir)/common/common-inflow.c \
>>  	$(srcdir)/common/gdb_vecs.c \
>>  	$(srcdir)/common/new-op.c \
>> @@ -235,6 +237,7 @@ OBS = \
>>  	cleanups.o \
>>  	common-debug.o \
>>  	common-exceptions.o \
>> +	common-fork-child.o \
>>  	common-inflow.o \
>>  	common-regcache.o \
>>  	common-utils.o \
>> @@ -269,6 +272,7 @@ OBS = \
>>  	version.o \
>>  	waitstatus.o \
>>  	xml-utils.o \
>> +	terminal.o \
>>  	$(DEPFILES) \
>>  	$(LIBOBJS) \
>>  	$(XML_BUILTIN)
>> @@ -772,6 +776,9 @@ format.o: ../common/format.c
>>  filestuff.o: ../common/filestuff.c
>>  	$(COMPILE) $<
>>  	$(POSTCOMPILE)
>> +common-fork-child.o: ../common/common-fork-child.c
>> +	$(COMPILE) $<
>> +	$(POSTCOMPILE)
>>  common-inflow.o: ../common/common-inflow.c
>>  	$(COMPILE) $<
>>  	$(POSTCOMPILE)
>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>> index 441ec2c..21346cb 100644
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>>
>>  #define get_thread(inf) ((struct thread_info *)(inf))
>>
>> +ptid_t inferior_ptid;
>> +
>>  void
>>  add_inferior_to_list (struct inferior_list *list,
>>  		      struct inferior_list_entry *new_inferior)
>> @@ -469,12 +471,31 @@ make_cleanup_restore_current_thread (void)
>>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>>  }
>>
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +inferior_appeared (struct inferior *inf, int pid)
>> +{
>> +  /* Placeholder needed for fork_inferior.  We do not have to do
>> +     anything in this case.  */
>> +}
>
> I'm still slightly confused about the presence of these empty
> functions. This particular one is meant to notify observers, correct?
> How do you envision this particular function being used for gdbserver
> in the future?

I understand your confusion, so I'll try to explain why these
placeholders are there.

I do not necessarily envision gdbserver using these functions in the
future.  Maybe it will, maybe it won't.  For now, they are needed to
have a full compilation of the fork_inferior function on gdbserver,
which is the biggest goal of this patch.  I don't plan to tackle the
problem of observers on gdbserver, or the problem of dealing with
inferior/target terminal modes on gdbserver, etc.  At least not in the
near future.  One could argue that maybe these functions will not be
useful for gdbserver at all (after all, why would we want to mess with
terminal modes there?  I don't know offhand).

Having said that, the situation now is that these functions are well
integrated into fork_inferior/startup_inferior, and it's not necessarily
easy to decouple them.  I chose the fastest route here and just added
the empty placeholders on gdbserver, with explanatory comments as to why
they are not needed right now.  I particularly don't think this is bad
per se; I think the number of placeholders is reasonable for a feature
like this.

In the future, I guess the idea would be to invest time on breaking
fork_inferior/startup_inferior even more, so that their dependency on
these GDB-specific functions could be split into smaller parts so that
we wouldn't have to worry about them on the gdbserver side.  But maybe
others will have different ideas on how to tackle the problem.

>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +struct inferior *
>> +current_inferior (void)
>> +{
>> +  /* Placeholder needed for fork_inferior.  gdbserver has other
>
> GDBserver

Fixed.

>> +     functions that serve this purpose.  */
>> +  return NULL;
>> +}
>> +
>>  /* See common/common-gdbthread.h.  */
>>
>>  void
>>  init_thread_list (void)
>>  {
>> -  /* To be implemented.  */
>> +  /* Placeholder needed for fork_inferior.  No action is needed.  */
>>  }
>
> Same here. Do you have an idea how this is going to be used for gdbserver?

See answer for inferior_appeared.

>>
>>  /* See common/common-gdbthread.h.  */
>> @@ -509,3 +530,11 @@ add_thread_silent (ptid_t ptid)
>>
>>    return add_thread (ptid_build (pid, pid, 0), NULL);
>>  }
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +int
>> +have_inferiors (void)
>> +{
>> +  return get_first_process () != NULL;
>> +}
>> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
>> index e27cbf8..170e8f2 100644
>> --- a/gdb/gdbserver/linux-low.c
>> +++ b/gdb/gdbserver/linux-low.c
>> @@ -47,6 +47,8 @@
>>  #include "tracepoint.h"
>>  #include "hostio.h"
>>  #include <inttypes.h>
>> +#include "common-inferior.h"
>> +#include "environ.h"
>>  #ifndef ELFMAG0
>>  /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
>>     then ELFMAG0 will have been defined.  If it didn't get included by
>> @@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
>>    free (lwp);
>>  }
>>
>> -/* Add a process to the common process list, and set its private
>> -   data.  */
>> +/* Update process represented by PID with necessary info.  */
>>
>>  static struct process_info *
>> -linux_add_process (int pid, int attached)
>> +linux_update_process (int pid)
>>  {
>> -  struct process_info *proc;
>> +  struct process_info *proc = find_process_pid (pid);
>>
>> -  proc = add_process (pid, attached);
>> +  gdb_assert (proc != NULL);
>>    proc->priv = XCNEW (struct process_info_private);
>>
>>    if (the_low_target.new_process != NULL)
>> @@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
>>    return proc;
>>  }
>>
>> +/* Add a process to the common process list, and set its private
>> +   data.  */
>> +
>> +static struct process_info *
>> +linux_add_process (int pid, int attached)
>> +{
>> +  add_process (pid, attached);
>> +  return linux_update_process (pid);
>> +}
>> +
>>  static CORE_ADDR get_pc (struct lwp_info *lwp);
>>
>>  /* Call the target arch_setup function on the current thread.  */
>> @@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
>>    return 1;
>>  }
>>
>> +/* Update the lwp associated to thread represented by PTID.  */
>> +
>> +static struct lwp_info *
>> +update_thread_lwp (ptid_t ptid)
>> +{
>> +  struct lwp_info *lwp;
>> +  struct thread_info *thread;
>> +
>> +  lwp = XCNEW (struct lwp_info);
>> +
>> +  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
>> +
>> +  if (the_low_target.new_thread != NULL)
>> +    the_low_target.new_thread (lwp);
>> +
>> +  thread = find_thread_ptid (ptid);
>> +  gdb_assert (thread != NULL);
>> +  thread->target_data = lwp;
>> +  lwp->thread = thread;
>> +
>> +  return lwp;
>> +}
>> +
>>  static struct lwp_info *
>>  add_lwp (ptid_t ptid)
>>  {
>> @@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
>>    return lwp;
>>  }
>>
>> +/* Callback to be used when calling fork_inferior, responsible for
>> +   actually initiating the tracing of the inferior.  */
>> +
>> +static void
>> +linux_ptrace_fun (void)
>> +{
>> +  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
>> +
>> +  setpgid (0, 0);
>> +
>> +  /* If gdbserver is connected to gdb via stdio, redirect the inferior's
>
> GDBserver.

I didn't write this comment, but I'll fix this anyway.

>> +     stdout to stderr so that inferior i/o doesn't corrupt the connection.
>> +     Also, redirect stdin to /dev/null.  */
>> +  if (remote_connection_is_stdio ())
>> +    {
>> +      close (0);
>> +      open ("/dev/null", O_RDONLY);
>> +      dup2 (2, 1);
>> +      if (write (2, "stdin/stdout redirected\n",
>> +		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
>> +	{
>> +	  /* Errors ignored.  */;
>> +	}
>> +    }
>> +}
>> +
>>  /* Start an inferior process and returns its pid.
>>     ALLARGS is a vector of program-name and args. */
>>
>>  static int
>> -linux_create_inferior (char *program, char **allargs)
>> +linux_create_inferior (std::vector<char *> &program_argv)
>>  {
>>    struct lwp_info *new_lwp;
>>    int pid;
>>    ptid_t ptid;
>>    struct cleanup *restore_personality
>>      = maybe_disable_address_space_randomization (disable_randomization);
>> +  std::string program_args = stringify_argv (program_argv);
>>
>> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>> -  pid = vfork ();
>> -#else
>> -  pid = fork ();
>> -#endif
>> -  if (pid < 0)
>> -    perror_with_name ("fork");
>> +  pre_fork_inferior (program_argv);
>>
>> -  if (pid == 0)
>> -    {
>> -      close_most_fds ();
>> -      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
>> -
>> -      setpgid (0, 0);
>> -
>> -      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
>> -	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
>> -	 Also, redirect stdin to /dev/null.  */
>> -      if (remote_connection_is_stdio ())
>> -	{
>> -	  close (0);
>> -	  open ("/dev/null", O_RDONLY);
>> -	  dup2 (2, 1);
>> -	  if (write (2, "stdin/stdout redirected\n",
>> -		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
>> -	    {
>> -	      /* Errors ignored.  */;
>> -	    }
>> -	}
>> -
>> -      restore_original_signals_state ();
>> -
>> -      execv (program, allargs);
>> -      if (errno == ENOENT)
>> -	execvp (program, allargs);
>> -
>> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
>> -	       strerror (errno));
>> -      fflush (stderr);
>> -      _exit (0177);
>> -    }
>> +  pid = fork_inferior (program_argv[0],
>> +		       (char *) program_args.c_str (),
>> +		       environ_vector (get_environ ()), linux_ptrace_fun,
>> +		       NULL, NULL, NULL, NULL);
>>
>>    do_cleanups (restore_personality);
>>
>> -  linux_add_process (pid, 0);
>> +  linux_update_process (pid);
>>
>>    ptid = ptid_build (pid, pid, 0);
>> -  new_lwp = add_lwp (ptid);
>> +  new_lwp = update_thread_lwp (ptid);
>>    new_lwp->must_set_ptrace_flags = 1;
>>
>> +  post_fork_inferior (pid, program_argv);
>> +
>>    return pid;
>>  }
>>
>> diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
>> index d300aae..296fd6f 100644
>> --- a/gdb/gdbserver/lynx-low.c
>> +++ b/gdb/gdbserver/lynx-low.c
>> @@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
>>    return result;
>>  }
>>
>> -/* Call add_process with the given parameters, and initializes
>> -   the process' private data.  */
>> +/* Update existing process represented by PID with necessary info.  */
>>
>>  static struct process_info *
>> -lynx_add_process (int pid, int attached)
>> +lynx_update_process (int pid)
>>  {
>> -  struct process_info *proc;
>> +  struct process_info *proc = find_process_pid (pid);
>> +
>> +  gdb_assert (proc != NULL);
>>
>> -  proc = add_process (pid, attached);
>>    proc->tdesc = lynx_tdesc;
>>    proc->priv = XCNEW (struct process_info_private);
>>    proc->priv->last_wait_event_ptid = null_ptid;
>> @@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
>>    return proc;
>>  }
>>
>> +/* Call add_process with the given parameters, and initializes
>> +   the process' private data.  */
>> +
>> +static struct process_info *
>> +lynx_add_process (int pid, int attached)
>> +{
>> +  add_process (pid, attached);
>> +  return lynx_update_process (pid);
>> +}
>> +
>> +static void
>> +lynx_ptrace_fun (void)
>> +{
>> +  int pgrp;
>> +
>> +  /* Switch child to its own process group so that signals won't
>> +     directly affect gdbserver. */
>
> GDBserver.

Likewise.

>> +  pgrp = getpid();
>> +  setpgid (0, pgrp);
>> +  ioctl (0, TIOCSPGRP, &pgrp);
>> +  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
>> +}
>> +
>>  /* Implement the create_inferior method of the target_ops vector.  */
>>
>>  static int
>> -lynx_create_inferior (char *program, char **allargs)
>> +lynx_create_inferior (std::vector<char *> &program_argv)
>>  {
>>    int pid;
>>
>>    lynx_debug ("lynx_create_inferior ()");
>>
>> -  pid = fork ();
>> -  if (pid < 0)
>> -    perror_with_name ("fork");
>> +  pre_fork_inferior (program_argv);
>>
>> -  if (pid == 0)
>> -    {
>> -      int pgrp;
>> -
>> -      close_most_fds ();
>> -
>> -      /* Switch child to its own process group so that signals won't
>> -         directly affect gdbserver. */
>> -      pgrp = getpid();
>> -      setpgid (0, pgrp);
>> -      ioctl (0, TIOCSPGRP, &pgrp);
>> -      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
>> -      execv (program, allargs);
>> -      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
>> -      fflush (stderr);
>> -      _exit (0177);
>> -    }
>> +  pid = fork_inferior (program_argv[0],
>> +		       (char *) program_args.c_str (),
>> +		       environ_vector (get_environ ()), lynx_ptrace_fun,
>> +		       NULL, NULL, NULL, NULL);
>>
>> -  lynx_add_process (pid, 0);
>> +  post_fork_inferior (pid, program_argv);
>> +
>> +  lynx_update_process (pid, 0);
>>    /* Do not add the process thread just yet, as we do not know its tid.
>>       We will add it later, during the wait for the STOP event corresponding
>>       to the lynx_ptrace (PTRACE_TRACEME) call above.  */
>> +  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
>> +
>>    return pid;
>>  }
>>
>> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
>> index 6229b4c..ea2a3a4 100644
>> --- a/gdb/gdbserver/nto-low.c
>> +++ b/gdb/gdbserver/nto-low.c
>> @@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
>>    return len_read;
>>  }
>>
>> -/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
>> +/* Start inferior specified by PROGRAM_ARGV.  */
>>
>>  static int
>> -nto_create_inferior (char *program, char **allargs)
>> +nto_create_inferior (std::vector<char *> &program_argv)
>>  {
>>    struct inheritance inherit;
>>    pid_t pid;
>>    sigset_t set;
>> +  std::string program_args = stringify_argv (program_argv);
>
> I'm thinking... Stringifying a vector of char * sounds like something
> that could be done outside of the target-specific create_inferior
> functions. Can't we pass the arguments already stringified to the
> target-specific create_inferior function?

Yes, the "stringification" could be done earlier, but then we'd have to
pull the argv[0] out of that string, so in the end I think it's a matter
of taste.  I prefer to stringify on demand.

As soon as this patch is approved, I intend to send other patches
cleaning up several parts of this code.  One of the cleanups I will make
is to C++-fy the arguments of fork_inferior et al.  So hold your horses
a little bit more ;-).

>>
>> -  TRACE ("%s %s\n", __func__, program);
>> +  TRACE ("%s %s\n", __func__, program_argv[0]);
>>    /* Clear any pending SIGUSR1's but keep the behavior the same.  */
>>    signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
>>
>> @@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
>>    memset (&inherit, 0, sizeof (inherit));
>>    inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
>>    inherit.pgroup = SPAWN_NEWPGROUP;
>> -  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
>> +  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
>>    sigprocmask (SIG_BLOCK, &set, NULL);
>>
>>    if (pid == -1)
>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>> index 43d9406..a26ad52 100644
>> --- a/gdb/gdbserver/server.c
>> +++ b/gdb/gdbserver/server.c
>> @@ -35,6 +35,26 @@
>>  #include "tracepoint.h"
>>  #include "dll.h"
>>  #include "hostio.h"
>> +#include "common-inferior.h"
>> +#include "common-terminal.h"
>> +#include "common-top.h"
>> +#include "environ.h"
>> +
>> +/* We don't have a concept of a UI yet.  Therefore, we just set these
>> +   to NULL.  */
>> +
>> +struct ui *main_ui = NULL;
>> +struct ui *current_ui = NULL;
>> +
>> +/* The environment to pass to the inferior when creating it.  */
>> +
>> +struct gdb_environ *our_environ = NULL;
>> +
>> +/* Start the inferior using a shell.  */
>> +
>> +/* We always try to start the inferior using a shell.  */
>> +
>> +int startup_with_shell = 1;
>
> Maybe turn startup_with_shell to bool now that we require C++? It will
> only be on/off, right?

I suppose it should be possible to turn that into a bool.  The only nit
is that add_setshow_boolean_cmd takes a pointer to an int as the
parameter to be modified by user, so I had to explicitly cast the
variable to (int *) in order to make it work.

>>  /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
>>     `vCont'.  Note the multi-process extensions made `vCont' a
>> @@ -78,7 +98,8 @@ static int vCont_supported;
>>     space randomization feature before starting an inferior.  */
>>  int disable_randomization = 1;
>>
>> -static char **program_argv, **wrapper_argv;
>> +static std::vector<char *> program_argv;
>> +static std::vector<char *> wrapper_argv;
>>
>>  int pass_signals[GDB_SIGNAL_LAST];
>>  int program_signals[GDB_SIGNAL_LAST];
>> @@ -244,33 +265,64 @@ get_last_target_waitstatus (void)
>>    return last_status;
>>  }
>>
>> -static int
>> -start_inferior (char **argv)
>> +/* See common/common-inferior.h.  */
>> +
>> +char *
>> +get_exec_wrapper (void)
>>  {
>> -  char **new_argv = argv;
>> +  static std::string ret;
>> +  static int initialized_p = 0;
>> +
>> +  if (wrapper_argv.empty ())
>> +    return NULL;
>>
>> -  if (wrapper_argv != NULL)
>> +  if (!initialized_p)
>>      {
>> -      int i, count = 1;
>> -
>> -      for (i = 0; wrapper_argv[i] != NULL; i++)
>> -	count++;
>> -      for (i = 0; argv[i] != NULL; i++)
>> -	count++;
>> -      new_argv = XALLOCAVEC (char *, count);
>> -      count = 0;
>> -      for (i = 0; wrapper_argv[i] != NULL; i++)
>> -	new_argv[count++] = wrapper_argv[i];
>> -      for (i = 0; argv[i] != NULL; i++)
>> -	new_argv[count++] = argv[i];
>> -      new_argv[count] = NULL;
>> +      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
>> +	   i != wrapper_argv.end ();
>> +	   ++i)
>> +	ret += *i + std::string (" ");
>> +
>> +      /* Erasing the last whitespace.  */
>> +      ret.erase (ret.end () - 1);
>> +
>> +      initialized_p = 1;
>>      }
>>
>> +  return (char *) ret.c_str ();
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +char *
>> +get_exec_file (int err)
>> +{
>> +  if (err && program_argv.empty ())
>> +    error (_("Could not get the exec file."));
>> +  return program_argv[0];
>> +}
>> +
>> +/* See server.h.  */
>> +
>> +struct gdb_environ *
>> +get_environ (void)
>> +{
>> +  return our_environ;
>> +}
>> +
>> +/* See server.h.  */
>> +
>> +void
>> +pre_fork_inferior (std::vector<char *> &argv)
>> +{
>>    if (debug_threads)
>>      {
>> -      int i;
>> -      for (i = 0; new_argv[i]; ++i)
>> -	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
>> +      int idx = 0;
>> +
>> +      for (std::vector<char *>::iterator i = argv.begin ();
>> +	   i != argv.end ();
>> +	   ++i, ++idx)
>> +	debug_printf ("new_argv[%d] = \"%s\"\n", idx, *i);
>
> Candidate for a range for loop format. Only a suggestion.

Right.  Done.

>>        debug_flush ();
>>      }
>>
>> @@ -279,67 +331,35 @@ start_inferior (char **argv)
>>    signal (SIGTTIN, SIG_DFL);
>>  #endif
>>
>> -  signal_pid = create_inferior (new_argv[0], new_argv);
>> +  /* Clear this so the backend doesn't get confused, thinking
>> +     CONT_THREAD died, and it needs to resume all threads.  */
>> +  cont_thread = null_ptid;
>> +}
>>
>> -  /* FIXME: we don't actually know at this point that the create
>> -     actually succeeded.  We won't know that until we wait.  */
>> -  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
>> -	   signal_pid);
>> -  fflush (stderr);
>> +/* See server.h.  */
>> +
>> +void
>> +post_fork_inferior (int pid,
>> +		    std::vector<char *> &argv)
>> +{
>> +  /* Number of traps to be expected by startup_inferior.  We always
>> +     expect at least one trap for the main executable.  */
>> +  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
>>
>>  #ifdef SIGTTOU
>>    signal (SIGTTOU, SIG_IGN);
>>    signal (SIGTTIN, SIG_IGN);
>>    terminal_fd = fileno (stderr);
>>    old_foreground_pgrp = tcgetpgrp (terminal_fd);
>> -  tcsetpgrp (terminal_fd, signal_pid);
>> +  tcsetpgrp (terminal_fd, pid);
>>    atexit (restore_old_foreground_pgrp);
>>  #endif
>>
>> -  if (wrapper_argv != NULL)
>> -    {
>> -      ptid_t ptid = pid_to_ptid (signal_pid);
>> -
>> -      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
>> -
>> -      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>> -	{
>> -	  do
>> -	    {
>> -	      target_continue_no_signal (ptid);
>> -
>> -	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
>> -	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
>> -		break;
>> -
>> -	      current_thread->last_resume_kind = resume_stop;
>> -	      current_thread->last_status = last_status;
>> -	    }
>> -	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
>> -	}
>> -      target_post_create_inferior ();
>> -      return signal_pid;
>> -    }
>> -
>> -  /* Wait till we are at 1st instruction in program, return new pid
>> -     (assuming success).  */
>> -  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
>> -
>> -  /* At this point, the target process, if it exits, is stopped.  Do not call
>> -     the function target_post_create_inferior if the process has already
>> -     exited, as the target implementation of the routine may rely on the
>> -     process being live. */
>> -  if (last_status.kind != TARGET_WAITKIND_EXITED
>> -      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
>> -    {
>> -      target_post_create_inferior ();
>> -      current_thread->last_resume_kind = resume_stop;
>> -      current_thread->last_status = last_status;
>> -    }
>> -  else
>> -    target_mourn_inferior (last_ptid);
>> -
>> -  return signal_pid;
>> +  startup_inferior (num_traps, &last_status, &last_ptid);
>> +  signal_pid = pid;
>> +  target_post_create_inferior ();
>> +  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
>> +  fflush (stderr);
>>  }
>>
>>  static int
>> @@ -2860,8 +2880,10 @@ handle_v_attach (char *own_buf)
>>  static int
>>  handle_v_run (char *own_buf)
>>  {
>> -  char *p, *next_p, **new_argv;
>> -  int i, new_argc;
>> +  char *p, *next_p;
>> +  std::vector<char *> new_argv;
>> +  int new_argc;
>> +  int i;
>>
>>    new_argc = 0;
>>    for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
>> @@ -2870,62 +2892,91 @@ handle_v_run (char *own_buf)
>>        new_argc++;
>>      }
>>
>> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
>> -  if (new_argv == NULL)
>> -    {
>> -      write_enn (own_buf);
>> -      return 0;
>> -    }
>> -
>> -  i = 0;
>> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
>> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>>      {
>>        next_p = strchr (p, ';');
>>        if (next_p == NULL)
>>  	next_p = p + strlen (p);
>>
>> -      if (i == 0 && p == next_p)
>> -	new_argv[i] = NULL;
>> +      if (p == next_p)
>> +	new_argv.push_back ("''");
>>        else
>>  	{
>>  	  /* FIXME: Fail request if out of memory instead of dying.  */
>> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
>> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
>> -	  new_argv[i][(next_p - p) / 2] = '\0';
>> +	  size_t len = 1 + (next_p - p) / 2;
>> +	  char *s = (char *) xmalloc (len);
>> +	  char *ss = (char *) xmalloc (len * 2);
>> +	  char *tmp_s, *tmp_ss;
>> +	  int need_quote;
>> +
>> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
>> +	  s[(next_p - p) / 2] = '\0';
>> +
>> +	  tmp_s = s;
>> +	  tmp_ss = ss;
>> +	  need_quote = 0;
>> +	  while (*tmp_s != '\0')
>> +	    {
>> +	      switch (*tmp_s)
>> +		{
>> +		case '\n':
>> +		  *tmp_ss = '\'';
>> +		  ++tmp_ss;
>> +		  need_quote = 1;
>> +		  break;
>> +
>> +		case '\'':
>> +		  *tmp_ss = '\\';
>> +		  ++tmp_ss;
>> +		  break;
>> +
>> +		default:
>> +		  break;
>> +		}
>> +
>> +	      *tmp_ss = *tmp_s;
>> +	      ++tmp_ss;
>> +	      ++tmp_s;
>> +	    }
>> +
>> +	  if (need_quote)
>> +	    *tmp_ss++ = '\'';
>> +
>> +	  *tmp_ss = '\0';
>> +	  new_argv.push_back (ss);
>> +	  xfree (s);
>>  	}
>>
>>        if (*next_p)
>>  	next_p++;
>> -      i++;
>>      }
>> -  new_argv[i] = NULL;
>>
>> -  if (new_argv[0] == NULL)
>> +  if (new_argv.empty () || new_argv[0] == NULL)
>>      {
>>        /* GDB didn't specify a program to run.  Use the program from the
>>  	 last run with the new argument list.  */
>>
>> -      if (program_argv == NULL)
>> +      if (program_argv.empty ())
>>  	{
>>  	  write_enn (own_buf);
>> -	  freeargv (new_argv);
>> +	  free_vector_argv (new_argv);
>>  	  return 0;
>>  	}
>>
>> -      new_argv[0] = strdup (program_argv[0]);
>> -      if (new_argv[0] == NULL)
>> +      new_argv.push_back (strdup (program_argv[0]));
>> +      if (new_argv.empty () || new_argv[0] == NULL)
>>  	{
>>  	  write_enn (own_buf);
>> -	  freeargv (new_argv);
>> +	  free_vector_argv (new_argv);
>>  	  return 0;
>>  	}
>>      }
>>
>>    /* Free the old argv and install the new one.  */
>> -  freeargv (program_argv);
>> +  free_vector_argv (program_argv);
>>    program_argv = new_argv;
>>
>> -  start_inferior (program_argv);
>> +  create_inferior (program_argv);
>>    if (last_status.kind == TARGET_WAITKIND_STOPPED)
>>      {
>>        prepare_resume_reply (own_buf, last_ptid, &last_status);
>> @@ -3543,13 +3594,18 @@ captured_main (int argc, char *argv[])
>>  	multi_mode = 1;
>>        else if (strcmp (*next_arg, "--wrapper") == 0)
>>  	{
>> +	  char **tmp;
>> +
>>  	  next_arg++;
>>
>> -	  wrapper_argv = next_arg;
>> +	  tmp = next_arg;
>>  	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
>> -	    next_arg++;
>> +	    {
>> +	      wrapper_argv.push_back (*next_arg);
>> +	      next_arg++;
>> +	    }
>>
>> -	  if (next_arg == wrapper_argv || *next_arg == NULL)
>> +	  if (next_arg == tmp || *next_arg == NULL)
>>  	    {
>>  	      gdbserver_usage (stderr);
>>  	      exit (1);
>> @@ -3680,8 +3736,14 @@ captured_main (int argc, char *argv[])
>>        exit (1);
>>      }
>>
>> +  /* Gather information about the environment.  */
>> +  our_environ = make_environ ();
>> +  init_environ (our_environ);
>> +
>>    initialize_async_io ();
>>    initialize_low ();
>> +  /* This is called when initializing inflow on GDB.  */
>> +  have_job_control ();
>>    initialize_event_loop ();
>>    if (target_supports_tracepoints ())
>>      initialize_tracepoint ();
>> @@ -3695,13 +3757,11 @@ captured_main (int argc, char *argv[])
>>        int i, n;
>>
>>        n = argc - (next_arg - argv);
>> -      program_argv = XNEWVEC (char *, n + 1);
>>        for (i = 0; i < n; i++)
>> -	program_argv[i] = xstrdup (next_arg[i]);
>> -      program_argv[i] = NULL;
>> +	program_argv.push_back (xstrdup (next_arg[i]));
>>
>>        /* Wait till we are at first instruction in program.  */
>> -      start_inferior (program_argv);
>> +      create_inferior (program_argv);
>>
>>        /* We are now (hopefully) stopped at the first instruction of
>>  	 the target process.  This assumes that the target process was
>> @@ -4316,9 +4376,9 @@ process_serial_event (void)
>>  	  fprintf (stderr, "GDBserver restarting\n");
>>
>>  	  /* Wait till we are at 1st instruction in prog.  */
>> -	  if (program_argv != NULL)
>> +	  if (!program_argv.empty ())
>>  	    {
>> -	      start_inferior (program_argv);
>> +	      create_inferior (program_argv);
>>  	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>>  		{
>>  		  /* Stopped at the first instruction of the target
>> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
>> index 71848f1..47e094a 100644
>> --- a/gdb/gdbserver/server.h
>> +++ b/gdb/gdbserver/server.h
>> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  #include "utils.h"
>>  #include "debug.h"
>>  #include "gdb_vecs.h"
>> +#include <vector>
>>
>>  /* Maximum number of bytes to read/write at once.  The value here
>>     is chosen to fill up a packet (the headers account for the 32).  */
>> @@ -151,4 +152,19 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  /* Return the global variable LAST_STATUS from server.c.  */
>>  extern struct target_waitstatus get_last_target_waitstatus (void);
>>
>> +/* Any pre-processing needed to be done before calling fork_inferior
>> +   shall be implemented here.  ARGV is a vector containing the full
>> +   argv of the inferior.  */
>> +extern void pre_fork_inferior (std::vector<char *> &argv);
>> +
>> +/* After fork_inferior has been called, we need to adjust a few
>> +   signals and call startup_inferior.  This is done here.  PID is the
>> +   pid of the new inferior, and ARGV is the vector containing the full
>> +   argv of the inferior.  */
>> +extern void post_fork_inferior (int pid, std::vector<char *> &argv);
>> +
>> +/* Get the 'struct gdb_environ *' being used in the current
>> +   session.  */
>> +extern struct gdb_environ *get_environ (void);
>> +
>>  #endif /* SERVER_H */
>> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
>> index 117b871..7f26331 100644
>> --- a/gdb/gdbserver/spu-low.c
>> +++ b/gdb/gdbserver/spu-low.c
>> @@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
>>    return ret;
>>  }
>>
>> +/* Callback to be used when calling fork_inferior, responsible for
>> +   actually initiating the tracing of the inferior.  */
>> +
>> +static void
>> +spu_ptrace_fun (void)
>> +{
>> +  ptrace (PTRACE_TRACEME, 0, 0, 0);
>> +  setpgid (0, 0);
>> +}
>>
>>  /* Start an inferior process and returns its pid.
>> -   ALLARGS is a vector of program-name and args. */
>> +   PROGRAM_ARGV is a vector of program-name and args. */
>>  static int
>> -spu_create_inferior (char *program, char **allargs)
>> +spu_create_inferior (std::vector<char *> &program_argv)
>>  {
>>    int pid;
>>    ptid_t ptid;
>>    struct process_info *proc;
>> +  std::string program_args = stringify_argv (program_argv);
>>
>> -  pid = fork ();
>> -  if (pid < 0)
>> -    perror_with_name ("fork");
>> -
>> -  if (pid == 0)
>> -    {
>> -      close_most_fds ();
>> -      ptrace (PTRACE_TRACEME, 0, 0, 0);
>> -
>> -      setpgid (0, 0);
>> +  pre_fork_inferior (program_argv);
>>
>> -      execv (program, allargs);
>> -      if (errno == ENOENT)
>> -	execvp (program, allargs);
>> +  pid = fork_inferior (program_argv[0],
>> +		       (char *) program_args.c_str (),
>> +		       environ_vector (get_environ ()), spu_ptrace_fun,
>> +		       NULL, NULL, NULL, NULL);
>>
>> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
>> -	       strerror (errno));
>> -      fflush (stderr);
>> -      _exit (0177);
>> -    }
>> +  post_fork_inferior (pid, program_argv);
>>
>> -  proc = add_process (pid, 0);
>> +  proc = find_process_pid (pid);
>> +  gdb_assert (proc != NULL);
>>    proc->tdesc = tdesc_spu;
>>
>> -  ptid = ptid_build (pid, pid, 0);
>> -  add_thread (ptid, NULL);
>>    return pid;
>>  }
>>
>> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
>> index fda72e8..1e1d193 100644
>> --- a/gdb/gdbserver/target.c
>> +++ b/gdb/gdbserver/target.c
>> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>>    return size;
>>  }
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_init (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_inferior (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_ours (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>
> Same question as the other TODO functions. How do you envision these
> being used for gdbserver in the future?

See answer for inferior_appeared.

>> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
>> index 3cc2bc4..3f94115 100644
>> --- a/gdb/gdbserver/target.h
>> +++ b/gdb/gdbserver/target.h
>> @@ -28,6 +28,7 @@
>>  #include "target/waitstatus.h"
>>  #include "mem-break.h"
>>  #include "btrace-common.h"
>> +#include <vector>
>>
>>  struct emit_ops;
>>  struct buffer;
>> @@ -73,7 +74,7 @@ struct target_ops
>>       Returns the new PID on success, -1 on failure.  Registers the new
>>       process with the process list.  */
>>
>> -  int (*create_inferior) (char *program, char **args);
>> +  int (*create_inferior) (std::vector<char *> &program_argv);
>>
>>    /* Do additional setup after a new process is created, including
>>       exec-wrapper completion.  */
>> @@ -480,8 +481,8 @@ extern struct target_ops *the_target;
>>
>>  void set_target_ops (struct target_ops *);
>>
>> -#define create_inferior(program, args) \
>> -  (*the_target->create_inferior) (program, args)
>> +#define create_inferior(program) \
>> +  (*the_target->create_inferior) (program)
>>
>>  #define target_post_create_inferior()			 \
>>    do							 \
>> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
>> index 307d15a..004a78e 100644
>> --- a/gdb/gdbserver/utils.c
>> +++ b/gdb/gdbserver/utils.c
>> @@ -137,3 +137,38 @@ pfildes (gdb_fildes_t fd)
>>    return plongest (fd);
>>  #endif
>>  }
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +gdb_flush_out_err (void)
>> +{
>> +  fflush (stdout);
>> +  fflush (stderr);
>> +}
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +free_vector_argv (std::vector<char *> &v)
>> +{
>> +  for (char *&i : v)
>> +    xfree (i);
>> +
>> +  v.clear ();
>> +}
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +std::string
>> +stringify_argv (std::vector<char *> &argv)
>> +{
>> +  std::string ret ("");
>> +
>> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
>> +       i != argv.end ();
>> +       ++i)
>> +    ret += *i + std::string (" ");
>> +
>> +  return ret;
>> +}
>
> Did you want to C++11-ify the above function as well?

I wanted, but as you can see the loop must start at the second element,
which C++11 doesn't offer when you use the range loop idiom.

>> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
>> index b4ded31..a30d99a 100644
>> --- a/gdb/gdbserver/utils.h
>> +++ b/gdb/gdbserver/utils.h
>> @@ -19,7 +19,17 @@
>>  #ifndef UTILS_H
>>  #define UTILS_H
>>
>> +#include <vector>
>> +
>>  char *paddress (CORE_ADDR addr);
>>  char *pfildes (gdb_fildes_t fd);
>>
>> +/* Works like FREEARGV, but with std::vector.  */
>> +extern void free_vector_argv (std::vector<char *> &v);
>> +
>> +/* Given a vector of arguments ARGV, return a string equivalent to
>> +   joining all the arguments (starting from ARGV + 1) with a
>> +   whitespace separating them.  */
>> +extern std::string stringify_argv (std::vector<char *> &argv);
>> +
>>  #endif /* UTILS_H */
>> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
>> index d3ddbf5..c005a70 100644
>> --- a/gdb/gdbserver/win32-low.c
>> +++ b/gdb/gdbserver/win32-low.c
>> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>>  }
>>
>>  /* Start a new process.
>> -   PROGRAM is a path to the program to execute.
>> -   ARGS is a standard NULL-terminated array of arguments,
>> -   to be passed to the inferior as ``argv''.
>> +   PROGRAM_ARGV is the vector containing the inferior's argv.
>>     Returns the new PID on success, -1 on failure.  Registers the new
>>     process with the process list.  */
>>  static int
>> -win32_create_inferior (char *program, char **program_args)
>> +win32_create_inferior (std::vector<char *> &program_argv)
>>  {
>>  #ifndef USE_WIN32API
>>    char real_path[PATH_MAX];
>> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>>    int argc;
>>    PROCESS_INFORMATION pi;
>>    DWORD err;
>> +  char *program = program_argv[0];
>> +  std::string program_args = stringify_argv (program_argv);
>> +  char *args = (char *) program_args.c_str ();
>>
>>    /* win32_wait needs to know we're not attaching.  */
>>    attaching = 0;
>> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>>
>>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>>
>> +  pre_fork_inferior (program, argv);
>> +
>>  #ifndef USE_WIN32API
>>    orig_path = NULL;
>>    path_ptr = getenv ("PATH");
>> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>>    program = real_path;
>>  #endif
>>
>> -  argslen = 1;
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    argslen += strlen (program_args[argc]) + 1;
>> -  args = (char *) alloca (argslen);
>> -  args[0] = '\0';
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    {
>> -      /* FIXME: Can we do better about quoting?  How does Cygwin
>> -	 handle this?  */
>> -      strcat (args, " ");
>> -      strcat (args, program_args[argc]);
>> -    }
>>    OUTMSG2 (("Command line is \"%s\"\n", args));
>>
>>  #ifdef CREATE_NEW_PROCESS_GROUP
>> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>>
>>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>>
>> +  post_fork_inferior (current_process_id, program_argv);
>> +
>>    return current_process_id;
>>  }
>>
>> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
>> index 9935dcb..bccfd9c 100644
>> --- a/gdb/gnu-nat.c
>> +++ b/gdb/gnu-nat.c
>> @@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
>>    thread_change_ptid (inferior_ptid,
>>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>    inf->pending_execs = 0;
>>    /* Get rid of the old shell threads.  */
>>    prune_threads ();
>> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
>> index f61bfe7..e9a7de2 100644
>> --- a/gdb/inf-ptrace.c
>> +++ b/gdb/inf-ptrace.c
>> @@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>>
>>    discard_cleanups (back_to);
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>
>>    /* On some targets, there must be some explicit actions taken after
>>       the inferior has been started up.  */
>> diff --git a/gdb/inferior.h b/gdb/inferior.h
>> index 258cc29..e56d4ba 100644
>> --- a/gdb/inferior.h
>> +++ b/gdb/inferior.h
>> @@ -42,6 +42,7 @@ struct target_desc_info;
>>
>>  #include "progspace.h"
>>  #include "registry.h"
>> +#include "common-inferior.h"
>>
>>  #include "symfile-add-flags.h"
>>
>> @@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
>>
>>  extern void child_terminal_init_with_pgrp (int pgrp);
>>
>> -/* From fork-child.c */
>> -
>> -extern int fork_inferior (char *, char *, char **,
>> -			  void (*)(void),
>> -			  void (*)(int), void (*)(void), char *,
>> -                          void (*)(const char *,
>> -                                   char * const *, char * const *));
>> -
>> -
>> -extern void startup_inferior (int);
>> -
>>  extern char *construct_inferior_arguments (int, char **);
>>
>>  /* From infcmd.c */
>> diff --git a/gdb/procfs.c b/gdb/procfs.c
>> index 2269016..ac76be6 100644
>> --- a/gdb/procfs.c
>> +++ b/gdb/procfs.c
>> @@ -4375,7 +4375,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
>>    thread_change_ptid (pid_to_ptid (pid),
>>  		      ptid_build (pid, lwpid, 0));
>>
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>>
>>  #ifdef SYS_syssgi
>>    /* On mips-irix, we need to stop the inferior early enough during
>> diff --git a/gdb/target.h b/gdb/target.h
>> index f2b9181..99a1e9b 100644
>> --- a/gdb/target.h
>> +++ b/gdb/target.h
>> @@ -1529,17 +1529,6 @@ extern int target_terminal_is_inferior (void);
>>
>>  extern int target_terminal_is_ours (void);
>>
>> -/* Initialize the terminal settings we record for the inferior,
>> -   before we actually run the inferior.  */
>> -
>> -extern void target_terminal_init (void);
>> -
>> -/* Put the inferior's terminal settings into effect.  This is
>> -   preparation for starting or resuming the inferior.  This is a no-op
>> -   unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_inferior (void);
>> -
>>  /* Put some of our terminal settings into effect, enough to get proper
>>     results from our output, but do not change into or out of RAW mode
>>     so that no input is discarded.  This is a no-op if terminal_ours
>> @@ -1548,12 +1537,6 @@ extern void target_terminal_inferior (void);
>>
>>  extern void target_terminal_ours_for_output (void);
>>
>> -/* Put our terminal settings into effect.  First record the inferior's
>> -   terminal settings so they can be restored properly later.  This is
>> -   a no-op unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_ours (void);
>> -
>>  /* Return true if the target stack has a non-default
>>    "to_terminal_ours" method.  */
>>
>> diff --git a/gdb/target/target.h b/gdb/target/target.h
>> index 582852c..06b859c 100644
>> --- a/gdb/target/target.h
>> +++ b/gdb/target/target.h
>> @@ -95,4 +95,21 @@ extern void target_mourn_inferior (ptid_t ptid);
>>
>>  extern int target_supports_multi_process (void);
>>
>> +/* Initialize the terminal settings we record for the inferior,
>> +   before we actually run the inferior.  */
>> +
>
> Spurious newline.
>
>> +extern void target_terminal_init (void);
>> +
>> +/* Put the inferior's terminal settings into effect.  This is
>> +   preparation for starting or resuming the inferior.  This is a no-op
>> +   unless called with the main UI as current UI.  */
>> +
>
> Spurious newline.
>
>> +extern void target_terminal_inferior (void);
>> +
>> +/* Put our terminal settings into effect.  First record the inferior's
>> +   terminal settings so they can be restored properly later.  This is
>> +   a no-op unless called with the main UI as current UI.  */
>> +
>
> Spurious newline.

These 3 functions were copied from GDB's target.h.  I did not fix
anything when copying and pasting, so that's why the spurious newlines
are there.  Anyway, fixed now.

>> +extern void target_terminal_ours (void);
>> +
>>  #endif /* TARGET_COMMON_H */
>> diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
>> index d404564..fec138d 100644
>> --- a/gdb/testsuite/gdb.server/non-existing-program.exp
>> +++ b/gdb/testsuite/gdb.server/non-existing-program.exp
>> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>>  set msg "gdbserver exits cleanly"
>>  set saw_exiting 0
>>  expect {
>> -    # This is what we get on ptrace-based targets.
>> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
>> +    # This is what we get on ptrace-based targets with
>> +    # startup-with-shell disabled.
>> + -re "stdin/stdout redirected.*gdbserver: Cannot exec
> non-existing-program\r\ngdbserver: Error: No such file or
> directory\r\n\r\nDuring startup program exited with code
> 127\.\r\nExiting\r\n$" {
>> +	set saw_exiting 1
>> +	exp_continue
>> +    }
>> +    # Likewise, but with startup-with-shell enabled.
>> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>>  	set saw_exiting 1
>>  	exp_continue
>>      }
>> diff --git a/gdb/top.h b/gdb/top.h
>> index 2da92df..0c8d324 100644
>> --- a/gdb/top.h
>> +++ b/gdb/top.h
>> @@ -22,6 +22,7 @@
>>
>>  #include "buffer.h"
>>  #include "event-loop.h"
>> +#include "common-top.h"
>>
>>  struct tl_interp_info;
>>
>> @@ -144,14 +145,6 @@ struct ui
>>    struct ui_out *m_current_uiout;
>>  };
>>
>> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>> -   It always exists and is created automatically when GDB starts
>> -   up.  */
>> -extern struct ui *main_ui;
>> -
>> -/* The current UI.  */
>> -extern struct ui *current_ui;
>> -
>>  /* The list of all UIs.  */
>>  extern struct ui *ui_list;
>>
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index 119992e..357ea4f 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -3404,6 +3404,15 @@ strip_leading_path_elements (const char *path, int n)
>>    return p;
>>  }
>>
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +gdb_flush_out_err (void)
>> +{
>> +  gdb_flush (main_ui->m_gdb_stdout);
>> +  gdb_flush (main_ui->m_gdb_stderr);
>> +}
>> +
>>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>>  extern initialize_file_ftype _initialize_utils;
>>
>>
>

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-02-01 18:37     ` Luis Machado
@ 2017-02-07 22:39       ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-07 22:39 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, Pedro Alves, Eli Zaretskii

Hey Luis,

Thanks for the review.  Comments below.

On Wednesday, February 01 2017, Luis Machado wrote:

> On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
>> As part of the bigger work of sharing fork_inferior with gdbserver,
>> some parts of gdb/terminal.h also needed to be moved to a common
>> place.  These parts are:
>>
>> - The code responsible for determining some terminal-based define's
>>   based on available features;
>>
>> - job control;
>>
>> - terminal-related functions needed by fork_inferior;
>>
>> gdb/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
>> 	* common/common-terminal.h: New file, with parts of "terminal.h".
>> 	* terminal.h: Move terminal-related defines to
>> 	"common/common-terminal.h".  Include "common/common-terminal.h".
>> 	(new_tty_prefork): Move to "common/common-terminal.h".
>> 	(new_tty): Likewise.
>> 	(new_tty_postfork): Likewise.
>> 	(job_control): Likewise.
>> 	(create_tty_session): Likewise.
>> 	(gdb_setpgid): Likewise.
>> 	* utils.c: Include "terminal.h".
>>
>> gdb/gdbserver/ChangeLog:
>> 2016-12-22  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* terminal.c: New file.
>> ---
>>  gdb/Makefile.in              |   1 +
>>  gdb/common/common-terminal.h | 119 +++++++++++++++++++++++++++++++++++++++++++
>>  gdb/gdbserver/terminal.c     |  88 ++++++++++++++++++++++++++++++++
>>  gdb/terminal.h               |  73 +-------------------------
>>  gdb/utils.c                  |   1 +
>>  5 files changed, 210 insertions(+), 72 deletions(-)
>>  create mode 100644 gdb/common/common-terminal.h
>>  create mode 100644 gdb/gdbserver/terminal.c
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 3f19818..c05d456 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1469,6 +1469,7 @@ HFILES_NO_SRCDIR = \
>>  	common/common-regcache.h \
>>  	common/common-types.h \
>>  	common/common-utils.h \
>> +	common/common-terminal.h \
>>  	common/errors.h \
>>  	common/environ.h \
>>  	common/fileio.h \
>> diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
>> new file mode 100644
>> index 0000000..f7ab96a
>> --- /dev/null
>> +++ b/gdb/common/common-terminal.h
>> @@ -0,0 +1,119 @@
>> +/* Common terminal interface definitions for GDB and gdbserver.
>> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_TERMINAL_H
>> +#define COMMON_TERMINAL_H
>> +
>> +/* If we're using autoconf, it will define HAVE_TERMIOS_H,
>> +   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>> +   ser-unix.c and inflow.c to inspect those names instead of
>> +   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
>> +   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
>> +   nothing has already defined the one of the names, and do the right
>> +   thing.  */
>> +
>> +#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
>> +#if defined(HAVE_TERMIOS_H)
>> +#define HAVE_TERMIOS
>> +#else /* ! defined (HAVE_TERMIOS_H) */
>> +#if defined(HAVE_TERMIO_H)
>> +#define HAVE_TERMIO
>> +#else /* ! defined (HAVE_TERMIO_H) */
>> +#if defined(HAVE_SGTTY_H)
>> +#define HAVE_SGTTY
>> +#endif /* ! defined (HAVE_SGTTY_H) */
>> +#endif /* ! defined (HAVE_TERMIO_H) */
>> +#endif /* ! defined (HAVE_TERMIOS_H) */
>> +#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
>> +	  !defined (HAVE_SGTTY) */
>> +
>> +#if defined(HAVE_TERMIOS)
>> +#include <termios.h>
>> +#endif
>> +
>> +#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
>> +
>> +/* Define a common set of macros -- BSD based -- and redefine whatever
>> +   the system offers to make it look like that.  FIXME: serial.h and
>> +   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
>> +   is converted to use them, can get rid of this crap.  */
>> +
>> +#ifdef HAVE_TERMIO
>> +
>> +#include <termio.h>
>> +
>> +#undef TIOCGETP
>> +#define TIOCGETP TCGETA
>> +#undef TIOCSETN
>> +#define TIOCSETN TCSETA
>> +#undef TIOCSETP
>> +#define TIOCSETP TCSETAF
>> +#define TERMINAL struct termio
>> +
>> +#else /* sgtty */
>> +
>> +#include <fcntl.h>
>> +#include <sgtty.h>
>> +#include <sys/ioctl.h>
>> +#define TERMINAL struct sgttyb
>> +
>> +#endif /* sgtty */
>> +#endif
>> +
>> +#include <sys/types.h>
>> +
>> +/* Do we have job control?  Can be assumed to always be the same
>> +   within a given run of GDB.  Use in gdb/inflow.c and
>> +   common/common-inflow.c.  */
>> +extern int job_control;
>> +
>> +extern void new_tty (void);
>> +
>> +/* NEW_TTY_PREFORK is called before forking a new child process,
>> +   so we can record the state of ttys in the child to be formed.
>> +   TTYNAME is null if we are to share the terminal with gdb;
>
> This is still referencing only gdb, but the code is now shared with
> gdbserver as well.
>
>> +   or points to a string containing the name of the desired tty.
>> +
>> +   NEW_TTY is called in new child processes under Unix, which will
>> +   become debugger target processes.  This actually switches to
>> +   the terminal specified in the NEW_TTY_PREFORK call.  */
>> +extern void new_tty_prefork (const char *ttyname);
>> +
>> +/* NEW_TTY_POSTFORK is called after forking a new child process, and
>> +   adding it to the inferior table, to store the TTYNAME being used by
>> +   the child, or null if it sharing the terminal with gdb.  */
>
> Here as well.
>
>> +extern void new_tty_postfork (void);
>> +
>> +/* Create a new session if the inferior will run in a different tty.
>> +   A session is UNIX's way of grouping processes that share a controlling
>> +   terminal, so a new one is needed if the inferior terminal will be
>> +   different from GDB's.
>
> And here.

These are actually right (for now, at least), since they are just used
by GDB and their gdbserver counterpart are just placeholders.  I will
expand the comment to mention that.

>> +
>> +   Returns the session id of the new session, 0 if no session was created
>> +   or -1 if an error occurred.  */
>> +extern pid_t create_tty_session (void);
>> +
>> +/* Set the process group of the caller to its own pid, or do nothing
>> +   if we lack job control.  */
>> +extern int gdb_setpgid (void);
>> +
>> +/* Determine whether we have job control, and set variable JOB_CONTROL
>> +   accordingly.  */
>> +extern void have_job_control (void);
>> +
>> +#endif /* ! COMMON_TERMINAL_H */
>> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
>> new file mode 100644
>> index 0000000..42ac651
>> --- /dev/null
>> +++ b/gdb/gdbserver/terminal.c
>> @@ -0,0 +1,88 @@
>> +/* Terminal interface definitions for the GDB remote server.
>> +   Copyright (C) 2016-2017 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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 "server.h"
>> +#include "common-terminal.h"
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty_prefork (const char *ttyname)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +void
>> +new_tty_postfork (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +}
>> +
>> +/* See common/common-terminal.h.  */
>> +
>> +pid_t
>> +create_tty_session (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +  return (pid_t) 1;
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +set_inferior_io_terminal (const char *terminal_name)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +const char *
>> +get_inferior_io_terminal (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +  return NULL;
>> +}
>> diff --git a/gdb/terminal.h b/gdb/terminal.h
>> index d8691b2..8139319 100644
>> --- a/gdb/terminal.h
>> +++ b/gdb/terminal.h
>> @@ -19,83 +19,12 @@
>>  #if !defined (TERMINAL_H)
>>  #define TERMINAL_H 1
>>
>> -
>> -/* If we're using autoconf, it will define HAVE_TERMIOS_H,
>> -   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>> -   ser-unix.c and inflow.c to inspect those names instead of
>> -   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
>> -   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
>> -   nothing has already defined the one of the names, and do the right
>> -   thing.  */
>> -
>> -#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
>> -#if defined(HAVE_TERMIOS_H)
>> -#define HAVE_TERMIOS
>> -#else /* ! defined (HAVE_TERMIOS_H) */
>> -#if defined(HAVE_TERMIO_H)
>> -#define HAVE_TERMIO
>> -#else /* ! defined (HAVE_TERMIO_H) */
>> -#if defined(HAVE_SGTTY_H)
>> -#define HAVE_SGTTY
>> -#endif /* ! defined (HAVE_SGTTY_H) */
>> -#endif /* ! defined (HAVE_TERMIO_H) */
>> -#endif /* ! defined (HAVE_TERMIOS_H) */
>> -#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
>> -	  !defined (HAVE_SGTTY) */
>> -
>> -#if defined(HAVE_TERMIOS)
>> -#include <termios.h>
>> -#endif
>> -
>> -#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
>> -
>> -/* Define a common set of macros -- BSD based -- and redefine whatever
>> -   the system offers to make it look like that.  FIXME: serial.h and
>> -   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
>> -   is converted to use them, can get rid of this crap.  */
>> -
>> -#ifdef HAVE_TERMIO
>> -
>> -#include <termio.h>
>> -
>> -#undef TIOCGETP
>> -#define TIOCGETP TCGETA
>> -#undef TIOCSETN
>> -#define TIOCSETN TCSETA
>> -#undef TIOCSETP
>> -#define TIOCSETP TCSETAF
>> -#define TERMINAL struct termio
>> -
>> -#else /* sgtty */
>> -
>> -#include <fcntl.h>
>> -#include <sgtty.h>
>> -#include <sys/ioctl.h>
>> -#define TERMINAL struct sgttyb
>> -
>> -#endif /* sgtty */
>> -#endif
>> +#include "common-terminal.h"
>>
>>  struct inferior;
>>
>> -extern void new_tty_prefork (const char *);
>> -
>> -extern void new_tty (void);
>> -
>> -extern void new_tty_postfork (void);
>> -
>>  extern void copy_terminal_info (struct inferior *to, struct inferior *from);
>>
>> -/* Do we have job control?  Can be assumed to always be the same within
>> -   a given run of GDB.  In inflow.c.  */
>> -extern int job_control;
>> -
>> -extern pid_t create_tty_session (void);
>> -
>> -/* Set the process group of the caller to its own pid, or do nothing if
>> -   we lack job control.  */
>> -extern int gdb_setpgid (void);
>> -
>>  /* Set up a serial structure describing standard input.  In inflow.c.  */
>>  extern void initialize_stdin_serial (void);
>>
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index f142ffe..4993145 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -53,6 +53,7 @@
>>  #include "top.h"
>>  #include "main.h"
>>  #include "solist.h"
>> +#include "terminal.h"
>>
>>  #include "inferior.h"		/* for signed_pointer_to_address */
>>
>>
>

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-02-01 18:54     ` Luis Machado
@ 2017-02-07 22:42       ` Sergio Durigan Junior
  2017-02-08  9:07         ` Luis Machado
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-07 22:42 UTC (permalink / raw)
  To: Luis Machado; +Cc: GDB Patches, Pedro Alves, Eli Zaretskii

On Wednesday, February 01 2017, Luis Machado wrote:

> On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
>> Again, it was necessary to share a few functions declared on
>> gdb/gdbthread.h with gdbserver, because they are needed by
>> fork_inferior.  I decided to implement them on
>> gdb/gdbserver/inferiors.c because that's where the thread functions
>> are also implemented on gdbserver.  Some of these functions do not
>> need to be implemented on gdbserver, or don't make sense there, so
>> they are left blank and commented properly.
>>
>> gdb/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
>> 	* common/common-gdbthread.h: New file, with parts from
>> 	"gdb/gdbthread.h".
>> 	* fork-child.c (fork_inferior): Update call of "set_executing".
>> 	* gdbthread.h: Include "common-gdbthread.h".
>> 	(init_thread_list): Moved to "common/common-gdbthread.h".
>> 	(add_thread_silent): Likewise.
>> 	(switch_to_thread): Likewise.
>> 	(set_executing): Likewise.
>> 	* thread.c (set_executing): Update function comment.
>>
>> gdb/gdbserver/ChangeLog:
>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>
>> 	* inferiors.c (init_thread_list): New function.
>> 	(switch_to_thread): Likewise.
>> 	(set_executing): Likewise.
>> 	(add_thread_silent): Likewise.
>> 	* server.c (get_last_target_waitstatus): Likewise.
>> 	* server.h (get_last_target_waitstatus): Likewise.
>> ---
>>  gdb/Makefile.in               |  1 +
>>  gdb/common/common-gdbthread.h | 45 +++++++++++++++++++++++++++++++++++++++++++
>>  gdb/gdbserver/inferiors.c     | 41 +++++++++++++++++++++++++++++++++++++++
>>  gdb/gdbserver/server.c        |  8 ++++++++
>>  gdb/gdbserver/server.h        |  3 +++
>>  gdb/gdbthread.h               | 20 +------------------
>>  gdb/thread.c                  |  2 ++
>>  7 files changed, 101 insertions(+), 19 deletions(-)
>>  create mode 100644 gdb/common/common-gdbthread.h
>>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index c0325d5..3e49e6e 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
>>  	common/common-debug.h \
>>  	common/common-defs.h \
>>  	common/common-exceptions.h \
>> +	common/common-gdbthread.h \
>>  	common/common-regcache.h \
>>  	common/common-types.h \
>>  	common/common-utils.h \
>> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
>> new file mode 100644
>> index 0000000..eb66de9
>> --- /dev/null
>> +++ b/gdb/common/common-gdbthread.h
>> @@ -0,0 +1,45 @@
>> +/* Common multi-process/thread control defs for GDB and gdbserver.
>> +   Copyright (C) 1987-2017 Free Software Foundation, Inc.
>> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
>> +
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_THREAD_H
>> +#define COMMON_THREAD_H
>> +
>> +struct target_waitstatus;
>> +
>> +/* Create an empty thread list, or empty the existing one.  */
>> +extern void init_thread_list (void);
>> +
>> +/* Switch from one thread to another.  */
>> +extern void switch_to_thread (ptid_t ptid);
>> +
>> +/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
>> +   marks all threads.
>> +
>> +   Note that this is different from the running state.  See the
>> +   description of state and executing fields of struct
>> +   thread_info.  */
>> +extern void set_executing (ptid_t ptid, int executing);
>> +
>> +/* Add a thread to the thread list and return the pointer to the new
>> +   thread.  Caller may use this pointer to initialize the private
>> +   thread data.  */
>> +extern struct thread_info *add_thread_silent (ptid_t ptid);
>> +
>> +#endif /* ! COMMON_THREAD_H */
>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>> index b65a726..441ec2c 100644
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -468,3 +468,44 @@ make_cleanup_restore_current_thread (void)
>>  {
>>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>>  }
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +init_thread_list (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +switch_to_thread (ptid_t ptid)
>> +{
>> +  if (!ptid_equal (ptid, minus_one_ptid))
>> +    current_thread = find_thread_ptid (ptid);
>> +}
>> +
>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
>> +{
>> +  gdb_assert (current_thread != NULL);
>> +  current_thread->last_resume_kind = resume_stop;
>> +  current_thread->last_status = get_last_target_waitstatus ();
>> +}
>> +
>
>
> I'm still not sure about this particular function. But i'd like to
> hear what other think.

What are your concerns?

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
@ 2017-02-08  3:25     ` Sergio Durigan Junior
  2017-02-15 15:54       ` Pedro Alves
  2017-02-08  3:25     ` [PATCH v3 3/6] Share parts of gdb/inflow.c " Sergio Durigan Junior
                       ` (6 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:25 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

As part of the bigger work of sharing fork_inferior with gdbserver,
some parts of gdb/terminal.h also needed to be moved to a common
place.  These parts are:

- The code responsible for determining some terminal-based define's
  based on available features;

- job control;

- terminal-related functions needed by fork_inferior;

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
	* common/common-terminal.h: New file, with parts of "terminal.h".
	* terminal.h: Move terminal-related defines to
	"common/common-terminal.h".  Include "common/common-terminal.h".
	(new_tty_prefork): Move to "common/common-terminal.h".
	(new_tty): Likewise.
	(new_tty_postfork): Likewise.
	(job_control): Likewise.
	(create_tty_session): Likewise.
	(gdb_setpgid): Likewise.
	* utils.c: Include "terminal.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* terminal.c: New file.
---
 gdb/Makefile.in              |   1 +
 gdb/common/common-terminal.h | 125 +++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/terminal.c     |  88 ++++++++++++++++++++++++++++++
 gdb/terminal.h               |  73 +------------------------
 gdb/utils.c                  |   1 +
 5 files changed, 216 insertions(+), 72 deletions(-)
 create mode 100644 gdb/common/common-terminal.h
 create mode 100644 gdb/gdbserver/terminal.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 74b4d79..6dc80ea 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1472,6 +1472,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/common-terminal.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
new file mode 100644
index 0000000..956bfcc
--- /dev/null
+++ b/gdb/common/common-terminal.h
@@ -0,0 +1,125 @@
+/* Common terminal interface definitions for GDB and gdbserver.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TERMINAL_H
+#define COMMON_TERMINAL_H
+
+/* If we're using autoconf, it will define HAVE_TERMIOS_H,
+   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
+   ser-unix.c and inflow.c to inspect those names instead of
+   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
+   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
+   nothing has already defined the one of the names, and do the right
+   thing.  */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
+	  !defined (HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  FIXME: serial.h and
+   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+   is converted to use them, can get rid of this crap.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+#include <sys/types.h>
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
+extern void new_tty (void);
+
+/* NEW_TTY_PREFORK is called before forking a new child process,
+   so we can record the state of ttys in the child to be formed.
+   TTYNAME is null if we are to share the terminal with gdb;
+   or points to a string containing the name of the desired tty.
+
+   NEW_TTY is called in new child processes under Unix, which will
+   become debugger target processes.  This actually switches to
+   the terminal specified in the NEW_TTY_PREFORK call.
+   
+   This function is implemented as a placeholder on GDBserver.  */
+extern void new_tty_prefork (const char *ttyname);
+
+/* NEW_TTY_POSTFORK is called after forking a new child process, and
+   adding it to the inferior table, to store the TTYNAME being used by
+   the child, or null if it sharing the terminal with gdb.
+
+   This function is implemented as a placeholder on GDBserver.  */
+extern void new_tty_postfork (void);
+
+/* Create a new session if the inferior will run in a different tty.
+   A session is UNIX's way of grouping processes that share a controlling
+   terminal, so a new one is needed if the inferior terminal will be
+   different from GDB's.
+
+   Returns the session id of the new session, 0 if no session was created
+   or -1 if an error occurred.
+
+   This function is implemented as a placeholder on GDBserver.  */
+extern pid_t create_tty_session (void);
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid (void);
+
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  */
+extern void have_job_control (void);
+
+#endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
new file mode 100644
index 0000000..42ac651
--- /dev/null
+++ b/gdb/gdbserver/terminal.c
@@ -0,0 +1,88 @@
+/* Terminal interface definitions for the GDB remote server.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "common-terminal.h"
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_prefork (const char *ttyname)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_postfork (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-terminal.h.  */
+
+pid_t
+create_tty_session (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+  return (pid_t) 1;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+set_inferior_io_terminal (const char *terminal_name)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+}
+
+/* See common/common-inferior.h.  */
+
+const char *
+get_inferior_io_terminal (void)
+{
+  /* Placeholder needed by fork_inferior.  For now, this function is
+     not needed nor useful to have on gdbserver.  When/If we properly
+     handle terminal modes, we can revisit and implement the needed
+     support.  */
+  return NULL;
+}
diff --git a/gdb/terminal.h b/gdb/terminal.h
index d8691b2..8139319 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,83 +19,12 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
+#include "common-terminal.h"
 
 struct inferior;
 
-extern void new_tty_prefork (const char *);
-
-extern void new_tty (void);
-
-extern void new_tty_postfork (void);
-
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
-extern pid_t create_tty_session (void);
-
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 3dc2f03..6cbaf07 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -53,6 +53,7 @@
 #include "top.h"
 #include "main.h"
 #include "solist.h"
+#include "terminal.h"
 
 #include "inferior.h"		/* for signed_pointer_to_address */
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 0/6] Implement the ability to start inferiors with a shell on gdbserver
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
                     ` (6 preceding siblings ...)
  2017-01-26 22:47   ` [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
@ 2017-02-08  3:25   ` Sergio Durigan Junior
  2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
                       ` (7 more replies)
  7 siblings, 8 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:25 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado

Hi again,

This is the third version of this patch series.  I addressed the
comments made by Luis.

Here's what changed from v2:

 - Fixed many formatting nits (spurious newlines, indentation, etc.)

 - Added description of expected values by QStartupWithShell packet

Additionally, here's what changed from v1:

 - Added NEWS entry

 - Mentioned that the feature is to be used on UNIX-like systems

 - Removed third argument from set_executing

 - Removed 'set remote startup-shell' command

 - Renamed the packet to QStartupWithShell.  Now, the packet has only
   a boolean argument: "1" (meaning that the remote target should use
   a shell to start the inferior), and "0" (the remote target should
   not use a shell to start the inferior).

 - Write documentation for this new packet

 - Fixed and rewrote ChangeLog entries

 - Fixed spurious newlines on comments.

 - Fix comments that only mentioned "GDB" on files that are now being
   shared with gdbserver.

 - Adjust copyright notices on files

 - Use "untested" where applicable on the testcase


This patch series implement the "startup-with-shell" feature on
gdbserver.  This means that it will be possible to start inferiors
using the shell (instead of calling execv*), which brings many
advantages.

First of all, it will be possible to use I/O redirection, variable
substitution and globbing expansion on gdbserver just like we do today
on GDB.  This is great because, among other things, it brings
gdbserver on a pair with GDB when considering the Feature Parity
project.

Secondly, a great deal of code had to be shared between GDB and
gdbserver, especially the fork_inferior function, which means that now
both programs are using virtually the same code to start inferiors.
I've also had to touch on other areas, like terminal.h, inflow.c and
gdbthread.h, and even though only the APIs were shared (i.e.,
gdbserver's version of a gdbthread.h function may differ from GDB's
version), this is also beneficial in the long run when we start to
unify the code more deeply.  But I'm "raining in the wet" here; all
this has been explained in better terms before.

I did my best to split the patches, but unfortunately the
fork_inferior patch is big and I couldn't see a better way to do that.
But it shouldn't be very hard to review them, because most of it is
just "code movement".


^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 1/6] Share gdb/environ.[ch] with gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
  2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
  2017-02-08  3:25     ` [PATCH v3 3/6] Share parts of gdb/inflow.c " Sergio Durigan Junior
@ 2017-02-08  3:25     ` Sergio Durigan Junior
  2017-02-15 15:36       ` Pedro Alves
  2017-02-08  3:32     ` [PATCH v3 5/6] Share fork_inferior et al " Sergio Durigan Junior
                       ` (4 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:25 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

We will need access to the environment functions when we share
fork_inferior between GDB and gdbserver, therefore we simply make the
API on gdb/environ.[ch] available on common/.  No extra adjustments
are needed to make it compile on gdbserver.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Replace "environ.c" with
	"common/environ.c".
	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
	to...
	* common/environ.c: ... here.
	* environ.h: Moved to...
	* common/environ.h: ... here.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/environ.c".
	(OBJS): Add "common/environ.h".
---
 gdb/Makefile.in            | 4 ++--
 gdb/{ => common}/environ.c | 2 +-
 gdb/{ => common}/environ.h | 0
 gdb/gdbserver/Makefile.in  | 5 +++++
 4 files changed, 8 insertions(+), 3 deletions(-)
 rename gdb/{ => common}/environ.c (99%)
 rename gdb/{ => common}/environ.h (100%)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e0fe442..74b4d79 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1049,7 +1049,6 @@ SFILES = \
 	dwarf2loc.c \
 	dwarf2read.c \
 	elfread.c \
-	environ.c \
 	eval.c \
 	event-loop.c \
 	event-top.c \
@@ -1195,6 +1194,7 @@ SFILES = \
 	common/common-regcache.c \
 	common/common-utils.c \
 	common/errors.c \
+	common/environ.c \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
@@ -1273,7 +1273,6 @@ HFILES_NO_SRCDIR = \
 	dwarf2-frame-tailcall.h \
 	dwarf2expr.h \
 	dwarf2loc.h \
-	environ.h \
 	event-loop.h \
 	event-top.h \
 	exceptions.h \
@@ -1474,6 +1473,7 @@ HFILES_NO_SRCDIR = \
 	common/common-types.h \
 	common/common-utils.h \
 	common/errors.h \
+	common/environ.h \
 	common/fileio.h \
 	common/format.h \
 	common/gdb_assert.h \
diff --git a/gdb/environ.c b/gdb/common/environ.c
similarity index 99%
rename from gdb/environ.c
rename to gdb/common/environ.c
index bfeabec..3145d01 100644
--- a/gdb/environ.c
+++ b/gdb/common/environ.c
@@ -15,7 +15,7 @@
    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 "defs.h"
+#include "common-defs.h"
 #include "environ.h"
 #include <algorithm>
 \f
diff --git a/gdb/environ.h b/gdb/common/environ.h
similarity index 100%
rename from gdb/environ.h
rename to gdb/common/environ.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 75736b6..ef0dc99 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -201,6 +201,7 @@ SFILES = \
 	$(srcdir)/common/common-regcache.c \
 	$(srcdir)/common/common-utils.c \
 	$(srcdir)/common/errors.c \
+	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
 	$(srcdir)/common/gdb_vecs.c \
@@ -238,6 +239,7 @@ OBS = \
 	debug.o \
 	dll.o \
 	errors.o \
+	environ.o \
 	event-loop.o \
 	fileio.o \
 	filestuff.o \
@@ -774,6 +776,9 @@ agent.o: ../common/agent.c
 errors.o: ../common/errors.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+environ.o: ../common/environ.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-debug.o: ../common/common-debug.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 3/6] Share parts of gdb/inflow.c with gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
  2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
@ 2017-02-08  3:25     ` Sergio Durigan Junior
  2017-02-15 16:02       ` Pedro Alves
  2017-02-08  3:25     ` [PATCH v3 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
                       ` (5 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:25 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

After sharing parts of gdb/terminal.h, it is also needed to share the
two functions on gdb/inflow.c that are going to be needed by the
fork_inferior sharing.  They are 'gdb_setpgid' and the new
'have_job_control'.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-inflow.c".
	(COMMON_OBS): Add "common/common-inflow.o".
	* common/common-inflow.c: New file, with contents from
	"gdb/inflow.c".
	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* utils.c (job_control): Delete.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in: Add rule for "common-inflow.o".
	(SFILE): Add "common/common-inflow.c".
	(OBS): Add "common-inflow.o".
---
 gdb/Makefile.in            |  2 +
 gdb/common/common-inflow.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/Makefile.in  |  5 +++
 gdb/inflow.c               | 63 +-------------------------------
 gdb/utils.c                |  4 --
 5 files changed, 100 insertions(+), 65 deletions(-)
 create mode 100644 gdb/common/common-inflow.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6dc80ea..84762c4 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1198,6 +1198,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1626,6 +1627,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
new file mode 100644
index 0000000..9871b5e
--- /dev/null
+++ b/gdb/common/common-inflow.c
@@ -0,0 +1,91 @@
+/* Low level interface to ptrace, for GDB and gdbserver when running under Unix.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "common-terminal.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* This is here because this is where we figure out whether we (probably)
+   have job control.  Just using job_control only does part of it because
+   setpgid or setpgrp might not exist on a system without job control.
+   It might be considered misplaced (on the other hand, process groups and
+   job control are closely related to ttys).
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index ef0dc99..74e199b 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
@@ -770,6 +772,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-inflow.o: ../common/common-inflow.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 agent.o: ../common/agent.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 7ffa83a..271278d 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -803,43 +803,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -860,30 +823,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 6cbaf07..c6f2527 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
                       ` (2 preceding siblings ...)
  2017-02-08  3:25     ` [PATCH v3 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2017-02-08  3:32     ` Sergio Durigan Junior
  2017-02-15 17:28       ` Pedro Alves
  2017-02-08  3:33     ` [PATCH v3 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
                       ` (3 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:32 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.  For some
feature, like the target_terminal_* functions, I chose to just use
placeholders for the real functions on gdbserver, that should be
implemented in the future.  For now, we don't need them in order to
make things work.  Also, since we don't manipulate terminal modes on
gdbserver the way we do on GDB, they are not possible to implement
right now (unless I chose to properly implement terminal handling on
gdbserver, which is something we don't know if we want now).

Last, but not least, I did a major revamp on the way gdbserver
computes and stores the inferior's arguments.  It's now using a
std::vector<char *> and std::string where applicable, which makes
things much easier even to understand.  This simplification was also
interesting for the "create_inferior" method of gdbserver's target.c;
now, it only needs one argument (a vector containing the full inferior
argv) instead of two char * that were confusing to
manipulate/generate.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
	"common/common-top.h".
	(COMMON_OBS): Add "common-fork-child.o".
	* common-fork-child.c: New file, with the majority of
	"gdb/fork-child.c".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* common/common-top.h: New file.
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Update call of
	"startup_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(fork_inferior): Likewise.  Update function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Update call to
	"startup_inferior".
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* inferior.h: Include "common-inferior.h".
	(fork_inferior): Move prototype to "common-inferior.h".
	(startup_inferior): Likewise.
	* procfs.c (procfs_init_inferior): Update call to
	"startup_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* top.h: Include "common-top.h".
	(main_ui): Move
	(current_ui): Move
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "terminal.c" and
	"common/common-fork-child.c".
	(OBS): Add common-fork-child.o and terminal.o.
	(common-fork-child.o): New rule.
	* inferiors (inferior_ptid): New variable.
	(inferior_appeared): New function.
	(current_inferior): Likewise.
	(have_inferiors): Likewise.
	* linux-low.c: Include "common-inferior.h" and "environ.h".
	(linux_update_process): New function.
	(linux_add_process): Update comment.  Adjust function to call
	"linux_update_process".
	(update_thread_lwp): New function.
	(linux_ptrace_fun): Likewise.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c (lynx_update_process): New function.
	(lynx_add_process): Update comment.  Adjust function to call
	"lynx_update_process".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".
	* server.c: Include "common-inferior.h", "common-terminal.h",
	"common-top.h", "environ.h".
	(main_ui): New variable.
	(current_ui): Likewise.
	(our_environ): Likewise.
	(startup_with_shell): Likewise.
	(program_argv): Convert to std::vector<char *>.
	(wrapper_argv): Likewise.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(pre_fork_inferior): New function, with parts of "start_inferior".
	(post_fork_inferior): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(pre_fork_inferior): New prototype.
	(post_fork_inferior): Likewise.
	(get_environ): Likewise.
	* spu-low.c (spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype
	to accept one std::vector<char *> representing the full program
	argv.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	(free_vector_argv): Likewise.
	(stringify_argv): Likewise.
	* utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	(stringify_argv): Likewise.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   4 +
 gdb/common/common-fork-child.c                    | 593 ++++++++++++++++++++++
 gdb/common/common-inferior.h                      | 105 ++++
 gdb/common/common-top.h                           |  31 ++
 gdb/common/common-utils.h                         |   4 +
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |   2 +-
 gdb/fork-child.c                                  | 528 +------------------
 gdb/gdbserver/Makefile.in                         |   7 +
 gdb/gdbserver/inferiors.c                         |  31 +-
 gdb/gdbserver/linux-low.c                         | 124 +++--
 gdb/gdbserver/lynx-low.c                          |  66 ++-
 gdb/gdbserver/nto-low.c                           |   9 +-
 gdb/gdbserver/server.c                            | 275 ++++++----
 gdb/gdbserver/server.h                            |  16 +
 gdb/gdbserver/spu-low.c                           |  43 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |   7 +-
 gdb/gdbserver/utils.c                             |  35 ++
 gdb/gdbserver/utils.h                             |  10 +
 gdb/gdbserver/win32-low.c                         |  25 +-
 gdb/gnu-nat.c                                     |   2 +-
 gdb/inf-ptrace.c                                  |   2 +-
 gdb/infcmd.c                                      |   2 +-
 gdb/inferior.h                                    |  14 +-
 gdb/procfs.c                                      |   2 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
 gdb/top.h                                         |   9 +-
 gdb/utils.c                                       |   9 +
 31 files changed, 1228 insertions(+), 796 deletions(-)
 create mode 100644 gdb/common/common-fork-child.c
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/common/common-top.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cc0fdec..a910c52 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1198,6 +1198,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/common-fork-child.c \
 	common/common-inflow.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
@@ -1486,6 +1487,8 @@ HFILES_NO_SRCDIR = \
 	common/gdb_sys_time.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
+	common/common-top.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1628,6 +1631,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
new file mode 100644
index 0000000..f4d7866
--- /dev/null
+++ b/gdb/common/common-fork-child.c
@@ -0,0 +1,593 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   Originally contributed by Cygnus Support.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "target/waitstatus.h"
+#include "common-terminal.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "common-top.h"
+#include "signals-state-save-restore.h"
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Break up SCRATCH into an argument vector suitable for passing to
+   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
+   would get as input the string "a b c d", and as output it would
+   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+
+static void
+breakup_args_for_exec (char *scratch, char **argv)
+{
+  char *cp = scratch, *tmp;
+
+  for (;;)
+    {
+      /* Scan past leading separators */
+      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
+	cp++;
+
+      /* Break if at end of string.  */
+      if (*cp == '\0')
+	break;
+
+      /* Take an arg.  */
+      *argv++ = cp;
+
+      /* Scan for next arg separator.  */
+      tmp = strchr (cp, ' ');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\t');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\n');
+
+      /* No separators => end of string => break.  */
+      if (tmp == NULL)
+	break;
+      cp = tmp;
+
+      /* Replace the separator with a terminator.  */
+      *cp++ = '\0';
+    }
+
+  /* Null-terminate the vector.  */
+  *argv = NULL;
+}
+
+/* When executing a command under the given shell, return non-zero if
+   the '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  const int shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return 0;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return 1;
+
+  return 0;
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_startup_shell (void)
+{
+  static char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* Quote the shell command that will be executed.  This function is
+   called when the inferior is going to be executed under a shell
+   (i.e., when 'startup-with-shell' is set).
+
+   SHELL_FILE is the shell which will be used to execute the inferior
+   (e.g., /bin/sh).
+
+   EXEC_FILE is the inferior executable itself.
+
+   ALLARGS contains all the arguments that will be passed to the
+   inferior.
+
+   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
+   the inferior.
+
+   SHELL_CMD is a pointer to the resulting shell command that will be
+   executed.  The resulting shell command will be returned in it.  It
+   must be pre-allocated and have a reasonable size.  For an example
+   on how to determine its size, see 'fork_inferior' on
+   fork-child.c.  */
+
+static void
+quote_shell_command (const char *shell_file, const char *exec_file,
+		     const char *allargs, const char *exec_wrapper,
+		     char **shell_cmd)
+{
+  char *shell_command = *shell_cmd;
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  shell_command[0] = '\0';
+  strcat (shell_command, "exec ");
+
+  /* Add any exec wrapper.  That may be a program name with arguments, so
+     the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      strcat (shell_command, exec_wrapper);
+      strcat (shell_command, " ");
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But
+     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
+     we need to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      strcat (shell_command, "'");
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    strcat (shell_command, "'\\''");
+	  else if (*p == '!' && escape_bang)
+	    strcat (shell_command, "\\!");
+	  else
+	    strncat (shell_command, p, 1);
+	}
+      strcat (shell_command, "'");
+    }
+  else
+    strcat (shell_command, exec_file);
+
+  strcat (shell_command, " ");
+  strcat (shell_command, allargs);
+}
+
+/* See common/common-inferior.h.  */
+
+int
+fork_inferior (char *exec_file_arg, char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+	       void (*exec_fun)(const char *file, char * const *argv,
+				char * const *env))
+{
+  int pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  static int debug_fork = 0;
+  /* This is set to the result of setpgrp, which if vforked, will be visible
+     to you in the parent process.  It's only used by humans for debugging.  */
+  static int debug_setpgrp = 657473;
+  static char *shell_file;
+  static char *exec_file;
+  char **save_our_env;
+  int shell = 0;
+  static char **argv;
+  const char *inferior_io_terminal = get_inferior_io_terminal ();
+  struct inferior *inf;
+  int i;
+  int save_errno;
+  struct ui *save_ui;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  exec_file = exec_file_arg;
+  if (exec_file == 0)
+    exec_file = get_exec_file (1);
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  shell_file = shell_file_arg;
+  if (startup_with_shell)
+    {
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+      shell = 1;
+    }
+
+  if (!shell)
+    {
+      /* We're going to call execvp.  Create argument vector.
+	 Calculate an upper bound on the length of the vector by
+	 assuming that every other character is a separate
+	 argument.  */
+      int argc = (strlen (allargs) + 1) / 2 + 2;
+
+      argv = XALLOCAVEC (char *, argc);
+      argv[0] = exec_file;
+      breakup_args_for_exec (allargs, &argv[1]);
+    }
+  else
+    {
+      /* We're going to call a shell.  */
+      char *shell_command;
+      char *exec_wrapper = get_exec_wrapper ();
+      size_t len;
+
+      /* Multiplying the length of exec_file by 4 is to account for the
+         fact that it may expand when quoted; it is a worst-case number
+         based on every character being '.  */
+      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
+      if (exec_wrapper != NULL)
+        len += strlen (exec_wrapper) + 1;
+
+      shell_command = (char *) alloca (len);
+      shell_command[0] = '\0';
+
+      quote_shell_command (shell_file, exec_file,
+			   allargs,
+			   exec_wrapper, &shell_command);
+
+      /* If we decided above to start up with a shell, we exec the
+	 shell, "-c" says to interpret the next arg as a shell command
+	 to execute, and this command is "exec <target-program>
+	 <args>".  */
+      argv = (char **) alloca (4 * sizeof (char *));
+      argv[0] = shell_file;
+      argv[1] = "-c";
+      argv[2] = shell_command;
+      argv[3] = (char *) 0;
+    }
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Likewise the current UI.  */
+  save_ui = current_ui;
+
+  /* Tell the terminal handling subsystem what tty we plan to run on;
+     it will just record the information for later.  */
+  new_tty_prefork (inferior_io_terminal);
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Switch to the main UI, so that gdb_std{in/out/err} in the
+	 child are mapped to std{in/out/err}.  This makes it possible
+	 to use fprintf_unfiltered/warning/error/etc. in the child
+	 from here on.  */
+      current_ui = main_ui;
+
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
+      close_most_fds ();
+
+      if (debug_fork)
+	sleep (debug_fork);
+
+      /* Create a new session for the inferior process, if necessary.
+         It will also place the inferior in a separate process group.  */
+      if (create_tty_session () <= 0)
+	{
+	  /* No session was created, but we still want to run the inferior
+	     in a separate process group.  */
+	  debug_setpgrp = gdb_setpgid ();
+	  if (debug_setpgrp == -1)
+	    perror (_("setpgrp failed in child"));
+	}
+
+      /* Ask the tty subsystem to switch to the one we specified
+         earlier (or to share the current terminal, if none was
+         specified).  */
+      new_tty ();
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], argv, env);
+      else
+        execvp (argv[0], argv);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  /* Likewise the current UI.  */
+  current_ui = save_ui;
+
+  if (!have_inferiors ())
+    init_thread_list ();
+
+  inf = current_inferior ();
+
+  inferior_appeared (inf, pid);
+
+  /* Needed for wait_for_inferior stuff below.  */
+  inferior_ptid = pid_to_ptid (pid);
+
+  new_tty_postfork ();
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point, but the pid shouldn't change.  Targets
+     supporting MT should fill this task's ptid with more data as soon
+     as they can.  */
+  add_thread_silent (inferior_ptid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+startup_inferior (int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  /* Mark all threads non-executing.  */
+  set_executing (resume_ptid, 0);
+}
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..bdff640
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,105 @@
+/* Variables that describe the inferior process running under GDB and
+   GDBserver: Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+struct inferior;
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern bool startup_with_shell;
+
+/* Collected pid, tid, etc. of the debugged inferior.  When there's
+   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
+extern ptid_t inferior_ptid;
+
+/* Accept NTRAPS traps from the inferior.  */
+extern void startup_inferior (int ntraps,
+			      struct target_waitstatus *mystatus,
+			      ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern int fork_inferior (char *exec_file_arg, char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+	       void (*exec_fun) (const char *file, char * const *argv,
+				 char * const *env));
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+extern char *get_startup_shell (void);
+
+/* Set file name for default use for standard in/out in the inferior.  */
+extern void set_inferior_io_terminal (const char *terminal_name);
+
+/* Get file name for default use for standard in/out in the inferior.  */
+extern const char *get_inferior_io_terminal (void);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+/* Returns true if the inferior list is not empty.  */
+extern int have_inferiors (void);
+
+extern void inferior_appeared (struct inferior *inf, int pid);
+
+/* Return a pointer to the current inferior.  It is an error to call
+   this if there is no current inferior.  */
+extern struct inferior *current_inferior (void);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-top.h b/gdb/common/common-top.h
new file mode 100644
index 0000000..98b1724
--- /dev/null
+++ b/gdb/common/common-top.h
@@ -0,0 +1,31 @@
+/* Common top level stuff for GDB and GDBserver.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TOP_H
+#define COMMON_TOP_H
+
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+extern struct ui *main_ui;
+
+/* The current UI.  */
+extern struct ui *current_ui;
+
+#endif /* ! COMMON_TOP_H */
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 618d266..b9bbdb9 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -103,4 +103,8 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err (void);
+
 #endif
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 54cb789..d76fa1a 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 8c5e8a0..ef94d10 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1782,7 +1782,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 }
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index eaa8cb5..527f4ce 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,531 +21,19 @@
 
 #include "defs.h"
 #include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
 #include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
-#include "top.h"
-#include "signals-state-save-restore.h"
-#include <signal.h>
 
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-extern char **environ;
+static char *exec_wrapper = NULL;
 
-static char *exec_wrapper;
+/* See common/common-inferior.h.  */
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
-
-static void
-breakup_args (char *scratch, char **argv)
+char *
+get_exec_wrapper (void)
 {
-  char *cp = scratch, *tmp;
-
-  for (;;)
-    {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
-    }
-
-  /* Null-terminate the vector.  */
-  *argv = NULL;
-}
-
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static int
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  const int shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return 0;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return 1;
-
-  return 0;
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static char *exec_file;
-  char **save_our_env;
-  int shell = 0;
-  static char **argv;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
-    exec_file = get_exec_file (1);
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
-  if (startup_with_shell)
-    {
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  strcat (shell_command, "'");
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
-	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
-	      else
-		strncat (shell_command, p, 1);
-	    }
-	  strcat (shell_command, "'");
-	}
-      else
-	strcat (shell_command, exec_file);
-
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
-    }
-
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
-
-  /* Tell the terminal handling subsystem what tty we plan to run on;
-     it will just record the information for later.  */
-  new_tty_prefork (inferior_io_terminal);
-
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
-      else
-        execvp (argv[0], argv);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
-
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
-
-  if (!have_inferiors ())
-    init_thread_list ();
-
-  inf = current_inferior ();
-
-  inferior_appeared (inf, pid);
-
-  /* Needed for wait_for_inferior stuff below.  */
-  inferior_ptid = pid_to_ptid (pid);
-
-  new_tty_postfork ();
-
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
-}
-
-/* Accept NTRAPS traps from the inferior.  */
-
-void
-startup_inferior (int ntraps)
-{
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
-
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
-
-  if (exec_wrapper)
-    pending_execs++;
-
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
-
-  /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  return exec_wrapper;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
@@ -585,7 +73,7 @@ Show the wrapper for running programs."), NULL,
            &unsetlist);
 
   add_setshow_boolean_cmd ("startup-with-shell", class_support,
-			   &startup_with_shell, _("\
+			   (int *) &startup_with_shell, _("\
 Set use of shell to start subprocesses.  The default is on."), _("\
 Show use of shell to start subprocesses."), NULL,
 			   NULL,
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 74e199b..9b6e96a 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,6 +185,7 @@ SFILES = \
 	$(srcdir)/target.c \
 	$(srcdir)/thread-db.c \
 	$(srcdir)/utils.c \
+	$(srcdir)/terminal.c \
 	$(srcdir)/win32-arm-low.c \
 	$(srcdir)/win32-i386-low.c \
 	$(srcdir)/win32-low.c \
@@ -204,6 +205,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/common-fork-child.c \
 	$(srcdir)/common/common-inflow.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
@@ -235,6 +237,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	common-fork-child.o \
 	common-inflow.o \
 	common-regcache.o \
 	common-utils.o \
@@ -269,6 +272,7 @@ OBS = \
 	version.o \
 	waitstatus.o \
 	xml-utils.o \
+	terminal.o \
 	$(DEPFILES) \
 	$(LIBOBJS) \
 	$(XML_BUILTIN)
@@ -772,6 +776,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-fork-child.o: ../common/common-fork-child.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 common-inflow.o: ../common/common-inflow.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 441ec2c..19f4d39 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,8 @@ struct thread_info *current_thread;
 
 #define get_thread(inf) ((struct thread_info *)(inf))
 
+ptid_t inferior_ptid;
+
 void
 add_inferior_to_list (struct inferior_list *list,
 		      struct inferior_list_entry *new_inferior)
@@ -469,12 +471,31 @@ make_cleanup_restore_current_thread (void)
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
 
+/* See common/common-inferior.h.  */
+
+void
+inferior_appeared (struct inferior *inf, int pid)
+{
+  /* Placeholder needed for fork_inferior.  We do not have to do
+     anything in this case.  */
+}
+
+/* See common/common-inferior.h.  */
+
+struct inferior *
+current_inferior (void)
+{
+  /* Placeholder needed for fork_inferior.  GDBserver has other
+     functions that serve this purpose.  */
+  return NULL;
+}
+
 /* See common/common-gdbthread.h.  */
 
 void
 init_thread_list (void)
 {
-  /* To be implemented.  */
+  /* Placeholder needed for fork_inferior.  No action is needed.  */
 }
 
 /* See common/common-gdbthread.h.  */
@@ -509,3 +530,11 @@ add_thread_silent (ptid_t ptid)
 
   return add_thread (ptid_build (pid, pid, 0), NULL);
 }
+
+/* See common/common-inferior.h.  */
+
+int
+have_inferiors (void)
+{
+  return get_first_process () != NULL;
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e27cbf8..8194da7 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -415,15 +417,14 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
-/* Add a process to the common process list, and set its private
-   data.  */
+/* Update process represented by PID with necessary info.  */
 
 static struct process_info *
-linux_add_process (int pid, int attached)
+linux_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
 
-  proc = add_process (pid, attached);
+  gdb_assert (proc != NULL);
   proc->priv = XCNEW (struct process_info_private);
 
   if (the_low_target.new_process != NULL)
@@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return linux_update_process (pid);
+}
+
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
 /* Call the target arch_setup function on the current thread.  */
@@ -929,6 +940,29 @@ save_stop_reason (struct lwp_info *lwp)
   return 1;
 }
 
+/* Update the lwp associated to thread represented by PTID.  */
+
+static struct lwp_info *
+update_thread_lwp (ptid_t ptid)
+{
+  struct lwp_info *lwp;
+  struct thread_info *thread;
+
+  lwp = XCNEW (struct lwp_info);
+
+  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
+  if (the_low_target.new_thread != NULL)
+    the_low_target.new_thread (lwp);
+
+  thread = find_thread_ptid (ptid);
+  gdb_assert (thread != NULL);
+  thread->target_data = lwp;
+  lwp->thread = thread;
+
+  return lwp;
+}
+
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 {
@@ -946,68 +980,62 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
+
+  setpgid (0, 0);
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      close (0);
+      open ("/dev/null", O_RDONLY);
+      dup2 (2, 1);
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args. */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (std::vector<char *> &program_argv)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string program_args = stringify_argv (program_argv);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
-  linux_add_process (pid, 0);
+  linux_update_process (pid);
 
   ptid = ptid_build (pid, pid, 0);
-  new_lwp = add_lwp (ptid);
+  new_lwp = update_thread_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program_argv);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..fa3f4ea 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -208,15 +208,15 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
-/* Call add_process with the given parameters, and initializes
-   the process' private data.  */
+/* Update existing process represented by PID with necessary info.  */
 
 static struct process_info *
-lynx_add_process (int pid, int attached)
+lynx_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
+
+  gdb_assert (proc != NULL);
 
-  proc = add_process (pid, attached);
   proc->tdesc = lynx_tdesc;
   proc->priv = XCNEW (struct process_info_private);
   proc->priv->last_wait_event_ptid = null_ptid;
@@ -224,41 +224,53 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return lynx_update_process (pid);
+}
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  setpgid (0, pgrp);
+  ioctl (0, TIOCSPGRP, &pgrp);
+  lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  lynx_add_process (pid, 0);
+  post_fork_inferior (pid, program_argv);
+
+  lynx_update_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..ea2a3a4 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,16 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM_ARGV.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (std::vector<char *> &program_argv)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string program_args = stringify_argv (program_argv);
 
-  TRACE ("%s %s\n", __func__, program);
+  TRACE ("%s %s\n", __func__, program_argv[0]);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
   signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
 
@@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 43d9406..025f7c4 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,26 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "common-terminal.h"
+#include "common-top.h"
+#include "environ.h"
+
+/* We don't have a concept of a UI yet.  Therefore, we just set these
+   to NULL.  */
+
+struct ui *main_ui = NULL;
+struct ui *current_ui = NULL;
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+bool startup_with_shell = true;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +98,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -244,33 +265,65 @@ get_last_target_waitstatus (void)
   return last_status;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_wrapper (void)
 {
-  char **new_argv = argv;
+  static std::string ret;
+  static int initialized_p = 0;
+
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  if (wrapper_argv != NULL)
+  if (!initialized_p)
     {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
+      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
+	   i != wrapper_argv.end ();
+	   ++i)
+	ret += *i + std::string (" ");
+
+      /* Erasing the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = 1;
     }
 
+  return (char *) ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_argv.empty ())
+    error (_("Could not get the exec file."));
+  return program_argv[0];
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See server.h.  */
+
+void
+pre_fork_inferior (std::vector<char *> &argv)
+{
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      int idx = 0;
+
+      for (char *&i : argv)
+	{
+	  debug_printf ("new_argv[%d] = \"%s\"\n", idx, i);
+	  ++idx;
+	}
       debug_flush ();
     }
 
@@ -279,67 +332,35 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid,
+		    std::vector<char *> &argv)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
-
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
-
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
-
-  return signal_pid;
+  startup_inferior (num_traps, &last_status, &last_ptid);
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], pid);
+  fflush (stderr);
 }
 
 static int
@@ -2860,8 +2881,10 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
-  int i, new_argc;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
+  int new_argc;
+  int i;
 
   new_argc = 0;
   for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
@@ -2870,62 +2893,91 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
-      if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+      if (p == next_p)
+	new_argv.push_back ("''");
       else
 	{
 	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = 1 + (next_p - p) / 2;
+	  char *s = (char *) xmalloc (len);
+	  char *ss = (char *) xmalloc (len * 2);
+	  char *tmp_s, *tmp_ss;
+	  int need_quote;
+
+	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
+	  s[(next_p - p) / 2] = '\0';
+
+	  tmp_s = s;
+	  tmp_ss = ss;
+	  need_quote = 0;
+	  while (*tmp_s != '\0')
+	    {
+	      switch (*tmp_s)
+		{
+		case '\n':
+		  *tmp_ss = '\'';
+		  ++tmp_ss;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  *tmp_ss = '\\';
+		  ++tmp_ss;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_ss = *tmp_s;
+	      ++tmp_ss;
+	      ++tmp_s;
+	    }
+
+	  if (need_quote)
+	    *tmp_ss++ = '\'';
+
+	  *tmp_ss = '\0';
+	  new_argv.push_back (ss);
+	  xfree (s);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
 
-  if (new_argv[0] == NULL)
+  if (new_argv.empty () || new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
 
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
+      new_argv.push_back (strdup (program_argv[0]));
+      if (new_argv.empty () || new_argv[0] == NULL)
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  create_inferior (program_argv);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3543,13 +3595,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3680,8 +3737,14 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  /* This is called when initializing inflow on GDB.  */
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3695,13 +3758,11 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      create_inferior (program_argv);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4316,9 +4377,9 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      create_inferior (program_argv);
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 71848f1..47e094a 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -151,4 +152,19 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Return the global variable LAST_STATUS from server.c.  */
 extern struct target_waitstatus get_last_target_waitstatus (void);
 
+/* Any pre-processing needed to be done before calling fork_inferior
+   shall be implemented here.  ARGV is a vector containing the full
+   argv of the inferior.  */
+extern void pre_fork_inferior (std::vector<char *> &argv);
+
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and ARGV is the vector containing the full
+   argv of the inferior.  */
+extern void post_fork_inferior (int pid, std::vector<char *> &argv);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..7f26331 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -261,42 +261,39 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  ptrace (PTRACE_TRACEME, 0, 0, 0);
+  setpgid (0, 0);
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM_ARGV is a vector of program-name and args. */
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string program_args = stringify_argv (program_argv);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
+  pre_fork_inferior (program_argv);
 
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program_argv[0],
+		       (char *) program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program_argv);
 
-  proc = add_process (pid, 0);
+  proc = find_process_pid (pid);
+  gdb_assert (proc != NULL);
   proc->tdesc = tdesc_spu;
 
-  ptid = ptid_build (pid, pid, 0);
-  add_thread (ptid, NULL);
   return pid;
 }
 
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..1e1d193 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..3f94115 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -73,7 +74,7 @@ struct target_ops
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
 
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (std::vector<char *> &program_argv);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program) \
+  (*the_target->create_inferior) (program)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..004a78e 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,38 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (char *&i : v)
+    xfree (i);
+
+  v.clear ();
+}
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (std::vector<char *> &argv)
+{
+  std::string ret ("");
+
+  for (std::vector<char *>::iterator i = argv.begin () + 1;
+       i != argv.end ();
+       ++i)
+    ret += *i + std::string (" ");
+
+  return ret;
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index b4ded31..a30d99a 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,7 +19,17 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
+/* Works like FREEARGV, but with std::vector.  */
+extern void free_vector_argv (std::vector<char *> &v);
+
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments (starting from ARGV + 1) with a
+   whitespace separating them.  */
+extern std::string stringify_argv (std::vector<char *> &argv);
+
 #endif /* UTILS_H */
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index d3ddbf5..c005a70 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,11 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM_ARGV is the vector containing the inferior's argv.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (std::vector<char *> &program_argv)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  char *program = program_argv[0];
+  std::string program_args = stringify_argv (program_argv);
+  char *args = (char *) program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
 
   flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
 
+  pre_fork_inferior (program, argv);
+
 #ifndef USE_WIN32API
   orig_path = NULL;
   path_ptr = getenv ("PATH");
@@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
@@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
 
   do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
+  post_fork_inferior (current_process_id, program_argv);
+
   return current_process_id;
 }
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 9935dcb..bccfd9c 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2161,7 +2161,7 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index f61bfe7..e9a7de2 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -111,7 +111,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d836162..b00cb5a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -139,7 +139,7 @@ int stopped_by_random_signal;
 
 /* See inferior.h.  */
 
-int startup_with_shell = 1;
+bool startup_with_shell = true;
 
 \f
 /* Accessor routines.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 258cc29..31eac00 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -42,6 +42,7 @@ struct target_desc_info;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 
@@ -130,17 +131,6 @@ extern void child_terminal_init (struct target_ops *self);
 
 extern void child_terminal_init_with_pgrp (int pgrp);
 
-/* From fork-child.c */
-
-extern int fork_inferior (char *, char *, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
-
 extern char *construct_inferior_arguments (int, char **);
 
 /* From infcmd.c */
@@ -200,7 +190,7 @@ extern void prepare_execution_command (struct target_ops *target,
 
    The catch-exec traps expected during start-up will be one more if
    the target is started up with a shell.  */
-extern int startup_with_shell;
+extern bool startup_with_shell;
 
 /* Address at which inferior stopped.  */
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 2269016..ac76be6 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4375,7 +4375,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
diff --git a/gdb/target.h b/gdb/target.h
index 8df117e..b73f242 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1532,17 +1532,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1551,12 +1540,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..f12262e 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..fec138d 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled.
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/top.h b/gdb/top.h
index 2da92df..0c8d324 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -22,6 +22,7 @@
 
 #include "buffer.h"
 #include "event-loop.h"
+#include "common-top.h"
 
 struct tl_interp_info;
 
@@ -144,14 +145,6 @@ struct ui
   struct ui_out *m_current_uiout;
 };
 
-/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
-   It always exists and is created automatically when GDB starts
-   up.  */
-extern struct ui *main_ui;
-
-/* The current UI.  */
-extern struct ui *current_ui;
-
 /* The list of all UIs.  */
 extern struct ui *ui_list;
 
diff --git a/gdb/utils.c b/gdb/utils.c
index c6f2527..292cb9a 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3390,6 +3390,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
                       ` (3 preceding siblings ...)
  2017-02-08  3:32     ` [PATCH v3 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-02-08  3:33     ` Sergio Durigan Junior
  2017-02-15 16:15       ` Pedro Alves
  2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
                       ` (2 subsequent siblings)
  7 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:33 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

Again, it was necessary to share a few functions declared on
gdb/gdbthread.h with gdbserver, because they are needed by
fork_inferior.  I decided to implement them on
gdb/gdbserver/inferiors.c because that's where the thread functions
are also implemented on gdbserver.  Some of these functions do not
need to be implemented on gdbserver, or don't make sense there, so
they are left blank and commented properly.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* fork-child.c (fork_inferior): Update call of "set_executing".
	* gdbthread.h: Include "common-gdbthread.h".
	(init_thread_list): Moved to "common/common-gdbthread.h".
	(add_thread_silent): Likewise.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	* thread.c (set_executing): Update function comment.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (init_thread_list): New function.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	(add_thread_silent): Likewise.
	* server.c (get_last_target_waitstatus): Likewise.
	* server.h (get_last_target_waitstatus): Likewise.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 45 +++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     | 41 +++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/server.c        |  8 ++++++++
 gdb/gdbserver/server.h        |  3 +++
 gdb/gdbthread.h               | 20 +------------------
 gdb/thread.c                  |  2 ++
 7 files changed, 101 insertions(+), 19 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 84762c4..cc0fdec 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1470,6 +1470,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..eb66de9
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,45 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
+   
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_THREAD_H
+#define COMMON_THREAD_H
+
+struct target_waitstatus;
+
+/* Create an empty thread list, or empty the existing one.  */
+extern void init_thread_list (void);
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
+   marks all threads.
+
+   Note that this is different from the running state.  See the
+   description of state and executing fields of struct
+   thread_info.  */
+extern void set_executing (ptid_t ptid, int executing);
+
+/* Add a thread to the thread list and return the pointer to the new
+   thread.  Caller may use this pointer to initialize the private
+   thread data.  */
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+#endif /* ! COMMON_THREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..441ec2c 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,44 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+init_thread_list (void)
+{
+  /* To be implemented.  */
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
+{
+  gdb_assert (current_thread != NULL);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = get_last_target_waitstatus ();
+}
+
+/* See common/common-gdbthread.h.  */
+
+struct thread_info *
+add_thread_silent (ptid_t ptid)
+{
+  pid_t pid = ptid_get_pid (ptid);
+
+  /* Check if there is a process already.  */
+  if (find_process_pid (pid) == NULL)
+    add_process (pid, 0);
+
+  return add_thread (ptid_build (pid, pid, 0), NULL);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 4bc7f71..43d9406 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -236,6 +236,14 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
+/* See server.h.  */
+
+struct target_waitstatus
+get_last_target_waitstatus (void)
+{
+  return last_status;
+}
+
 static int
 start_inferior (char **argv)
 {
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..71848f1 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -148,4 +148,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* Return the global variable LAST_STATUS from server.c.  */
+extern struct target_waitstatus get_last_target_waitstatus (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 06ed78f..0d84f77 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -31,6 +31,7 @@ struct symtab;
 #include "common/vec.h"
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -344,19 +345,12 @@ struct thread_info
   struct thread_info *step_over_next;
 };
 
-/* Create an empty thread list, or empty the existing one.  */
-extern void init_thread_list (void);
-
 /* Add a thread to the thread list, print a message
    that a new thread is found, and return the pointer to
    the new thread.  Caller my use this pointer to 
    initialize the private thread data.  */
 extern struct thread_info *add_thread (ptid_t ptid);
 
-/* Same as add_thread, but does not print a message
-   about new thread.  */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
-
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
 						 struct private_thread_info *);
@@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
@@ -518,14 +508,6 @@ extern int is_exited (ptid_t ptid);
 /* In the frontend's perpective, is this thread stopped?  */
 extern int is_stopped (ptid_t ptid);
 
-/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
-   marks all threads.
-
-   Note that this is different from the running state.  See the
-   description of state and executing fields of struct
-   thread_info.  */
-extern void set_executing (ptid_t ptid, int executing);
-
 /* Reports if thread PTID is executing.  */
 extern int is_executing (ptid_t ptid);
 
diff --git a/gdb/thread.c b/gdb/thread.c
index 99fe424..b4ba4c9 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1011,6 +1011,8 @@ is_executing (ptid_t ptid)
   return tp->executing;
 }
 
+/* See common/common-gdbthread.h.  */
+
 void
 set_executing (ptid_t ptid, int executing)
 {
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
                       ` (4 preceding siblings ...)
  2017-02-08  3:33     ` [PATCH v3 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2017-02-08  3:33     ` Sergio Durigan Junior
  2017-02-08 17:34       ` Eli Zaretskii
  2017-02-17 16:05       ` Pedro Alves
  2017-02-13 19:50     ` [PATCH v3 0/6] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
  7 siblings, 2 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-08  3:33 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS (Changes since GDB 7.12): Announce that GDBserver is now
	able to start inferiors	using a shell.
	(New remote packets): Announce new packet "QStartupWithShell".
	* remote.c: Add PACKET_QStartupWithShell.
	(remote_start_remote): 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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
yyyy-mm-dd  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/NEWS                                        | 10 +++
 gdb/doc/gdb.texinfo                             | 31 +++++++++
 gdb/gdbserver/server.c                          | 36 ++++++++++-
 gdb/remote.c                                    | 20 ++++++
 gdb/testsuite/gdb.server/startup-with-shell.c   | 29 +++++++++
 gdb/testsuite/gdb.server/startup-with-shell.exp | 84 +++++++++++++++++++++++++
 6 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 21e8cd3..f26e95e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
 
 *** Changes since GDB 7.12
 
+* GDBserver is now able to start inferiors using a shell.  When using
+  "target extended-remote", the host GDB honors the value of "set
+  startup-with-shell" in order to inform GDBserver whether the remote
+  inferior should be started with a shell or not.  When using "target
+  remote", it is possible to disable the startup with shell by using
+  the new parameter "--no-startup-with-shell" when starting GDBserver.
+
 * Building GDB and GDBserver now requires a C++11 compiler.
 
   For example, GCC 4.8 or later.
@@ -367,6 +374,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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b9b4c82..04688c7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
@@ -20782,6 +20783,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}
@@ -36362,6 +36367,32 @@ 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 @var{0}, @command{gdbserver} will not use a shell to
+start the inferior.  If @var{value} is @var{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 give as hex digits.
+@end table
+
 @item qfThreadInfo
 @itemx qsThreadInfo
 @cindex list active threads, remote request
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 025f7c4..e2c4a30 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -867,6 +867,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      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;
@@ -2303,7 +2328,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 ())
@@ -3397,6 +3422,11 @@ 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.\n"
+	   "  --no-startup-with-shell\n"
+	   "                        Don't start PROG using a shell (i.e., use the exec*\n"
+	   "                        family of functions).\n"
 	   "\n"
 	   "Debug options:\n"
 	   "\n"
@@ -3680,6 +3710,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
diff --git a/gdb/remote.c b/gdb/remote.c
index 3befbd3..4d32a65 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1428,6 +1428,7 @@ enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QStartupWithShell,
   PACKET_qCRC,
   PACKET_qSearch_memory,
   PACKET_vAttach,
@@ -4079,6 +4080,20 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     remote_set_permissions (target);
 
+  /* 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);
+    }
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an
@@ -4633,6 +4648,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,
@@ -14117,6 +14134,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);
 
diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.c
@@ -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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
new file mode 100644
index 0000000..5630366
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
@@ -0,0 +1,84 @@
+# 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/>.
+
+# Test startup-with-shell support using extended-remote.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+if { [skip_gdbserver_tests] } {
+    untested "skipping gdbserver tests"
+    return 0
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+# Initial setup for simple test (wildcard expansion, variable substitution).
+
+proc initial_setup_simple { startup_with_shell run_args } {
+    global hex decimal binfile
+
+    clean_restart $binfile
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+
+    gdb_test_no_output "set startup-with-shell $startup_with_shell"
+
+    set target_exec [gdbserver_download_current_prog]
+    gdbserver_start_extended
+    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+
+    gdb_breakpoint main
+
+    gdb_test "run $run_args" \
+	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
+	"run to main"
+}
+
+## Doing the actual tests
+
+with_test_prefix "startup_with_shell = on; run_args = *.log" {
+    initial_setup_simple "on" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
+	"testing first argument"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.log" {
+    initial_setup_simple "off" "*.log"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
+	"testing first argument"
+}
+
+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)
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v2 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-02-07 22:42       ` Sergio Durigan Junior
@ 2017-02-08  9:07         ` Luis Machado
  0 siblings, 0 replies; 157+ messages in thread
From: Luis Machado @ 2017-02-08  9:07 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Pedro Alves, Eli Zaretskii

On 02/07/2017 04:41 PM, Sergio Durigan Junior wrote:
> On Wednesday, February 01 2017, Luis Machado wrote:
>
>> On 01/18/2017 09:36 AM, Sergio Durigan Junior wrote:
>>> Again, it was necessary to share a few functions declared on
>>> gdb/gdbthread.h with gdbserver, because they are needed by
>>> fork_inferior.  I decided to implement them on
>>> gdb/gdbserver/inferiors.c because that's where the thread functions
>>> are also implemented on gdbserver.  Some of these functions do not
>>> need to be implemented on gdbserver, or don't make sense there, so
>>> they are left blank and commented properly.
>>>
>>> gdb/ChangeLog:
>>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>
>>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
>>> 	* common/common-gdbthread.h: New file, with parts from
>>> 	"gdb/gdbthread.h".
>>> 	* fork-child.c (fork_inferior): Update call of "set_executing".
>>> 	* gdbthread.h: Include "common-gdbthread.h".
>>> 	(init_thread_list): Moved to "common/common-gdbthread.h".
>>> 	(add_thread_silent): Likewise.
>>> 	(switch_to_thread): Likewise.
>>> 	(set_executing): Likewise.
>>> 	* thread.c (set_executing): Update function comment.
>>>
>>> gdb/gdbserver/ChangeLog:
>>> 2017-01-17  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>
>>> 	* inferiors.c (init_thread_list): New function.
>>> 	(switch_to_thread): Likewise.
>>> 	(set_executing): Likewise.
>>> 	(add_thread_silent): Likewise.
>>> 	* server.c (get_last_target_waitstatus): Likewise.
>>> 	* server.h (get_last_target_waitstatus): Likewise.
>>> ---
>>>  gdb/Makefile.in               |  1 +
>>>  gdb/common/common-gdbthread.h | 45 +++++++++++++++++++++++++++++++++++++++++++
>>>  gdb/gdbserver/inferiors.c     | 41 +++++++++++++++++++++++++++++++++++++++
>>>  gdb/gdbserver/server.c        |  8 ++++++++
>>>  gdb/gdbserver/server.h        |  3 +++
>>>  gdb/gdbthread.h               | 20 +------------------
>>>  gdb/thread.c                  |  2 ++
>>>  7 files changed, 101 insertions(+), 19 deletions(-)
>>>  create mode 100644 gdb/common/common-gdbthread.h
>>>
>>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>>> index c0325d5..3e49e6e 100644
>>> --- a/gdb/Makefile.in
>>> +++ b/gdb/Makefile.in
>>> @@ -1467,6 +1467,7 @@ HFILES_NO_SRCDIR = \
>>>  	common/common-debug.h \
>>>  	common/common-defs.h \
>>>  	common/common-exceptions.h \
>>> +	common/common-gdbthread.h \
>>>  	common/common-regcache.h \
>>>  	common/common-types.h \
>>>  	common/common-utils.h \
>>> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
>>> new file mode 100644
>>> index 0000000..eb66de9
>>> --- /dev/null
>>> +++ b/gdb/common/common-gdbthread.h
>>> @@ -0,0 +1,45 @@
>>> +/* Common multi-process/thread control defs for GDB and gdbserver.
>>> +   Copyright (C) 1987-2017 Free Software Foundation, Inc.
>>> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
>>> +
>>> +
>>> +   This file is part of GDB.
>>> +
>>> +   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/>.  */
>>> +
>>> +#ifndef COMMON_THREAD_H
>>> +#define COMMON_THREAD_H
>>> +
>>> +struct target_waitstatus;
>>> +
>>> +/* Create an empty thread list, or empty the existing one.  */
>>> +extern void init_thread_list (void);
>>> +
>>> +/* Switch from one thread to another.  */
>>> +extern void switch_to_thread (ptid_t ptid);
>>> +
>>> +/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
>>> +   marks all threads.
>>> +
>>> +   Note that this is different from the running state.  See the
>>> +   description of state and executing fields of struct
>>> +   thread_info.  */
>>> +extern void set_executing (ptid_t ptid, int executing);
>>> +
>>> +/* Add a thread to the thread list and return the pointer to the new
>>> +   thread.  Caller may use this pointer to initialize the private
>>> +   thread data.  */
>>> +extern struct thread_info *add_thread_silent (ptid_t ptid);
>>> +
>>> +#endif /* ! COMMON_THREAD_H */
>>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>>> index b65a726..441ec2c 100644
>>> --- a/gdb/gdbserver/inferiors.c
>>> +++ b/gdb/gdbserver/inferiors.c
>>> @@ -468,3 +468,44 @@ make_cleanup_restore_current_thread (void)
>>>  {
>>>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>>>  }
>>> +
>>> +/* See common/common-gdbthread.h.  */
>>> +
>>> +void
>>> +init_thread_list (void)
>>> +{
>>> +  /* To be implemented.  */
>>> +}
>>> +
>>> +/* See common/common-gdbthread.h.  */
>>> +
>>> +void
>>> +switch_to_thread (ptid_t ptid)
>>> +{
>>> +  if (!ptid_equal (ptid, minus_one_ptid))
>>> +    current_thread = find_thread_ptid (ptid);
>>> +}
>>> +
>>> +/* See common/common-gdbthread.h.  */
>>> +
>>> +void
>>> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
>>> +{
>>> +  gdb_assert (current_thread != NULL);
>>> +  current_thread->last_resume_kind = resume_stop;
>>> +  current_thread->last_status = get_last_target_waitstatus ();
>>> +}
>>> +
>>
>>
>> I'm still not sure about this particular function. But i'd like to
>> hear what other think.
>
> What are your concerns?

Having those parameters that are not actually used, as opposed to having 
a function that is the same for both GDB and GDBserver.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-02-08 17:34       ` Eli Zaretskii
  2017-02-09  0:02         ` Sergio Durigan Junior
  2017-02-17 16:05       ` Pedro Alves
  1 sibling, 1 reply; 157+ messages in thread
From: Eli Zaretskii @ 2017-02-08 17:34 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves, lgustavo

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>, Luis Machado <lgustavo@codesourcery.com>,        Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Tue,  7 Feb 2017 22:22:57 -0500
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 21e8cd3..f26e95e 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,13 @@
>  
>  *** Changes since GDB 7.12
>  
> +* GDBserver is now able to start inferiors using a shell.  When using
> +  "target extended-remote", the host GDB honors the value of "set
> +  startup-with-shell" in order to inform GDBserver whether the remote
> +  inferior should be started with a shell or not.  When using "target
> +  remote", it is possible to disable the startup with shell by using
> +  the new parameter "--no-startup-with-shell" when starting GDBserver.
> +
>  * Building GDB and GDBserver now requires a C++11 compiler.
>  
>    For example, GCC 4.8 or later.
> @@ -367,6 +374,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.

This part is OK.

> +If @var{value} is @var{0}, @command{gdbserver} will not use a shell to
> +start the inferior.  If @var{value} is @var{1}, @command{gdbserver}

"0" and "1" should be in @samp, not @var, because they are literal
symbols.

> +@item E @var{nn}
> +An error occurred.  The error number @var{nn} is give as hex digits.
                                                    ^^^^
"given"

Documentation patch is OK with those minor issues fixed.

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-08 17:34       ` Eli Zaretskii
@ 2017-02-09  0:02         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-09  0:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, palves, lgustavo

On Wednesday, February 08 2017, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: Pedro Alves <palves@redhat.com>, Luis Machado <lgustavo@codesourcery.com>,        Sergio Durigan Junior <sergiodj@redhat.com>
>> Date: Tue,  7 Feb 2017 22:22:57 -0500
>> 
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index 21e8cd3..f26e95e 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -3,6 +3,13 @@
>>  
>>  *** Changes since GDB 7.12
>>  
>> +* GDBserver is now able to start inferiors using a shell.  When using
>> +  "target extended-remote", the host GDB honors the value of "set
>> +  startup-with-shell" in order to inform GDBserver whether the remote
>> +  inferior should be started with a shell or not.  When using "target
>> +  remote", it is possible to disable the startup with shell by using
>> +  the new parameter "--no-startup-with-shell" when starting GDBserver.
>> +
>>  * Building GDB and GDBserver now requires a C++11 compiler.
>>  
>>    For example, GCC 4.8 or later.
>> @@ -367,6 +374,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.
>
> This part is OK.
>
>> +If @var{value} is @var{0}, @command{gdbserver} will not use a shell to
>> +start the inferior.  If @var{value} is @var{1}, @command{gdbserver}
>
> "0" and "1" should be in @samp, not @var, because they are literal
> symbols.
>
>> +@item E @var{nn}
>> +An error occurred.  The error number @var{nn} is give as hex digits.
>                                                     ^^^^
> "given"
>
> Documentation patch is OK with those minor issues fixed.

Thanks, I fixed the minor issues you pointed.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 0/6] Implement the ability to start inferiors with a shell on gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
                       ` (5 preceding siblings ...)
  2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-02-13 19:50     ` Sergio Durigan Junior
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
  7 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-13 19:50 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado

On Tuesday, February 07 2017, I wrote:

> Hi again,
>
> This is the third version of this patch series.  I addressed the
> comments made by Luis.

Ping.

> Here's what changed from v2:
>
>  - Fixed many formatting nits (spurious newlines, indentation, etc.)
>
>  - Added description of expected values by QStartupWithShell packet
>
> Additionally, here's what changed from v1:
>
>  - Added NEWS entry
>
>  - Mentioned that the feature is to be used on UNIX-like systems
>
>  - Removed third argument from set_executing
>
>  - Removed 'set remote startup-shell' command
>
>  - Renamed the packet to QStartupWithShell.  Now, the packet has only
>    a boolean argument: "1" (meaning that the remote target should use
>    a shell to start the inferior), and "0" (the remote target should
>    not use a shell to start the inferior).
>
>  - Write documentation for this new packet
>
>  - Fixed and rewrote ChangeLog entries
>
>  - Fixed spurious newlines on comments.
>
>  - Fix comments that only mentioned "GDB" on files that are now being
>    shared with gdbserver.
>
>  - Adjust copyright notices on files
>
>  - Use "untested" where applicable on the testcase
>
>
> This patch series implement the "startup-with-shell" feature on
> gdbserver.  This means that it will be possible to start inferiors
> using the shell (instead of calling execv*), which brings many
> advantages.
>
> First of all, it will be possible to use I/O redirection, variable
> substitution and globbing expansion on gdbserver just like we do today
> on GDB.  This is great because, among other things, it brings
> gdbserver on a pair with GDB when considering the Feature Parity
> project.
>
> Secondly, a great deal of code had to be shared between GDB and
> gdbserver, especially the fork_inferior function, which means that now
> both programs are using virtually the same code to start inferiors.
> I've also had to touch on other areas, like terminal.h, inflow.c and
> gdbthread.h, and even though only the APIs were shared (i.e.,
> gdbserver's version of a gdbthread.h function may differ from GDB's
> version), this is also beneficial in the long run when we start to
> unify the code more deeply.  But I'm "raining in the wet" here; all
> this has been explained in better terms before.
>
> I did my best to split the patches, but unfortunately the
> fork_inferior patch is big and I couldn't see a better way to do that.
> But it shouldn't be very hard to review them, because most of it is
> just "code movement".

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 1/6] Share gdb/environ.[ch] with gdbserver
  2017-02-08  3:25     ` [PATCH v3 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
@ 2017-02-15 15:36       ` Pedro Alves
  2017-03-07 20:50         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-02-15 15:36 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
> We will need access to the environment functions when we share
> fork_inferior between GDB and gdbserver, therefore we simply make the
> API on gdb/environ.[ch] available on common/.  No extra adjustments
> are needed to make it compile on gdbserver.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in (SFILES): Replace "environ.c" with
> 	"common/environ.c".
> 	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
> 	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
> 	to...
> 	* common/environ.c: ... here.
> 	* environ.h: Moved to...
> 	* common/environ.h: ... here.
> 
> gdb/gdbserver/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in (SFILES): Add "common/environ.c".
> 	(OBJS): Add "common/environ.h".

OK.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
@ 2017-02-15 15:54       ` Pedro Alves
  2017-02-16 21:37         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-02-15 15:54 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
> As part of the bigger work of sharing fork_inferior with gdbserver,
> some parts of gdb/terminal.h also needed to be moved to a common
> place.  These parts are:
> 
> - The code responsible for determining some terminal-based define's
>   based on available features;
> 
> - job control;
> 
> - terminal-related functions needed by fork_inferior;
> 


> diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
> new file mode 100644
> index 0000000..956bfcc
> --- /dev/null
> +++ b/gdb/common/common-terminal.h
> @@ -0,0 +1,125 @@


> +#ifndef COMMON_TERMINAL_H
> +#define COMMON_TERMINAL_H
> +
> +/* If we're using autoconf, it will define HAVE_TERMIOS_H,
> +   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
> +   ser-unix.c and inflow.c to inspect those names instead of
> +   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
> +   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
> +   nothing has already defined the one of the names, and do the right
> +   thing.  */

We try to keep common/ self-contained wrt autoconf -- i.e.,
corresponding autoconf checks should be added to common/common.m4.

> +
> +#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
> +#if defined(HAVE_TERMIOS_H)
> +#define HAVE_TERMIOS


> +/* Do we have job control?  Can be assumed to always be the same
> +   within a given run of GDB.  Use in gdb/inflow.c and
> +   common/common-inflow.c.  */
> +extern int job_control;
> +

...

> +/* Set the process group of the caller to its own pid, or do nothing
> +   if we lack job control.  */
> +extern int gdb_setpgid (void);
> +
> +/* Determine whether we have job control, and set variable JOB_CONTROL
> +   accordingly.  */
> +extern void have_job_control (void);

It had been clearer if these three were moved in the patch that
moves the corresponding .c code.  I was going to comment in that
patch that the "have_job_control" documentation should
mention that it must be called early, before "job_control"
is ever used.  And that that patch would have better been the one
that adds the have_job_control() calls to the appropriate
places.  With the split as is, this detail ends up easily missed.

> +
> +#endif /* ! COMMON_TERMINAL_H */
> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
> new file mode 100644
> index 0000000..42ac651
> --- /dev/null
> +++ b/gdb/gdbserver/terminal.c
> @@ -0,0 +1,88 @@

> +/* See common/common-terminal.h.  */
> +
> +pid_t
> +create_tty_session (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +  return (pid_t) 1;

Without looking at the caller, it would seem to me that -1 / 0 
would make more sense, and "1" kind of looks like a typo/bug.
Please add a comment mentioning why this returns 1.

> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +void
> +set_inferior_io_terminal (const char *terminal_name)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +const char *
> +get_inferior_io_terminal (void)
> +{
> +  /* Placeholder needed by fork_inferior.  For now, this function is
> +     not needed nor useful to have on gdbserver.  When/If we properly
> +     handle terminal modes, we can revisit and implement the needed
> +     support.  */

How about instead of repeating the same comment multiple times,
we add it once at the top:

  /* Placeholders needed by fork_inferior.  For now, these functions are
     not needed nor useful to have on gdbserver.  When/If we properly
     handle terminal modes, we can revisit and implement the needed
     support.  */

?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 3/6] Share parts of gdb/inflow.c with gdbserver
  2017-02-08  3:25     ` [PATCH v3 3/6] Share parts of gdb/inflow.c " Sergio Durigan Junior
@ 2017-02-15 16:02       ` Pedro Alves
  2017-02-16 22:06         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-02-15 16:02 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:

> gdb/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in (SFILES): Add "common/common-inflow.c".
> 	(COMMON_OBS): Add "common/common-inflow.o".
> 	* common/common-inflow.c: New file, with contents from
> 	"gdb/inflow.c".
> 	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
> 	(_initialize_inflow): Move setting of "job_control" to
> 	"handle_job_control".
> 	* utils.c (job_control): Delete.
> 
> gdb/gdbserver/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in: Add rule for "common-inflow.o".
> 	(SFILE): Add "common/common-inflow.c".
> 	(OBS): Add "common-inflow.o".


We should take the opportunity to rename the file to something that
makes a more sense wrt to its contents.  "inflow.c" in gdb is
horribly named, I think simply due to code evolution.  It used to
contain, many many years ago the (from the top of the file):

/* Low level interface to ptrace, for GDB when running under Unix.

but everything related to low level ptrace stuff moved away, and
all it was left with was the terminal/job control stuff.

Maybe call it common/job-control.c or maybe something even more
to the point or something like that.

> diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
> new file mode 100644
> index 0000000..9871b5e
> --- /dev/null
> +++ b/gdb/common/common-inflow.c
> @@ -0,0 +1,91 @@
> +/* Low level interface to ptrace, for GDB and gdbserver when running under Unix.

Please update this.  The file really has nothing to do with ptrace.

> +
> +#include "common-defs.h"
> +#include "common-terminal.h"
> +
> +/* Nonzero if we have job control.  */
> +int job_control;
> +
> +/* This is here because this is where we figure out whether we (probably)
> +   have job control.  Just using job_control only does part of it because
> +   setpgid or setpgrp might not exist on a system without job control.
> +   It might be considered misplaced (on the other hand, process groups and
> +   job control are closely related to ttys).


This "misplaced" comment could use some updating.  This is no longer
next to the tty stuff.

> +
> +   For a more clean implementation, in libiberty, put a setpgid which merely
> +   calls setpgrp and a setpgrp which does nothing (any system with job control
> +   will have one or the other).  */
> +
> +int
> +gdb_setpgid (void)
> +{
> +  int retval = 0;
> +
> +  if (job_control)
> +    {
> +#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
> +#ifdef HAVE_SETPGID
> +      /* The call setpgid (0, 0) is supposed to work and mean the same
> +         thing as this, but on Ultrix 4.2A it fails with EPERM (and
> +         setpgid (getpid (), getpid ()) succeeds).  */
> +      retval = setpgid (getpid (), getpid ());
> +#else
> +#ifdef HAVE_SETPGRP

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-02-08  3:33     ` [PATCH v3 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2017-02-15 16:15       ` Pedro Alves
  2017-02-21 21:27         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-02-15 16:15 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:

> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
> new file mode 100644
> index 0000000..eb66de9
> --- /dev/null
> +++ b/gdb/common/common-gdbthread.h
> @@ -0,0 +1,45 @@
> +/* Common multi-process/thread control defs for GDB and gdbserver.
> +   Copyright (C) 1987-2017 Free Software Foundation, Inc.
> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
> +   
> +

Spurious blank line.  That "contributed by" line is meaningless
for this new file, please remove it.

> +   This file is part of GDB.

> +#ifndef COMMON_THREAD_H
> +#define COMMON_THREAD_H

This macro name does not patch the file name.

> +/* See common/common-gdbthread.h.  */
> +
> +void
> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
> +{
> +  gdb_assert (current_thread != NULL);
> +  current_thread->last_resume_kind = resume_stop;
> +  current_thread->last_status = get_last_target_waitstatus ();
> +}
> +

This is a bit too hacky to live IMO.  :-/  The implementation
of the function is doing nothing related to its interface.

Do we really need the set_executing call in the new shared file?  AFAICS, 
set_executing is only called at the very end of startup_inferior today.
Couldn't we leave that call out of the common code and add it on the
gdb side, after the common startup_inferior returns?

>  
> -/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
> -   marks all threads.
> -
> -   Note that this is different from the running state.  See the
> -   description of state and executing fields of struct
> -   thread_info.  */
> -extern void set_executing (ptid_t ptid, int executing);
> -
>  /* Reports if thread PTID is executing.  */
>  extern int is_executing (ptid_t ptid);

Having a setter in one place, and the getter somewhere
else is sure to generate confusion.  In cases like these,
please leave a breadcrumb comment.  (there may be more cases.)

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-08  3:32     ` [PATCH v3 5/6] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-02-15 17:28       ` Pedro Alves
  2017-02-16 12:23         ` Philipp Rudo
  2017-03-07 19:51         ` Sergio Durigan Junior
  0 siblings, 2 replies; 157+ messages in thread
From: Pedro Alves @ 2017-02-15 17:28 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

Hi Sergio,

I think I'll likely have more comments, but this large, so
here's a first pass.

> diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
> new file mode 100644
> index 0000000..f4d7866
> --- /dev/null
> +++ b/gdb/common/common-fork-child.c
> @@ -0,0 +1,593 @@
> +/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
> +
> +   Copyright (C) 1990-2017 Free Software Foundation, Inc.
> +
> +   Originally contributed by Cygnus Support.

We should just take the opportunity to drop that per recent policy.
Plenty of files added by Cygnus (nowadays Red Hat) don't have that marker,
this won't be missed, IMO.

> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +

> +int
> +fork_inferior (char *exec_file_arg, char *allargs, char **env,
> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
> +	       void (*exec_fun)(const char *file, char * const *argv,
> +				char * const *env))
> +{

> +  /* Retain a copy of our environment variables, since the child will
> +     replace the value of environ and if we're vforked, we have to
> +     restore it.  */
> +  save_our_env = environ;
> +
> +  /* Likewise the current UI.  */
> +  save_ui = current_ui;

Hmm, making this compile on gdbserver is of course a hack,
since there's not such thing as a "UI" concept on gdbserver...

> +
> +  /* Tell the terminal handling subsystem what tty we plan to run on;
> +     it will just record the information for later.  */
> +  new_tty_prefork (inferior_io_terminal);

I wonder about calling here instead a more generalized hook, and
moving the save_ui saving and the new_tty_prefork calls to
that hook's gdb implementation.  Might be easier to do that after
the series is in...

> +
> +  /* It is generally good practice to flush any possible pending stdio
> +     output prior to doing a fork, to avoid the possibility of both
> +     the parent and child flushing the same data after the fork.  */
> +  gdb_flush_out_err ();
> +
> +  /* If there's any initialization of the target layers that must
> +     happen to prepare to handle the child we're about fork, do it
> +     now...  */
> +  if (pre_trace_fun != NULL)
> +    (*pre_trace_fun) ();
> +


> +++ b/gdb/common/common-top.h
> @@ -0,0 +1,31 @@
> +/* Common top level stuff for GDB and GDBserver.
> +
> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_TOP_H
> +#define COMMON_TOP_H
> +
> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> +   It always exists and is created automatically when GDB starts
> +   up.  */
> +extern struct ui *main_ui;
> +
> +/* The current UI.  */
> +extern struct ui *current_ui;
> +

Not exactly thrilled with moving this to common.

> +#endif /* ! COMMON_TOP_H */

>  /* Implement the "unset exec-wrapper" command.  */
> @@ -585,7 +73,7 @@ Show the wrapper for running programs."), NULL,
>             &unsetlist);
>  
>    add_setshow_boolean_cmd ("startup-with-shell", class_support,
> -			   &startup_with_shell, _("\
> +			   (int *) &startup_with_shell, _("\

That's invalid C/C++.  Don't do that.

>  Set use of shell to start subprocesses.  The default is on."), _("\
>  Show use of shell to start subprocesses."), NULL,
>  			   NULL,


> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>  
>  #define get_thread(inf) ((struct thread_info *)(inf))
>  
> +ptid_t inferior_ptid;

What do we need this for?  gdbserver already has
a "current thread" global.  Another one looks like asking
for out-of-sync trouble.

>  /* See common/common-gdbthread.h.  */
>  
>  void
>  init_thread_list (void)
>  {
> -  /* To be implemented.  */
> +  /* Placeholder needed for fork_inferior.  No action is needed.  */

Pick one of the comments, and move it to the right patch.

>  }
>  

> -/* Add a process to the common process list, and set its private
> -   data.  */
> +/* Update process represented by PID with necessary info.  */
>  
>  static struct process_info *
> -linux_add_process (int pid, int attached)
> +linux_update_process (int pid)

I'm not sure I understand the need for this yet.  I need
to look deeper.  "update what?  why?"  Or maybe the
comments should be improved.  :-)


>  {
> -  struct process_info *proc;
> +  struct process_info *proc = find_process_pid (pid);
>  
> -  proc = add_process (pid, attached);
> +  gdb_assert (proc != NULL);
>    proc->priv = XCNEW (struct process_info_private);
>  
>    if (the_low_target.new_process != NULL)
> @@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
>    return proc;
>  }
>  

> +/* Update the lwp associated to thread represented by PTID.  */
> +
> +static struct lwp_info *
> +update_thread_lwp (ptid_t ptid)

Ditto.

>  /* Start an inferior process and returns its pid.
>     ALLARGS is a vector of program-name and args. */
>  
>  static int
> -linux_create_inferior (char *program, char **allargs)
> +linux_create_inferior (std::vector<char *> &program_argv)

"const std::vector<char *> &" ?  Same comment for the whole
call chain, of course.

>  {
>    struct lwp_info *new_lwp;
>    int pid;
>    ptid_t ptid;
>    struct cleanup *restore_personality
>      = maybe_disable_address_space_randomization (disable_randomization);
> +  std::string program_args = stringify_argv (program_argv);
>  
> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
> -  pid = vfork ();
> -#else
> -  pid = fork ();
> -#endif
> -  if (pid < 0)
> -    perror_with_name ("fork");
> +  pre_fork_inferior (program_argv);
>  
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> -
> -      setpgid (0, 0);
> -
> -      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
> -	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
> -	 Also, redirect stdin to /dev/null.  */
> -      if (remote_connection_is_stdio ())
> -	{
> -	  close (0);
> -	  open ("/dev/null", O_RDONLY);
> -	  dup2 (2, 1);
> -	  if (write (2, "stdin/stdout redirected\n",
> -		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
> -	    {
> -	      /* Errors ignored.  */;
> -	    }
> -	}
> -
> -      restore_original_signals_state ();
> -
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> -
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  pid = fork_inferior (program_argv[0],
> +		       (char *) program_args.c_str (),

Can we constify fork_inferior's parameters to avoid such
cast hacks ?

> +		       environ_vector (get_environ ()), linux_ptrace_fun,
> +		       NULL, NULL, NULL, NULL);
>  
>    do_cleanups (restore_personality);
>  
> -  linux_add_process (pid, 0);
> +  linux_update_process (pid);
>  
>    ptid = ptid_build (pid, pid, 0);
> -  new_lwp = add_lwp (ptid);
> +  new_lwp = update_thread_lwp (ptid);
>    new_lwp->must_set_ptrace_flags = 1;
>  
> +  post_fork_inferior (pid, program_argv);
> +
>    return pid;
>  }
>  

> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_wrapper (void)
>  {
> -  char **new_argv = argv;
> +  static std::string ret;
> +  static int initialized_p = 0;

bool.

> +
> +  if (wrapper_argv.empty ())
> +    return NULL;
>  
> -  if (wrapper_argv != NULL)
> +  if (!initialized_p)
>      {
> -      int i, count = 1;
> -
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	count++;
> -      for (i = 0; argv[i] != NULL; i++)
> -	count++;
> -      new_argv = XALLOCAVEC (char *, count);
> -      count = 0;
> -      for (i = 0; wrapper_argv[i] != NULL; i++)
> -	new_argv[count++] = wrapper_argv[i];
> -      for (i = 0; argv[i] != NULL; i++)
> -	new_argv[count++] = argv[i];
> -      new_argv[count] = NULL;
> +      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
> +	   i != wrapper_argv.end ();
> +	   ++i)
> +	ret += *i + std::string (" ");

      for (auto arg : wrapper_argv)
	ret += arg + " ";

> +
> +      /* Erasing the last whitespace.  */

"Erase".

> +      ret.erase (ret.end () - 1);
> +
> +      initialized_p = 1;
>      }
>  
> +  return (char *) ret.c_str ();

Can the function return const instead?

> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +char *
> +get_exec_file (int err)
> +{
> +  if (err && program_argv.empty ())
> +    error (_("Could not get the exec file."));

I think this error message could be improved.  If I see
that on the gdbserver terminal, I'll have no clue what
it means.  "get from where??"  How about just saying
the same thing gdb says, sans the "Use the ..." part?

> +  return program_argv[0];
> +}
> +
> +/* See server.h.  */
> +
> +struct gdb_environ *
> +get_environ (void)
> +{
> +  return our_environ;
> +}
> +
> +/* See server.h.  */
> +
> +void
> +pre_fork_inferior (std::vector<char *> &argv)
> +{
>    if (debug_threads)
>      {
> -      int i;
> -      for (i = 0; new_argv[i]; ++i)
> -	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
> +      int idx = 0;
> +
> +      for (char *&i : argv)

Reference to pointer is pointless, it's like pointer to
pointer.  This should be fine:

      for (char *i : argv)

I'd suggest naming the variable something else, since
it's not really an iterator.  Like e.g.,:

      for (char *str : argv)
      for (char *arg : argv)

> +	{
> +	  debug_printf ("new_argv[%d] = \"%s\"\n", idx, i);
> +	  ++idx;

OTOH, if you're needing/maintaining an index anyway,
this ends up clearer IMO:

      for (int idx = 0; idx < argv.size(); idx++)
        debug_printf ("new_argv[%d] = \"%s\"\n", idx, argv[idx]);

> +	}
>        debug_flush ();
>      }
>  



>  handle_v_run (char *own_buf)
>  {
> -  char *p, *next_p, **new_argv;
> -  int i, new_argc;
> +  char *p, *next_p;
> +  std::vector<char *> new_argv;
> +  int new_argc;
> +  int i;
>  
>    new_argc = 0;
>    for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
> @@ -2870,62 +2893,91 @@ handle_v_run (char *own_buf)
>        new_argc++;
>      }
>  
> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
> -  if (new_argv == NULL)
> -    {
> -      write_enn (own_buf);
> -      return 0;
> -    }
> -
> -  i = 0;
> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>      {
>        next_p = strchr (p, ';');
>        if (next_p == NULL)
>  	next_p = p + strlen (p);
>  
> -      if (i == 0 && p == next_p)
> -	new_argv[i] = NULL;
> +      if (p == next_p)
> +	new_argv.push_back ("''");
>        else
>  	{
>  	  /* FIXME: Fail request if out of memory instead of dying.  */
> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
> -	  new_argv[i][(next_p - p) / 2] = '\0';
> +	  size_t len = 1 + (next_p - p) / 2;
> +	  char *s = (char *) xmalloc (len);
> +	  char *ss = (char *) xmalloc (len * 2);
> +	  char *tmp_s, *tmp_ss;
> +	  int need_quote;
> +
> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
> +	  s[(next_p - p) / 2] = '\0';
> +
> +	  tmp_s = s;
> +	  tmp_ss = ss;
> +	  need_quote = 0;
> +	  while (*tmp_s != '\0')
> +	    {
> +	      switch (*tmp_s)
> +		{
> +		case '\n':
> +		  *tmp_ss = '\'';
> +		  ++tmp_ss;
> +		  need_quote = 1;
> +		  break;
> +
> +		case '\'':
> +		  *tmp_ss = '\\';
> +		  ++tmp_ss;
> +		  break;
> +
> +		default:
> +		  break;
> +		}
> +
> +	      *tmp_ss = *tmp_s;
> +	      ++tmp_ss;
> +	      ++tmp_s;
> +	    }
> +
> +	  if (need_quote)
> +	    *tmp_ss++ = '\'';

Hmm, is this quoting stuff being moved from somewhere,
or it is new?

> +
> +	  *tmp_ss = '\0';
> +	  new_argv.push_back (ss);
> +	  xfree (s);
>  	}
>  
>        if (*next_p)
>  	next_p++;
> -      i++;
>      }
> -  new_argv[i] = NULL;

>  
> +  /* Gather information about the environment.  */
> +  our_environ = make_environ ();
> +  init_environ (our_environ);
> +
>    initialize_async_io ();
>    initialize_low ();
> +  /* This is called when initializing inflow on GDB.  */

What is this comment supposed be to telling?

> +  have_job_control ();
>    initialize_event_loop ();
>    if (target_supports_tracepoints ())
>      initialize_tracepoint ();
> @@ -3695,13 +3758,11 @@ captured_main (int argc, char *argv[])
>        int i, n;
>  
>        n = argc - (next_arg - argv);
> -      program_argv = XNEWVEC (char *, n + 1);
>        for (i = 0; i < n; i++)
> -	program_argv[i] = xstrdup (next_arg[i]);
> -      program_argv[i] = NULL;
> +	program_argv.push_back (xstrdup (next_arg[i]));
>  

> -#define create_inferior(program, args) \
> -  (*the_target->create_inferior) (program, args)
> +#define create_inferior(program) \
> +  (*the_target->create_inferior) (program)

program_argv, I suppose.

> +/* See common/common-utils.h.  */
> +
> +std::string
> +stringify_argv (std::vector<char *> &argv)
> +{
> +  std::string ret ("");

   std::string ret;

> +
> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
> +       i != argv.end ();
> +       ++i)
> +    ret += *i + std::string (" ");

Should we remove the last empty space?

> +
> +  return ret;
> +}
> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
> index b4ded31..a30d99a 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/gdbserver/utils.h
> @@ -19,7 +19,17 @@
>  #ifndef UTILS_H
>  #define UTILS_H
>  
> +#include <vector>
> +
>  char *paddress (CORE_ADDR addr);
>  char *pfildes (gdb_fildes_t fd);
>  
> +/* Works like FREEARGV, but with std::vector.  */
> +extern void free_vector_argv (std::vector<char *> &v);

At some point, freeargv is eliminated, and this comment will
stay behind.  Can we expand it a bit?

> +
> +/* Given a vector of arguments ARGV, return a string equivalent to
> +   joining all the arguments (starting from ARGV + 1) with a
> +   whitespace separating them.  */
> +extern std::string stringify_argv (std::vector<char *> &argv);

const ?

This "starting from ARGV + 1" contract was surprising to me.
I only noticed this when I saw the implementation.

Does it really make sense to put the program name inside the
vector instead of on a separate argument if we're always going
to treat argv[0] differently?

I.e., would:

- ...create_inferior (char *program, char **program_args)
+ ...create_inferior (char *program, std::vector<char *> &program_args)

make more sense?

>  static int
> -win32_create_inferior (char *program, char **program_args)
> +win32_create_inferior (std::vector<char *> &program_argv)
>  {
>  #ifndef USE_WIN32API
>    char real_path[PATH_MAX];
> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>    int argc;
>    PROCESS_INFORMATION pi;
>    DWORD err;
> +  char *program = program_argv[0];
> +  std::string program_args = stringify_argv (program_argv);
> +  char *args = (char *) program_args.c_str ();
>  
>    /* win32_wait needs to know we're not attaching.  */
>    attaching = 0;
> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>  
>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>  
> +  pre_fork_inferior (program, argv);

Hmm, fork on Windows?

> +
>  #ifndef USE_WIN32API
>    orig_path = NULL;
>    path_ptr = getenv ("PATH");
> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>    program = real_path;
>  #endif
>  
> -  argslen = 1;
> -  for (argc = 1; program_args[argc]; argc++)
> -    argslen += strlen (program_args[argc]) + 1;
> -  args = (char *) alloca (argslen);
> -  args[0] = '\0';
> -  for (argc = 1; program_args[argc]; argc++)
> -    {
> -      /* FIXME: Can we do better about quoting?  How does Cygwin
> -	 handle this?  */
> -      strcat (args, " ");
> -      strcat (args, program_args[argc]);
> -    }
>    OUTMSG2 (("Command line is \"%s\"\n", args));
>  
>  #ifdef CREATE_NEW_PROCESS_GROUP
> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>  
>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>  
> +  post_fork_inferior (current_process_id, program_argv);
> +
>    return current_process_id;
>  }
>  


> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>  set msg "gdbserver exits cleanly"
>  set saw_exiting 0
>  expect {
> -    # This is what we get on ptrace-based targets.
> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
> +    # This is what we get on ptrace-based targets with
> +    # startup-with-shell disabled.
> +    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
> +	set saw_exiting 1
> +	exp_continue

Shouldn't this be a part of the next patch?

> +    }
> +    # Likewise, but with startup-with-shell enabled.
> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>  	set saw_exiting 1
>  	exp_continue
>      }

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-15 17:28       ` Pedro Alves
@ 2017-02-16 12:23         ` Philipp Rudo
  2017-02-16 12:26           ` Pedro Alves
  2017-03-07 19:51         ` Sergio Durigan Junior
  1 sibling, 1 reply; 157+ messages in thread
From: Philipp Rudo @ 2017-02-16 12:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Sergio Durigan Junior, GDB Patches, Luis Machado

On Wed, 15 Feb 2017 17:28:24 +0000
Pedro Alves <palves@redhat.com> wrote:

[...]

> > +      ret.erase (ret.end () - 1);
> > +
> > +      initialized_p = 1;
> >      }
> >  
> > +  return (char *) ret.c_str ();  
> 
> Can the function return const instead?

No it can't. The function must either return the std::string or
xstrdup (ret.c_str ()).  'std::string ret' is declared for this
function only.  Thus it is freed once the function returns ret.c_str ()
leaving a dangling pointer.

Philipp

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-16 12:23         ` Philipp Rudo
@ 2017-02-16 12:26           ` Pedro Alves
  2017-02-16 12:37             ` Philipp Rudo
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-02-16 12:26 UTC (permalink / raw)
  To: Philipp Rudo; +Cc: Sergio Durigan Junior, GDB Patches, Luis Machado

On 02/16/2017 12:23 PM, Philipp Rudo wrote:
> On Wed, 15 Feb 2017 17:28:24 +0000
> Pedro Alves <palves@redhat.com> wrote:
> 
> [...]
> 
>>> +      ret.erase (ret.end () - 1);
>>> +
>>> +      initialized_p = 1;
>>>      }
>>>  
>>> +  return (char *) ret.c_str ();  
>>
>> Can the function return const instead?
> 
> No it can't. The function must either return the std::string or
> xstrdup (ret.c_str ()).  'std::string ret' is declared for this
> function only.  Thus it is freed once the function returns ret.c_str ()
> leaving a dangling pointer.

Nope, it's not freed on return.  You've missed the "static":

char *
get_exec_wrapper (void)
{
  char **new_argv = argv;
  static std::string ret;
  ^^^^^^

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-16 12:26           ` Pedro Alves
@ 2017-02-16 12:37             ` Philipp Rudo
  0 siblings, 0 replies; 157+ messages in thread
From: Philipp Rudo @ 2017-02-16 12:37 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Sergio Durigan Junior, GDB Patches, Luis Machado

On Thu, 16 Feb 2017 12:26:05 +0000
Pedro Alves <palves@redhat.com> wrote:

> On 02/16/2017 12:23 PM, Philipp Rudo wrote:
> > On Wed, 15 Feb 2017 17:28:24 +0000
> > Pedro Alves <palves@redhat.com> wrote:
> > 
> > [...]
> >   
> >>> +      ret.erase (ret.end () - 1);
> >>> +
> >>> +      initialized_p = 1;
> >>>      }
> >>>  
> >>> +  return (char *) ret.c_str ();    
> >>
> >> Can the function return const instead?  
> > 
> > No it can't. The function must either return the std::string or
> > xstrdup (ret.c_str ()).  'std::string ret' is declared for this
> > function only.  Thus it is freed once the function returns
> > ret.c_str () leaving a dangling pointer.  
> 
> Nope, it's not freed on return.  You've missed the "static":
> 
> char *
> get_exec_wrapper (void)
> {
>   char **new_argv = argv;
>   static std::string ret;
>   ^^^^^^

Indeed I did...
Sorry for the spam

Philipp

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver
  2017-02-15 15:54       ` Pedro Alves
@ 2017-02-16 21:37         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-16 21:37 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

Hey Pedro,

Thanks for the review.  Comments below.

On Wednesday, February 15 2017, Pedro Alves wrote:

> On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
>> As part of the bigger work of sharing fork_inferior with gdbserver,
>> some parts of gdb/terminal.h also needed to be moved to a common
>> place.  These parts are:
>> 
>> - The code responsible for determining some terminal-based define's
>>   based on available features;
>> 
>> - job control;
>> 
>> - terminal-related functions needed by fork_inferior;
>> 
>
>
>> diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
>> new file mode 100644
>> index 0000000..956bfcc
>> --- /dev/null
>> +++ b/gdb/common/common-terminal.h
>> @@ -0,0 +1,125 @@
>
>
>> +#ifndef COMMON_TERMINAL_H
>> +#define COMMON_TERMINAL_H
>> +
>> +/* If we're using autoconf, it will define HAVE_TERMIOS_H,
>> +   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
>> +   ser-unix.c and inflow.c to inspect those names instead of
>> +   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
>> +   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
>> +   nothing has already defined the one of the names, and do the right
>> +   thing.  */
>
> We try to keep common/ self-contained wrt autoconf -- i.e.,
> corresponding autoconf checks should be added to common/common.m4.

Done.  Thanks for bringing this to my attention.

>> +
>> +#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
>> +#if defined(HAVE_TERMIOS_H)
>> +#define HAVE_TERMIOS
>
>
>> +/* Do we have job control?  Can be assumed to always be the same
>> +   within a given run of GDB.  Use in gdb/inflow.c and
>> +   common/common-inflow.c.  */
>> +extern int job_control;
>> +
>
> ...
>
>> +/* Set the process group of the caller to its own pid, or do nothing
>> +   if we lack job control.  */
>> +extern int gdb_setpgid (void);
>> +
>> +/* Determine whether we have job control, and set variable JOB_CONTROL
>> +   accordingly.  */
>> +extern void have_job_control (void);
>
> It had been clearer if these three were moved in the patch that
> moves the corresponding .c code.  I was going to comment in that
> patch that the "have_job_control" documentation should
> mention that it must be called early, before "job_control"
> is ever used.  And that that patch would have better been the one
> that adds the have_job_control() calls to the appropriate
> places.  With the split as is, this detail ends up easily missed.

Hm, OK.  I'll reorganize this part of the patch, then.  Sorry about
that.

>> +#endif /* ! COMMON_TERMINAL_H */
>> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
>> new file mode 100644
>> index 0000000..42ac651
>> --- /dev/null
>> +++ b/gdb/gdbserver/terminal.c
>> @@ -0,0 +1,88 @@
>
>> +/* See common/common-terminal.h.  */
>> +
>> +pid_t
>> +create_tty_session (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +  return (pid_t) 1;
>
> Without looking at the caller, it would seem to me that -1 / 0 
> would make more sense, and "1" kind of looks like a typo/bug.
> Please add a comment mentioning why this returns 1.

You're right, this should have been 0.  Fixed now.

>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +set_inferior_io_terminal (const char *terminal_name)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +const char *
>> +get_inferior_io_terminal (void)
>> +{
>> +  /* Placeholder needed by fork_inferior.  For now, this function is
>> +     not needed nor useful to have on gdbserver.  When/If we properly
>> +     handle terminal modes, we can revisit and implement the needed
>> +     support.  */
>
> How about instead of repeating the same comment multiple times,
> we add it once at the top:
>
>   /* Placeholders needed by fork_inferior.  For now, these functions are
>      not needed nor useful to have on gdbserver.  When/If we properly
>      handle terminal modes, we can revisit and implement the needed
>      support.  */
>
> ?

Yeah, I did that on the other file but forgot about this one.  Done,
thanks.

I'll wait until all of your comments are addressed before I send v4.

Cheers,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 3/6] Share parts of gdb/inflow.c with gdbserver
  2017-02-15 16:02       ` Pedro Alves
@ 2017-02-16 22:06         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-16 22:06 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

Thanks for the review.  Comments below.

On Wednesday, February 15 2017, Pedro Alves wrote:

> On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
>
>> gdb/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in (SFILES): Add "common/common-inflow.c".
>> 	(COMMON_OBS): Add "common/common-inflow.o".
>> 	* common/common-inflow.c: New file, with contents from
>> 	"gdb/inflow.c".
>> 	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
>> 	(_initialize_inflow): Move setting of "job_control" to
>> 	"handle_job_control".
>> 	* utils.c (job_control): Delete.
>> 
>> gdb/gdbserver/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in: Add rule for "common-inflow.o".
>> 	(SFILE): Add "common/common-inflow.c".
>> 	(OBS): Add "common-inflow.o".
>
>
> We should take the opportunity to rename the file to something that
> makes a more sense wrt to its contents.  "inflow.c" in gdb is
> horribly named, I think simply due to code evolution.  It used to
> contain, many many years ago the (from the top of the file):
>
> /* Low level interface to ptrace, for GDB when running under Unix.
>
> but everything related to low level ptrace stuff moved away, and
> all it was left with was the terminal/job control stuff.
>
> Maybe call it common/job-control.c or maybe something even more
> to the point or something like that.

Good point, I hadn't thought about that.  I renamed the file to
common/job-control.c, because even though it also contains terminal
related stuff, the main purpose of the functions there is to help with
job control.

>> diff --git a/gdb/common/common-inflow.c b/gdb/common/common-inflow.c
>> new file mode 100644
>> index 0000000..9871b5e
>> --- /dev/null
>> +++ b/gdb/common/common-inflow.c
>> @@ -0,0 +1,91 @@
>> +/* Low level interface to ptrace, for GDB and gdbserver when running under Unix.
>
> Please update this.  The file really has nothing to do with ptrace.

Done.

>> +
>> +#include "common-defs.h"
>> +#include "common-terminal.h"
>> +
>> +/* Nonzero if we have job control.  */
>> +int job_control;
>> +
>> +/* This is here because this is where we figure out whether we (probably)
>> +   have job control.  Just using job_control only does part of it because
>> +   setpgid or setpgrp might not exist on a system without job control.
>> +   It might be considered misplaced (on the other hand, process groups and
>> +   job control are closely related to ttys).
>
>
> This "misplaced" comment could use some updating.  This is no longer
> next to the tty stuff.

Done.

>> +
>> +   For a more clean implementation, in libiberty, put a setpgid which merely
>> +   calls setpgrp and a setpgrp which does nothing (any system with job control
>> +   will have one or the other).  */
>> +
>> +int
>> +gdb_setpgid (void)
>> +{
>> +  int retval = 0;
>> +
>> +  if (job_control)
>> +    {
>> +#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
>> +#ifdef HAVE_SETPGID
>> +      /* The call setpgid (0, 0) is supposed to work and mean the same
>> +         thing as this, but on Ultrix 4.2A it fails with EPERM (and
>> +         setpgid (getpid (), getpid ()) succeeds).  */
>> +      retval = setpgid (getpid (), getpid ());
>> +#else
>> +#ifdef HAVE_SETPGRP

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  2017-02-08 17:34       ` Eli Zaretskii
@ 2017-02-17 16:05       ` Pedro Alves
  2017-02-17 16:27         ` Eli Zaretskii
  2017-03-07 20:59         ` Sergio Durigan Junior
  1 sibling, 2 replies; 157+ messages in thread
From: Pedro Alves @ 2017-02-17 16:05 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:

>  
>  *** Changes since GDB 7.12
>  
> +* GDBserver is now able to start inferiors using a shell.  When using
> +  "target extended-remote", the host GDB honors the value of "set
> +  startup-with-shell" in order to inform GDBserver whether the remote
> +  inferior should be started with a shell or not.  When using "target
> +  remote", it is possible to disable the startup with shell by using
> +  the new parameter "--no-startup-with-shell" when starting GDBserver.
> +

IMO, this is missing the "something that makes users curious to
try the feature".  I.e., talking in terms of user-visible features.
I.e., talk about why starting with a shell would be useful.

I'd suggest reworking/extended like this:

* 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.


Note, you'll need NEWS entries for the new remote protocol packets too.




>  @item qfThreadInfo
>  @itemx qsThreadInfo
>  @cindex list active threads, remote request
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 025f7c4..e2c4a30 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -867,6 +867,31 @@ handle_general_set (char *own_buf)
>        return;
>      }
>  
> +  if (startswith (own_buf, "QStartupWithShell:"))
> +    {
> +      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;
> @@ -2303,7 +2328,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 ())
> @@ -3397,6 +3422,11 @@ 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.\n"
> +	   "  --no-startup-with-shell\n"
> +	   "                        Don't start PROG using a shell (i.e., use the exec*\n"
> +	   "                        family of functions).\n"

I wonder whether this "i.e., use the exec family of functions" comment
remark really belongs here.  If you're not very familiar with
what the internal implementation, I think it meaningless.  If you are
familiar with the internals, then like me you'll wonder what does
that mean, because we also use exec to run the shell?  :-)

Maybe replace with:

 --startup-with-shell
                      Start PROG using a shell.  I.e., exec a shell that
                      then execs PROG.  (default)
 --no-startup-with-shell
                      Exec PROG  directly instead of using a shell. 
                      Disables argument globbing, and variable substitution
                      on Unix-like systems.


> @@ -4079,6 +4080,20 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
>    if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
>      remote_set_permissions (target);
>  
> +  /* 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);
> +    }

Can you explain the rationale for doing this here?  What about:

 (gdb) target extended-remote ....
 (gdb) set startup-with-shell off
 (gdb) run

?

> +
> +# Initial setup for simple test (wildcard expansion, variable substitution).
> +
> +proc initial_setup_simple { startup_with_shell run_args } {
> +    global hex decimal binfile
> +
> +    clean_restart $binfile
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +
> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
> +
> +    set target_exec [gdbserver_download_current_prog]
> +    gdbserver_start_extended
> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
> +
> +    gdb_breakpoint main
> +
> +    gdb_test "run $run_args" \
> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
> +	"run to main"
> +}
> +
> +## Doing the actual tests

"Run the actual tests."

> +
> +with_test_prefix "startup_with_shell = on; run_args = *.log" {
> +    initial_setup_simple "on" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
> +	"testing first argument"

"test first argument".  Or better:

    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
 	"first argument expanded"

> +}
> +
> +with_test_prefix "startup_with_shell = off; run_args = *.log" {
> +    initial_setup_simple "off" "*.log"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
> +	"testing first argument"

 	"first argument not expanded"

Relying on "config.log" existing on the current dir, and that showing
up as first argument seems fragile.  Better would be to create some
file with some unique-ish name in the standard output dir, and use
a pattern that is unlikely to find anything else.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-17 16:05       ` Pedro Alves
@ 2017-02-17 16:27         ` Eli Zaretskii
  2017-03-07 20:59         ` Sergio Durigan Junior
  1 sibling, 0 replies; 157+ messages in thread
From: Eli Zaretskii @ 2017-02-17 16:27 UTC (permalink / raw)
  To: Pedro Alves; +Cc: sergiodj, gdb-patches, lgustavo

> Cc: Luis Machado <lgustavo@codesourcery.com>
> From: Pedro Alves <palves@redhat.com>
> Date: Fri, 17 Feb 2017 16:05:53 +0000
> 
> I'd suggest reworking/extended like this:
> 
> * 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.

This text is fine with me.

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 4/6] Share parts of gdb/gdbthread.h with gdbserver
  2017-02-15 16:15       ` Pedro Alves
@ 2017-02-21 21:27         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-02-21 21:27 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

Thanks for the review.

On Wednesday, February 15 2017, Pedro Alves wrote:

> On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
>
>> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
>> new file mode 100644
>> index 0000000..eb66de9
>> --- /dev/null
>> +++ b/gdb/common/common-gdbthread.h
>> @@ -0,0 +1,45 @@
>> +/* Common multi-process/thread control defs for GDB and gdbserver.
>> +   Copyright (C) 1987-2017 Free Software Foundation, Inc.
>> +   Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
>> +   
>> +
>
> Spurious blank line.  That "contributed by" line is meaningless
> for this new file, please remove it.

Fixed.

>> +   This file is part of GDB.
>
>> +#ifndef COMMON_THREAD_H
>> +#define COMMON_THREAD_H
>
> This macro name does not patch the file name.

Fixed.

>> +/* See common/common-gdbthread.h.  */
>> +
>> +void
>> +set_executing (ptid_t ptid ATTRIBUTE_UNUSED, int executing ATTRIBUTE_UNUSED)
>> +{
>> +  gdb_assert (current_thread != NULL);
>> +  current_thread->last_resume_kind = resume_stop;
>> +  current_thread->last_status = get_last_target_waitstatus ();
>> +}
>> +
>
> This is a bit too hacky to live IMO.  :-/  The implementation
> of the function is doing nothing related to its interface.
>
> Do we really need the set_executing call in the new shared file?  AFAICS, 
> set_executing is only called at the very end of startup_inferior today.
> Couldn't we leave that call out of the common code and add it on the
> gdb side, after the common startup_inferior returns?

Yes, that works and is better than the current solution, I agree.  I'll
implement it.

>>  
>> -/* Marks thread PTID as executing, or not.  If PTID is minus_one_ptid,
>> -   marks all threads.
>> -
>> -   Note that this is different from the running state.  See the
>> -   description of state and executing fields of struct
>> -   thread_info.  */
>> -extern void set_executing (ptid_t ptid, int executing);
>> -
>>  /* Reports if thread PTID is executing.  */
>>  extern int is_executing (ptid_t ptid);
>
> Having a setter in one place, and the getter somewhere
> else is sure to generate confusion.  In cases like these,
> please leave a breadcrumb comment.  (there may be more cases.)

With set_executing being called after startup_inferior on GDB, this
change will not be there anymore (i.e., set_executing will not be
touched).  But thanks for the heads up, I'll check other places where I
moved functions from GDB to gdbserver and make sure everything is
commented.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-02-15 17:28       ` Pedro Alves
  2017-02-16 12:23         ` Philipp Rudo
@ 2017-03-07 19:51         ` Sergio Durigan Junior
  2017-03-13 15:34           ` Pedro Alves
  1 sibling, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-07 19:51 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

On Wednesday, February 15 2017, Pedro Alves wrote:

> Hi Sergio,
>
> I think I'll likely have more comments, but this large, so
> here's a first pass.

Cool, thanks for the comments so far.  I had to spend a bit of time
thinking about some of them and addressing everything.  Sorry about the
delay.

>> diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
>> new file mode 100644
>> index 0000000..f4d7866
>> --- /dev/null
>> +++ b/gdb/common/common-fork-child.c
>> @@ -0,0 +1,593 @@
>> +/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
>> +
>> +   Copyright (C) 1990-2017 Free Software Foundation, Inc.
>> +
>> +   Originally contributed by Cygnus Support.
>
> We should just take the opportunity to drop that per recent policy.
> Plenty of files added by Cygnus (nowadays Red Hat) don't have that marker,
> this won't be missed, IMO.

Done.

>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>
>> +int
>> +fork_inferior (char *exec_file_arg, char *allargs, char **env,
>> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
>> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
>> +	       void (*exec_fun)(const char *file, char * const *argv,
>> +				char * const *env))
>> +{
>
>> +  /* Retain a copy of our environment variables, since the child will
>> +     replace the value of environ and if we're vforked, we have to
>> +     restore it.  */
>> +  save_our_env = environ;
>> +
>> +  /* Likewise the current UI.  */
>> +  save_ui = current_ui;
>
> Hmm, making this compile on gdbserver is of course a hack,
> since there's not such thing as a "UI" concept on gdbserver...
>
>> +
>> +  /* Tell the terminal handling subsystem what tty we plan to run on;
>> +     it will just record the information for later.  */
>> +  new_tty_prefork (inferior_io_terminal);
>
> I wonder about calling here instead a more generalized hook, and
> moving the save_ui saving and the new_tty_prefork calls to
> that hook's gdb implementation.  Might be easier to do that after
> the series is in...

Right, it is a hack indeed, and not a beautiful one.

I implemented a bunch of new functions that solve this problem.  Two of
them, tty_{pre,post}fork_hook, are responsible for saving/restoring the
current 'struct ui' and also for calling the new_tty_{pre,post}fork
functions (which are now static).  One more function was needed:
switch_ui_postfork, which is responsible for switching the current_ui to
main_ui, as is done currently after we successfully fork.  These 3
functions are implemented only on GDB; they're stubs on gdbserver.

>> +
>> +  /* It is generally good practice to flush any possible pending stdio
>> +     output prior to doing a fork, to avoid the possibility of both
>> +     the parent and child flushing the same data after the fork.  */
>> +  gdb_flush_out_err ();
>> +
>> +  /* If there's any initialization of the target layers that must
>> +     happen to prepare to handle the child we're about fork, do it
>> +     now...  */
>> +  if (pre_trace_fun != NULL)
>> +    (*pre_trace_fun) ();
>> +
>
>
>> +++ b/gdb/common/common-top.h
>> @@ -0,0 +1,31 @@
>> +/* Common top level stuff for GDB and GDBserver.
>> +
>> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_TOP_H
>> +#define COMMON_TOP_H
>> +
>> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>> +   It always exists and is created automatically when GDB starts
>> +   up.  */
>> +extern struct ui *main_ui;
>> +
>> +/* The current UI.  */
>> +extern struct ui *current_ui;
>> +
>
> Not exactly thrilled with moving this to common.

See comment above.  This is now back on GDB land.

>> +#endif /* ! COMMON_TOP_H */
>
>>  /* Implement the "unset exec-wrapper" command.  */
>> @@ -585,7 +73,7 @@ Show the wrapper for running programs."), NULL,
>>             &unsetlist);
>>  
>>    add_setshow_boolean_cmd ("startup-with-shell", class_support,
>> -			   &startup_with_shell, _("\
>> +			   (int *) &startup_with_shell, _("\
>
> That's invalid C/C++.  Don't do that.

Ops, thanks for pointing that out.  I decided to revert the change and
use an integer instead of a boolean there; at least until we have proper
add_setshow* functions for real booleans.

>>  Set use of shell to start subprocesses.  The default is on."), _("\
>>  Show use of shell to start subprocesses."), NULL,
>>  			   NULL,
>
>
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>>  
>>  #define get_thread(inf) ((struct thread_info *)(inf))
>>  
>> +ptid_t inferior_ptid;
>
> What do we need this for?  gdbserver already has
> a "current thread" global.  Another one looks like asking
> for out-of-sync trouble.

This is needed because fork_inferior et al reference this variable
directly, and so I moved the 'extern' declaration of it to commom/.

A possible solution to this would be to create a get/set pair of
functions for it, but I'm not sure this would be a good idea due to (a)
the number of direct references to it, and (b) the fact that these
functions would probably end up being stubs on gdbserver as well.

>>  /* See common/common-gdbthread.h.  */
>>  
>>  void
>>  init_thread_list (void)
>>  {
>> -  /* To be implemented.  */
>> +  /* Placeholder needed for fork_inferior.  No action is needed.  */
>
> Pick one of the comments, and move it to the right patch.

Sorry, fixed.

>>  }
>>  
>
>> -/* Add a process to the common process list, and set its private
>> -   data.  */
>> +/* Update process represented by PID with necessary info.  */
>>  
>>  static struct process_info *
>> -linux_add_process (int pid, int attached)
>> +linux_update_process (int pid)
>
> I'm not sure I understand the need for this yet.  I need
> to look deeper.  "update what?  why?"  Or maybe the
> comments should be improved.  :-)

The reason these 'update' functions were created is because
fork_inferior already creates the process/thread structures, but we (the
caller) still need to fill in some of the fields of these structures
with more information.  They are the same functions that existed before,
but now we work with an existing process/thread, while before we
*created* these structures.

>>  {
>> -  struct process_info *proc;
>> +  struct process_info *proc = find_process_pid (pid);
>>  
>> -  proc = add_process (pid, attached);
>> +  gdb_assert (proc != NULL);
>>    proc->priv = XCNEW (struct process_info_private);
>>  
>>    if (the_low_target.new_process != NULL)
>> @@ -432,6 +433,16 @@ linux_add_process (int pid, int attached)
>>    return proc;
>>  }
>>  
>
>> +/* Update the lwp associated to thread represented by PTID.  */
>> +
>> +static struct lwp_info *
>> +update_thread_lwp (ptid_t ptid)
>
> Ditto.
>
>>  /* Start an inferior process and returns its pid.
>>     ALLARGS is a vector of program-name and args. */
>>  
>>  static int
>> -linux_create_inferior (char *program, char **allargs)
>> +linux_create_inferior (std::vector<char *> &program_argv)
>
> "const std::vector<char *> &" ?  Same comment for the whole
> call chain, of course.

Fixed.

>>  {
>>    struct lwp_info *new_lwp;
>>    int pid;
>>    ptid_t ptid;
>>    struct cleanup *restore_personality
>>      = maybe_disable_address_space_randomization (disable_randomization);
>> +  std::string program_args = stringify_argv (program_argv);
>>  
>> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>> -  pid = vfork ();
>> -#else
>> -  pid = fork ();
>> -#endif
>> -  if (pid < 0)
>> -    perror_with_name ("fork");
>> +  pre_fork_inferior (program_argv);
>>  
>> -  if (pid == 0)
>> -    {
>> -      close_most_fds ();
>> -      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
>> -
>> -      setpgid (0, 0);
>> -
>> -      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
>> -	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
>> -	 Also, redirect stdin to /dev/null.  */
>> -      if (remote_connection_is_stdio ())
>> -	{
>> -	  close (0);
>> -	  open ("/dev/null", O_RDONLY);
>> -	  dup2 (2, 1);
>> -	  if (write (2, "stdin/stdout redirected\n",
>> -		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
>> -	    {
>> -	      /* Errors ignored.  */;
>> -	    }
>> -	}
>> -
>> -      restore_original_signals_state ();
>> -
>> -      execv (program, allargs);
>> -      if (errno == ENOENT)
>> -	execvp (program, allargs);
>> -
>> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
>> -	       strerror (errno));
>> -      fflush (stderr);
>> -      _exit (0177);
>> -    }
>> +  pid = fork_inferior (program_argv[0],
>> +		       (char *) program_args.c_str (),
>
> Can we constify fork_inferior's parameters to avoid such
> cast hacks ?

I constified the args as requested, and now most of the casts are gone.
I have a patch here that I'll send later, which constifies more parts of
this code.

>> +		       environ_vector (get_environ ()), linux_ptrace_fun,
>> +		       NULL, NULL, NULL, NULL);
>>  
>>    do_cleanups (restore_personality);
>>  
>> -  linux_add_process (pid, 0);
>> +  linux_update_process (pid);
>>  
>>    ptid = ptid_build (pid, pid, 0);
>> -  new_lwp = add_lwp (ptid);
>> +  new_lwp = update_thread_lwp (ptid);
>>    new_lwp->must_set_ptrace_flags = 1;
>>  
>> +  post_fork_inferior (pid, program_argv);
>> +
>>    return pid;
>>  }
>>  
>
>> +/* See common/common-inferior.h.  */
>> +
>> +char *
>> +get_exec_wrapper (void)
>>  {
>> -  char **new_argv = argv;
>> +  static std::string ret;
>> +  static int initialized_p = 0;
>
> bool.

Fixed.

>> +
>> +  if (wrapper_argv.empty ())
>> +    return NULL;
>>  
>> -  if (wrapper_argv != NULL)
>> +  if (!initialized_p)
>>      {
>> -      int i, count = 1;
>> -
>> -      for (i = 0; wrapper_argv[i] != NULL; i++)
>> -	count++;
>> -      for (i = 0; argv[i] != NULL; i++)
>> -	count++;
>> -      new_argv = XALLOCAVEC (char *, count);
>> -      count = 0;
>> -      for (i = 0; wrapper_argv[i] != NULL; i++)
>> -	new_argv[count++] = wrapper_argv[i];
>> -      for (i = 0; argv[i] != NULL; i++)
>> -	new_argv[count++] = argv[i];
>> -      new_argv[count] = NULL;
>> +      for (std::vector<char *>::iterator i = wrapper_argv.begin ();
>> +	   i != wrapper_argv.end ();
>> +	   ++i)
>> +	ret += *i + std::string (" ");
>
>       for (auto arg : wrapper_argv)
> 	ret += arg + " ";

Fixed.

>> +
>> +      /* Erasing the last whitespace.  */
>
> "Erase".

Fixed.

>> +      ret.erase (ret.end () - 1);
>> +
>> +      initialized_p = 1;
>>      }
>>  
>> +  return (char *) ret.c_str ();
>
> Can the function return const instead?

Fixed.

>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +char *
>> +get_exec_file (int err)
>> +{
>> +  if (err && program_argv.empty ())
>> +    error (_("Could not get the exec file."));
>
> I think this error message could be improved.  If I see
> that on the gdbserver terminal, I'll have no clue what
> it means.  "get from where??"  How about just saying
> the same thing gdb says, sans the "Use the ..." part?

Fixed.

>> +  return program_argv[0];
>> +}
>> +
>> +/* See server.h.  */
>> +
>> +struct gdb_environ *
>> +get_environ (void)
>> +{
>> +  return our_environ;
>> +}
>> +
>> +/* See server.h.  */
>> +
>> +void
>> +pre_fork_inferior (std::vector<char *> &argv)
>> +{
>>    if (debug_threads)
>>      {
>> -      int i;
>> -      for (i = 0; new_argv[i]; ++i)
>> -	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
>> +      int idx = 0;
>> +
>> +      for (char *&i : argv)
>
> Reference to pointer is pointless, it's like pointer to
> pointer.  This should be fine:
>
>       for (char *i : argv)
>
> I'd suggest naming the variable something else, since
> it's not really an iterator.  Like e.g.,:
>
>       for (char *str : argv)
>       for (char *arg : argv)

Thanks for the tip.

>> +	{
>> +	  debug_printf ("new_argv[%d] = \"%s\"\n", idx, i);
>> +	  ++idx;
>
> OTOH, if you're needing/maintaining an index anyway,
> this ends up clearer IMO:
>
>       for (int idx = 0; idx < argv.size(); idx++)
>         debug_printf ("new_argv[%d] = \"%s\"\n", idx, argv[idx]);

Fixed.

>> +	}
>>        debug_flush ();
>>      }
>>  
>
>
>
>>  handle_v_run (char *own_buf)
>>  {
>> -  char *p, *next_p, **new_argv;
>> -  int i, new_argc;
>> +  char *p, *next_p;
>> +  std::vector<char *> new_argv;
>> +  int new_argc;
>> +  int i;
>>  
>>    new_argc = 0;
>>    for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
>> @@ -2870,62 +2893,91 @@ handle_v_run (char *own_buf)
>>        new_argc++;
>>      }
>>  
>> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
>> -  if (new_argv == NULL)
>> -    {
>> -      write_enn (own_buf);
>> -      return 0;
>> -    }
>> -
>> -  i = 0;
>> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
>> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>>      {
>>        next_p = strchr (p, ';');
>>        if (next_p == NULL)
>>  	next_p = p + strlen (p);
>>  
>> -      if (i == 0 && p == next_p)
>> -	new_argv[i] = NULL;
>> +      if (p == next_p)
>> +	new_argv.push_back ("''");
>>        else
>>  	{
>>  	  /* FIXME: Fail request if out of memory instead of dying.  */
>> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
>> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
>> -	  new_argv[i][(next_p - p) / 2] = '\0';
>> +	  size_t len = 1 + (next_p - p) / 2;
>> +	  char *s = (char *) xmalloc (len);
>> +	  char *ss = (char *) xmalloc (len * 2);
>> +	  char *tmp_s, *tmp_ss;
>> +	  int need_quote;
>> +
>> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
>> +	  s[(next_p - p) / 2] = '\0';
>> +
>> +	  tmp_s = s;
>> +	  tmp_ss = ss;
>> +	  need_quote = 0;
>> +	  while (*tmp_s != '\0')
>> +	    {
>> +	      switch (*tmp_s)
>> +		{
>> +		case '\n':
>> +		  *tmp_ss = '\'';
>> +		  ++tmp_ss;
>> +		  need_quote = 1;
>> +		  break;
>> +
>> +		case '\'':
>> +		  *tmp_ss = '\\';
>> +		  ++tmp_ss;
>> +		  break;
>> +
>> +		default:
>> +		  break;
>> +		}
>> +
>> +	      *tmp_ss = *tmp_s;
>> +	      ++tmp_ss;
>> +	      ++tmp_s;
>> +	    }
>> +
>> +	  if (need_quote)
>> +	    *tmp_ss++ = '\'';
>
> Hmm, is this quoting stuff being moved from somewhere,
> or it is new?

This is new, even though GDB has a lot of places that do the same
thing...

>> +
>> +	  *tmp_ss = '\0';
>> +	  new_argv.push_back (ss);
>> +	  xfree (s);
>>  	}
>>  
>>        if (*next_p)
>>  	next_p++;
>> -      i++;
>>      }
>> -  new_argv[i] = NULL;
>
>>  
>> +  /* Gather information about the environment.  */
>> +  our_environ = make_environ ();
>> +  init_environ (our_environ);
>> +
>>    initialize_async_io ();
>>    initialize_low ();
>> +  /* This is called when initializing inflow on GDB.  */
>
> What is this comment supposed be to telling?

Nothing; this was a leftover from another patch.  Removed.

>> +  have_job_control ();
>>    initialize_event_loop ();
>>    if (target_supports_tracepoints ())
>>      initialize_tracepoint ();
>> @@ -3695,13 +3758,11 @@ captured_main (int argc, char *argv[])
>>        int i, n;
>>  
>>        n = argc - (next_arg - argv);
>> -      program_argv = XNEWVEC (char *, n + 1);
>>        for (i = 0; i < n; i++)
>> -	program_argv[i] = xstrdup (next_arg[i]);
>> -      program_argv[i] = NULL;
>> +	program_argv.push_back (xstrdup (next_arg[i]));
>>  
>
>> -#define create_inferior(program, args) \
>> -  (*the_target->create_inferior) (program, args)
>> +#define create_inferior(program) \
>> +  (*the_target->create_inferior) (program)
>
> program_argv, I suppose.

Fixed.

>> +/* See common/common-utils.h.  */
>> +
>> +std::string
>> +stringify_argv (std::vector<char *> &argv)
>> +{
>> +  std::string ret ("");
>
>    std::string ret;

Fixed.

>> +
>> +  for (std::vector<char *>::iterator i = argv.begin () + 1;
>> +       i != argv.end ();
>> +       ++i)
>> +    ret += *i + std::string (" ");
>
> Should we remove the last empty space?

Yep, always a good practice.  Fixed.

>> +
>> +  return ret;
>> +}
>> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
>> index b4ded31..a30d99a 100644
>> --- a/gdb/gdbserver/utils.h
>> +++ b/gdb/gdbserver/utils.h
>> @@ -19,7 +19,17 @@
>>  #ifndef UTILS_H
>>  #define UTILS_H
>>  
>> +#include <vector>
>> +
>>  char *paddress (CORE_ADDR addr);
>>  char *pfildes (gdb_fildes_t fd);
>>  
>> +/* Works like FREEARGV, but with std::vector.  */
>> +extern void free_vector_argv (std::vector<char *> &v);
>
> At some point, freeargv is eliminated, and this comment will
> stay behind.  Can we expand it a bit?

Expanded.

>> +
>> +/* Given a vector of arguments ARGV, return a string equivalent to
>> +   joining all the arguments (starting from ARGV + 1) with a
>> +   whitespace separating them.  */
>> +extern std::string stringify_argv (std::vector<char *> &argv);
>
> const ?
>
> This "starting from ARGV + 1" contract was surprising to me.
> I only noticed this when I saw the implementation.
>
> Does it really make sense to put the program name inside the
> vector instead of on a separate argument if we're always going
> to treat argv[0] differently?
>
> I.e., would:
>
> - ...create_inferior (char *program, char **program_args)
> + ...create_inferior (char *program, std::vector<char *> &program_args)
>
> make more sense?

Right.  I reverted this change, and now we're passing *program as the
first argument again.

>>  static int
>> -win32_create_inferior (char *program, char **program_args)
>> +win32_create_inferior (std::vector<char *> &program_argv)
>>  {
>>  #ifndef USE_WIN32API
>>    char real_path[PATH_MAX];
>> @@ -627,6 +625,9 @@ win32_create_inferior (char *program, char **program_args)
>>    int argc;
>>    PROCESS_INFORMATION pi;
>>    DWORD err;
>> +  char *program = program_argv[0];
>> +  std::string program_args = stringify_argv (program_argv);
>> +  char *args = (char *) program_args.c_str ();
>>  
>>    /* win32_wait needs to know we're not attaching.  */
>>    attaching = 0;
>> @@ -636,6 +637,8 @@ win32_create_inferior (char *program, char **program_args)
>>  
>>    flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
>>  
>> +  pre_fork_inferior (program, argv);
>
> Hmm, fork on Windows?

Ops.  Removed.

>> +
>>  #ifndef USE_WIN32API
>>    orig_path = NULL;
>>    path_ptr = getenv ("PATH");
>> @@ -652,18 +655,6 @@ win32_create_inferior (char *program, char **program_args)
>>    program = real_path;
>>  #endif
>>  
>> -  argslen = 1;
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    argslen += strlen (program_args[argc]) + 1;
>> -  args = (char *) alloca (argslen);
>> -  args[0] = '\0';
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    {
>> -      /* FIXME: Can we do better about quoting?  How does Cygwin
>> -	 handle this?  */
>> -      strcat (args, " ");
>> -      strcat (args, program_args[argc]);
>> -    }
>>    OUTMSG2 (("Command line is \"%s\"\n", args));
>>  
>>  #ifdef CREATE_NEW_PROCESS_GROUP
>> @@ -704,6 +695,8 @@ win32_create_inferior (char *program, char **program_args)
>>  
>>    do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
>>  
>> +  post_fork_inferior (current_process_id, program_argv);
>> +
>>    return current_process_id;
>>  }
>>  
>
>
>> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>>  set msg "gdbserver exits cleanly"
>>  set saw_exiting 0
>>  expect {
>> -    # This is what we get on ptrace-based targets.
>> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
>> +    # This is what we get on ptrace-based targets with
>> +    # startup-with-shell disabled.
>> + -re "stdin/stdout redirected.*gdbserver: Cannot exec
>> non-existing-program\r\ngdbserver: Error: No such file or
>> directory\r\n\r\nDuring startup program exited with code
>> 127\.\r\nExiting\r\n$" {
>> +	set saw_exiting 1
>> +	exp_continue
>
> Shouldn't this be a part of the next patch?

Not really.  I put this here because without it a regreession is
introduced, and I wanted each patch to be regression-free.

>> +    }
>> +    # Likewise, but with startup-with-shell enabled.
>> +    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
>>  	set saw_exiting 1
>>  	exp_continue
>>      }

I'll send the next version soon.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 1/6] Share gdb/environ.[ch] with gdbserver
  2017-02-15 15:36       ` Pedro Alves
@ 2017-03-07 20:50         ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-07 20:50 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

On Wednesday, February 15 2017, Pedro Alves wrote:

> On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
>> We will need access to the environment functions when we share
>> fork_inferior between GDB and gdbserver, therefore we simply make the
>> API on gdb/environ.[ch] available on common/.  No extra adjustments
>> are needed to make it compile on gdbserver.
>> 
>> gdb/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in (SFILES): Replace "environ.c" with
>> 	"common/environ.c".
>> 	(HFILES_NO_SRCDIR): Likewise, for "environ.h".
>> 	* environ.c: Include "common-defs.h" instead of "defs.h.  Moved
>> 	to...
>> 	* common/environ.c: ... here.
>> 	* environ.h: Moved to...
>> 	* common/environ.h: ... here.
>> 
>> gdb/gdbserver/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in (SFILES): Add "common/environ.c".
>> 	(OBJS): Add "common/environ.h".
>
> OK.

Thanks, checked in:

  1672e0d98d88d11b5c7d5793bd2cf29cbb56696f

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-02-17 16:05       ` Pedro Alves
  2017-02-17 16:27         ` Eli Zaretskii
@ 2017-03-07 20:59         ` Sergio Durigan Junior
  2017-03-13 15:12           ` Pedro Alves
  1 sibling, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-07 20:59 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

Thanks for the review.  Comments below.

On Friday, February 17 2017, Pedro Alves wrote:

> On 02/08/2017 03:22 AM, Sergio Durigan Junior wrote:
>
>>  
>>  *** Changes since GDB 7.12
>>  
>> +* GDBserver is now able to start inferiors using a shell.  When using
>> +  "target extended-remote", the host GDB honors the value of "set
>> +  startup-with-shell" in order to inform GDBserver whether the remote
>> +  inferior should be started with a shell or not.  When using "target
>> +  remote", it is possible to disable the startup with shell by using
>> +  the new parameter "--no-startup-with-shell" when starting GDBserver.
>> +
>
> IMO, this is missing the "something that makes users curious to
> try the feature".  I.e., talking in terms of user-visible features.
> I.e., talk about why starting with a shell would be useful.
>
> I'd suggest reworking/extended like this:
>
> * 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.

Thanks, I've adopted your idea.

> Note, you'll need NEWS entries for the new remote protocol packets too.

I've added a NEWS entry for QStartupWithShell under the "New remote
packets" section.  Do you want me to add another entry somewhere else?

>>  @item qfThreadInfo
>>  @itemx qsThreadInfo
>>  @cindex list active threads, remote request
>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>> index 025f7c4..e2c4a30 100644
>> --- a/gdb/gdbserver/server.c
>> +++ b/gdb/gdbserver/server.c
>> @@ -867,6 +867,31 @@ handle_general_set (char *own_buf)
>>        return;
>>      }
>>  
>> +  if (startswith (own_buf, "QStartupWithShell:"))
>> +    {
>> +      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;
>> @@ -2303,7 +2328,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 ())
>> @@ -3397,6 +3422,11 @@ 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.\n"
>> +	   "  --no-startup-with-shell\n"
>> +	   "                        Don't start PROG using a shell (i.e., use the exec*\n"
>> +	   "                        family of functions).\n"
>
> I wonder whether this "i.e., use the exec family of functions" comment
> remark really belongs here.  If you're not very familiar with
> what the internal implementation, I think it meaningless.  If you are
> familiar with the internals, then like me you'll wonder what does
> that mean, because we also use exec to run the shell?  :-)
>
> Maybe replace with:
>
>  --startup-with-shell
>                       Start PROG using a shell.  I.e., exec a shell that
>                       then execs PROG.  (default)
>  --no-startup-with-shell
>                       Exec PROG  directly instead of using a shell. 
>                       Disables argument globbing, and variable substitution
>                       on Unix-like systems.

Fair enough.  I've adopted the texts.

>
>> @@ -4079,6 +4080,20 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
>>    if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
>>      remote_set_permissions (target);
>>  
>> +  /* 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);
>> +    }
>
> Can you explain the rationale for doing this here?  What about:
>
>  (gdb) target extended-remote ....
>  (gdb) set startup-with-shell off
>  (gdb) run
>
> ?

Hm, I guess it just seemed like a good place to initialize the packet.
But you're right, this won't work if the user sets the
startup-with-shell parameter *after* connecting to the target.  So I'll
move this code to the extended_remote_create_inferior function, if
that's alright.

>> +
>> +# Initial setup for simple test (wildcard expansion, variable substitution).
>> +
>> +proc initial_setup_simple { startup_with_shell run_args } {
>> +    global hex decimal binfile
>> +
>> +    clean_restart $binfile
>> +    # Make sure we're disconnected, in case we're testing with an
>> +    # extended-remote board, therefore already connected.
>> +    gdb_test "disconnect" ".*"
>> +
>> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
>> +
>> +    set target_exec [gdbserver_download_current_prog]
>> +    gdbserver_start_extended
>> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
>> +
>> +    gdb_breakpoint main
>> +
>> +    gdb_test "run $run_args" \
>> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
>> +	"run to main"
>> +}
>> +
>> +## Doing the actual tests
>
> "Run the actual tests."

Fixed.

>> +
>> +with_test_prefix "startup_with_shell = on; run_args = *.log" {
>> +    initial_setup_simple "on" "*.log"
>> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
>> +	"testing first argument"
>
> "test first argument".  Or better:
>
>     gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"config\.log\"" \
>  	"first argument expanded"

Fixed.

>> +}
>> +
>> +with_test_prefix "startup_with_shell = off; run_args = *.log" {
>> +    initial_setup_simple "off" "*.log"
>> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.log\"" \
>> +	"testing first argument"
>
>  	"first argument not expanded"

Fixed the three nits.

> Relying on "config.log" existing on the current dir, and that showing
> up as first argument seems fragile.  Better would be to create some
> file with some unique-ish name in the standard output dir, and use
> a pattern that is unlikely to find anything else.

Hm, OK.  I'll take care of that.

Patch will be sent soon.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 2/5] Share parts of gdb/inflow.c with gdbserver
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 1/5] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-03-08  5:29       ` Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 3/5] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 4/5] Share fork_inferior et al " Sergio Durigan Junior
  4 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

After sharing parts of gdb/terminal.h, it is also needed to share the
two functions on gdb/inflow.c that are going to be needed by the
fork_inferior sharing.  They are 'gdb_setpgid' and the new
'have_job_control'.  I've also taken the opportunity to give a more
meaningful name to "inflow.c" on common/.  Now it is called
"job-control.c".

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/job-control.c".
	(COMMON_OBS): Add "common/job-control.o".
	* common/job-control.c: New file, with contents from
	"gdb/inflow.c".
	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* terminal.h (job_control): Moved to "common/common-terminal.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in: Add rule for "job-control.o".
	(SFILE): Add "common/job-control.c".
	(OBS): Add "job-control.o".
---
 gdb/Makefile.in              |  2 +
 gdb/common/common-terminal.h | 10 +++++
 gdb/common/job-control.c     | 92 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/Makefile.in    |  5 +++
 gdb/inflow.c                 | 63 +-----------------------------
 gdb/terminal.h               |  4 --
 gdb/utils.c                  |  4 --
 7 files changed, 111 insertions(+), 69 deletions(-)
 create mode 100644 gdb/common/job-control.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 177c853..6ad03d7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1210,6 +1210,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/job-control.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1638,6 +1639,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
index 87a19f0..7a1bcfe 100644
--- a/gdb/common/common-terminal.h
+++ b/gdb/common/common-terminal.h
@@ -77,6 +77,11 @@
 
 #include <sys/types.h>
 
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
 extern void new_tty (void);
 
 /* NEW_TTY_PREFORK is called before forking a new child process,
@@ -113,4 +118,9 @@ extern pid_t create_tty_session (void);
    if we lack job control.  */
 extern int gdb_setpgid (void);
 
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  This function must be called before any use of
+   JOB_CONTROL.  */
+extern void have_job_control (void);
+
 #endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/common/job-control.c b/gdb/common/job-control.c
new file mode 100644
index 0000000..14b719e
--- /dev/null
+++ b/gdb/common/job-control.c
@@ -0,0 +1,92 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "common-terminal.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* Set the process group ID of the inferior.
+
+   Just using job_control only does part of it because setpgid or
+   setpgrp might not exist on a system without job control.
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1cccbbf..adbeb16 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/job-control.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
@@ -778,6 +780,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+job-control.o: ../common/job-control.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 agent.o: ../common/agent.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 7ffa83a..271278d 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -803,43 +803,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -860,30 +823,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/terminal.h b/gdb/terminal.h
index 438eb40..16628cb 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -25,10 +25,6 @@ struct inferior;
 
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
diff --git a/gdb/utils.c b/gdb/utils.c
index fdb983a..ace2539 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -103,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 1/5] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
@ 2017-03-08  5:29       ` Sergio Durigan Junior
  2017-03-08 15:49         ` Eli Zaretskii
  2017-03-13 17:26         ` Pedro Alves
  2017-03-08  5:29       ` [PATCH v4 2/5] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
                         ` (2 subsequent siblings)
  4 siblings, 2 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS (Changes since GDB 7.12): 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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
yyyy-mm-dd  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/NEWS                                        | 12 ++++
 gdb/doc/gdb.texinfo                             | 31 +++++++++
 gdb/gdbserver/server.c                          | 38 ++++++++++-
 gdb/remote.c                                    | 20 ++++++
 gdb/testsuite/gdb.server/startup-with-shell.c   | 29 ++++++++
 gdb/testsuite/gdb.server/startup-with-shell.exp | 90 +++++++++++++++++++++++++
 6 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index cf58595..7c235f7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,15 @@
 
 *** Changes since GDB 7.12
 
+* 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.
+
 * GDB now supports access to the PKU register on GNU/Linux. The register is
   added by the Memory Protection Keys for Userspace feature which will be
   available in future Intel CPUs.
@@ -393,6 +402,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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ba56ab2..b6bc7c7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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}
@@ -36420,6 +36425,32 @@ 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
+
 @item qfThreadInfo
 @itemx qsThreadInfo
 @cindex list active threads, remote request
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 1677926..8411aad 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -847,6 +847,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      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;
@@ -2283,7 +2308,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 ())
@@ -3379,6 +3404,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"
@@ -3662,6 +3694,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
diff --git a/gdb/remote.c b/gdb/remote.c
index 2f34c4c..cb6e194 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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)
@@ -14112,6 +14129,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);
 
diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.c
@@ -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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
new file mode 100644
index 0000000..81be68b
--- /dev/null
+++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
@@ -0,0 +1,90 @@
+# 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/>.
+
+# Test startup-with-shell support using extended-remote.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+if { [skip_gdbserver_tests] } {
+    untested "skipping gdbserver tests"
+    return 0
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+set unique_file [standard_output_file "unique-file.unique-extension"]
+remote_exec build "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
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+
+    gdb_test_no_output "set startup-with-shell $startup_with_shell"
+
+    set target_exec [gdbserver_download_current_prog]
+    gdbserver_start_extended
+    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+    gdb_test "remote put $unique_file [file tail $unique_file]"
+
+    gdb_breakpoint main
+
+    gdb_test "run $run_args" \
+	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
+	"run to main"
+}
+
+## Run the actual tests
+
+with_test_prefix "startup_with_shell = on; run_args = *.unique-extension" {
+    initial_setup_simple "on" "*.unique-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"unique-file\.unique-extension\"" \
+	"first argument expanded"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.unique-extension" {
+    initial_setup_simple "off" "*.unique-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.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)
+}
+
+remote_exec build "rm -f $unique_file"
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 4/5] Share fork_inferior et al with gdbserver
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
                         ` (3 preceding siblings ...)
  2017-03-08  5:29       ` [PATCH v4 3/5] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
@ 2017-03-08  5:29       ` Sergio Durigan Junior
  2017-03-13 17:04         ` Pedro Alves
  4 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.  For some
feature, like the target_terminal_* functions, I chose to just use
placeholders for the real functions on gdbserver, that should be
implemented in the future.  For now, we don't need them in order to
make things work.  Also, since we don't manipulate terminal modes on
gdbserver the way we do on GDB, they are not possible to implement
right now (unless I chose to properly implement terminal handling on
gdbserver, which is something we don't know if we want now).

Last, but not least, I did a major revamp on the way gdbserver
computes and stores the inferior's arguments.  It's now using a
std::vector<char *> and std::string where applicable, which makes
things much easier even to understand.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(HFILES_NO_SRCDIR): Add "common/common-inferior.h" and
	"common/common-top.h".
	(COMMON_OBS): Add "common-fork-child.o".
	* common-fork-child.c: New file, with the majority of
	"gdb/fork-child.c".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* common/common-terminal.h (new_tty_prefork): Remove prototype.
	(tty_prefork_hook): New function.
	(new_tty_postfork): Remove prototype.
	(tty_postfork_hook): New function.
	* common/common-top.h: New file.
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Update call of
	"startup_inferior".  Call "set_executing" after it.
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(fork_inferior): Likewise.  Update function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Update call to
	"startup_inferior".  Call "set_executing" after it.
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* inferior.h: Include "common-inferior.h".
	(fork_inferior): Move prototype to "common-inferior.h".
	(startup_inferior): Likewise.
	* inflow.c: Include "common-top.h".
	(new_tty_prefork): Make static.
	(tty_prefork_hook): New function.
	(new_tty_postfork): Make static.
	(tty_postfork_hook): New function.
	* procfs.c (procfs_init_inferior): Update call to
	"startup_inferior".  Call "set_executing" after it.
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* top.c (switch_ui_postfork): New function.
	* top.h: Include "common-top.h".
	(main_ui): Move
	(current_ui): Move
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "terminal.c" and
	"common/common-fork-child.c".
	(OBS): Add common-fork-child.o and terminal.o.
	(common-fork-child.o): New rule.
	* inferiors (inferior_ptid): New variable.
	(inferior_appeared): New function.
	(current_inferior): Likewise.
	(have_inferiors): Likewise.
	* linux-low.c: Include "common-inferior.h" and "environ.h".
	(linux_update_process): New function.
	(linux_add_process): Update comment.  Adjust function to call
	"linux_update_process".
	(update_thread_lwp): New function.
	(linux_ptrace_fun): Likewise.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c: Include "common-inferior.h".
	(lynx_update_process): New function.
	(lynx_add_process): Update comment.  Adjust function to call
	"lynx_update_process".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".
	* server.c: Include "common-inferior.h", "common-terminal.h",
	"common-top.h", "environ.h".
	(our_environ): Likewise.
	(startup_with_shell): Likewise.
	(program_argv): Convert to std::vector<char *>.
	(wrapper_argv): Likewise.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(pre_fork_inferior): New function, with parts of "start_inferior".
	(post_fork_inferior): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(pre_fork_inferior): New prototype.
	(post_fork_inferior): Likewise.
	(get_environ): Likewise.
	* spu-low.c: Include "common-inferior.h".
	(spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype
	to accept one std::vector<char *> representing the full program
	argv.
	(create_inferior): Update macro.
	* terminal.c: Include "common-top.h".
	(new_tty_prefork): Delete function.
	(tty_prefork_hook): New function.
	(new_tty_postfork): Delete function.
	(tty_postfork_hook): New function.
	(switch_ui_postfork): Likewise.
	* utils.c (gdb_flush_out_err): New function.
	(free_vector_argv): Likewise.
	(stringify_argv): Likewise.
	* utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	(stringify_argv): Likewise.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   4 +
 gdb/common/common-fork-child.c                    | 604 ++++++++++++++++++++++
 gdb/common/common-inferior.h                      | 121 +++++
 gdb/common/common-terminal.h                      |  23 +-
 gdb/common/common-top.h                           |  28 +
 gdb/common/common-utils.h                         |   4 +
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |   6 +-
 gdb/fork-child.c                                  | 551 +-------------------
 gdb/gdbserver/Makefile.in                         |   7 +
 gdb/gdbserver/inferiors.c                         |  31 ++
 gdb/gdbserver/linux-low.c                         | 141 +++--
 gdb/gdbserver/lynx-low.c                          |  80 ++-
 gdb/gdbserver/nto-low.c                           |   7 +-
 gdb/gdbserver/server.c                            | 268 ++++++----
 gdb/gdbserver/server.h                            |  17 +
 gdb/gdbserver/spu-low.c                           |  46 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |   8 +-
 gdb/gdbserver/terminal.c                          |  12 +-
 gdb/gdbserver/utils.c                             |  36 ++
 gdb/gdbserver/utils.h                             |  11 +
 gdb/gdbserver/win32-low.c                         |  20 +-
 gdb/gnu-nat.c                                     |   6 +-
 gdb/inf-ptrace.c                                  |   7 +-
 gdb/inferior.h                                    |  24 +-
 gdb/inflow.c                                      |  38 +-
 gdb/procfs.c                                      |   6 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  10 +-
 gdb/top.c                                         |   8 +
 gdb/top.h                                         |   1 +
 gdb/utils.c                                       |   9 +
 34 files changed, 1351 insertions(+), 842 deletions(-)
 create mode 100644 gdb/common/common-fork-child.c
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/common/common-top.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e5b0363..88ce813 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1211,6 +1211,7 @@ SFILES = \
 	common/filestuff.c \
 	common/format.c \
 	common/job-control.c \
+	common/common-fork-child.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1498,6 +1499,8 @@ HFILES_NO_SRCDIR = \
 	common/gdb_sys_time.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
+	common/common-top.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1641,6 +1644,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-debug.o \
 	common-exceptions.o \
 	job-control.o \
+	common-fork-child.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
new file mode 100644
index 0000000..669771e
--- /dev/null
+++ b/gdb/common/common-fork-child.c
@@ -0,0 +1,604 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "target/waitstatus.h"
+#include "common-terminal.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "common-top.h"
+#include "signals-state-save-restore.h"
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Break up SCRATCH into an argument vector suitable for passing to
+   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
+   would get as input the string "a b c d", and as output it would
+   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+
+static void
+breakup_args_for_exec (const char *scratch, char **argv)
+{
+  char *cp = (char *) scratch, *tmp;
+
+  for (;;)
+    {
+      /* Scan past leading separators */
+      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
+	cp++;
+
+      /* Break if at end of string.  */
+      if (*cp == '\0')
+	break;
+
+      /* Take an arg.  */
+      *argv++ = cp;
+
+      /* Scan for next arg separator.  */
+      tmp = strchr (cp, ' ');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\t');
+      if (tmp == NULL)
+	tmp = strchr (cp, '\n');
+
+      /* No separators => end of string => break.  */
+      if (tmp == NULL)
+	break;
+      cp = tmp;
+
+      /* Replace the separator with a terminator.  */
+      *cp++ = '\0';
+    }
+
+  /* Null-terminate the vector.  */
+  *argv = NULL;
+}
+
+/* When executing a command under the given shell, return non-zero if
+   the '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  const int shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return 0;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return 1;
+
+  return 0;
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_startup_shell (void)
+{
+  static char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* Quote the shell command that will be executed.  This function is
+   called when the inferior is going to be executed under a shell
+   (i.e., when 'startup-with-shell' is set).
+
+   SHELL_FILE is the shell which will be used to execute the inferior
+   (e.g., /bin/sh).
+
+   EXEC_FILE is the inferior executable itself.
+
+   ALLARGS contains all the arguments that will be passed to the
+   inferior.
+
+   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
+   the inferior.
+
+   SHELL_CMD is a pointer to the resulting shell command that will be
+   executed.  The resulting shell command will be returned in it.  It
+   must be pre-allocated and have a reasonable size.  For an example
+   on how to determine its size, see 'fork_inferior' on
+   fork-child.c.  */
+
+static void
+quote_shell_command (const char *shell_file, const char *exec_file,
+		     const char *allargs, const char *exec_wrapper,
+		     char **shell_cmd)
+{
+  char *shell_command = *shell_cmd;
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  shell_command[0] = '\0';
+  strcat (shell_command, "exec ");
+
+  /* Add any exec wrapper.  That may be a program name with arguments, so
+     the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      strcat (shell_command, exec_wrapper);
+      strcat (shell_command, " ");
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But
+     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
+     we need to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      strcat (shell_command, "'");
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    strcat (shell_command, "'\\''");
+	  else if (*p == '!' && escape_bang)
+	    strcat (shell_command, "\\!");
+	  else
+	    strncat (shell_command, p, 1);
+	}
+      strcat (shell_command, "'");
+    }
+  else
+    strcat (shell_command, exec_file);
+
+  strcat (shell_command, " ");
+  strcat (shell_command, allargs);
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
+
+/* See common/common-inferior.h.  */
+
+int
+fork_inferior (char *exec_file_arg, const char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+	       void (*exec_fun)(const char *file, char * const *argv,
+				char * const *env))
+{
+  int pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  static int debug_fork = 0;
+  /* This is set to the result of setpgrp, which if vforked, will be visible
+     to you in the parent process.  It's only used by humans for debugging.  */
+  static int debug_setpgrp = 657473;
+  static char *shell_file;
+  static char *exec_file;
+  char **save_our_env;
+  int shell = 0;
+  static char **argv;
+  struct inferior *inf;
+  int i;
+  int save_errno;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  exec_file = exec_file_arg;
+  if (exec_file == 0)
+    exec_file = get_exec_file (1);
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  shell_file = shell_file_arg;
+  if (startup_with_shell)
+    {
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+      shell = 1;
+    }
+
+  if (!shell)
+    {
+      /* We're going to call execvp.  Create argument vector.
+	 Calculate an upper bound on the length of the vector by
+	 assuming that every other character is a separate
+	 argument.  */
+      int argc = (strlen (allargs) + 1) / 2 + 2;
+
+      argv = XALLOCAVEC (char *, argc);
+      argv[0] = exec_file;
+      breakup_args_for_exec (allargs, &argv[1]);
+    }
+  else
+    {
+      /* We're going to call a shell.  */
+      char *shell_command;
+      const char *exec_wrapper = get_exec_wrapper ();
+      size_t len;
+
+      /* Multiplying the length of exec_file by 4 is to account for the
+         fact that it may expand when quoted; it is a worst-case number
+         based on every character being '.  */
+      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
+      if (exec_wrapper != NULL)
+        len += strlen (exec_wrapper) + 1;
+
+      shell_command = (char *) alloca (len);
+      shell_command[0] = '\0';
+
+      quote_shell_command (shell_file, exec_file,
+			   allargs,
+			   exec_wrapper, &shell_command);
+
+      /* If we decided above to start up with a shell, we exec the
+	 shell, "-c" says to interpret the next arg as a shell command
+	 to execute, and this command is "exec <target-program>
+	 <args>".  */
+      argv = (char **) alloca (4 * sizeof (char *));
+      argv[0] = shell_file;
+      argv[1] = "-c";
+      argv[2] = shell_command;
+      argv[3] = (char *) 0;
+    }
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Perform any necessary actions regarding to TTY before the
+     fork/vfork call.  */
+  tty_prefork_hook ();
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Make sure we switch to main_ui here in order to be able to
+	 use the fprintf_unfiltered/warning/error functions.  */
+      switch_ui_postfork ();
+
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
+      close_most_fds ();
+
+      if (debug_fork)
+	sleep (debug_fork);
+
+      /* Create a new session for the inferior process, if necessary.
+         It will also place the inferior in a separate process group.  */
+      if (create_tty_session () <= 0)
+	{
+	  /* No session was created, but we still want to run the inferior
+	     in a separate process group.  */
+	  debug_setpgrp = gdb_setpgid ();
+	  if (debug_setpgrp == -1)
+	    perror (_("setpgrp failed in child"));
+	}
+
+      /* Ask the tty subsystem to switch to the one we specified
+         earlier (or to share the current terminal, if none was
+         specified).  */
+      new_tty ();
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], argv, env);
+      else
+        execvp (argv[0], argv);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  if (!have_inferiors ())
+    init_thread_list ();
+
+  inf = current_inferior ();
+
+  inferior_appeared (inf, pid);
+
+  /* Needed for wait_for_inferior stuff below.  */
+  inferior_ptid = pid_to_ptid (pid);
+
+  tty_postfork_hook ();
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point, but the pid shouldn't change.  Targets
+     supporting MT should fill this task's ptid with more data as soon
+     as they can.  */
+  add_thread_silent (inferior_ptid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See common/common-inferior.h.  */
+
+ptid_t
+startup_inferior (int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  return resume_ptid;
+}
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..bab308a
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,121 @@
+/* Variables that describe the inferior process running under GDB and
+   GDBserver: Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+struct inferior;
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Collected pid, tid, etc. of the debugged inferior.  When there's
+   no inferior, ptid_get_pid (inferior_ptid) will be 0.  */
+extern ptid_t inferior_ptid;
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
+/* Accept NTRAPS traps from the inferior.
+
+   Return the ptid of the inferior being started.  */
+extern ptid_t startup_inferior (int ntraps,
+				struct target_waitstatus *mystatus,
+				ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern int fork_inferior (char *exec_file_arg, const char *allargs, char **env,
+	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+	       void (*exec_fun) (const char *file, char * const *argv,
+				 char * const *env));
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+extern char *get_startup_shell (void);
+
+/* Set file name for default use for standard in/out in the inferior.  */
+extern void set_inferior_io_terminal (const char *terminal_name);
+
+/* Get file name for default use for standard in/out in the inferior.  */
+extern const char *get_inferior_io_terminal (void);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern const char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+/* Returns true if the inferior list is not empty.  */
+extern int have_inferiors (void);
+
+extern void inferior_appeared (struct inferior *inf, int pid);
+
+/* Return a pointer to the current inferior.  It is an error to call
+   this if there is no current inferior.  */
+extern struct inferior *current_inferior (void);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
index 7a1bcfe..c32aec8 100644
--- a/gdb/common/common-terminal.h
+++ b/gdb/common/common-terminal.h
@@ -84,24 +84,13 @@ extern int job_control;
 
 extern void new_tty (void);
 
-/* NEW_TTY_PREFORK is called before forking a new child process,
-   so we can record the state of ttys in the child to be formed.
-   TTYNAME is null if we are to share the terminal with gdb;
-   or points to a string containing the name of the desired tty.
-
-   NEW_TTY is called in new child processes under Unix, which will
-   become debugger target processes.  This actually switches to
-   the terminal specified in the NEW_TTY_PREFORK call.
-   
-   This function is implemented as a placeholder on GDBserver.  */
-extern void new_tty_prefork (const char *ttyname);
-
-/* NEW_TTY_POSTFORK is called after forking a new child process, and
-   adding it to the inferior table, to store the TTYNAME being used by
-   the child, or null if it sharing the terminal with gdb.
+/* Perform any necessary TTY-related tasks before a fork/vfork takes
+   place.  This function is mainly used by fork_inferior.  */
+extern void tty_prefork_hook (void);
 
-   This function is implemented as a placeholder on GDBserver.  */
-extern void new_tty_postfork (void);
+/* Perform any necessary TTY-related tasks after a fork/vfork takes
+   place.  This function is mainly used by fork_inferior.  */
+extern void tty_postfork_hook (void);
 
 /* Create a new session if the inferior will run in a different tty.
    A session is UNIX's way of grouping processes that share a controlling
diff --git a/gdb/common/common-top.h b/gdb/common/common-top.h
new file mode 100644
index 0000000..ec06460
--- /dev/null
+++ b/gdb/common/common-top.h
@@ -0,0 +1,28 @@
+/* Common top level stuff for GDB and GDBserver.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TOP_H
+#define COMMON_TOP_H
+
+/* Switch to the main UI, so that gdb_std{in/out/err} in the child are
+   mapped to std{in/out/err}.  This makes it possible to use
+   fprintf_unfiltered/warning/error/etc. in the child.  */
+extern void switch_ui_postfork (void);
+
+#endif /* ! COMMON_TOP_H */
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 618d266..b9bbdb9 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -103,4 +103,8 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err (void);
+
 #endif
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 54cb789..d76fa1a 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index edee1be..b8ae247 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1772,6 +1772,7 @@ static void
 darwin_ptrace_him (int pid)
 {
   task_t itask;
+  ptid_t ptid;
   kern_return_t kret;
   mach_port_t prev_port;
   int traps_expected;
@@ -1788,7 +1789,10 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  ptid = startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
+
+  /* Mark all threads non-executing.  */
+  set_executing (ptid, 0);
 }
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index dc2a314..ecb69a4 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,556 +21,19 @@
 
 #include "defs.h"
 #include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
 #include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
-#include "top.h"
-#include "signals-state-save-restore.h"
-#include <signal.h>
 
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-extern char **environ;
+static char *exec_wrapper = NULL;
 
-static char *exec_wrapper;
+/* See common/common-inferior.h.  */
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
-
-static void
-breakup_args (char *scratch, char **argv)
-{
-  char *cp = scratch, *tmp;
-
-  for (;;)
-    {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
-    }
-
-  /* Null-terminate the vector.  */
-  *argv = NULL;
-}
-
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static int
-escape_bang_in_quoted_argument (const char *shell_file)
+const char *
+get_exec_wrapper (void)
 {
-  const int shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return 0;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return 1;
-
-  return 0;
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
-		                  "process.\nError: ");
-  vfprintf_unfiltered (gdb_stderr, fmt, ap);
-  va_end (ap);
-
-  gdb_flush (gdb_stderr);
-  _exit (0177);
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error_with_name (const char *string)
-{
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static char *exec_file;
-  char **save_our_env;
-  int shell = 0;
-  static char **argv;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
-    exec_file = get_exec_file (1);
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
-  if (startup_with_shell)
-    {
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  strcat (shell_command, "'");
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
-	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
-	      else
-		strncat (shell_command, p, 1);
-	    }
-	  strcat (shell_command, "'");
-	}
-      else
-	strcat (shell_command, exec_file);
-
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
-    }
-
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
-
-  /* Tell the terminal handling subsystem what tty we plan to run on;
-     it will just record the information for later.  */
-  new_tty_prefork (inferior_io_terminal);
-
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
-      else
-        execvp (argv[0], argv);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
-
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
-
-  if (!have_inferiors ())
-    init_thread_list ();
-
-  inf = current_inferior ();
-
-  inferior_appeared (inf, pid);
-
-  /* Needed for wait_for_inferior stuff below.  */
-  inferior_ptid = pid_to_ptid (pid);
-
-  new_tty_postfork ();
-
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
-}
-
-/* Accept NTRAPS traps from the inferior.  */
-
-void
-startup_inferior (int ntraps)
-{
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
-
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
-
-  if (exec_wrapper)
-    pending_execs++;
-
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
-
-  /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  return exec_wrapper;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index adbeb16..ce41656 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,6 +185,7 @@ SFILES = \
 	$(srcdir)/target.c \
 	$(srcdir)/thread-db.c \
 	$(srcdir)/utils.c \
+	$(srcdir)/terminal.c \
 	$(srcdir)/win32-arm-low.c \
 	$(srcdir)/win32-i386-low.c \
 	$(srcdir)/win32-low.c \
@@ -205,6 +206,7 @@ SFILES = \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
 	$(srcdir)/common/job-control.c \
+	$(srcdir)/common/common-fork-child.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -236,6 +238,7 @@ OBS = \
 	common-debug.o \
 	common-exceptions.o \
 	job-control.o \
+	common-fork-child.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
@@ -269,6 +272,7 @@ OBS = \
 	version.o \
 	waitstatus.o \
 	xml-utils.o \
+	terminal.o \
 	$(DEPFILES) \
 	$(LIBOBJS) \
 	$(XML_BUILTIN)
@@ -780,6 +784,9 @@ format.o: ../common/format.c
 filestuff.o: ../common/filestuff.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+common-fork-child.o: ../common/common-fork-child.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 job-control.o: ../common/job-control.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index c9d03a8..74d5269 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -29,6 +29,10 @@ struct thread_info *current_thread;
 
 #define get_thread(inf) ((struct thread_info *)(inf))
 
+/* Even though we do not use/need INFERIOR_PTID here, we still have to
+   declare it because fork_inferior uses it directly.  */
+ptid_t inferior_ptid;
+
 void
 add_inferior_to_list (struct inferior_list *list,
 		      struct inferior_list_entry *new_inferior)
@@ -469,6 +473,25 @@ make_cleanup_restore_current_thread (void)
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
 
+/* See common/common-inferior.h.  */
+
+void
+inferior_appeared (struct inferior *inf, int pid)
+{
+  /* Placeholder needed for fork_inferior.  We do not have to do
+     anything in this case.  */
+}
+
+/* See common/common-inferior.h.  */
+
+struct inferior *
+current_inferior (void)
+{
+  /* Placeholder needed for fork_inferior.  GDBserver has other
+     functions that serve this purpose.  */
+  return NULL;
+}
+
 /* See common/common-gdbthread.h.  */
 
 void
@@ -499,3 +522,11 @@ add_thread_silent (ptid_t ptid)
 
   return add_thread (ptid_build (pid, pid, 0), NULL);
 }
+
+/* See common/common-inferior.h.  */
+
+int
+have_inferiors (void)
+{
+  return get_first_process () != NULL;
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e27cbf8..4c9bf28 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -415,15 +417,20 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
-/* Add a process to the common process list, and set its private
-   data.  */
+/* Update an existing process represented by PID with the necessary
+   info.  Make sure that the private data structure is allocated, as
+   well as fill the ->arch_private structure if needed.
+
+   This function exists because fork_inferior already creates a
+   process when called, but it is up to us to complete the
+   process_info structure with extra information.  */
 
 static struct process_info *
-linux_add_process (int pid, int attached)
+linux_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
 
-  proc = add_process (pid, attached);
+  gdb_assert (proc != NULL);
   proc->priv = XCNEW (struct process_info_private);
 
   if (the_low_target.new_process != NULL)
@@ -432,6 +439,16 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return linux_update_process (pid);
+}
+
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
 /* Call the target arch_setup function on the current thread.  */
@@ -929,6 +946,33 @@ save_stop_reason (struct lwp_info *lwp)
   return 1;
 }
 
+/* Update the lwp associated to thread represented by PTID.
+
+   This function exists because fork_inferior already calls
+   'add_thread_silent', which creates the 'struct thread_info'.
+   However, we still need to set a few more things on the struct.  */
+
+static struct lwp_info *
+update_thread_lwp (ptid_t ptid)
+{
+  struct lwp_info *lwp;
+  struct thread_info *thread;
+
+  lwp = XCNEW (struct lwp_info);
+
+  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
+  if (the_low_target.new_thread != NULL)
+    the_low_target.new_thread (lwp);
+
+  thread = find_thread_ptid (ptid);
+  gdb_assert (thread != NULL);
+  thread->target_data = lwp;
+  lwp->thread = thread;
+
+  return lwp;
+}
+
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 {
@@ -946,68 +990,69 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+	trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+	trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+	trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args. */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (char *program,
+		       const std::vector<char *> &program_argv)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string program_args = stringify_argv (program_argv);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
+  pre_fork_inferior (program_argv);
 
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
-  linux_add_process (pid, 0);
+  linux_update_process (pid);
 
   ptid = ptid_build (pid, pid, 0);
-  new_lwp = add_lwp (ptid);
+  new_lwp = update_thread_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program, program_argv);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..e8221b8 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,7 @@
 #include "gdb_wait.h"
 #include <signal.h>
 #include "filestuff.h"
+#include "common-inferior.h"
 
 int using_threads = 1;
 
@@ -208,15 +209,21 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
-/* Call add_process with the given parameters, and initializes
-   the process' private data.  */
+/* Update an existing process represented by PID with the necessary
+   info.  Make sure that the private data structure is allocated, as
+   well as fill the ->arch_private structure if needed.
+
+   This function exists because fork_inferior already creates a
+   process when called, but it is up to us to complete the
+   process_info structure with extra information.  */
 
 static struct process_info *
-lynx_add_process (int pid, int attached)
+lynx_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
+
+  gdb_assert (proc != NULL);
 
-  proc = add_process (pid, attached);
   proc->tdesc = lynx_tdesc;
   proc->priv = XCNEW (struct process_info_private);
   proc->priv->last_wait_event_ptid = null_ptid;
@@ -224,41 +231,60 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return lynx_update_process (pid);
+}
+
+/* Callback used by fork_inferior to start tracing the inferior.  */
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  if (pgrp < 0)
+    trace_start_error_with_name ("pgrp");
+  if (setpgid (0, pgrp) < 0)
+    trace_start_error_with_name ("setpgid");
+  if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+    trace_start_error_with_name ("ioctl");
+  if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+    trace_start_error_with_name ("lynx_ptrace");
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (char *program, const std::vector<char *> &program_argv)
 {
   int pid;
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pre_fork_inferior (program_argv);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  lynx_add_process (pid, 0);
+  post_fork_inferior (pid, program, program_argv);
+
+  lynx_update_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..8cee363 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,15 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM_ARGV.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (char *program, const std::vector<char *> &program_argv)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string program_args = stringify_argv (program_argv);
 
   TRACE ("%s %s\n", __func__, program);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
@@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 4bc7f71..1677926 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,20 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "common-terminal.h"
+#include "common-top.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +92,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -236,33 +251,59 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+const char *
+get_exec_wrapper (void)
 {
-  char **new_argv = argv;
+  static std::string ret;
+  static bool initialized_p = false;
+
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  if (wrapper_argv != NULL)
+  if (!initialized_p)
     {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
+      for (auto s : wrapper_argv)
+	ret += s + std::string (" ");
+
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = true;
     }
 
+  return ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_argv.empty ())
+    error (_("No executable file specified."));
+
+  return program_argv[0];
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See server.h.  */
+
+void
+pre_fork_inferior (const std::vector<char *> &argv)
+{
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      for (int idx = 0; idx < argv.size (); ++idx)
+	debug_printf ("new_argv[%d] = \"%s\"\n", idx, argv[idx]);
       debug_flush ();
     }
 
@@ -271,67 +312,35 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, char *program,
+		    const std::vector<char *> &argv)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
-
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
-
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
-
-  return signal_pid;
+  startup_inferior (num_traps, &last_status, &last_ptid);
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
 }
 
 static int
@@ -2852,8 +2861,10 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
-  int i, new_argc;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
+  int new_argc;
+  int i;
 
   new_argc = 0;
   for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
@@ -2862,62 +2873,93 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
-      if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+      if (p == next_p)
+	new_argv.push_back ("''");
       else
 	{
 	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = 1 + (next_p - p) / 2;
+	  char *s = (char *) xmalloc (len);
+	  char *ss = (char *) xmalloc (len * 2);
+	  char *tmp_s, *tmp_ss;
+	  int need_quote;
+
+	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
+	  s[(next_p - p) / 2] = '\0';
+
+	  tmp_s = s;
+	  tmp_ss = ss;
+	  need_quote = 0;
+	  while (*tmp_s != '\0')
+	    {
+	      switch (*tmp_s)
+		{
+		case '\n':
+		  *tmp_ss = '\'';
+		  ++tmp_ss;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  *tmp_ss = '\\';
+		  ++tmp_ss;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_ss = *tmp_s;
+	      ++tmp_ss;
+	      ++tmp_s;
+	    }
+
+	  if (need_quote)
+	    *tmp_ss++ = '\'';
+
+	  *tmp_ss = '\0';
+	  new_argv.push_back (ss);
+	  xfree (s);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
 
-  if (new_argv[0] == NULL)
+  if (new_argv.empty () || new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
 
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
+      new_argv.push_back (strdup (program_argv[0]));
+      if (new_argv.empty () || new_argv[0] == NULL)
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  create_inferior (program_argv[0],
+		   std::vector<char *> (program_argv.begin () + 1,
+					program_argv.end ()));
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3535,13 +3577,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3672,8 +3719,13 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3687,13 +3739,13 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      create_inferior (program_argv[0],
+		       std::vector<char *> (program_argv.begin () + 1,
+					    program_argv.end ()));
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4308,9 +4360,11 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      create_inferior (program_argv[0],
+			       std::vector<char *> (program_argv.begin () + 1,
+						    program_argv.end ()));
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..5b65597 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -148,4 +149,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* Any pre-processing needed to be done before calling fork_inferior
+   shall be implemented here.  ARGV is a vector containing the full
+   argv of the inferior.  */
+extern void pre_fork_inferior (const std::vector<char *> &argv);
+
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and ARGV is the vector containing the full
+   argv of the inferior.  */
+extern void post_fork_inferior (int pid, char *program,
+				const std::vector<char *> &argv);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..49cfd65 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
+#include "common-inferior.h"
 
 /* Some older glibc versions do not define this.  */
 #ifndef __WNOTHREAD
@@ -261,42 +262,41 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM_ARGV is a vector of program-name and args. */
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (char *program, const std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string program_args = stringify_argv (program_argv);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
+  pre_fork_inferior (program_argv);
 
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program,
+		       program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program, program_argv);
 
-  proc = add_process (pid, 0);
+  proc = find_process_pid (pid);
+  gdb_assert (proc != NULL);
   proc->tdesc = tdesc_spu;
 
-  ptid = ptid_build (pid, pid, 0);
-  add_thread (ptid, NULL);
   return pid;
 }
 
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..1e1d193 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..e47ed78 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -73,7 +74,8 @@ struct target_ops
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
 
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (char *program,
+			  const std::vector<char *> &program_argv);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +482,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_argv)	\
+  (*the_target->create_inferior) (program, program_argv)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
index fb06209..ee361d1 100644
--- a/gdb/gdbserver/terminal.c
+++ b/gdb/gdbserver/terminal.c
@@ -18,6 +18,7 @@
 
 #include "server.h"
 #include "common-terminal.h"
+#include "common-top.h"
 
 /* Placeholders needed by fork_inferior.  For now, these functions are
    not needed nor useful to have on gdbserver.  When/If we properly
@@ -34,14 +35,14 @@ new_tty (void)
 /* See common/common-terminal.h.  */
 
 void
-new_tty_prefork (const char *ttyname)
+tty_prefork_hook (void)
 {
 }
 
 /* See common/common-terminal.h.  */
 
 void
-new_tty_postfork (void)
+tty_postfork_hook (void)
 {
 }
 
@@ -67,3 +68,10 @@ get_inferior_io_terminal (void)
 {
   return NULL;
 }
+
+/* See common/common-top.h.  */
+
+void
+switch_ui_postfork (void)
+{
+}
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..70e8b18 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,39 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (char *&i : v)
+    xfree (i);
+
+  v.clear ();
+}
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (const std::vector<char *> &argv)
+{
+  std::string ret;
+
+  for (auto s : argv)
+    ret += s + std::string (" ");
+
+  /* Erase the last whitespace.  */
+  ret.erase (ret.end () - 1);
+
+  return ret;
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index b4ded31..172a2ec 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,7 +19,18 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
+/* Assumes that V is an argv for a program, and iterates through
+   freeing all the elements.  */
+extern void free_vector_argv (std::vector<char *> &v);
+
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments (starting from ARGV + 1) with a
+   whitespace separating them.  */
+extern std::string stringify_argv (const std::vector<char *> &argv);
+
 #endif /* UTILS_H */
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index d3ddbf5..b86ae2b 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,11 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM_ARGV is the vector containing the inferior's argv.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (char *program, const std::vector<char *> &program_argv)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +625,8 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string program_args = stringify_argv (program_argv);
+  char *args = (char *) program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -652,18 +652,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 7efb3c1..21445f5 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2136,6 +2136,7 @@ gnu_create_inferior (struct target_ops *ops,
 {
   struct inf *inf = cur_inf ();
   int pid;
+  ptid_t ptid;
 
   inf_debug (inf, "creating inferior");
 
@@ -2161,7 +2162,10 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
+  /* Mark all threads non-executing.  */
+  set_executing (ptid, 0);
+
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 21578742..e3ddaa8 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -94,7 +94,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 			    int from_tty)
 {
   int pid;
-
+  ptid_t ptid;
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
   int ops_already_pushed = target_is_pushed (ops);
@@ -112,7 +112,10 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  ptid = startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
+
+  /* Mark all threads non-executing.  */
+  set_executing (ptid, 0);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7c0ddf3..011efd0 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -42,6 +42,7 @@ struct target_desc_info;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 
@@ -132,29 +133,6 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
-extern int fork_inferior (char *, char *, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
-
 extern char *construct_inferior_arguments (int, char **);
 
 /* From infcmd.c */
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 271278d..faf14d2 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -18,6 +18,7 @@
 
 #include "defs.h"
 #include "frame.h"
+#include "top.h"
 #include "inferior.h"
 #include "command.h"
 #include "serial.h"
@@ -632,7 +633,7 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
    become debugger target processes.  This actually switches to
    the terminal specified in the NEW_TTY_PREFORK call.  */
 
-void
+static void
 new_tty_prefork (const char *ttyname)
 {
   /* Save the name for later, for determining whether we and the child
@@ -640,6 +641,27 @@ new_tty_prefork (const char *ttyname)
   inferior_thisrun_terminal = ttyname;
 }
 
+/* The ui structure that will be saved on 'tty_prefork_hook' and
+   restored on 'tty_postfork_hook'.  */
+static struct ui *saved_ui = NULL;
+
+/* See common/common-terminal.h.  */
+
+void
+tty_prefork_hook (void)
+{
+  const char *inferior_io_terminal = get_inferior_io_terminal ();
+
+  gdb_assert (saved_ui == NULL);
+  /* Retain a copy of our UI, since the child will replace this value
+     and if we're vforked, we have to restore it.  */
+  saved_ui = current_ui;
+
+  /* Tell the terminal handling subsystem what tty we plan to run on;
+     it will just record the information for later.  */
+  new_tty_prefork (inferior_io_terminal);
+}
+
 #if !defined(__GO32__) && !defined(_WIN32)
 /* If RESULT, assumed to be the return value from a system call, is
    negative, print the error message indicated by errno and exit.
@@ -718,7 +740,7 @@ new_tty (void)
    adding it to the inferior table, to store the TTYNAME being used by
    the child, or null if it sharing the terminal with gdb.  */
 
-void
+static void
 new_tty_postfork (void)
 {
   /* Save the name for later, for determining whether we and the child
@@ -735,6 +757,18 @@ new_tty_postfork (void)
   inferior_thisrun_terminal = NULL;
 }
 
+/* See common/common-terminal.h.  */
+
+void
+tty_postfork_hook (void)
+{
+  gdb_assert (saved_ui != NULL);
+  current_ui = saved_ui;
+  saved_ui = NULL;
+
+  new_tty_postfork ();
+}
+
 \f
 /* Call set_sigint_trap when you need to pass a signal on to an attached
    process when handling SIGINT.  */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 2269016..399b8b7 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4308,6 +4308,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   gdb_sigset_t signals;
   int fail;
   int lwpid;
+  ptid_t ptid;
 
   /* This routine called on the parent side (GDB side)
      after GDB forks the inferior.  */
@@ -4375,7 +4376,10 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  ptid = startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
+
+  /* Mark all threads non-executing.  */
+  set_executing (ptid, 0);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
diff --git a/gdb/target.h b/gdb/target.h
index 943a0e2..91f5927 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1537,17 +1537,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1556,12 +1545,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..f12262e 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..fec138d 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled.
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/top.c b/gdb/top.c
index 6bf9d8c..16fdeba 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -419,6 +419,14 @@ new_ui_command (char *args, int from_tty)
   printf_unfiltered ("New UI allocated\n");
 }
 
+/* See common/common-top.h.  */
+
+void
+switch_ui_postfork (void)
+{
+  current_ui = main_ui;
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
diff --git a/gdb/top.h b/gdb/top.h
index 2da92df..d9daa97 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -22,6 +22,7 @@
 
 #include "buffer.h"
 #include "event-loop.h"
+#include "common-top.h"
 
 struct tl_interp_info;
 
diff --git a/gdb/utils.c b/gdb/utils.c
index ace2539..51453d5 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3392,6 +3392,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 3/5] Share parts of gdb/gdbthread.h with gdbserver
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
                         ` (2 preceding siblings ...)
  2017-03-08  5:29       ` [PATCH v4 2/5] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
@ 2017-03-08  5:29       ` Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 4/5] Share fork_inferior et al " Sergio Durigan Junior
  4 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

Again, it was necessary to share a few functions declared on
gdb/gdbthread.h with gdbserver, because they are needed by
fork_inferior.  I decided to implement them on
gdb/gdbserver/inferiors.c because that's where the thread functions
are also implemented on gdbserver.  Some of these functions do not
need to be implemented on gdbserver, or don't make sense there, so
they are left blank and commented properly.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* gdbthread.h: Include "common-gdbthread.h".
	(init_thread_list): Moved to "common/common-gdbthread.h".
	(add_thread_silent): Likewise.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	* thread.c (set_executing): Update function comment.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (init_thread_list): New function.
	(switch_to_thread): Likewise.
	(set_executing): Likewise.
	(add_thread_silent): Likewise.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 35 +++++++++++++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     | 31 +++++++++++++++++++++++++++++++
 gdb/gdbthread.h               | 12 +-----------
 4 files changed, 68 insertions(+), 11 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6ad03d7..e5b0363 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1482,6 +1482,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..c8a4422
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,35 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_GDBTHREAD_H
+#define COMMON_GDBTHREAD_H
+
+struct target_waitstatus;
+
+/* Create an empty thread list, or empty the existing one.  */
+extern void init_thread_list (void);
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+/* Add a thread to the thread list and return the pointer to the new
+   thread.  Caller may use this pointer to initialize the private
+   thread data.  */
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+#endif /* ! COMMON_GDBTHREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..c9d03a8 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,34 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+init_thread_list (void)
+{
+  /* Placeholder needed for fork_inferior.  No action is needed.  */
+}
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
+
+/* See common/common-gdbthread.h.  */
+
+struct thread_info *
+add_thread_silent (ptid_t ptid)
+{
+  pid_t pid = ptid_get_pid (ptid);
+
+  /* Check if there is a process already.  */
+  if (find_process_pid (pid) == NULL)
+    add_process (pid, 0);
+
+  return add_thread (ptid_build (pid, pid, 0), NULL);
+}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 06ed78f..5647ae6 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -31,6 +31,7 @@ struct symtab;
 #include "common/vec.h"
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -344,19 +345,12 @@ struct thread_info
   struct thread_info *step_over_next;
 };
 
-/* Create an empty thread list, or empty the existing one.  */
-extern void init_thread_list (void);
-
 /* Add a thread to the thread list, print a message
    that a new thread is found, and return the pointer to
    the new thread.  Caller my use this pointer to 
    initialize the private thread data.  */
 extern struct thread_info *add_thread (ptid_t ptid);
 
-/* Same as add_thread, but does not print a message
-   about new thread.  */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
-
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
 						 struct private_thread_info *);
@@ -469,10 +463,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 0/5] Implement the ability to start inferiors with a shell on gdbserver
  2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
                       ` (6 preceding siblings ...)
  2017-02-13 19:50     ` [PATCH v3 0/6] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
@ 2017-03-08  5:29     ` Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 1/5] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
                         ` (4 more replies)
  7 siblings, 5 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado

Hi again,

This is the fourth version of this patch series.  You can look at the
last version sent here:

  <https://sourceware.org/ml/gdb-patches/2017-02/msg00173.html>

This version now has 5 patches instead of 6 because the first patch,
which shared gdb/environ.[ch] between GDB and gdbserver, got accepted
and pushed upstream.

The changes in this version were almost entirely made to address
Pedro's reviews (thanks!).  Here's the bulk of what changed from v3:

- We now check if the necessary headers for some terminal.h features
  are present on common/common.m4.

- Reorganized the job_control part; moved it to the correct patch (2/5
  instead of 1/5).

- Return the proper value (0) on create_tty_session.

- Reformatted the comments on gdbserver/terminal.c.

- Renamed the file to "common/job-control.c" instead of
  "common/common-inflow.c".

- Call set_executing after calling fork_inferior, which makes it
  unnecessary to expand its prototype and accept more arguments.

- Removed the "struct ui" hacks on gdbserver; replace them by some new
  functions that take care of everything from the GDB side.

- Fixed use of invalid C++ for "startup_with_shell" variable.

- Still declaring "inferior_ptid" on gdbserver/inferiors.c, but added
  a comment explaining why.

- Expanded the comment on {linux,lynx}_update_process and
  update_thread_lwp.

- Constified second argument of fork_inferior.

- Improved a few error messages.

- Improved some C++ range loops.

- Constified a few things and improved comments.

- Removed erroneous call to post_fork_inferior on Windows code.

- Improved text on NEWS file.

- Improved help text for
  "--startup-with-shell"/"--no-startup-with-shell" parameters on
  gdbserver.

- Moved code to set startup-with-shell packet to the "create_inferior"
  function on extended remote code.

- Fixed a bunch of testcase nits.


If you go to the v3 version of the patch, you can see the cover letter
as well.

This has been tested on BuildBot, and no regressions were found.

Thanks,

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v4 1/5] Share parts of gdb/terminal.h with gdbserver
  2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
@ 2017-03-08  5:29       ` Sergio Durigan Junior
  2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-08  5:29 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Luis Machado, Sergio Durigan Junior

As part of the bigger work of sharing fork_inferior with gdbserver,
some parts of gdb/terminal.h also needed to be moved to a common
place.  These parts are:

- The code responsible for determining some terminal-based define's
  based on available features;

- terminal-related functions needed by fork_inferior;

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-terminal.h".
	* common/common-terminal.h: New file, with parts of "terminal.h".
	* common/common.m4: Check headers 'termios.h', 'termio.h' and
	'sgtty.h'.
	* terminal.h: Move terminal-related defines to
	"common/common-terminal.h".  Include "common/common-terminal.h".
	(new_tty_prefork): Move to "common/common-terminal.h".
	(new_tty): Likewise.
	(new_tty_postfork): Likewise.
	(create_tty_session): Likewise.
	(gdb_setpgid): Likewise.
	* utils.c: Include "terminal.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* terminal.c: New file.
---
 gdb/Makefile.in              |   1 +
 gdb/common/common-terminal.h | 116 +++++++++++++++++++++++++++++++++++++++++++
 gdb/common/common.m4         |   3 +-
 gdb/gdbserver/terminal.c     |  69 +++++++++++++++++++++++++
 gdb/terminal.h               |  73 +--------------------------
 gdb/utils.c                  |   1 +
 6 files changed, 190 insertions(+), 73 deletions(-)
 create mode 100644 gdb/common/common-terminal.h
 create mode 100644 gdb/gdbserver/terminal.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0818742..177c853 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1484,6 +1484,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/common-terminal.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
new file mode 100644
index 0000000..87a19f0
--- /dev/null
+++ b/gdb/common/common-terminal.h
@@ -0,0 +1,116 @@
+/* Common terminal interface definitions for GDB and gdbserver.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TERMINAL_H
+#define COMMON_TERMINAL_H
+
+/* If we're using autoconf, it will define HAVE_TERMIOS_H,
+   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
+   ser-unix.c and inflow.c to inspect those names instead of
+   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
+   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
+   nothing has already defined the one of the names, and do the right
+   thing.  */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
+	  !defined (HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  FIXME: serial.h and
+   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+   is converted to use them, can get rid of this crap.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+#include <sys/types.h>
+
+extern void new_tty (void);
+
+/* NEW_TTY_PREFORK is called before forking a new child process,
+   so we can record the state of ttys in the child to be formed.
+   TTYNAME is null if we are to share the terminal with gdb;
+   or points to a string containing the name of the desired tty.
+
+   NEW_TTY is called in new child processes under Unix, which will
+   become debugger target processes.  This actually switches to
+   the terminal specified in the NEW_TTY_PREFORK call.
+   
+   This function is implemented as a placeholder on GDBserver.  */
+extern void new_tty_prefork (const char *ttyname);
+
+/* NEW_TTY_POSTFORK is called after forking a new child process, and
+   adding it to the inferior table, to store the TTYNAME being used by
+   the child, or null if it sharing the terminal with gdb.
+
+   This function is implemented as a placeholder on GDBserver.  */
+extern void new_tty_postfork (void);
+
+/* Create a new session if the inferior will run in a different tty.
+   A session is UNIX's way of grouping processes that share a controlling
+   terminal, so a new one is needed if the inferior terminal will be
+   different from GDB's.
+
+   Returns the session id of the new session, 0 if no session was created
+   or -1 if an error occurred.
+
+   This function is implemented as a placeholder on GDBserver.  */
+extern pid_t create_tty_session (void);
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid (void);
+
+#endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/common/common.m4 b/gdb/common/common.m4
index e21e6e5..45726ab 100644
--- a/gdb/common/common.m4
+++ b/gdb/common/common.m4
@@ -28,7 +28,8 @@ AC_DEFUN([GDB_AC_COMMON], [
   AC_CHECK_HEADERS(linux/perf_event.h locale.h memory.h signal.h dnl
 		   sys/resource.h sys/socket.h sys/syscall.h dnl
 		   sys/un.h sys/wait.h dnl
-		   thread_db.h wait.h)
+		   thread_db.h wait.h dnl
+		   termios.h termio.h sgtty.h)
 
   AC_CHECK_FUNCS([fdwalk getrlimit pipe pipe2 socketpair sigaction])
 
diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
new file mode 100644
index 0000000..fb06209
--- /dev/null
+++ b/gdb/gdbserver/terminal.c
@@ -0,0 +1,69 @@
+/* Terminal interface definitions for the GDB remote server.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "common-terminal.h"
+
+/* Placeholders needed by fork_inferior.  For now, these functions are
+   not needed nor useful to have on gdbserver.  When/If we properly
+   handle terminal modes, we can revisit and implement the needed
+   support.  */
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty (void)
+{
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_prefork (const char *ttyname)
+{
+}
+
+/* See common/common-terminal.h.  */
+
+void
+new_tty_postfork (void)
+{
+}
+
+/* See common/common-terminal.h.  */
+
+pid_t
+create_tty_session (void)
+{
+  return (pid_t) 0;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+set_inferior_io_terminal (const char *terminal_name)
+{
+}
+
+/* See common/common-inferior.h.  */
+
+const char *
+get_inferior_io_terminal (void)
+{
+  return NULL;
+}
diff --git a/gdb/terminal.h b/gdb/terminal.h
index d8691b2..438eb40 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,83 +19,16 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
+#include "common-terminal.h"
 
 struct inferior;
 
-extern void new_tty_prefork (const char *);
-
-extern void new_tty (void);
-
-extern void new_tty_postfork (void);
-
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
 /* Do we have job control?  Can be assumed to always be the same within
    a given run of GDB.  In inflow.c.  */
 extern int job_control;
 
-extern pid_t create_tty_session (void);
-
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
@@ -105,8 +38,4 @@ extern void gdb_save_tty_state (void);
    have had a chance to alter it.  */
 extern void set_initial_gdb_ttystate (void);
 
-/* Set the process group of the caller to its own pid, or do nothing
-   if we lack job control.  */
-extern int gdb_setpgid (void);
-
 #endif /* !defined (TERMINAL_H) */
diff --git a/gdb/utils.c b/gdb/utils.c
index 27021a1..fdb983a 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -53,6 +53,7 @@
 #include "top.h"
 #include "main.h"
 #include "solist.h"
+#include "terminal.h"
 
 #include "inferior.h"		/* for signed_pointer_to_address */
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver
  2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-03-08 15:49         ` Eli Zaretskii
  2017-03-13 17:26         ` Pedro Alves
  1 sibling, 0 replies; 157+ messages in thread
From: Eli Zaretskii @ 2017-03-08 15:49 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves, lgustavo

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>, Luis Machado <lgustavo@codesourcery.com>,        Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Wed,  8 Mar 2017 00:29:31 -0500
> 
> 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.

The NEWS part is OK.

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver
  2017-03-07 20:59         ` Sergio Durigan Junior
@ 2017-03-13 15:12           ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-03-13 15:12 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Luis Machado

On 03/07/2017 08:59 PM, Sergio Durigan Junior wrote:

>> Note, you'll need NEWS entries for the new remote protocol packets too.
> 
> I've added a NEWS entry for QStartupWithShell under the "New remote
> packets" section.  Do you want me to add another entry somewhere else?
> 

Not offhand.  I'll take a look at v4.

>> Can you explain the rationale for doing this here?  What about:
>>
>>  (gdb) target extended-remote ....
>>  (gdb) set startup-with-shell off
>>  (gdb) run
>>
>> ?
> 
> Hm, I guess it just seemed like a good place to initialize the packet.
> But you're right, this won't work if the user sets the
> startup-with-shell parameter *after* connecting to the target.  So I'll
> move this code to the extended_remote_create_inferior function, if
> that's alright.

Yes, that sounds like the right place.  This is quite similar to
disabling address space randomization, and we do that in
extended_remote_create_inferior too.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v3 5/6] Share fork_inferior et al with gdbserver
  2017-03-07 19:51         ` Sergio Durigan Junior
@ 2017-03-13 15:34           ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-03-13 15:34 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Luis Machado

On 03/07/2017 07:51 PM, Sergio Durigan Junior wrote:
> On Wednesday, February 15 2017, Pedro Alves wrote:
> 

>>> +int
>>> +fork_inferior (char *exec_file_arg, char *allargs, char **env,
>>> +	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
>>> +	       void (*pre_trace_fun) (void), char *shell_file_arg,
>>> +	       void (*exec_fun)(const char *file, char * const *argv,
>>> +				char * const *env))
>>> +{
>>
>>> +  /* Retain a copy of our environment variables, since the child will
>>> +     replace the value of environ and if we're vforked, we have to
>>> +     restore it.  */
>>> +  save_our_env = environ;
>>> +
>>> +  /* Likewise the current UI.  */
>>> +  save_ui = current_ui;
>>
>> Hmm, making this compile on gdbserver is of course a hack,
>> since there's not such thing as a "UI" concept on gdbserver...
>>
>>> +
>>> +  /* Tell the terminal handling subsystem what tty we plan to run on;
>>> +     it will just record the information for later.  */
>>> +  new_tty_prefork (inferior_io_terminal);
>>
>> I wonder about calling here instead a more generalized hook, and
>> moving the save_ui saving and the new_tty_prefork calls to
>> that hook's gdb implementation.  Might be easier to do that after
>> the series is in...
> 
> Right, it is a hack indeed, and not a beautiful one.
> 
> I implemented a bunch of new functions that solve this problem.  Two of
> them, tty_{pre,post}fork_hook, are responsible for saving/restoring the
> current 'struct ui' and also for calling the new_tty_{pre,post}fork
> functions (which are now static).  One more function was needed:
> switch_ui_postfork, which is responsible for switching the current_ui to
> main_ui, as is done currently after we successfully fork.  These 3
> functions are implemented only on GDB; they're stubs on gdbserver.

Thanks.  Sounds better, though the "ui" in switch_ui_postfork makes me
wonder whether it's generalized enough, but I'll leave further
comments (if any) for v4, which I haven't read yet.

>>> --- a/gdb/gdbserver/inferiors.c
>>> +++ b/gdb/gdbserver/inferiors.c
>>> @@ -29,6 +29,8 @@ struct thread_info *current_thread;
>>>  
>>>  #define get_thread(inf) ((struct thread_info *)(inf))
>>>  
>>> +ptid_t inferior_ptid;
>>
>> What do we need this for?  gdbserver already has
>> a "current thread" global.  Another one looks like asking
>> for out-of-sync trouble.
> 
> This is needed because fork_inferior et al reference this variable
> directly, and so I moved the 'extern' declaration of it to commom/.
> 
> A possible solution to this would be to create a get/set pair of
> functions for it, but I'm not sure this would be a good idea due to (a)
> the number of direct references to it, and (b) the fact that these
> functions would probably end up being stubs on gdbserver as well.

Or we can re-evaluate why do fork_inferior et al  need to reference
the variable directly.

>>> -/* Add a process to the common process list, and set its private
>>> -   data.  */
>>> +/* Update process represented by PID with necessary info.  */
>>>  
>>>  static struct process_info *
>>> -linux_add_process (int pid, int attached)
>>> +linux_update_process (int pid)
>>
>> I'm not sure I understand the need for this yet.  I need
>> to look deeper.  "update what?  why?"  Or maybe the
>> comments should be improved.  :-)
> 
> The reason these 'update' functions were created is because
> fork_inferior already creates the process/thread structures, but we (the
> caller) still need to fill in some of the fields of these structures
> with more information.  They are the same functions that existed before,
> but now we work with an existing process/thread, while before we
> *created* these structures.

I think that that's only somewhat clear because you're looking at
a diff.  ISTM that someone looking at the resulting code with
no other context has no clue what's being updated, and/or why.  All one
has to go by is "update".  But, what kind of information is being
updated?  I guess what I'm saying is that "Update process" is so vague
that it's borderline meaningless.


>>> @@ -2870,62 +2893,91 @@ handle_v_run (char *own_buf)
>>>        new_argc++;
>>>      }
>>>  
>>> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
>>> -  if (new_argv == NULL)
>>> -    {
>>> -      write_enn (own_buf);
>>> -      return 0;
>>> -    }
>>> -
>>> -  i = 0;
>>> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
>>> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>>>      {
>>>        next_p = strchr (p, ';');
>>>        if (next_p == NULL)
>>>  	next_p = p + strlen (p);
>>>  
>>> -      if (i == 0 && p == next_p)
>>> -	new_argv[i] = NULL;
>>> +      if (p == next_p)
>>> +	new_argv.push_back ("''");
>>>        else
>>>  	{
>>>  	  /* FIXME: Fail request if out of memory instead of dying.  */
>>> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
>>> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
>>> -	  new_argv[i][(next_p - p) / 2] = '\0';
>>> +	  size_t len = 1 + (next_p - p) / 2;
>>> +	  char *s = (char *) xmalloc (len);
>>> +	  char *ss = (char *) xmalloc (len * 2);
>>> +	  char *tmp_s, *tmp_ss;
>>> +	  int need_quote;
>>> +
>>> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
>>> +	  s[(next_p - p) / 2] = '\0';
>>> +
>>> +	  tmp_s = s;
>>> +	  tmp_ss = ss;
>>> +	  need_quote = 0;
>>> +	  while (*tmp_s != '\0')
>>> +	    {
>>> +	      switch (*tmp_s)
>>> +		{
>>> +		case '\n':
>>> +		  *tmp_ss = '\'';
>>> +		  ++tmp_ss;
>>> +		  need_quote = 1;
>>> +		  break;
>>> +
>>> +		case '\'':
>>> +		  *tmp_ss = '\\';
>>> +		  ++tmp_ss;
>>> +		  break;
>>> +
>>> +		default:
>>> +		  break;
>>> +		}
>>> +
>>> +	      *tmp_ss = *tmp_s;
>>> +	      ++tmp_ss;
>>> +	      ++tmp_s;
>>> +	    }
>>> +
>>> +	  if (need_quote)
>>> +	    *tmp_ss++ = '\'';
>>
>> Hmm, is this quoting stuff being moved from somewhere,
>> or it is new?
> 
> This is new, even though GDB has a lot of places that do the same
> thing...

OK, but then what is the code doing?  Can we at least add some
comment?

> 
>>> +
>>> +	  *tmp_ss = '\0';
>>> +	  new_argv.push_back (ss);
>>> +	  xfree (s);
>>>  	}
>>>  
>>>        if (*next_p)
>>>  	next_p++;
>>> -      i++;
>>>      }
>>> -  new_argv[i] = NULL;
>>
>>>  
>>> +  /* Gather information about the environment.  */
>>> +  our_environ = make_environ ();
>>> +  init_environ (our_environ);
>>> +
>>>    initialize_async_io ();
>>>    initialize_low ();


>>> @@ -39,8 +39,14 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
>>>  set msg "gdbserver exits cleanly"
>>>  set saw_exiting 0
>>>  expect {
>>> -    # This is what we get on ptrace-based targets.
>>> -    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
>>> +    # This is what we get on ptrace-based targets with
>>> +    # startup-with-shell disabled.
>>> + -re "stdin/stdout redirected.*gdbserver: Cannot exec
>>> non-existing-program\r\ngdbserver: Error: No such file or
>>> directory\r\n\r\nDuring startup program exited with code
>>> 127\.\r\nExiting\r\n$" {
>>> +	set saw_exiting 1
>>> +	exp_continue
>>
>> Shouldn't this be a part of the next patch?
> 
> Not really.  I put this here because without it a regreession is
> introduced, and I wanted each patch to be regression-free.

I'm confused then.  The comment above says:

 "This is what we get on ptrace-based targets with startup-with-shell disabled"

But the patch's intro said:

 "I decided to go ahead and implement a partial support for starting the
 inferior with a shell on gdbserver, although the full feature comes in
 the next patch.  The user won't have the option to disable the
 startup-with-shell, and also won't be able to change which shell
 gdbserver will use (other than setting the $SHELL environment
 variable, that is)."

So which one is right?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v4 4/5] Share fork_inferior et al with gdbserver
  2017-03-08  5:29       ` [PATCH v4 4/5] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-03-13 17:04         ` Pedro Alves
  2017-03-17  1:02           ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-03-13 17:04 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

Hi Sergio,

[I think at least some of my comments I sent earlier
today on v3 still apply, so I won't repeat them.]

On 03/08/2017 05:29 AM, Sergio Durigan Junior wrote:

> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index c9d03a8..74d5269 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -29,6 +29,10 @@ struct thread_info *current_thread;
>  
>  #define get_thread(inf) ((struct thread_info *)(inf))
>  
> +/* Even though we do not use/need INFERIOR_PTID here, we still have to
> +   declare it because fork_inferior uses it directly.  */
> +ptid_t inferior_ptid;
> +

This is the bit that I hope we can get rid of.  Can we try
poking at it a bit more?

>  void
>  add_inferior_to_list (struct inferior_list *list,
>  		      struct inferior_list_entry *new_inferior)
> @@ -469,6 +473,25 @@ make_cleanup_restore_current_thread (void)
>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>  }
>  
> +/* See common/common-inferior.h.  */
> +
> +void
> +inferior_appeared (struct inferior *inf, int pid)
> +{
> +  /* Placeholder needed for fork_inferior.  We do not have to do
> +     anything in this case.  */
> +}
> +
> +/* See common/common-inferior.h.  */
> +
> +struct inferior *
> +current_inferior (void)
> +{
> +  /* Placeholder needed for fork_inferior.  GDBserver has other
> +     functions that serve this purpose.  */
> +  return NULL;
> +}
> +

And these, which I think are related.


>  /* See common/common-gdbthread.h.  */
>  
>  void
> @@ -499,3 +522,11 @@ add_thread_silent (ptid_t ptid)
>  
>    return add_thread (ptid_build (pid, pid, 0), NULL);
>  }
> +
> +/* See common/common-inferior.h.  */
> +
> +int
> +have_inferiors (void)
> +{
> +  return get_first_process () != NULL;
> +}

> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
> index 6229b4c..8cee363 100644
> --- a/gdb/gdbserver/nto-low.c
> +++ b/gdb/gdbserver/nto-low.c
> @@ -347,14 +347,15 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
>    return len_read;
>  }
>  
> -/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
> +/* Start inferior specified by PROGRAM_ARGV.  */
>  
>  static int
> -nto_create_inferior (char *program, char **allargs)
> +nto_create_inferior (char *program, const std::vector<char *> &program_argv)

The change to the comment no longer reflects the code change.
Spotted a few other places with the same.  It'll be worth it
to go over the whole patch and make sure those are kept consistent.
But see further below before embarking in that.


>  {
>    struct inheritance inherit;
>    pid_t pid;
>    sigset_t set;
> +  std::string program_args = stringify_argv (program_argv);
>  
>    TRACE ("%s %s\n", __func__, program);
>    /* Clear any pending SIGUSR1's but keep the behavior the same.  */
> @@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
>    memset (&inherit, 0, sizeof (inherit));
>    inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
>    inherit.pgroup = SPAWN_NEWPGROUP;
> -  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
> +  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
>    sigprocmask (SIG_BLOCK, &set, NULL);
>  
>    if (pid == -1)
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c

> @@ -2862,62 +2873,93 @@ handle_v_run (char *own_buf)
>        new_argc++;
>      }
>  
> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
> -  if (new_argv == NULL)
> -    {
> -      write_enn (own_buf);
> -      return 0;
> -    }
> -
> -  i = 0;
> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>      {
>        next_p = strchr (p, ';');
>        if (next_p == NULL)
>  	next_p = p + strlen (p);
>  
> -      if (i == 0 && p == next_p)
> -	new_argv[i] = NULL;
> +      if (p == next_p)
> +	new_argv.push_back ("''");
>        else
>  	{
>  	  /* FIXME: Fail request if out of memory instead of dying.  */
> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
> -	  new_argv[i][(next_p - p) / 2] = '\0';
> +	  size_t len = 1 + (next_p - p) / 2;
> +	  char *s = (char *) xmalloc (len);
> +	  char *ss = (char *) xmalloc (len * 2);
> +	  char *tmp_s, *tmp_ss;
> +	  int need_quote;
> +
> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
> +	  s[(next_p - p) / 2] = '\0';
> +
> +	  tmp_s = s;
> +	  tmp_ss = ss;
> +	  need_quote = 0;
> +	  while (*tmp_s != '\0')
> +	    {
> +	      switch (*tmp_s)
> +		{
> +		case '\n':
> +		  *tmp_ss = '\'';
> +		  ++tmp_ss;
> +		  need_quote = 1;
> +		  break;
> +
> +		case '\'':
> +		  *tmp_ss = '\\';
> +		  ++tmp_ss;
> +		  break;
> +
> +		default:
> +		  break;
> +		}
> +
> +	      *tmp_ss = *tmp_s;
> +	      ++tmp_ss;
> +	      ++tmp_s;
> +	    }
> +
> +	  if (need_quote)
> +	    *tmp_ss++ = '\'';
> +
> +	  *tmp_ss = '\0';
> +	  new_argv.push_back (ss);
> +	  xfree (s);
>  	}
>  
>        if (*next_p)
>  	next_p++;
> -      i++;
>      }
> -  new_argv[i] = NULL;
>  
> -  if (new_argv[0] == NULL)
> +  if (new_argv.empty () || new_argv[0] == NULL)
>      {
>        /* GDB didn't specify a program to run.  Use the program from the
>  	 last run with the new argument list.  */
>  
> -      if (program_argv == NULL)
> +      if (program_argv.empty ())
>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>  
> -      new_argv[0] = strdup (program_argv[0]);
> -      if (new_argv[0] == NULL)
> +      new_argv.push_back (strdup (program_argv[0]));
> +      if (new_argv.empty () || new_argv[0] == NULL)

On the "empty()" check: you've just pushed an element to the vector,
so the vector can't be empty.

On the "== NULL" check: IIUC, the old NULL check was there to
handle strdup returning NULL due to out-of-memory.
See NULL checks and comments further above in this function.
Now that you're using a std::vector, that doesn't work or make
sense any longer, since if push_back fails to allocate space for
its internal buffer (with operator new), our operator new replacement
(common/new-op.c) calls malloc_failure, which aborts gdbserver.

Not sure it makes sense to handle out-of-memory specially in
the gdb/rsp-facing functions nowadays (maybe git blame/log/patch
submission for that code shows some guidelines).  Maybe (or, probably)
it's OK to stop caring about it, but then we should consistently remove
left over code, by using xstrdup instead and remove the NULL checks.

>  	{
>  	  write_enn (own_buf);
> -	  freeargv (new_argv);
> +	  free_vector_argv (new_argv);
>  	  return 0;
>  	}
>      }
>  
>    /* Free the old argv and install the new one.  */
> -  freeargv (program_argv);
> +  free_vector_argv (program_argv);
>    program_argv = new_argv;
>  
> -  start_inferior (program_argv);
> +  create_inferior (program_argv[0],
> +		   std::vector<char *> (program_argv.begin () + 1,
> +					program_argv.end ()));

This creates a copy of the vector.  How about keeping program_argv[0]
as a separate variable to avoid this copy?  I suspect it'd simplify
some other things in the function.

>    if (last_status.kind == TARGET_WAITKIND_STOPPED)
>      {
>        prepare_resume_reply (own_buf, last_ptid, &last_status);
> @@ -3535,13 +3577,18 @@ captured_main (int argc, char *argv[])
>  	multi_mode = 1;
>        else if (strcmp (*next_arg, "--wrapper") == 0)
>  	{
> +	  char **tmp;
> +
>  	  next_arg++;
>  
> -	  wrapper_argv = next_arg;
> +	  tmp = next_arg;
>  	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
> -	    next_arg++;
> +	    {
> +	      wrapper_argv.push_back (*next_arg);
> +	      next_arg++;
> +	    }
>  
> -	  if (next_arg == wrapper_argv || *next_arg == NULL)
> +	  if (next_arg == tmp || *next_arg == NULL)
>  	    {
>  	      gdbserver_usage (stderr);
>  	      exit (1);
> @@ -3672,8 +3719,13 @@ captured_main (int argc, char *argv[])
>        exit (1);
>      }
>  
> +  /* Gather information about the environment.  */
> +  our_environ = make_environ ();
> +  init_environ (our_environ);
> +
>    initialize_async_io ();
>    initialize_low ();
> +  have_job_control ();
>    initialize_event_loop ();
>    if (target_supports_tracepoints ())
>      initialize_tracepoint ();
> @@ -3687,13 +3739,13 @@ captured_main (int argc, char *argv[])
>        int i, n;
>  
>        n = argc - (next_arg - argv);
> -      program_argv = XNEWVEC (char *, n + 1);
>        for (i = 0; i < n; i++)
> -	program_argv[i] = xstrdup (next_arg[i]);
> -      program_argv[i] = NULL;
> +	program_argv.push_back (xstrdup (next_arg[i]));
>  
>        /* Wait till we are at first instruction in program.  */
> -      start_inferior (program_argv);
> +      create_inferior (program_argv[0],
> +		       std::vector<char *> (program_argv.begin () + 1,
> +					    program_argv.end ()));

Ditto.

>  
>        /* We are now (hopefully) stopped at the first instruction of
>  	 the target process.  This assumes that the target process was
> @@ -4308,9 +4360,11 @@ process_serial_event (void)
>  	  fprintf (stderr, "GDBserver restarting\n");
>  
>  	  /* Wait till we are at 1st instruction in prog.  */
> -	  if (program_argv != NULL)
> +	  if (!program_argv.empty ())
>  	    {
> -	      start_inferior (program_argv);
> +	      create_inferior (program_argv[0],
> +			       std::vector<char *> (program_argv.begin () + 1,
> +						    program_argv.end ()));
>  	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>  		{
>  		  /* Stopped at the first instruction of the target
> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index d5fee38..5b65597 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  #include "utils.h"
>  #include "debug.h"
>  #include "gdb_vecs.h"
> +#include <vector>
>  
>  /* Maximum number of bytes to read/write at once.  The value here
>     is chosen to fill up a packet (the headers account for the 32).  */
> @@ -148,4 +149,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  /* Definition for any syscall, used for unfiltered syscall reporting.  */
>  #define ANY_SYSCALL (-2)
>  
> +/* Any pre-processing needed to be done before calling fork_inferior
> +   shall be implemented here.  ARGV is a vector containing the full
> +   argv of the inferior.  */
> +extern void pre_fork_inferior (const std::vector<char *> &argv);
> +
> +/* After fork_inferior has been called, we need to adjust a few
> +   signals and call startup_inferior.  This is done here.  PID is the
> +   pid of the new inferior, and ARGV is the vector containing the full
> +   argv of the inferior.  */
> +extern void post_fork_inferior (int pid, char *program,
> +				const std::vector<char *> &argv);

The "full argv" would include the program name, but ARGV is no
longer including it, right?  Or am I confused?

> +
> +/* Get the 'struct gdb_environ *' being used in the current
> +   session.  */
> +extern struct gdb_environ *get_environ (void);
> +
>  #endif /* SERVER_H */
> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
> index 117b871..49cfd65 100644
> --- a/gdb/gdbserver/spu-low.c
> +++ b/gdb/gdbserver/spu-low.c
> @@ -27,6 +27,7 @@
>  #include <sys/syscall.h>
>  #include "filestuff.h"
>  #include "hostio.h"
> +#include "common-inferior.h"
>  
>  /* Some older glibc versions do not define this.  */
>  #ifndef __WNOTHREAD
> @@ -261,42 +262,41 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
>    return ret;
>  }
>  
> +/* Callback to be used when calling fork_inferior, responsible for
> +   actually initiating the tracing of the inferior.  */
> +
> +static void
> +spu_ptrace_fun (void)
> +{
> +  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
> +    trace_start_error_with_name ("ptrace");
> +  if (setpgid (0, 0) < 0)
> +    trace_start_error_with_name ("setpgid");
> +}
>  
>  /* Start an inferior process and returns its pid.
> -   ALLARGS is a vector of program-name and args. */
> +   PROGRAM_ARGV is a vector of program-name and args. */

Stale?

>  static int
> -spu_create_inferior (char *program, char **allargs)
> +spu_create_inferior (char *program, const std::vector<char *> &program_argv)
>  {
>    int pid;
>    ptid_t ptid;
>    struct process_info *proc;
> +  std::string program_args = stringify_argv (program_argv);
>  
> -  pid = fork ();
> -  if (pid < 0)
> -    perror_with_name ("fork");
> -
> -  if (pid == 0)
> -    {
> -      close_most_fds ();
> -      ptrace (PTRACE_TRACEME, 0, 0, 0);
> -
> -      setpgid (0, 0);
> +  pre_fork_inferior (program_argv);
>  
> -      execv (program, allargs);
> -      if (errno == ENOENT)
> -	execvp (program, allargs);
> +  pid = fork_inferior (program,
> +		       program_args.c_str (),
> +		       environ_vector (get_environ ()), spu_ptrace_fun,
> +		       NULL, NULL, NULL, NULL);
>  
> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
> -	       strerror (errno));
> -      fflush (stderr);
> -      _exit (0177);
> -    }
> +  post_fork_inferior (pid, program, program_argv);
>  
> -  proc = add_process (pid, 0);
> +  proc = find_process_pid (pid);
> +  gdb_assert (proc != NULL);
>    proc->tdesc = tdesc_spu;
>  
> -  ptid = ptid_build (pid, pid, 0);
> -  add_thread (ptid, NULL);
>    return pid;
>  }
>  
> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
> index fda72e8..1e1d193 100644
> --- a/gdb/gdbserver/target.c
> +++ b/gdb/gdbserver/target.c
> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>    return size;
>  }
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_init (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_inferior (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_ours (void)
> +{
> +  /* To be implemented.  */
> +}
> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
> index 3cc2bc4..e47ed78 100644
> --- a/gdb/gdbserver/target.h
> +++ b/gdb/gdbserver/target.h
> @@ -28,6 +28,7 @@
>  #include "target/waitstatus.h"
>  #include "mem-break.h"
>  #include "btrace-common.h"
> +#include <vector>
>  
>  struct emit_ops;
>  struct buffer;
> @@ -73,7 +74,8 @@ struct target_ops
>       Returns the new PID on success, -1 on failure.  Registers the new
>       process with the process list.  */
>  
> -  int (*create_inferior) (char *program, char **args);
> +  int (*create_inferior) (char *program,
> +			  const std::vector<char *> &program_argv);
>  
>    /* Do additional setup after a new process is created, including
>       exec-wrapper completion.  */
> @@ -480,8 +482,8 @@ extern struct target_ops *the_target;
>  
>  void set_target_ops (struct target_ops *);
>  
> -#define create_inferior(program, args) \
> -  (*the_target->create_inferior) (program, args)
> +#define create_inferior(program, program_argv)	\
> +  (*the_target->create_inferior) (program, program_argv)
>  
>  #define target_post_create_inferior()			 \
>    do							 \
> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
> index fb06209..ee361d1 100644
> --- a/gdb/gdbserver/terminal.c
> +++ b/gdb/gdbserver/terminal.c
> @@ -18,6 +18,7 @@
>  
>  #include "server.h"
>  #include "common-terminal.h"
> +#include "common-top.h"
>  
>  /* Placeholders needed by fork_inferior.  For now, these functions are
>     not needed nor useful to have on gdbserver.  When/If we properly
> @@ -34,14 +35,14 @@ new_tty (void)
>  /* See common/common-terminal.h.  */
>  
>  void
> -new_tty_prefork (const char *ttyname)
> +tty_prefork_hook (void)
>  {
>  }
>  
>  /* See common/common-terminal.h.  */
>  
>  void
> -new_tty_postfork (void)
> +tty_postfork_hook (void)
>  {
>  }
>  
> @@ -67,3 +68,10 @@ get_inferior_io_terminal (void)
>  {
>    return NULL;
>  }
> +
> +/* See common/common-top.h.  */
> +
> +void
> +switch_ui_postfork (void)
> +{
> +}
> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
> index 307d15a..70e8b18 100644
> --- a/gdb/gdbserver/utils.c
> +++ b/gdb/gdbserver/utils.c
> @@ -137,3 +137,39 @@ pfildes (gdb_fildes_t fd)
>    return plongest (fd);
>  #endif
>  }
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +gdb_flush_out_err (void)
> +{
> +  fflush (stdout);
> +  fflush (stderr);
> +}
> +
> +/* See common/common-utils.h.  */
> +
> +void
> +free_vector_argv (std::vector<char *> &v)
> +{
> +  for (char *&i : v)

Iterating over pointers, no need for reference indirection,
copy is fine:

  for (char *el: v)
    xfree (el);

> +    xfree (i);
> +
> +  v.clear ();
> +}
> +
> +/* See common/common-utils.h.  */
> +
> +std::string
> +stringify_argv (const std::vector<char *> &argv)
> +{
> +  std::string ret;
> +
> +  for (auto s : argv)
> +    ret += s + std::string (" ");
> +
> +  /* Erase the last whitespace.  */
> +  ret.erase (ret.end () - 1);

Are we always sure ARGV wasn't empty here?

> +
> +  return ret;
> +}
> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
> index b4ded31..172a2ec 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/gdbserver/utils.h
> @@ -19,7 +19,18 @@
>  #ifndef UTILS_H
>  #define UTILS_H
>  
> +#include <vector>
> +
>  char *paddress (CORE_ADDR addr);
>  char *pfildes (gdb_fildes_t fd);
>  
> +/* Assumes that V is an argv for a program, and iterates through
> +   freeing all the elements.  */
> +extern void free_vector_argv (std::vector<char *> &v);
> +
> +/* Given a vector of arguments ARGV, return a string equivalent to
> +   joining all the arguments (starting from ARGV + 1) with a
> +   whitespace separating them.  */

Stale?

> +extern std::string stringify_argv (const std::vector<char *> &argv);
> +
>  #endif /* UTILS_H */
> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
> index d3ddbf5..b86ae2b 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>  }
>  
>  /* Start a new process.
> -   PROGRAM is a path to the program to execute.
> -   ARGS is a standard NULL-terminated array of arguments,
> -   to be passed to the inferior as ``argv''.
> +   PROGRAM_ARGV is the vector containing the inferior's argv.

Stale?  I also wonder about the variable renamings that were preserved
(throughout) in the patch.  Maybe calling the vector of arguments
some other than "argv", like in the preexisting "args" would result in
clearer code for avoiding a confusion with "argv" generaly understood
as including the argv[0]==program name.


>     Returns the new PID on success, -1 on failure.  Registers the new
>     process with the process list.  */
>  static int
> -win32_create_inferior (char *program, char **program_args)
> +win32_create_inferior (char *program, const std::vector<char *> &program_argv)
>  {
>  #ifndef USE_WIN32API
>    char real_path[PATH_MAX];
> @@ -627,6 +625,8 @@ win32_create_inferior (char *program, char **program_args)
>    int argc;
>    PROCESS_INFORMATION pi;
>    DWORD err;
> +  std::string program_args = stringify_argv (program_argv);
> +  char *args = (char *) program_args.c_str ();

Why do we need the cast?

>  
>    /* win32_wait needs to know we're not attaching.  */
>    attaching = 0;
> @@ -652,18 +652,6 @@ win32_create_inferior (char *program, char **program_args)
>    program = real_path;
>  #endif
>  
> -  argslen = 1;
> -  for (argc = 1; program_args[argc]; argc++)
> -    argslen += strlen (program_args[argc]) + 1;
> -  args = (char *) alloca (argslen);
> -  args[0] = '\0';
> -  for (argc = 1; program_args[argc]; argc++)
> -    {
> -      /* FIXME: Can we do better about quoting?  How does Cygwin
> -	 handle this?  */
> -      strcat (args, " ");
> -      strcat (args, program_args[argc]);
> -    }
>    OUTMSG2 (("Command line is \"%s\"\n", args));
>  
>  #ifdef CREATE_NEW_PROCESS_GROUP
> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index 7efb3c1..21445f5 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -2136,6 +2136,7 @@ gnu_create_inferior (struct target_ops *ops,
>  {
>    struct inf *inf = cur_inf ();
>    int pid;
> +  ptid_t ptid;
>  
>    inf_debug (inf, "creating inferior");
>  
> @@ -2161,7 +2162,10 @@ gnu_create_inferior (struct target_ops *ops,
>    thread_change_ptid (inferior_ptid,
>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>  
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
> +  /* Mark all threads non-executing.  */
> +  set_executing (ptid, 0);
> +
>    inf->pending_execs = 0;
>    /* Get rid of the old shell threads.  */
>    prune_threads ();
> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
> index 21578742..e3ddaa8 100644
> --- a/gdb/inf-ptrace.c
> +++ b/gdb/inf-ptrace.c
> @@ -94,7 +94,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>  			    int from_tty)
>  {
>    int pid;
> -
> +  ptid_t ptid;
>    /* Do not change either targets above or the same target if already present.
>       The reason is the target stack is shared across multiple inferiors.  */
>    int ops_already_pushed = target_is_pushed (ops);
> @@ -112,7 +112,10 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>  
>    discard_cleanups (back_to);
>  
> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
> +  ptid = startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
> +
> +  /* Mark all threads non-executing.  */
> +  set_executing (ptid, 0);

Since all callers on the gdb side need to do this, wouldn't it
be better to add a gdb_startup_inferior function that calls
the common startup_inferior and calls set_executing ?
(or call the common one something else)

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver
  2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  2017-03-08 15:49         ` Eli Zaretskii
@ 2017-03-13 17:26         ` Pedro Alves
  1 sibling, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-03-13 17:26 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches; +Cc: Luis Machado

On 03/08/2017 05:29 AM, Sergio Durigan Junior wrote:
> 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:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* NEWS (Changes since GDB 7.12): 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:
> yyyy-mm-dd  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:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* gdb.server/startup-with-shell.c: New file.
> 	* gdb.server/startup-with-shell.exp: Likewise.
> 
> gdb/doc/ChangeLog:
> yyyy-mm-dd  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/NEWS                                        | 12 ++++
>  gdb/doc/gdb.texinfo                             | 31 +++++++++
>  gdb/gdbserver/server.c                          | 38 ++++++++++-
>  gdb/remote.c                                    | 20 ++++++
>  gdb/testsuite/gdb.server/startup-with-shell.c   | 29 ++++++++
>  gdb/testsuite/gdb.server/startup-with-shell.exp | 90 +++++++++++++++++++++++++
>  6 files changed, 219 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.c
>  create mode 100644 gdb/testsuite/gdb.server/startup-with-shell.exp
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index cf58595..7c235f7 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,15 @@
>  
>  *** Changes since GDB 7.12
>  
> +* 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.
> +
>  * GDB now supports access to the PKU register on GNU/Linux. The register is
>    added by the Memory Protection Keys for Userspace feature which will be
>    available in future Intel CPUs.
> @@ -393,6 +402,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.
>  
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index ba56ab2..b6bc7c7 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -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}
> @@ -36420,6 +36425,32 @@ 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


It seems like the usual "This packet is not probed by default" text
is missing, along with a "Use of this packet is controlled by the"
blurb mentioning the packet control command (search for those sentences 
in the manual).

> +
>  @item qfThreadInfo
>  @itemx qsThreadInfo
>  @cindex list active threads, remote request
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 1677926..8411aad 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -847,6 +847,31 @@ handle_general_set (char *own_buf)
>        return;
>      }
>  
> +  if (startswith (own_buf, "QStartupWithShell:"))
> +    {
> +      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;
> @@ -2283,7 +2308,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 ())
> @@ -3379,6 +3404,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"
> @@ -3662,6 +3694,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
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 2f34c4c..cb6e194 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -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)
> @@ -14112,6 +14129,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);
>  
> diff --git a/gdb/testsuite/gdb.server/startup-with-shell.c b/gdb/testsuite/gdb.server/startup-with-shell.c
> new file mode 100644
> index 0000000..6278447
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.c
> @@ -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.server/startup-with-shell.exp b/gdb/testsuite/gdb.server/startup-with-shell.exp
> new file mode 100644
> index 0000000..81be68b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.server/startup-with-shell.exp
> @@ -0,0 +1,90 @@
> +# 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/>.
> +
> +# Test startup-with-shell support using extended-remote.
> +
> +load_lib gdbserver-support.exp
> +
> +standard_testfile
> +
> +if { [skip_gdbserver_tests] } {
> +    untested "skipping gdbserver tests"
> +    return 0
> +}
> +
> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
> +    return -1
> +}
> +
> +set unique_file [standard_output_file "unique-file.unique-extension"]
> +remote_exec build "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
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +
> +    gdb_test_no_output "set startup-with-shell $startup_with_shell"
> +
> +    set target_exec [gdbserver_download_current_prog]
> +    gdbserver_start_extended
> +    gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
> +    gdb_test "remote put $unique_file [file tail $unique_file]"

Why do we need this "put"?  Because CWD is set to gdbserver's directly?
Does this mean that this "put" is putting the file in gdbserver's directory?

> +
> +    gdb_breakpoint main
> +
> +    gdb_test "run $run_args" \
> +	"Breakpoint ${decimal}, main \\(argc=${decimal}, argv=${hex}\\).*" \
> +	"run to main"
> +}
> +
> +## Run the actual tests
> +
> +with_test_prefix "startup_with_shell = on; run_args = *.unique-extension" {
> +    initial_setup_simple "on" "*.unique-extension"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"unique-file\.unique-extension\"" \
> +	"first argument expanded"
> +}
> +
> +with_test_prefix "startup_with_shell = off; run_args = *.unique-extension" {
> +    initial_setup_simple "off" "*.unique-extension"
> +    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.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)
> +}
> +
> +remote_exec build "rm -f $unique_file"

It's better to leave the file in place to help with debugging
testsuite failures.

I'm wondering if the test really needs to be specifically coded for
gdbserver.  If we use the normal run_tomain etc., wouldn't
the test work against native testing as well?  When Eli added support
for shell expansion to the Windows ports a while ago I noticed that there
are no tests for these things for native targets at all.  This new test
would address that nicely.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v4 4/5] Share fork_inferior et al with gdbserver
  2017-03-13 17:04         ` Pedro Alves
@ 2017-03-17  1:02           ` Sergio Durigan Junior
  2017-03-17 10:27             ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-17  1:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches, Luis Machado

On Monday, March 13 2017, Pedro Alves wrote:

> Hi Sergio,
>
> [I think at least some of my comments I sent earlier
> today on v3 still apply, so I won't repeat them.]

Hey Pedro,

You mean I haven't addressed everything you commented?  If that is the
case, I truly apologize.  I'll go over the comments again.

> On 03/08/2017 05:29 AM, Sergio Durigan Junior wrote:
>
>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>> index c9d03a8..74d5269 100644
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -29,6 +29,10 @@ struct thread_info *current_thread;
>>  
>>  #define get_thread(inf) ((struct thread_info *)(inf))
>>  
>> +/* Even though we do not use/need INFERIOR_PTID here, we still have to
>> +   declare it because fork_inferior uses it directly.  */
>> +ptid_t inferior_ptid;
>> +
>
> This is the bit that I hope we can get rid of.  Can we try
> poking at it a bit more?

Sure, I'll see what I can come up with.

>>  void
>>  add_inferior_to_list (struct inferior_list *list,
>>  		      struct inferior_list_entry *new_inferior)
>> @@ -469,6 +473,25 @@ make_cleanup_restore_current_thread (void)
>>    return make_cleanup (do_restore_current_thread_cleanup, current_thread);
>>  }
>>  
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +inferior_appeared (struct inferior *inf, int pid)
>> +{
>> +  /* Placeholder needed for fork_inferior.  We do not have to do
>> +     anything in this case.  */
>> +}
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +struct inferior *
>> +current_inferior (void)
>> +{
>> +  /* Placeholder needed for fork_inferior.  GDBserver has other
>> +     functions that serve this purpose.  */
>> +  return NULL;
>> +}
>> +
>
> And these, which I think are related.

Offhand I don't see how to get rid of these functions (on fork_inferior)
without creating even more stubs on gdbserver, but I'll see.

>>  /* See common/common-gdbthread.h.  */
>>  
>>  void
>> @@ -499,3 +522,11 @@ add_thread_silent (ptid_t ptid)
>>  
>>    return add_thread (ptid_build (pid, pid, 0), NULL);
>>  }
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +int
>> +have_inferiors (void)
>> +{
>> +  return get_first_process () != NULL;
>> +}
>
>> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
>> index 6229b4c..8cee363 100644
>> --- a/gdb/gdbserver/nto-low.c
>> +++ b/gdb/gdbserver/nto-low.c
>> @@ -347,14 +347,15 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
>>    return len_read;
>>  }
>>  
>> -/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
>> +/* Start inferior specified by PROGRAM_ARGV.  */
>>  
>>  static int
>> -nto_create_inferior (char *program, char **allargs)
>> +nto_create_inferior (char *program, const std::vector<char *> &program_argv)
>
> The change to the comment no longer reflects the code change.
> Spotted a few other places with the same.  It'll be worth it
> to go over the whole patch and make sure those are kept consistent.
> But see further below before embarking in that.

OK.

>>  {
>>    struct inheritance inherit;
>>    pid_t pid;
>>    sigset_t set;
>> +  std::string program_args = stringify_argv (program_argv);
>>  
>>    TRACE ("%s %s\n", __func__, program);
>>    /* Clear any pending SIGUSR1's but keep the behavior the same.  */
>> @@ -367,7 +368,7 @@ nto_create_inferior (char *program, char **allargs)
>>    memset (&inherit, 0, sizeof (inherit));
>>    inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
>>    inherit.pgroup = SPAWN_NEWPGROUP;
>> -  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
>> +  pid = spawnp (program, 0, NULL, &inherit, (char *) program_args.c_str (), 0);
>>    sigprocmask (SIG_BLOCK, &set, NULL);
>>  
>>    if (pid == -1)
>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>
>> @@ -2862,62 +2873,93 @@ handle_v_run (char *own_buf)
>>        new_argc++;
>>      }
>>  
>> -  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
>> -  if (new_argv == NULL)
>> -    {
>> -      write_enn (own_buf);
>> -      return 0;
>> -    }
>> -
>> -  i = 0;
>> -  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
>> +  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
>>      {
>>        next_p = strchr (p, ';');
>>        if (next_p == NULL)
>>  	next_p = p + strlen (p);
>>  
>> -      if (i == 0 && p == next_p)
>> -	new_argv[i] = NULL;
>> +      if (p == next_p)
>> +	new_argv.push_back ("''");
>>        else
>>  	{
>>  	  /* FIXME: Fail request if out of memory instead of dying.  */
>> -	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
>> -	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
>> -	  new_argv[i][(next_p - p) / 2] = '\0';
>> +	  size_t len = 1 + (next_p - p) / 2;
>> +	  char *s = (char *) xmalloc (len);
>> +	  char *ss = (char *) xmalloc (len * 2);
>> +	  char *tmp_s, *tmp_ss;
>> +	  int need_quote;
>> +
>> +	  hex2bin (p, (gdb_byte *) s, (next_p - p) / 2);
>> +	  s[(next_p - p) / 2] = '\0';
>> +
>> +	  tmp_s = s;
>> +	  tmp_ss = ss;
>> +	  need_quote = 0;
>> +	  while (*tmp_s != '\0')
>> +	    {
>> +	      switch (*tmp_s)
>> +		{
>> +		case '\n':
>> +		  *tmp_ss = '\'';
>> +		  ++tmp_ss;
>> +		  need_quote = 1;
>> +		  break;
>> +
>> +		case '\'':
>> +		  *tmp_ss = '\\';
>> +		  ++tmp_ss;
>> +		  break;
>> +
>> +		default:
>> +		  break;
>> +		}
>> +
>> +	      *tmp_ss = *tmp_s;
>> +	      ++tmp_ss;
>> +	      ++tmp_s;
>> +	    }
>> +
>> +	  if (need_quote)
>> +	    *tmp_ss++ = '\'';
>> +
>> +	  *tmp_ss = '\0';
>> +	  new_argv.push_back (ss);
>> +	  xfree (s);
>>  	}
>>  
>>        if (*next_p)
>>  	next_p++;
>> -      i++;
>>      }
>> -  new_argv[i] = NULL;
>>  
>> -  if (new_argv[0] == NULL)
>> +  if (new_argv.empty () || new_argv[0] == NULL)
>>      {
>>        /* GDB didn't specify a program to run.  Use the program from the
>>  	 last run with the new argument list.  */
>>  
>> -      if (program_argv == NULL)
>> +      if (program_argv.empty ())
>>  	{
>>  	  write_enn (own_buf);
>> -	  freeargv (new_argv);
>> +	  free_vector_argv (new_argv);
>>  	  return 0;
>>  	}
>>  
>> -      new_argv[0] = strdup (program_argv[0]);
>> -      if (new_argv[0] == NULL)
>> +      new_argv.push_back (strdup (program_argv[0]));
>> +      if (new_argv.empty () || new_argv[0] == NULL)
>
> On the "empty()" check: you've just pushed an element to the vector,
> so the vector can't be empty.

Indeed.

> On the "== NULL" check: IIUC, the old NULL check was there to
> handle strdup returning NULL due to out-of-memory.
> See NULL checks and comments further above in this function.
> Now that you're using a std::vector, that doesn't work or make
> sense any longer, since if push_back fails to allocate space for
> its internal buffer (with operator new), our operator new replacement
> (common/new-op.c) calls malloc_failure, which aborts gdbserver.
>
> Not sure it makes sense to handle out-of-memory specially in
> the gdb/rsp-facing functions nowadays (maybe git blame/log/patch
> submission for that code shows some guidelines).  Maybe (or, probably)
> it's OK to stop caring about it, but then we should consistently remove
> left over code, by using xstrdup instead and remove the NULL checks.

OK, so from what I understood, this part of the code can be removed,
right?  I guess removing all the leftover code is something to be done
in another patch series.

>>  	{
>>  	  write_enn (own_buf);
>> -	  freeargv (new_argv);
>> +	  free_vector_argv (new_argv);
>>  	  return 0;
>>  	}
>>      }
>>  
>>    /* Free the old argv and install the new one.  */
>> -  freeargv (program_argv);
>> +  free_vector_argv (program_argv);
>>    program_argv = new_argv;
>>  
>> -  start_inferior (program_argv);
>> +  create_inferior (program_argv[0],
>> +		   std::vector<char *> (program_argv.begin () + 1,
>> +					program_argv.end ()));
>
> This creates a copy of the vector.  How about keeping program_argv[0]
> as a separate variable to avoid this copy?  I suspect it'd simplify
> some other things in the function.

Right, I'll do that, thanks for the catch.

>>    if (last_status.kind == TARGET_WAITKIND_STOPPED)
>>      {
>>        prepare_resume_reply (own_buf, last_ptid, &last_status);
>> @@ -3535,13 +3577,18 @@ captured_main (int argc, char *argv[])
>>  	multi_mode = 1;
>>        else if (strcmp (*next_arg, "--wrapper") == 0)
>>  	{
>> +	  char **tmp;
>> +
>>  	  next_arg++;
>>  
>> -	  wrapper_argv = next_arg;
>> +	  tmp = next_arg;
>>  	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
>> -	    next_arg++;
>> +	    {
>> +	      wrapper_argv.push_back (*next_arg);
>> +	      next_arg++;
>> +	    }
>>  
>> -	  if (next_arg == wrapper_argv || *next_arg == NULL)
>> +	  if (next_arg == tmp || *next_arg == NULL)
>>  	    {
>>  	      gdbserver_usage (stderr);
>>  	      exit (1);
>> @@ -3672,8 +3719,13 @@ captured_main (int argc, char *argv[])
>>        exit (1);
>>      }
>>  
>> +  /* Gather information about the environment.  */
>> +  our_environ = make_environ ();
>> +  init_environ (our_environ);
>> +
>>    initialize_async_io ();
>>    initialize_low ();
>> +  have_job_control ();
>>    initialize_event_loop ();
>>    if (target_supports_tracepoints ())
>>      initialize_tracepoint ();
>> @@ -3687,13 +3739,13 @@ captured_main (int argc, char *argv[])
>>        int i, n;
>>  
>>        n = argc - (next_arg - argv);
>> -      program_argv = XNEWVEC (char *, n + 1);
>>        for (i = 0; i < n; i++)
>> -	program_argv[i] = xstrdup (next_arg[i]);
>> -      program_argv[i] = NULL;
>> +	program_argv.push_back (xstrdup (next_arg[i]));
>>  
>>        /* Wait till we are at first instruction in program.  */
>> -      start_inferior (program_argv);
>> +      create_inferior (program_argv[0],
>> +		       std::vector<char *> (program_argv.begin () + 1,
>> +					    program_argv.end ()));
>
> Ditto.

Will do that here too.

>>  
>>        /* We are now (hopefully) stopped at the first instruction of
>>  	 the target process.  This assumes that the target process was
>> @@ -4308,9 +4360,11 @@ process_serial_event (void)
>>  	  fprintf (stderr, "GDBserver restarting\n");
>>  
>>  	  /* Wait till we are at 1st instruction in prog.  */
>> -	  if (program_argv != NULL)
>> +	  if (!program_argv.empty ())
>>  	    {
>> -	      start_inferior (program_argv);
>> +	      create_inferior (program_argv[0],
>> +			       std::vector<char *> (program_argv.begin () + 1,
>> +						    program_argv.end ()));
>>  	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
>>  		{
>>  		  /* Stopped at the first instruction of the target
>> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
>> index d5fee38..5b65597 100644
>> --- a/gdb/gdbserver/server.h
>> +++ b/gdb/gdbserver/server.h
>> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  #include "utils.h"
>>  #include "debug.h"
>>  #include "gdb_vecs.h"
>> +#include <vector>
>>  
>>  /* Maximum number of bytes to read/write at once.  The value here
>>     is chosen to fill up a packet (the headers account for the 32).  */
>> @@ -148,4 +149,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  /* Definition for any syscall, used for unfiltered syscall reporting.  */
>>  #define ANY_SYSCALL (-2)
>>  
>> +/* Any pre-processing needed to be done before calling fork_inferior
>> +   shall be implemented here.  ARGV is a vector containing the full
>> +   argv of the inferior.  */
>> +extern void pre_fork_inferior (const std::vector<char *> &argv);
>> +
>> +/* After fork_inferior has been called, we need to adjust a few
>> +   signals and call startup_inferior.  This is done here.  PID is the
>> +   pid of the new inferior, and ARGV is the vector containing the full
>> +   argv of the inferior.  */
>> +extern void post_fork_inferior (int pid, char *program,
>> +				const std::vector<char *> &argv);
>
> The "full argv" would include the program name, but ARGV is no
> longer including it, right?  Or am I confused?

Yes, that's right.  I'll rewrite the comment to address the changes.

>> +
>> +/* Get the 'struct gdb_environ *' being used in the current
>> +   session.  */
>> +extern struct gdb_environ *get_environ (void);
>> +
>>  #endif /* SERVER_H */
>> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
>> index 117b871..49cfd65 100644
>> --- a/gdb/gdbserver/spu-low.c
>> +++ b/gdb/gdbserver/spu-low.c
>> @@ -27,6 +27,7 @@
>>  #include <sys/syscall.h>
>>  #include "filestuff.h"
>>  #include "hostio.h"
>> +#include "common-inferior.h"
>>  
>>  /* Some older glibc versions do not define this.  */
>>  #ifndef __WNOTHREAD
>> @@ -261,42 +262,41 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
>>    return ret;
>>  }
>>  
>> +/* Callback to be used when calling fork_inferior, responsible for
>> +   actually initiating the tracing of the inferior.  */
>> +
>> +static void
>> +spu_ptrace_fun (void)
>> +{
>> +  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
>> +    trace_start_error_with_name ("ptrace");
>> +  if (setpgid (0, 0) < 0)
>> +    trace_start_error_with_name ("setpgid");
>> +}
>>  
>>  /* Start an inferior process and returns its pid.
>> -   ALLARGS is a vector of program-name and args. */
>> +   PROGRAM_ARGV is a vector of program-name and args. */
>
> Stale?

Yes, I'll rewrite this.

>>  static int
>> -spu_create_inferior (char *program, char **allargs)
>> +spu_create_inferior (char *program, const std::vector<char *> &program_argv)
>>  {
>>    int pid;
>>    ptid_t ptid;
>>    struct process_info *proc;
>> +  std::string program_args = stringify_argv (program_argv);
>>  
>> -  pid = fork ();
>> -  if (pid < 0)
>> -    perror_with_name ("fork");
>> -
>> -  if (pid == 0)
>> -    {
>> -      close_most_fds ();
>> -      ptrace (PTRACE_TRACEME, 0, 0, 0);
>> -
>> -      setpgid (0, 0);
>> +  pre_fork_inferior (program_argv);
>>  
>> -      execv (program, allargs);
>> -      if (errno == ENOENT)
>> -	execvp (program, allargs);
>> +  pid = fork_inferior (program,
>> +		       program_args.c_str (),
>> +		       environ_vector (get_environ ()), spu_ptrace_fun,
>> +		       NULL, NULL, NULL, NULL);
>>  
>> -      fprintf (stderr, "Cannot exec %s: %s.\n", program,
>> -	       strerror (errno));
>> -      fflush (stderr);
>> -      _exit (0177);
>> -    }
>> +  post_fork_inferior (pid, program, program_argv);
>>  
>> -  proc = add_process (pid, 0);
>> +  proc = find_process_pid (pid);
>> +  gdb_assert (proc != NULL);
>>    proc->tdesc = tdesc_spu;
>>  
>> -  ptid = ptid_build (pid, pid, 0);
>> -  add_thread (ptid, NULL);
>>    return pid;
>>  }
>>  
>> diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
>> index fda72e8..1e1d193 100644
>> --- a/gdb/gdbserver/target.c
>> +++ b/gdb/gdbserver/target.c
>> @@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
>>    (*the_target->sw_breakpoint_from_kind) (0, &size);
>>    return size;
>>  }
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_init (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_inferior (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_ours (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
>> index 3cc2bc4..e47ed78 100644
>> --- a/gdb/gdbserver/target.h
>> +++ b/gdb/gdbserver/target.h
>> @@ -28,6 +28,7 @@
>>  #include "target/waitstatus.h"
>>  #include "mem-break.h"
>>  #include "btrace-common.h"
>> +#include <vector>
>>  
>>  struct emit_ops;
>>  struct buffer;
>> @@ -73,7 +74,8 @@ struct target_ops
>>       Returns the new PID on success, -1 on failure.  Registers the new
>>       process with the process list.  */
>>  
>> -  int (*create_inferior) (char *program, char **args);
>> +  int (*create_inferior) (char *program,
>> +			  const std::vector<char *> &program_argv);
>>  
>>    /* Do additional setup after a new process is created, including
>>       exec-wrapper completion.  */
>> @@ -480,8 +482,8 @@ extern struct target_ops *the_target;
>>  
>>  void set_target_ops (struct target_ops *);
>>  
>> -#define create_inferior(program, args) \
>> -  (*the_target->create_inferior) (program, args)
>> +#define create_inferior(program, program_argv)	\
>> +  (*the_target->create_inferior) (program, program_argv)
>>  
>>  #define target_post_create_inferior()			 \
>>    do							 \
>> diff --git a/gdb/gdbserver/terminal.c b/gdb/gdbserver/terminal.c
>> index fb06209..ee361d1 100644
>> --- a/gdb/gdbserver/terminal.c
>> +++ b/gdb/gdbserver/terminal.c
>> @@ -18,6 +18,7 @@
>>  
>>  #include "server.h"
>>  #include "common-terminal.h"
>> +#include "common-top.h"
>>  
>>  /* Placeholders needed by fork_inferior.  For now, these functions are
>>     not needed nor useful to have on gdbserver.  When/If we properly
>> @@ -34,14 +35,14 @@ new_tty (void)
>>  /* See common/common-terminal.h.  */
>>  
>>  void
>> -new_tty_prefork (const char *ttyname)
>> +tty_prefork_hook (void)
>>  {
>>  }
>>  
>>  /* See common/common-terminal.h.  */
>>  
>>  void
>> -new_tty_postfork (void)
>> +tty_postfork_hook (void)
>>  {
>>  }
>>  
>> @@ -67,3 +68,10 @@ get_inferior_io_terminal (void)
>>  {
>>    return NULL;
>>  }
>> +
>> +/* See common/common-top.h.  */
>> +
>> +void
>> +switch_ui_postfork (void)
>> +{
>> +}
>> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
>> index 307d15a..70e8b18 100644
>> --- a/gdb/gdbserver/utils.c
>> +++ b/gdb/gdbserver/utils.c
>> @@ -137,3 +137,39 @@ pfildes (gdb_fildes_t fd)
>>    return plongest (fd);
>>  #endif
>>  }
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +gdb_flush_out_err (void)
>> +{
>> +  fflush (stdout);
>> +  fflush (stderr);
>> +}
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +void
>> +free_vector_argv (std::vector<char *> &v)
>> +{
>> +  for (char *&i : v)
>
> Iterating over pointers, no need for reference indirection,
> copy is fine:
>
>   for (char *el: v)
>     xfree (el);

Wait, I could swear I had removed this!  Anyway, doing it now, thanks.

>> +    xfree (i);
>> +
>> +  v.clear ();
>> +}
>> +
>> +/* See common/common-utils.h.  */
>> +
>> +std::string
>> +stringify_argv (const std::vector<char *> &argv)
>> +{
>> +  std::string ret;
>> +
>> +  for (auto s : argv)
>> +    ret += s + std::string (" ");
>> +
>> +  /* Erase the last whitespace.  */
>> +  ret.erase (ret.end () - 1);
>
> Are we always sure ARGV wasn't empty here?

No.  And I see what you mean: we should check it before erasing the last
whitespace.  Will fix.

>> +
>> +  return ret;
>> +}
>> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
>> index b4ded31..172a2ec 100644
>> --- a/gdb/gdbserver/utils.h
>> +++ b/gdb/gdbserver/utils.h
>> @@ -19,7 +19,18 @@
>>  #ifndef UTILS_H
>>  #define UTILS_H
>>  
>> +#include <vector>
>> +
>>  char *paddress (CORE_ADDR addr);
>>  char *pfildes (gdb_fildes_t fd);
>>  
>> +/* Assumes that V is an argv for a program, and iterates through
>> +   freeing all the elements.  */
>> +extern void free_vector_argv (std::vector<char *> &v);
>> +
>> +/* Given a vector of arguments ARGV, return a string equivalent to
>> +   joining all the arguments (starting from ARGV + 1) with a
>> +   whitespace separating them.  */
>
> Stale?

Yes, I'll fix it.

>> +extern std::string stringify_argv (const std::vector<char *> &argv);
>> +
>>  #endif /* UTILS_H */
>> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
>> index d3ddbf5..b86ae2b 100644
>> --- a/gdb/gdbserver/win32-low.c
>> +++ b/gdb/gdbserver/win32-low.c
>> @@ -608,13 +608,11 @@ create_process (const char *program, char *args,
>>  }
>>  
>>  /* Start a new process.
>> -   PROGRAM is a path to the program to execute.
>> -   ARGS is a standard NULL-terminated array of arguments,
>> -   to be passed to the inferior as ``argv''.
>> +   PROGRAM_ARGV is the vector containing the inferior's argv.
>
> Stale?  I also wonder about the variable renamings that were preserved
> (throughout) in the patch.  Maybe calling the vector of arguments
> some other than "argv", like in the preexisting "args" would result in
> clearer code for avoiding a confusion with "argv" generaly understood
> as including the argv[0]==program name.

OK, that's a fair point.  I had renamed the variable to "argv" because
it was really acting like argv, but with your recent request to use
"program" again that doesn't make sense anymore.  I'll rename the
variable back to "args".

>>     Returns the new PID on success, -1 on failure.  Registers the new
>>     process with the process list.  */
>>  static int
>> -win32_create_inferior (char *program, char **program_args)
>> +win32_create_inferior (char *program, const std::vector<char *> &program_argv)
>>  {
>>  #ifndef USE_WIN32API
>>    char real_path[PATH_MAX];
>> @@ -627,6 +625,8 @@ win32_create_inferior (char *program, char **program_args)
>>    int argc;
>>    PROCESS_INFORMATION pi;
>>    DWORD err;
>> +  std::string program_args = stringify_argv (program_argv);
>> +  char *args = (char *) program_args.c_str ();
>
> Why do we need the cast?

Because "args" is a char *?  I haven't checked if "args" could be made a
const, but I can.

>>  
>>    /* win32_wait needs to know we're not attaching.  */
>>    attaching = 0;
>> @@ -652,18 +652,6 @@ win32_create_inferior (char *program, char **program_args)
>>    program = real_path;
>>  #endif
>>  
>> -  argslen = 1;
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    argslen += strlen (program_args[argc]) + 1;
>> -  args = (char *) alloca (argslen);
>> -  args[0] = '\0';
>> -  for (argc = 1; program_args[argc]; argc++)
>> -    {
>> -      /* FIXME: Can we do better about quoting?  How does Cygwin
>> -	 handle this?  */
>> -      strcat (args, " ");
>> -      strcat (args, program_args[argc]);
>> -    }
>>    OUTMSG2 (("Command line is \"%s\"\n", args));
>>  
>>  #ifdef CREATE_NEW_PROCESS_GROUP
>> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
>> index 7efb3c1..21445f5 100644
>> --- a/gdb/gnu-nat.c
>> +++ b/gdb/gnu-nat.c
>> @@ -2136,6 +2136,7 @@ gnu_create_inferior (struct target_ops *ops,
>>  {
>>    struct inf *inf = cur_inf ();
>>    int pid;
>> +  ptid_t ptid;
>>  
>>    inf_debug (inf, "creating inferior");
>>  
>> @@ -2161,7 +2162,10 @@ gnu_create_inferior (struct target_ops *ops,
>>    thread_change_ptid (inferior_ptid,
>>  		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
>>  
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>> +  /* Mark all threads non-executing.  */
>> +  set_executing (ptid, 0);
>> +
>>    inf->pending_execs = 0;
>>    /* Get rid of the old shell threads.  */
>>    prune_threads ();
>> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
>> index 21578742..e3ddaa8 100644
>> --- a/gdb/inf-ptrace.c
>> +++ b/gdb/inf-ptrace.c
>> @@ -94,7 +94,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>>  			    int from_tty)
>>  {
>>    int pid;
>> -
>> +  ptid_t ptid;
>>    /* Do not change either targets above or the same target if already present.
>>       The reason is the target stack is shared across multiple inferiors.  */
>>    int ops_already_pushed = target_is_pushed (ops);
>> @@ -112,7 +112,10 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>>  
>>    discard_cleanups (back_to);
>>  
>> -  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
>> +  ptid = startup_inferior (START_INFERIOR_TRAPS_EXPECTED, NULL, NULL);
>> +
>> +  /* Mark all threads non-executing.  */
>> +  set_executing (ptid, 0);
>
> Since all callers on the gdb side need to do this, wouldn't it
> be better to add a gdb_startup_inferior function that calls
> the common startup_inferior and calls set_executing ?
> (or call the common one something else)

Sure, that works too.  I'll do that.

Thanks for the review,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v4 4/5] Share fork_inferior et al with gdbserver
  2017-03-17  1:02           ` Sergio Durigan Junior
@ 2017-03-17 10:27             ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-03-17 10:27 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Luis Machado

On 03/17/2017 01:02 AM, Sergio Durigan Junior wrote:
> On Monday, March 13 2017, Pedro Alves wrote:
>>
>> [I think at least some of my comments I sent earlier
>> today on v3 still apply, so I won't repeat them.]
> 
> You mean I haven't addressed everything you commented?  If that is the
> case, I truly apologize.  I'll go over the comments again.

No, I meant what I said.  :-)  I had sent comments to patches in v3 on 
the same day immediately before reading v4 and replying to this thread,
and some of the comments I had sent to v3 applied to v4 too, so I
didn't repeat them against v4:

 https://sourceware.org/ml/gdb-patches/2017-03/msg00189.html
 https://sourceware.org/ml/gdb-patches/2017-03/msg00190.html
 https://sourceware.org/ml/gdb-patches/2017-03/msg00191.html

> Offhand I don't see how to get rid of these functions (on fork_inferior)
> without creating even more stubs on gdbserver, but I'll see.

The first line of action would be I think to look at why do we
even need to reference inferior_ptid there, see if we can
do something else that avoids it.

>>> -  if (new_argv[0] == NULL)
>>> +  if (new_argv.empty () || new_argv[0] == NULL)
>>>      {
>>>        /* GDB didn't specify a program to run.  Use the program from the
>>>  	 last run with the new argument list.  */
>>>  
>>> -      if (program_argv == NULL)
>>> +      if (program_argv.empty ())
>>>  	{
>>>  	  write_enn (own_buf);
>>> -	  freeargv (new_argv);
>>> +	  free_vector_argv (new_argv);
>>>  	  return 0;
>>>  	}
>>>  
>>> -      new_argv[0] = strdup (program_argv[0]);
>>> -      if (new_argv[0] == NULL)
>>> +      new_argv.push_back (strdup (program_argv[0]));
>>> +      if (new_argv.empty () || new_argv[0] == NULL)
>>
>> On the "empty()" check: you've just pushed an element to the vector,
>> so the vector can't be empty.
> 
> Indeed.
> 
>> On the "== NULL" check: IIUC, the old NULL check was there to
>> handle strdup returning NULL due to out-of-memory.
>> See NULL checks and comments further above in this function.
>> Now that you're using a std::vector, that doesn't work or make
>> sense any longer, since if push_back fails to allocate space for
>> its internal buffer (with operator new), our operator new replacement
>> (common/new-op.c) calls malloc_failure, which aborts gdbserver.
>>
>> Not sure it makes sense to handle out-of-memory specially in
>> the gdb/rsp-facing functions nowadays (maybe git blame/log/patch
>> submission for that code shows some guidelines).  Maybe (or, probably)
>> it's OK to stop caring about it, but then we should consistently remove
>> left over code, by using xstrdup instead and remove the NULL checks.
> 
> OK, so from what I understood, this part of the code can be removed,
> right?  I guess removing all the leftover code is something to be done
> in another patch series.

Well, it only becomes "left over code" when we switch to use vector.

Is it possible to split these C++fication changes (std::vector/std::string)
to a separate preparatory patch?

>>> +void
>>> +free_vector_argv (std::vector<char *> &v)
>>> +{
>>> +  for (char *&i : v)
>>
>> Iterating over pointers, no need for reference indirection,
>> copy is fine:
>>
>>   for (char *el: v)
>>     xfree (el);
> 
> Wait, I could swear I had removed this!  Anyway, doing it now, thanks.

You had removed it elsewhere in the patch, but missed here.

> 
>>> +    xfree (i);
>>> +
>>> +  v.clear ();
>>> +}
>>> +
>>> +/* See common/common-utils.h.  */
>>> +
>>> +std::string
>>> +stringify_argv (const std::vector<char *> &argv)
>>> +{
>>> +  std::string ret;
>>> +
>>> +  for (auto s : argv)
>>> +    ret += s + std::string (" ");
>>> +
>>> +  /* Erase the last whitespace.  */
>>> +  ret.erase (ret.end () - 1);
>>
>> Are we always sure ARGV wasn't empty here?
> 
> No.  And I see what you mean: we should check it before erasing the last
> whitespace.  Will fix.

Exactly.

>>> @@ -627,6 +625,8 @@ win32_create_inferior (char *program, char **program_args)
>>>    int argc;
>>>    PROCESS_INFORMATION pi;
>>>    DWORD err;
>>> +  std::string program_args = stringify_argv (program_argv);
>>> +  char *args = (char *) program_args.c_str ();
>>
>> Why do we need the cast?
> 
> Because "args" is a char *?  I haven't checked if "args" could be made a
> const, but I can.

Right, why is it that "char *" needs to be non-const.  The cast
was just what made the alarm bell ring.  :-)

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
@ 2017-03-30  1:50   ` Sergio Durigan Junior
  2017-03-31 17:11     ` Pedro Alves
  2017-03-30  1:50   ` [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior Sergio Durigan Junior
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:50 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This commit moves a few bits responsible for dealing with inferior job
control from GDB to common/, which makes them available to gdbserver.
This is necessary for the upcoming patches that will share
fork_inferior et al between GDB and gdbserver.

We move some parts of gdb/terminal.h to gdb/common/common-terminal.h,
especifically the code that checks terminal features and that are used
to set job_control accordingly.

After sharing parts of gdb/terminal.h, we also to share the two
functions on gdb/inflow.c that are going to be needed by the
fork_inferior rework.  They are 'gdb_setpgid' and the new
'have_job_control'.  I've also taken the opportunity to give a more
meaningful name to "inflow.c" on common/.  Now it is called
"job-control.c" (thanks Pedro for the suggestion).

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/job-control.c".
	(HFILES_NO_SRCDIR): Add "common/common-terminal.h".
	(COMMON_OBS): Add "common/job-control.o".
	* common/common-terminal.h: New file, with parts of "terminal.h".
	* common/common.m4: Check headers 'termios.h', 'termio.h' and
	'sgtty.h'.
	* common/job-control.c: New file, with contents from
	"gdb/inflow.c".
	* inflow.c (gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* terminal.h: Move terminal-related defines to
	"common/common-terminal.h".  Include "common/common-terminal.h".
	(job_control): Moved to "common/common-terminal.h".
	(gdb_setpgid): Likewise.
	* utils.c (job_control): Remove.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILE): Add "common/job-control.c".
	(OBS): Add "job-control.o".
	* terminal.h: Include "common-terminal.h".
---
 gdb/Makefile.in              |  3 ++
 gdb/common/common-terminal.h | 94 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/common/common.m4         |  3 +-
 gdb/common/job-control.c     | 92 +++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/Makefile.in    |  2 +
 gdb/gdbserver/terminal.h     |  2 +
 gdb/inflow.c                 | 63 +----------------------------
 gdb/terminal.h               | 69 +-------------------------------
 gdb/utils.c                  |  4 --
 9 files changed, 198 insertions(+), 134 deletions(-)
 create mode 100644 gdb/common/common-terminal.h
 create mode 100644 gdb/common/job-control.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0818742..6ad03d7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1210,6 +1210,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/job-control.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1484,6 +1485,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/common-terminal.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
@@ -1637,6 +1639,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-terminal.h b/gdb/common/common-terminal.h
new file mode 100644
index 0000000..4026a08
--- /dev/null
+++ b/gdb/common/common-terminal.h
@@ -0,0 +1,94 @@
+/* Common terminal interface definitions for GDB and gdbserver.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_TERMINAL_H
+#define COMMON_TERMINAL_H
+
+/* If we're using autoconf, it will define HAVE_TERMIOS_H,
+   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
+   ser-unix.c and inflow.c to inspect those names instead of
+   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
+   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
+   nothing has already defined the one of the names, and do the right
+   thing.  */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
+	  !defined (HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  FIXME: serial.h and
+   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+   is converted to use them, can get rid of this crap.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+#include <sys/types.h>
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid (void);
+
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  This function must be called before any use of
+   JOB_CONTROL.  */
+extern void have_job_control (void);
+
+#endif /* ! COMMON_TERMINAL_H */
diff --git a/gdb/common/common.m4 b/gdb/common/common.m4
index e21e6e5..45726ab 100644
--- a/gdb/common/common.m4
+++ b/gdb/common/common.m4
@@ -28,7 +28,8 @@ AC_DEFUN([GDB_AC_COMMON], [
   AC_CHECK_HEADERS(linux/perf_event.h locale.h memory.h signal.h dnl
 		   sys/resource.h sys/socket.h sys/syscall.h dnl
 		   sys/un.h sys/wait.h dnl
-		   thread_db.h wait.h)
+		   thread_db.h wait.h dnl
+		   termios.h termio.h sgtty.h)
 
   AC_CHECK_FUNCS([fdwalk getrlimit pipe pipe2 socketpair sigaction])
 
diff --git a/gdb/common/job-control.c b/gdb/common/job-control.c
new file mode 100644
index 0000000..14b719e
--- /dev/null
+++ b/gdb/common/job-control.c
@@ -0,0 +1,92 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "common-terminal.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* Set the process group ID of the inferior.
+
+   Just using job_control only does part of it because setpgid or
+   setpgrp might not exist on a system without job control.
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 9935012..340c9c0 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/job-control.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
diff --git a/gdb/gdbserver/terminal.h b/gdb/gdbserver/terminal.h
index 3bdd5f5..498ab26 100644
--- a/gdb/gdbserver/terminal.h
+++ b/gdb/gdbserver/terminal.h
@@ -19,6 +19,8 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
+#include "common-terminal.h"
+
 /* Autoconf will have defined HAVE_TERMIOS_H, HAVE_TERMIO_H,
    and HAVE_SGTTY_H for us as appropriate.  */
 
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 7ffa83a..271278d 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -803,43 +803,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -860,30 +823,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/terminal.h b/gdb/terminal.h
index d8691b2..3243279 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,62 +19,7 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
+#include "common-terminal.h"
 
 struct inferior;
 
@@ -86,16 +31,8 @@ extern void new_tty_postfork (void);
 
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
 extern pid_t create_tty_session (void);
 
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
@@ -105,8 +42,4 @@ extern void gdb_save_tty_state (void);
    have had a chance to alter it.  */
 extern void set_initial_gdb_ttystate (void);
 
-/* Set the process group of the caller to its own pid, or do nothing
-   if we lack job control.  */
-extern int gdb_setpgid (void);
-
 #endif /* !defined (TERMINAL_H) */
diff --git a/gdb/utils.c b/gdb/utils.c
index 39798cc..d7a1993 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -102,10 +102,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
  2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
@ 2017-03-30  1:50   ` Sergio Durigan Junior
  2017-04-07 18:30     ` Pedro Alves
  2017-03-30  1:50   ` [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:50 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

As a preparation for the next patch, which will move fork_inferior
from GDB to common/ (and therefore share it with gdbserver), it is
interesting to convert a few functions to C++.

This patch touches functions related to parsing command-line arguments
to the inferior (see gdb/fork-child.c:breakup_args), the way the
arguments are stored on fork_inferior (using std::vector instead of
char **), and the code responsible for dealing with argv also on
gdbserver.

I've taken this opportunity and decided to constify a few arguments to
fork_inferior/create_inferior as well, in order to make the code
cleaner.  And now, on gdbserver, we're using xstrdup everywhere and
aren't checking for memory allocation failures anymore, as requested
by Pedro.

IMO this refactoring was very good to increase the readability of the
code as well, because some parts of the argument handling were
unnecessarily confusing before.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* common/common-utils.c (free_vector_argv): New function.
	* common/common-utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	* darwin-nat.c (darwin_create_inferior): Rewrite function
	prototype in order to constify "exec_file" and accept a
	"std::string" for "allargs".
	* fork-child.c: Include <vector>.
	(breakup_args): Rewrite function, using C++.
	(fork_inferior): Rewrite function header, constify "exec_file_arg"
	and accept "std::string" for "allargs".  Update the code to
	calculate "argv" based on "allargs".  Update calls to "exec_fun"
	and "execvp".
	* gnu-nat.c (gnu_create_inferior): Rewrite function prototype in
	order to constify "exec_file" and accept a "std::string" for
	"allargs".
	* go32-nat.c (go32_create_inferior): Likewise.
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* infcmd.c (run_command_1): Constify "exec_file".  Use
	"std::string" for inferior arguments.
	* inferior.h (fork_inferior): Update prototype.
	* linux-nat.c (linux_nat_create_inferior): Rewrite function
	prototype in order to constify "exec_file" and accept a
	"std::string" for "allargs".
	* nto-procfs.c (procfs_create_inferior): Likewise.
	* procfs.c (procfs_create_inferior): Likewise.
	* remote-sim.c (gdbsim_create_inferior): Likewise.
	* remote.c (extended_remote_run): Update code to accept
	"std::string" as argument.
	(extended_remote_create_inferior): Rewrite function prototype in
	order to constify "exec_file" and accept a "std::string" for
	"allargs".
	* rs6000-nat.c (super_create_inferior): Likewise.
	(rs6000_create_inferior): Likewise.
	* target.h (struct target_ops) <to_create_inferior>: Likewise.
	* windows-nat.c (windows_create_inferior): Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* server.c: Include <vector>.
	<program_argv, wrapper_argv>: Convert to std::vector.
	(start_inferior): Rewrite function to use C++.
	(handle_v_run): Likewise.  Update code that calculates the argv
	based on the vRun packet; use C++.
	(captured_main): Likewise.
---
 gdb/common/common-utils.c |  11 ++++
 gdb/common/common-utils.h |   5 ++
 gdb/darwin-nat.c          |  12 ++--
 gdb/fork-child.c          | 139 ++++++++++++++++++++--------------------------
 gdb/gdbserver/server.c    | 108 ++++++++++++++++-------------------
 gdb/gnu-nat.c             |   3 +-
 gdb/go32-nat.c            |   6 +-
 gdb/inf-ptrace.c          |   4 +-
 gdb/infcmd.c              |   7 ++-
 gdb/inferior.h            |   2 +-
 gdb/linux-nat.c           |   4 +-
 gdb/nto-procfs.c          |   9 +--
 gdb/procfs.c              |   4 +-
 gdb/remote-sim.c          |   7 ++-
 gdb/remote.c              |  12 ++--
 gdb/rs6000-nat.c          |  10 ++--
 gdb/target.h              |   3 +-
 gdb/windows-nat.c         |   6 +-
 18 files changed, 175 insertions(+), 177 deletions(-)

diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index afc0af9..e94fdc4 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -317,3 +317,14 @@ skip_to_space_const (const char *chp)
     chp++;
   return chp;
 }
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (char *el : v)
+    xfree (el);
+
+  v.clear ();
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 618d266..c331f0d 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -21,6 +21,7 @@
 #define COMMON_UTILS_H
 
 #include <string>
+#include <vector>
 
 /* If possible, define FUNCTION_NAME, a macro containing the name of
    the function being defined.  Since this macro may not always be
@@ -103,4 +104,8 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Assumes that V is an argv for a program, and iterates through
+   freeing all the elements.  */
+extern void free_vector_argv (std::vector<char *> &v);
+
 #endif
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index edee1be..47ec922 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -102,8 +102,10 @@ static void darwin_ptrace_me (void);
 
 static void darwin_ptrace_him (int pid);
 
-static void darwin_create_inferior (struct target_ops *ops, char *exec_file,
-				    char *allargs, char **env, int from_tty);
+static void darwin_create_inferior (struct target_ops *ops,
+				    const char *exec_file,
+				    const std::string &allargs,
+				    char **env, int from_tty);
 
 static void darwin_files_info (struct target_ops *ops);
 
@@ -1826,8 +1828,10 @@ darwin_execvp (const char *file, char * const argv[], char * const env[])
 }
 
 static void
-darwin_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+darwin_create_inferior (struct target_ops *ops,
+			const char *exec_file,
+			const std::string &allargs,
+			char **env, int from_tty)
 {
   /* Do the hard work.  */
   fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index dc2a314..e586c3e 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -1,4 +1,4 @@
-/* Fork a Unix child process, and set up to debug it, for GDB.
+ /* Fork a Unix child process, and set up to debug it, for GDB.
 
    Copyright (C) 1990-2017 Free Software Foundation, Inc.
 
@@ -34,6 +34,7 @@
 #include "top.h"
 #include "signals-state-save-restore.h"
 #include <signal.h>
+#include <vector>
 
 /* This just gets used as a default if we can't find SHELL.  */
 #define SHELL_FILE "/bin/sh"
@@ -48,41 +49,33 @@ static char *exec_wrapper;
    fill in ARGV with the four arguments "a", "b", "c", "d".  */
 
 static void
-breakup_args (char *scratch, char **argv)
+breakup_args (const std::string &scratch, std::vector<char *> &argv)
 {
-  char *cp = scratch, *tmp;
-
-  for (;;)
+  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
     {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
+
+      /* No separator found, which means this is the last
+	 argument.  */
+      if (next_sep == std::string::npos)
+	next_sep = scratch.size ();
+
+      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
+
+      argv.push_back (xstrdup (arg.c_str ()));
+
+      cur_pos = next_sep;
     }
 
-  /* Null-terminate the vector.  */
-  *argv = NULL;
+  /* NULL-terminating the vector.  */
+  argv.push_back (NULL);
 }
 
 /* When executing a command under the given shell, return non-zero if
@@ -145,9 +138,10 @@ trace_start_error_with_name (const char *string)
    made static to ensure that they survive the vfork call.  */
 
 int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (void),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
+	       char *shell_file_arg,
                void (*exec_fun)(const char *file, char * const *argv,
                                 char * const *env))
 {
@@ -159,10 +153,10 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
      to you in the parent process.  It's only used by humans for debugging.  */
   static int debug_setpgrp = 657473;
   static char *shell_file;
-  static char *exec_file;
+  static const char *exec_file;
   char **save_our_env;
   int shell = 0;
-  static char **argv;
+  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -171,9 +165,10 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   /* If no exec file handed to us, get it from the exec-file command
      -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
+  if (exec_file_arg == NULL)
     exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
 
   /* 'startup_with_shell' is declared in inferior.h and bound to the
      "set startup-with-shell" option.  If 0, we'll just do a
@@ -191,43 +186,26 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   if (!shell)
     {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
+      /* We're going to call execvp.  Create argument vector.  */
+      argv.push_back (xstrdup (exec_file));
+      breakup_args (allargs, argv);
     }
   else
     {
       /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
+      std::string shell_command;
+      const char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
+      shell_command = std::string ("exec ");
 
       /* Add any exec wrapper.  That may be a program name with arguments, so
 	 the user must handle quoting.  */
       if (exec_wrapper)
 	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
+	  shell_command += exec_wrapper;
+	  shell_command += " ";
 	}
 
       /* Now add exec_file, quoting as necessary.  */
@@ -268,33 +246,32 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
     end_scan:
       if (need_to_quote)
 	{
-	  strcat (shell_command, "'");
+	  shell_command += "'";
 	  for (p = exec_file; *p != '\0'; ++p)
 	    {
 	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
+		shell_command += "'\\''";
 	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
+		shell_command += "\\!";
 	      else
-		strncat (shell_command, p, 1);
+		shell_command += *p;
 	    }
-	  strcat (shell_command, "'");
+	  shell_command += "'";
 	}
       else
-	strcat (shell_command, exec_file);
+	shell_command += exec_file;
 
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
+      shell_command += " " + allargs;
 
       /* If we decided above to start up with a shell, we exec the
 	 shell, "-c" says to interpret the next arg as a shell command
 	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
+	 <args>".  We xstrdup all the strings here because they will
+	 be free'd later in the code.  */
+      argv.push_back (xstrdup (shell_file));
+      argv.push_back (xstrdup ("-c"));
+      argv.push_back (xstrdup (shell_command.c_str ()));
+      argv.push_back (NULL);
     }
 
   /* Retain a copy of our environment variables, since the child will
@@ -401,9 +378,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       environ = env;
 
       if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
+        (*exec_fun) (argv[0], &argv[0], env);
       else
-        execvp (argv[0], argv);
+        execvp (argv[0], &argv[0]);
 
       /* If we get here, it's an error.  */
       save_errno = errno;
@@ -417,6 +394,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       _exit (0177);
     }
 
+  free_vector_argv (argv);
+
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 4bc7f71..b22dfab 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,7 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include <vector>
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +79,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -239,29 +241,21 @@ target_running (void)
 static int
 start_inferior (char **argv)
 {
-  char **new_argv = argv;
+  std::vector<char *> new_argv;
 
-  if (wrapper_argv != NULL)
-    {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
-    }
+  if (!wrapper_argv.empty ())
+    new_argv.insert (new_argv.begin (),
+		     wrapper_argv.begin (),
+		     wrapper_argv.end ());
+
+  for (int i = 0; argv[i] != NULL; ++i)
+    new_argv.push_back (argv[i]);
+
+  new_argv.push_back (NULL);
 
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
+      for (int i = 0; i < new_argv.size (); ++i)
 	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
       debug_flush ();
     }
@@ -271,7 +265,7 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
 
   /* FIXME: we don't actually know at this point that the create
      actually succeeded.  We won't know that until we wait.  */
@@ -288,7 +282,7 @@ start_inferior (char **argv)
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
+  if (!wrapper_argv.empty ())
     {
       ptid_t ptid = pid_to_ptid (signal_pid);
 
@@ -2852,7 +2846,8 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
   int i, new_argc;
 
   new_argc = 0;
@@ -2862,62 +2857,51 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
       if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+	{
+	  /* No program specified.  */
+	  new_argv.push_back (NULL);
+	}
       else
 	{
-	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = (next_p - p) / 2;
+	  char *arg = (char *) xmalloc (len + 1);
+
+	  hex2bin (p, (gdb_byte *) arg, len);
+	  arg[len] = '\0';
+	  new_argv.push_back (arg);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
+  new_argv.push_back (NULL);
 
   if (new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
-	{
-	  write_enn (own_buf);
-	  freeargv (new_argv);
-	  return 0;
-	}
+      new_argv.push_back (xstrdup (program_argv[0]));
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3535,13 +3519,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3687,13 +3676,12 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
+      program_argv.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      start_inferior (&program_argv[0]);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4308,9 +4296,9 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      start_inferior (&program_argv[0]);
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 7efb3c1..818be15 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2131,7 +2131,8 @@ gnu_ptrace_me (void)
 
 static void
 gnu_create_inferior (struct target_ops *ops, 
-		     char *exec_file, char *allargs, char **env,
+		     const char *exec_file, const std::string &allargs,
+		     char **env,
 		     int from_tty)
 {
   struct inf *inf = cur_inf ();
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 1fca8e2..1976081 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -631,8 +631,9 @@ go32_kill_inferior (struct target_ops *ops)
 }
 
 static void
-go32_create_inferior (struct target_ops *ops, char *exec_file,
-		      char *args, char **env, int from_tty)
+go32_create_inferior (struct target_ops *ops,
+		      const char *exec_file,
+		      const std::string &allargs, char **env, int from_tty)
 {
   extern char **environ;
   jmp_buf start_state;
@@ -641,6 +642,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
   size_t cmdlen;
   struct inferior *inf;
   int result;
+  char *args = (char *) allargs.c_str ();
 
   /* If no exec file handed to us, get it from the exec-file command -- with
      a good, common error message if none is specified.  */
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index f912d28..787310d 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -90,8 +90,8 @@ inf_ptrace_me (void)
 
 static void
 inf_ptrace_create_inferior (struct target_ops *ops,
-			    char *exec_file, char *allargs, char **env,
-			    int from_tty)
+			    const char *exec_file, const std::string &allargs,
+			    char **env, int from_tty)
 {
   int pid;
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d41e609..742d4c4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -526,7 +526,7 @@ prepare_execution_command (struct target_ops *target, int background)
 static void
 run_command_1 (char *args, int from_tty, int tbreak_at_main)
 {
-  char *exec_file;
+  const char *exec_file;
   struct cleanup *old_chain;
   ptid_t ptid;
   struct ui_out *uiout = current_uiout;
@@ -574,7 +574,7 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
   if (tbreak_at_main)
     tbreak_command (main_name (), 0);
 
-  exec_file = (char *) get_exec_file (0);
+  exec_file = get_exec_file (0);
 
   /* We keep symbols from add-symbol-file, on the grounds that the
      user might want to add some symbols before running the program
@@ -607,7 +607,8 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
 
   /* We call get_inferior_args() because we might need to compute
      the value now.  */
-  run_target->to_create_inferior (run_target, exec_file, get_inferior_args (),
+  run_target->to_create_inferior (run_target, exec_file,
+				  std::string (get_inferior_args ()),
 				  environ_vector (current_inferior ()->environment),
 				  from_tty);
   /* to_create_inferior should push the target, so after this point we
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7c0ddf3..bf06ac1 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -146,7 +146,7 @@ extern void trace_start_error (const char *fmt, ...)
 extern void trace_start_error_with_name (const char *string)
   ATTRIBUTE_NORETURN;
 
-extern int fork_inferior (char *, char *, char **,
+extern int fork_inferior (const char *, const std::string &, char **,
 			  void (*)(void),
 			  void (*)(int), void (*)(void), char *,
                           void (*)(const char *,
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index dff0da5..b0b3d1c 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1105,8 +1105,8 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *signalled)
 
 static void
 linux_nat_create_inferior (struct target_ops *ops, 
-			   char *exec_file, char *allargs, char **env,
-			   int from_tty)
+			   const char *exec_file, const std::string &allargs,
+			   char **env, int from_tty)
 {
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 75f92dc..7fb7095 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1163,8 +1163,9 @@ breakup_args (char *scratch, char **argv)
 }
 
 static void
-procfs_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+procfs_create_inferior (struct target_ops *ops, const char *exec_file,
+			const std::string &allargs,
+			char **env, int from_tty)
 {
   struct inheritance inherit;
   pid_t pid;
@@ -1176,7 +1177,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
 
-  argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) *
+  argv = xmalloc ((allargs.size () / (unsigned) 2 + 2) *
 		  sizeof (*argv));
   argv[0] = get_exec_file (1);
   if (!argv[0])
@@ -1187,7 +1188,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
 	return;
     }
 
-  args = xstrdup (allargs);
+  args = xstrdup (allargs.c_str ());
   breakup_args (args, (exec_file != NULL) ? &argv[1] : &argv[0]);
 
   argv = nto_parse_redirection (argv, &in, &out, &err);
diff --git a/gdb/procfs.c b/gdb/procfs.c
index b860f16..e8f26be 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4526,8 +4526,8 @@ procfs_set_exec_trap (void)
    inf-ptrace?  */
 
 static void
-procfs_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+procfs_create_inferior (struct target_ops *ops, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   char *shell_file = getenv ("SHELL");
   char *tryname;
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 0e8d657..bf992da 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -607,13 +607,14 @@ gdbsim_load (struct target_ops *self, const char *args, int fromtty)
    user types "run" after having attached.  */
 
 static void
-gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
-			char **env, int from_tty)
+gdbsim_create_inferior (struct target_ops *target, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   struct sim_inferior_data *sim_data
     = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
   int len;
   char *arg_buf, **argv;
+  const char *args = allargs.c_str ();
 
   if (exec_file == 0 || exec_bfd == 0)
     warning (_("No executable file specified."));
@@ -633,7 +634,7 @@ gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
 
   if (exec_file != NULL)
     {
-      len = strlen (exec_file) + 1 + strlen (args) + 1 + /*slop */ 10;
+      len = strlen (exec_file) + 1 + allargs.size () + 1 + /*slop */ 10;
       arg_buf = (char *) alloca (len);
       arg_buf[0] = '\0';
       strcat (arg_buf, exec_file);
diff --git a/gdb/remote.c b/gdb/remote.c
index 2791ac8..92e3e6e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9526,7 +9526,7 @@ extended_remote_disable_randomization (int val)
 }
 
 static int
-extended_remote_run (char *args)
+extended_remote_run (const std::string &args)
 {
   struct remote_state *rs = get_remote_state ();
   int len;
@@ -9545,14 +9545,13 @@ extended_remote_run (char *args)
   len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
 		      strlen (remote_exec_file));
 
-  gdb_assert (args != NULL);
-  if (*args)
+  if (!args.empty ())
     {
       struct cleanup *back_to;
       int i;
       char **argv;
 
-      argv = gdb_buildargv (args);
+      argv = gdb_buildargv (args.c_str ());
       back_to = make_cleanup_freeargv (argv);
       for (i = 0; argv[i] != NULL; i++)
 	{
@@ -9597,7 +9596,8 @@ extended_remote_run (char *args)
 
 static void
 extended_remote_create_inferior (struct target_ops *ops,
-				 char *exec_file, char *args,
+				 const char *exec_file,
+				 const std::string &args,
 				 char **env, int from_tty)
 {
   int run_worked;
@@ -9622,7 +9622,7 @@ extended_remote_create_inferior (struct target_ops *ops,
 	 user requested.  */
       if (remote_exec_file[0])
 	error (_("Remote target does not support \"set remote exec-file\""));
-      if (args[0])
+      if (!args.empty ())
 	error (_("Remote target does not support \"set args\" or run <ARGS>"));
 
       /* Fall back to "R".  */
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index 8f5d25c..83e0693 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -524,11 +524,13 @@ rs6000_wait (struct target_ops *ops,
 /* Set the current architecture from the host running GDB.  Called when
    starting a child process.  */
 
-static void (*super_create_inferior) (struct target_ops *,char *exec_file, 
-				      char *allargs, char **env, int from_tty);
+static void (*super_create_inferior) (struct target_ops *,
+				      const char *exec_file,
+				      const std::string &allargs,
+				      char **env, int from_tty);
 static void
-rs6000_create_inferior (struct target_ops * ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+rs6000_create_inferior (struct target_ops * ops, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   enum bfd_architecture arch;
   unsigned long mach;
diff --git a/gdb/target.h b/gdb/target.h
index 943a0e2..bc935ef 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -591,7 +591,8 @@ struct target_ops
        ENV is the environment vector to pass.  Errors reported with error().
        On VxWorks and various standalone systems, we ignore exec_file.  */
     void (*to_create_inferior) (struct target_ops *, 
-				char *, char *, char **, int);
+				const char *, const std::string &,
+				char **, int);
     void (*to_post_startup_inferior) (struct target_ops *, ptid_t)
       TARGET_DEFAULT_IGNORE ();
     int (*to_insert_fork_catchpoint) (struct target_ops *, int)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 76313db..b907512 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2412,8 +2412,9 @@ redirect_inferior_handles (const char *cmd_orig, char *cmd,
    ENV is the environment vector to pass.  Errors reported with error().  */
 
 static void
-windows_create_inferior (struct target_ops *ops, char *exec_file,
-		       char *allargs, char **in_env, int from_tty)
+windows_create_inferior (struct target_ops *ops, const char *exec_file,
+			 const std::string &origallargs, char **in_env,
+			 int from_tty)
 {
   STARTUPINFO si;
 #ifdef __CYGWIN__
@@ -2432,6 +2433,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   char real_path[__PMAX];
   char shell[__PMAX]; /* Path to shell */
   char *toexec;
+  const char *allargs = origallargs.c_str ();
   char *args, *allargs_copy;
   size_t args_len, allargs_len;
   int fd_inp = -1, fd_out = -1, fd_err = -1;
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
  2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
  2017-03-30  1:50   ` [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior Sergio Durigan Junior
@ 2017-03-30  1:50   ` Sergio Durigan Junior
  2017-03-31 17:15     ` Pedro Alves
  2017-03-30  1:55   ` [PATCH v5 4/5] Share fork_inferior et al " Sergio Durigan Junior
  2017-03-30  1:55   ` [PATCH v5 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  4 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:50 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

Again, it was necessary to share a few functions declared on
gdb/gdbthread.h with gdbserver, because they are needed by
fork_inferior.  I decided to implement them on
gdb/gdbserver/inferiors.c because that's where the thread functions
are also implemented on gdbserver.  Some of these functions do not
need to be implemented on gdbserver, or don't make sense there, so
they are left blank and commented properly.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* gdbthread.h: Include "common-gdbthread.h".
	(init_thread_list): Moved to "common/common-gdbthread.h".
	(add_thread_silent): Likewise.
	(switch_to_thread): Likewise.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (init_thread_list): New function.
	(switch_to_thread): Likewise.
	(add_thread_silent): Likewise.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 32 ++++++++++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     | 23 +++++++++++++++++++++++
 gdb/gdbthread.h               |  9 +--------
 4 files changed, 57 insertions(+), 8 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6ad03d7..e5b0363 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1482,6 +1482,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..8a1dfaa
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,32 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_GDBTHREAD_H
+#define COMMON_GDBTHREAD_H
+
+struct target_waitstatus;
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+/* Add a thread to the thread list and return the pointer to the new
+   thread.  Caller may use this pointer to initialize the private
+   thread data.  */
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+#endif /* ! COMMON_GDBTHREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..4ed5e00 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,26 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
+
+/* See common/common-gdbthread.h.  */
+
+struct thread_info *
+add_thread_silent (ptid_t ptid)
+{
+  pid_t pid = ptid_get_pid (ptid);
+
+  /* Check if there is a process already.  */
+  if (find_process_pid (pid) == NULL)
+    add_process (pid, 0);
+
+  return add_thread (ptid_build (pid, pid, 0), NULL);
+}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9a16fe6..1fd73ea 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -31,6 +31,7 @@ struct symtab;
 #include "common/vec.h"
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -357,10 +358,6 @@ extern void init_thread_list (void);
    initialize the private thread data.  */
 extern struct thread_info *add_thread (ptid_t ptid);
 
-/* Same as add_thread, but does not print a message
-   about new thread.  */
-extern struct thread_info *add_thread_silent (ptid_t ptid);
-
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
 						 struct private_thread_info *);
@@ -473,10 +470,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (7 preceding siblings ...)
  2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
@ 2017-03-30  1:50 ` Sergio Durigan Junior
  2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
                     ` (4 more replies)
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  10 siblings, 5 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:50 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves

Hi there,

This is the fifth iteration of the patch series.  You can see the last
version here:

  <https://sourceware.org/ml/gdb-patches/2017-03/msg00084.html>

This version was made to address several comments made by Pedro
regarding the last two versions of the series.  Various things were
changed and improved in this version, including the merge of two
commits (the first two commits of the last version are now the first
commit of this version) and the addition of a C++ preparation commit,
as requested.

Here's what has changed:

- A bunch of new hooks on fork_inferior, which made it easier to get
  rid of some of the GDB-specific functions that were being shared
  with gdbserver (implemented as placeholders).

- GDB's remote backend is now setting startup-with-shell on the right
  place (on extended_remote_create_inferior).

- Got rid of the "ui switching" hack; now this is all done on
  postfork_child_hook.

- Wrote more info about the *_update functions on
  gdbserver/{linux,lynx}-low.c

- Added more rationale on the non-existing-program.exp testcase.

- Got rid of the inferior_ptid global on gdbserver, which allowed the
  deletion of some placeholders (inferior_appeared, current_inferior).

- Update comments on all *_create_inferior functions on gdbserver.

- Improved the code and the comments of handle_v_run, especifically
  the part that deals with argument parsing.

- Created a new program_name variable on gdbserver, which makes it
  easier to call create_inferior without having to create a copy of
  the args vector.

- Got rid of the pre_fork_inferior function, transforming it into the
  prefork_hook generic function.

- Constified the first argument of create_inferior (const char
  *program).

- Fixed vector iteration on C++ using range-based loop.

- Fixed possible problem with stringify_argv, where it was trying to
  erase a char from a string without knowing if the string wasn't
  empty.

- Created gdb_startup_inferior so that set_executing gets called
  automatically after startup_inferior.

- Improved the entry about the new QStartupWithShell packet on the
  documentation.

- Improved the startup-with-shell.exp testcase, which now doesn't
  depend on gdbserver and can be run by the native target as well.


Tested, and no regressions found.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 4/5] Share fork_inferior et al with gdbserver
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                     ` (2 preceding siblings ...)
  2017-03-30  1:50   ` [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
@ 2017-03-30  1:55   ` Sergio Durigan Junior
  2017-03-30  1:55   ` [PATCH v5 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  4 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:55 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(HFILES_NO_SRCDIR): Add "common/common-inferior.h".
	(COMMON_OBS): Add "common-fork-child.o".
	* common-fork-child.c: New file, with the majority of
	"gdb/fork-child.c".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* commom/common-utils.c (stringify_argv): New function.
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	(stringify_argv): Likewise.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(saved_ui): New variable.
	(prefork_hook): New function.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(gdb_startup_inferior): Likewise.
	(fork_inferior): Move to "common/common-fork-child.c".  Update
	function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* inferior.h: Include "common-inferior.h".
	(fork_inferior): Move prototype to "common-inferior.h".
	(startup_inferior): Likewise.
	(gdb_startup_inferior): New prototype.
	* procfs.c (procfs_init_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/common-fork-child.c".
	(OBS): Add common-fork-child.o.
	* linux-low.c: Include "common-inferior.h" and "environ.h".
	(linux_update_process): New function.
	(linux_add_process): Update comment.  Adjust function to call
	"linux_update_process".
	(update_thread_lwp): New function.
	(linux_ptrace_fun): Likewise.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c: Include "common-inferior.h".
	(lynx_update_process): New function.
	(lynx_add_process): Update comment.  Adjust function to call
	"lynx_update_process".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".  Update comments.
	* server.c: Include "common-inferior.h", "common-terminal.h",
	"environ.h".
	(our_environ): New variable.
	(startup_with_shell): Likewise.
	(program_name): Likewise.
	(program_argv): Rename to...
	(program_args): ...this.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(prefork_hook): Likewise.
	(post_fork_inferior): Likewise.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(post_fork_inferior): New prototype.
	(get_environ): Likewise.
	* spu-low.c: Include "common-inferior.h".
	(spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	* utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   3 +
 gdb/common/common-fork-child.c                    | 547 +++++++++++++++++++++
 gdb/common/common-inferior.h                      | 123 +++++
 gdb/common/common-utils.c                         |  20 +
 gdb/common/common-utils.h                         |   8 +
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |   2 +-
 gdb/fork-child.c                                  | 550 +++-------------------
 gdb/gdbserver/Makefile.in                         |   2 +
 gdb/gdbserver/linux-low.c                         | 144 ++++--
 gdb/gdbserver/lynx-low.c                          |  80 ++--
 gdb/gdbserver/nto-low.c                           |  10 +-
 gdb/gdbserver/server.c                            | 257 +++++++---
 gdb/gdbserver/server.h                            |  10 +
 gdb/gdbserver/spu-low.c                           |  49 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |  13 +-
 gdb/gdbserver/utils.c                             |   9 +
 gdb/gdbserver/utils.h                             |   2 +
 gdb/gdbserver/win32-low.c                         |  22 +-
 gdb/gnu-nat.c                                     |   3 +-
 gdb/inf-ptrace.c                                  |   2 +-
 gdb/inferior.h                                    |  27 +-
 gdb/procfs.c                                      |   2 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  12 +-
 gdb/utils.c                                       |   9 +
 28 files changed, 1233 insertions(+), 732 deletions(-)
 create mode 100644 gdb/common/common-fork-child.c
 create mode 100644 gdb/common/common-inferior.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e5b0363..e24c66c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1211,6 +1211,7 @@ SFILES = \
 	common/filestuff.c \
 	common/format.c \
 	common/job-control.c \
+	common/common-fork-child.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1498,6 +1499,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_sys_time.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1641,6 +1643,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-debug.o \
 	common-exceptions.o \
 	job-control.o \
+	common-fork-child.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/common-fork-child.c b/gdb/common/common-fork-child.c
new file mode 100644
index 0000000..64dbd0c
--- /dev/null
+++ b/gdb/common/common-fork-child.c
@@ -0,0 +1,547 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "target/waitstatus.h"
+#include "common-terminal.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "signals-state-save-restore.h"
+#include <vector>
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Break up SCRATCH into an argument vector suitable for passing to
+   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
+   would get as input the string "a b c d", and as output it would
+   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+
+static void
+breakup_args_for_exec (const std::string &scratch, std::vector<char *> &argv)
+{
+  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
+    {
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
+
+      /* No separator found, which means this is the last
+	 argument.  */
+      if (next_sep == std::string::npos)
+	next_sep = scratch.size ();
+
+      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
+
+      argv.push_back (xstrdup (arg.c_str ()));
+
+      cur_pos = next_sep;
+    }
+
+  /* NULL-terminating the vector.  */
+  argv.push_back (NULL);
+}
+
+/* When executing a command under the given shell, return non-zero if
+   the '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  const int shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return 0;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return 1;
+
+  return 0;
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_startup_shell (void)
+{
+  static char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* Quote the shell command that will be executed.  This function is
+   called when the inferior is going to be executed under a shell
+   (i.e., when 'startup-with-shell' is set).
+
+   SHELL_FILE is the shell which will be used to execute the inferior
+   (e.g., /bin/sh).
+
+   EXEC_FILE is the inferior executable itself.
+
+   ALLARGS contains all the arguments that will be passed to the
+   inferior.
+
+   EXEC_WRAPPER, if set, is the wrapper that will be used to execute
+   the inferior.
+
+   SHELL_CMD is a pointer to the resulting shell command that will be
+   executed.  The resulting shell command will be returned in it.  It
+   must be pre-allocated and have a reasonable size.  For an example
+   on how to determine its size, see 'fork_inferior' on
+   fork-child.c.  */
+
+static std::string
+quote_shell_command (const char *shell_file, const char *exec_file,
+		     const std::string &allargs, const char *exec_wrapper)
+{
+  std::string shell_command;
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  shell_command = std::string ("exec ");
+
+  /* Add any exec wrapper.  That may be a program name with arguments, so
+     the user must handle quoting.  */
+  if (exec_wrapper)
+    {
+      shell_command += exec_wrapper;
+      shell_command += " ";
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  fprintf (stderr, "exec_file = %s\n", exec_file);
+  /* Quoting in this style is said to work with all shells.  But
+     csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
+     we need to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      shell_command += "'";
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    shell_command += "\\!";
+	  else
+	    shell_command += *p;
+	}
+      shell_command += "'";
+    }
+  else
+    shell_command += exec_file;
+
+  shell_command += " " + allargs;
+
+  return shell_command;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
+
+/* See common/common-inferior.h.  */
+
+int
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (void),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
+	       char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
+{
+  int pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  static int debug_fork = 0;
+  static char *shell_file;
+  static const char *exec_file;
+  char **save_our_env;
+  int shell = 0;
+  std::vector<char *> argv;
+  int i;
+  int save_errno;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  if (exec_file_arg == NULL)
+    exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  shell_file = shell_file_arg;
+  if (startup_with_shell)
+    {
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+      shell = 1;
+    }
+
+  if (!shell)
+    {
+      /* We're going to call execvp.  Create argument vector.  */
+      argv.push_back (xstrdup (exec_file));
+      breakup_args_for_exec (allargs, argv);
+    }
+  else
+    {
+      /* We're going to call a shell.  */
+      std::string shell_command;
+      const char *exec_wrapper = get_exec_wrapper ();
+      size_t len;
+
+      shell_command = quote_shell_command (shell_file, exec_file,
+					   allargs, exec_wrapper);
+
+      /* If we decided above to start up with a shell, we exec the
+	 shell, "-c" says to interpret the next arg as a shell command
+	 to execute, and this command is "exec <target-program>
+	 <args>".  We xstrdup all the strings here because they will
+	 be free'd later in the code.  */
+      argv.push_back (xstrdup (shell_file));
+      argv.push_back (xstrdup ("-c"));
+      argv.push_back (xstrdup (shell_command.c_str ()));
+      argv.push_back (NULL);
+    }
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Perform any necessary actions regarding to TTY before the
+     fork/vfork call.  */
+  prefork_hook (allargs.c_str ());
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Execute any necessary post-fork actions before we exec.  */
+      postfork_child_hook (debug_fork);
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], &argv[0], env);
+      else
+        execvp (argv[0], &argv[0]);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  for (char *el : argv)
+    {
+      /* Free the strings allocated on ARGV.  */
+      xfree (el);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  postfork_hook (pid);
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point, but the pid shouldn't change.  Targets
+     supporting MT should fill this task's ptid with more data as soon
+     as they can.  */
+  add_thread_silent (pid_to_ptid (pid));
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See common/common-inferior.h.  */
+
+ptid_t
+startup_inferior (pid_t pid, int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (pid);
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  return resume_ptid;
+}
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..239cab4
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,123 @@
+/* Variables that describe the inferior process running under GDB and
+   GDBserver: Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+#include <vector>
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+struct inferior;
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
+/* Accept NTRAPS traps from the inferior.
+
+   Return the ptid of the inferior being started.  */
+extern ptid_t startup_inferior (pid_t pid, int ntraps,
+				struct target_waitstatus *mystatus,
+				ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern int fork_inferior (const char *exec_file_arg,
+			  const std::string &allargs,
+			  char **env, void (*traceme_fun) (void),
+			  void (*init_trace_fun) (int),
+			  void (*pre_trace_fun) (void), char *shell_file_arg,
+			  void (*exec_fun) (const char *file,
+					    char * const *argv,
+					    char * const *env));
+
+/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
+   is a string containing all the arguments received by the inferior.
+   This function is mainly used by fork_inferior.  */
+extern void prefork_hook (const char *args);
+
+/* Perform any necessary tasks after a fork/vfork takes place.  This
+   function is mainly used by fork_inferior.  */
+extern void postfork_hook (pid_t pid);
+
+/* Perform any necessary tasks *on the child* after a fork/vfork takes
+   place.  DEBUG_FORK is the number of seconds that we should sleep
+   before exec'ing (see fork_inferior).
+
+   This function is mainly used by fork_inferior.  */
+extern void postfork_child_hook (int debug_fork);
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+extern char *get_startup_shell (void);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern const char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index e94fdc4..6682c51 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -328,3 +328,23 @@ free_vector_argv (std::vector<char *> &v)
 
   v.clear ();
 }
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (const std::vector<char *> &args)
+{
+  std::string ret ("");
+
+  if (!args.empty ())
+    {
+      for (auto s : args)
+	if (s != NULL)
+	  ret += s + std::string (" ");
+
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+    }
+
+  return ret;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index c331f0d..934d207 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -108,4 +108,12 @@ extern const char *skip_to_space_const (const char *inp);
    freeing all the elements.  */
 extern void free_vector_argv (std::vector<char *> &v);
 
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments with a whitespace separating them.  */
+extern std::string stringify_argv (const std::vector<char *> &argv);
+
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err (void);
+
 #endif
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 54cb789..d76fa1a 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 47ec922..2d80ad5 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1790,7 +1790,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 }
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index e586c3e..e111fad 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,386 +21,52 @@
 
 #include "defs.h"
 #include "inferior.h"
+#include "gdbcmd.h"
 #include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
 #include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
-#include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
 #include "top.h"
-#include "signals-state-save-restore.h"
-#include <signal.h>
-#include <vector>
-
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
+#include "filestuff.h"
 
-extern char **environ;
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-static char *exec_wrapper;
+static char *exec_wrapper = NULL;
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+/* See common/common-inferior.h.  */
 
-static void
-breakup_args (const std::string &scratch, std::vector<char *> &argv)
+const char *
+get_exec_wrapper (void)
 {
-  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
-    {
-      /* Skip whitespace-like chars.  */
-      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
-
-      if (pos != std::string::npos)
-	cur_pos = pos;
-
-      /* Find the position of the next separator.  */
-      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
-
-      /* No separator found, which means this is the last
-	 argument.  */
-      if (next_sep == std::string::npos)
-	next_sep = scratch.size ();
-
-      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
-
-      argv.push_back (xstrdup (arg.c_str ()));
-
-      cur_pos = next_sep;
-    }
-
-  /* NULL-terminating the vector.  */
-  argv.push_back (NULL);
+  return exec_wrapper;
 }
 
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static int
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  const int shell_file_len = strlen (shell_file);
+/* The ui structure that will be saved on 'prefork_hook' and
+   restored on 'postfork_hook'.  */
+static struct ui *saved_ui = NULL;
 
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return 0;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return 1;
-
-  return 0;
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
-		                  "process.\nError: ");
-  vfprintf_unfiltered (gdb_stderr, fmt, ap);
-  va_end (ap);
-
-  gdb_flush (gdb_stderr);
-  _exit (0177);
-}
-
-/* See inferior.h.  */
+/* See common/common-inferior.h.  */
 
 void
-trace_start_error_with_name (const char *string)
+prefork_hook (const char *args)
 {
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (const char *exec_file_arg, const std::string &allargs,
-	       char **env, void (*traceme_fun) (void),
-	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
-	       char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static const char *exec_file;
-  char **save_our_env;
-  int shell = 0;
-  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  if (exec_file_arg == NULL)
-    exec_file = get_exec_file (1);
-  else
-    exec_file = exec_file_arg;
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
-  if (startup_with_shell)
-    {
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.  */
-      argv.push_back (xstrdup (exec_file));
-      breakup_args (allargs, argv);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      std::string shell_command;
-      const char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      shell_command = std::string ("exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  shell_command += exec_wrapper;
-	  shell_command += " ";
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  shell_command += "'";
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		shell_command += "'\\''";
-	      else if (*p == '!' && escape_bang)
-		shell_command += "\\!";
-	      else
-		shell_command += *p;
-	    }
-	  shell_command += "'";
-	}
-      else
-	shell_command += exec_file;
-
-      shell_command += " " + allargs;
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  We xstrdup all the strings here because they will
-	 be free'd later in the code.  */
-      argv.push_back (xstrdup (shell_file));
-      argv.push_back (xstrdup ("-c"));
-      argv.push_back (xstrdup (shell_command.c_str ()));
-      argv.push_back (NULL);
-    }
 
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
+  gdb_assert (saved_ui == NULL);
+  /* Retain a copy of our UI, since the child will replace this value
+     and if we're vforked, we have to restore it.  */
+  saved_ui = current_ui;
 
   /* Tell the terminal handling subsystem what tty we plan to run on;
      it will just record the information for later.  */
   new_tty_prefork (inferior_io_terminal);
+}
 
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], &argv[0], env);
-      else
-        execvp (argv[0], &argv[0]);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  free_vector_argv (argv);
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
+/* See common/common-inferior.h.  */
 
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
+void
+postfork_hook (pid_t pid)
+{
+  struct inferior *inf;
 
   if (!have_inferiors ())
     init_thread_list ();
@@ -412,144 +78,64 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   /* Needed for wait_for_inferior stuff below.  */
   inferior_ptid = pid_to_ptid (pid);
 
-  new_tty_postfork ();
+  gdb_assert (saved_ui != NULL);
+  current_ui = saved_ui;
+  saved_ui = NULL;
 
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
+  new_tty_postfork ();
 }
 
-/* Accept NTRAPS traps from the inferior.  */
+/* See common/common-inferior.h.  */
 
 void
-startup_inferior (int ntraps)
+postfork_child_hook (int debug_fork)
 {
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
 
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
+  /* Make sure we switch to main_ui here in order to be able to
+     use the fprintf_unfiltered/warning/error functions.  */
+  current_ui = main_ui;
 
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
+  /* Close all file descriptors except those that gdb inherited
+     (usually 0/1/2), so they don't leak to the inferior.  Note
+     that this closes the file descriptors of all secondary
+     UIs.  */
+  close_most_fds ();
 
-  if (exec_wrapper)
-    pending_execs++;
+  if (debug_fork)
+    sleep (debug_fork);
 
-  while (1)
+  /* Create a new session for the inferior process, if necessary.
+     It will also place the inferior in a separate process group.  */
+  if (create_tty_session () <= 0)
     {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
+      /* No session was created, but we still want to run the inferior
+	 in a separate process group.  */
+      debug_setpgrp = gdb_setpgid ();
+      if (debug_setpgrp == -1)
+	perror (_("setpgrp failed in child"));
     }
 
+  /* Ask the tty subsystem to switch to the one we specified
+     earlier (or to share the current terminal, if none was
+     specified).  */
+  new_tty ();
+}
+
+/* See inferior.h.  */
+
+ptid_t
+gdb_startup_inferior (pid_t pid, int num_traps)
+{
+  ptid_t ptid = startup_inferior (pid, num_traps, NULL, NULL);
+
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  set_executing (ptid, 0);
+
+  return ptid;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 340c9c0..d8d6ff6 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -205,6 +205,7 @@ SFILES = \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
 	$(srcdir)/common/job-control.c \
+	$(srcdir)/common/common-fork-child.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -236,6 +237,7 @@ OBS = \
 	common-debug.o \
 	common-exceptions.o \
 	job-control.o \
+	common-fork-child.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e27cbf8..2e5d4f7 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -415,15 +417,20 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
-/* Add a process to the common process list, and set its private
-   data.  */
+/* Update an existing process represented by PID with the necessary
+   info.  Make sure that the private data structure is allocated, as
+   well as fill the ->arch_private structure if needed.
+
+   This function exists because fork_inferior already creates a
+   process when called, but it is up to us to complete the
+   process_info structure with extra information.  */
 
 static struct process_info *
-linux_add_process (int pid, int attached)
+linux_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
 
-  proc = add_process (pid, attached);
+  gdb_assert (proc != NULL);
   proc->priv = XCNEW (struct process_info_private);
 
   if (the_low_target.new_process != NULL)
@@ -432,6 +439,16 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return linux_update_process (pid);
+}
+
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
 /* Call the target arch_setup function on the current thread.  */
@@ -929,6 +946,33 @@ save_stop_reason (struct lwp_info *lwp)
   return 1;
 }
 
+/* Update the lwp associated to thread represented by PTID.
+
+   This function exists because fork_inferior already calls
+   'add_thread_silent', which creates the 'struct thread_info'.
+   However, we still need to set a few more things on the struct.  */
+
+static struct lwp_info *
+update_thread_lwp (ptid_t ptid)
+{
+  struct lwp_info *lwp;
+  struct thread_info *thread;
+
+  lwp = XCNEW (struct lwp_info);
+
+  lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
+  if (the_low_target.new_thread != NULL)
+    the_low_target.new_thread (lwp);
+
+  thread = find_thread_ptid (ptid);
+  gdb_assert (thread != NULL);
+  thread->target_data = lwp;
+  lwp->thread = thread;
+
+  return lwp;
+}
+
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 {
@@ -946,68 +990,68 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+	trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+	trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+	trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string str_program_args = stringify_argv (program_args);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
-  linux_add_process (pid, 0);
+  linux_update_process (pid);
 
   ptid = ptid_build (pid, pid, 0);
-  new_lwp = add_lwp (ptid);
+  new_lwp = update_thread_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..6040599 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,7 @@
 #include "gdb_wait.h"
 #include <signal.h>
 #include "filestuff.h"
+#include "common-inferior.h"
 
 int using_threads = 1;
 
@@ -208,15 +209,21 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
-/* Call add_process with the given parameters, and initializes
-   the process' private data.  */
+/* Update an existing process represented by PID with the necessary
+   info.  Make sure that the private data structure is allocated, as
+   well as fill the ->arch_private structure if needed.
+
+   This function exists because fork_inferior already creates a
+   process when called, but it is up to us to complete the
+   process_info structure with extra information.  */
 
 static struct process_info *
-lynx_add_process (int pid, int attached)
+lynx_update_process (int pid)
 {
-  struct process_info *proc;
+  struct process_info *proc = find_process_pid (pid);
+
+  gdb_assert (proc != NULL);
 
-  proc = add_process (pid, attached);
   proc->tdesc = lynx_tdesc;
   proc->priv = XCNEW (struct process_info_private);
   proc->priv->last_wait_event_ptid = null_ptid;
@@ -224,41 +231,60 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  add_process (pid, attached);
+  return lynx_update_process (pid);
+}
+
+/* Callback used by fork_inferior to start tracing the inferior.  */
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  if (pgrp < 0)
+    trace_start_error_with_name ("pgrp");
+  if (setpgid (0, pgrp) < 0)
+    trace_start_error_with_name ("setpgid");
+  if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+    trace_start_error_with_name ("ioctl");
+  if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+    trace_start_error_with_name ("lynx_ptrace");
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (const char *program,
+		      const std::vector<char *> &program_args)
 {
   int pid;
+  std::string str_program_args = stringify_argv (program_args);
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program);
 
-  lynx_add_process (pid, 0);
+  lynx_update_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  remove_thread (find_thread_ptid (ptid_build (pid, pid, 0)));
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..a5f1543 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
+   arguments.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (const char *program,
+		     const std::vector<char *> &program_args)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string str_program_args = stringify_argv (program_args);
 
   TRACE ("%s %s\n", __func__, program);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
@@ -367,7 +370,8 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit,
+		(char *) str_program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index b22dfab..31c6a6e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -36,6 +36,19 @@
 #include "dll.h"
 #include "hostio.h"
 #include <vector>
+#include "common-inferior.h"
+#include "common-terminal.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -79,7 +92,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static std::vector<char *> program_argv;
+static char *program_name = NULL;
+static std::vector<char *> program_args;
 static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
@@ -238,25 +252,58 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+const char *
+get_exec_wrapper (void)
 {
-  std::vector<char *> new_argv;
+  static std::string ret;
+  static bool initialized_p = false;
 
-  if (!wrapper_argv.empty ())
-    new_argv.insert (new_argv.begin (),
-		     wrapper_argv.begin (),
-		     wrapper_argv.end ());
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  for (int i = 0; argv[i] != NULL; ++i)
-    new_argv.push_back (argv[i]);
+  if (!initialized_p)
+    {
+      for (auto s : wrapper_argv)
+	ret += s + std::string (" ");
 
-  new_argv.push_back (NULL);
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = true;
+    }
+
+  return ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_name == NULL)
+    error (_("No executable file specified."));
+
+  return program_name;
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See common-inferior.h.  */
 
+void
+prefork_hook (const char *args)
+{
   if (debug_threads)
     {
-      for (int i = 0; i < new_argv.size (); ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      debug_printf ("args: %s\n", args);
       debug_flush ();
     }
 
@@ -265,67 +312,64 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, const char *program)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (!wrapper_argv.empty ())
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
+  startup_inferior (pid, num_traps, &last_status, &last_ptid);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = last_status;
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
+}
 
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
+/* See common/common-inferior.h.  */
 
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+void
+postfork_hook (pid_t pid)
+{
+}
 
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
+/* See common/common-inferior.h.  */
 
-  return signal_pid;
+void
+postfork_child_hook (int debug_fork)
+{
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  /* Close all file descriptors except those that gdb inherited
+     (usually 0/1/2), so they don't leak to the inferior.  Note
+     that this closes the file descriptors of all secondary
+     UIs.  */
+  close_most_fds ();
+
+  debug_setpgrp = gdb_setpgid ();
+  if (debug_setpgrp == -1)
+    perror (_("setpgrp failed in child"));
 }
 
 static int
@@ -2848,6 +2892,7 @@ handle_v_run (char *own_buf)
 {
   char *p, *next_p;
   std::vector<char *> new_argv;
+  char *new_program_name = NULL;
   int i, new_argc;
 
   new_argc = 0;
@@ -2866,42 +2911,95 @@ handle_v_run (char *own_buf)
       if (i == 0 && p == next_p)
 	{
 	  /* No program specified.  */
-	  new_argv.push_back (NULL);
+	  new_program_name = NULL;
+	}
+      else if (p == next_p)
+	{
+	  /* Empty argument.  */
+	  new_argv.push_back ("''");
 	}
       else
 	{
+	  /* FIXME: Fail request if out of memory instead of dying.  */
 	  size_t len = (next_p - p) / 2;
+	  /* ARG is the unquoted argument received via the RSP.  */
 	  char *arg = (char *) xmalloc (len + 1);
+	  /* FULL_ARGS will contain the quoted version of ARG.  */
+	  char *full_arg = (char *) xmalloc ((len + 1) * 2);
+	  /* These are pointers used to navigate the strings above.  */
+	  char *tmp_arg = arg;
+	  char *tmp_full_arg = full_arg;
+	  int need_quote = 0;
 
 	  hex2bin (p, (gdb_byte *) arg, len);
 	  arg[len] = '\0';
-	  new_argv.push_back (arg);
-	}
 
+	  while (*tmp_arg != '\0')
+	    {
+	      switch (*tmp_arg)
+		{
+		case '\n':
+		  /* Quote \n.  */
+		  *tmp_full_arg = '\'';
+		  ++tmp_full_arg;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  /* Quote single quote.  */
+		  *tmp_full_arg = '\\';
+		  ++tmp_full_arg;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_full_arg = *tmp_arg;
+	      ++tmp_full_arg;
+	      ++tmp_arg;
+	    }
+
+	  if (need_quote)
+	    *tmp_full_arg++ = '\'';
+
+	  /* Finish FULL_ARG and push it into the vector containing
+	     the argv.  */
+	  *tmp_full_arg = '\0';
+	  if (i == 0)
+	    new_program_name = full_arg;
+	  else
+	    new_argv.push_back (full_arg);
+	  xfree (arg);
+	}
       if (*next_p)
 	next_p++;
     }
   new_argv.push_back (NULL);
 
-  if (new_argv[0] == NULL)
+  if (new_program_name == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-      if (program_argv.empty ())
+      if (program_name == NULL)
 	{
 	  write_enn (own_buf);
 	  free_vector_argv (new_argv);
 	  return 0;
 	}
-
-      new_argv.push_back (xstrdup (program_argv[0]));
+    }
+  else
+    {
+      xfree (program_name);
+      program_name = new_program_name;
     }
 
   /* Free the old argv and install the new one.  */
-  free_vector_argv (program_argv);
-  program_argv = new_argv;
+  free_vector_argv (program_args);
+  program_args = new_argv;
+
+  create_inferior (program_name, program_args);
 
-  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3661,8 +3759,13 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3676,12 +3779,13 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      for (i = 0; i < n; i++)
-	program_argv.push_back (xstrdup (next_arg[i]));
-      program_argv.push_back (NULL);
+      program_name = xstrdup (next_arg[0]);
+      for (i = 1; i < n; i++)
+	program_args.push_back (xstrdup (next_arg[i]));
+      program_args.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (&program_argv[0]);
+      create_inferior (program_name, program_args);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4296,9 +4400,10 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (!program_argv.empty ())
+	  if (program_name != NULL)
 	    {
-	      start_inferior (&program_argv[0]);
+	      create_inferior (program_name, program_args);
+
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..5087614 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -148,4 +149,13 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and PROGRAM is its name.  */
+extern void post_fork_inferior (int pid, const char *program);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..8ab3c1c 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
+#include "common-inferior.h"
 
 /* Some older glibc versions do not define this.  */
 #ifndef __WNOTHREAD
@@ -261,42 +262,42 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
+
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (const char *program,
+		     const std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string str_program_args = stringify_argv (program_args);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  post_fork_inferior (pid, program);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
-
-  proc = add_process (pid, 0);
+  proc = find_process_pid (pid);
+  gdb_assert (proc != NULL);
   proc->tdesc = tdesc_spu;
 
-  ptid = ptid_build (pid, pid, 0);
-  add_thread (ptid, NULL);
   return pid;
 }
 
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..1e1d193 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..be89258 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -67,13 +68,13 @@ struct target_ops
   /* Start a new process.
 
      PROGRAM is a path to the program to execute.
-     ARGS is a standard NULL-terminated array of arguments,
-     to be passed to the inferior as ``argv''.
+     PROGRAM_ARGS is a standard NULL-terminated array of arguments,
+     to be passed to the inferior as ``argv'' (along with PROGRAM).
 
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
-
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (const char *program,
+			  const std::vector<char *> &program_args);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_args)	\
+  (*the_target->create_inferior) (program, program_args)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..a7a5f81 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,12 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index b4ded31..48804c5 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,6 +19,8 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index d3ddbf5..e4c6fc7 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,13 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM is the program name.
+   PROGRAM_ARGS is the vector containing the inferior's args.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +627,8 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string str_program_args = stringify_argv (program_argv);
+  char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -652,18 +654,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 818be15..25336df 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2162,7 +2162,8 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
+
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 787310d..b754b74 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -112,7 +112,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index bf06ac1..2fa6ae9 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -42,6 +42,7 @@ struct target_desc_info;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 
@@ -132,28 +133,10 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
-extern int fork_inferior (const char *, const std::string &, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
+/* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
+   This function already calls set_executing.  Return the ptid_t from
+   STARTUP_INFERIOR.  */
+extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
 
 extern char *construct_inferior_arguments (int, char **);
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index e8f26be..ca7882b 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4377,7 +4377,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
diff --git a/gdb/target.h b/gdb/target.h
index bc935ef..78b9728 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1538,17 +1538,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1557,12 +1546,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..f12262e 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..68d4d53 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,16 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled (e.g., when the SHELL variable is
+    # unset).
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled, which is the
+    # default behaviour.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/utils.c b/gdb/utils.c
index d7a1993..888445e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3389,6 +3389,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v5 5/5] Implement proper "startup-with-shell" support on gdbserver
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                     ` (3 preceding siblings ...)
  2017-03-30  1:55   ` [PATCH v5 4/5] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-03-30  1:55   ` Sergio Durigan Junior
  4 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-30  1:55 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS (Changes since GDB 7.12): 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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
yyyy-mm-dd  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/NEWS                                      | 12 ++++
 gdb/doc/gdb.texinfo                           | 39 +++++++++++++
 gdb/gdbserver/server.c                        | 38 ++++++++++++-
 gdb/remote.c                                  | 20 +++++++
 gdb/testsuite/gdb.base/startup-with-shell.c   | 29 ++++++++++
 gdb/testsuite/gdb.base/startup-with-shell.exp | 79 +++++++++++++++++++++++++++
 6 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 29ae40c..485b9dd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,15 @@
 
 *** Changes since GDB 7.12
 
+* 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.
+
 * GDB now supports access to the PKU register on GNU/Linux. The register is
   added by the Memory Protection Keys for Userspace feature which will be
   available in future Intel CPUs.
@@ -403,6 +412,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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 300d78e..01059ca 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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}
@@ -36443,6 +36448,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
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 31c6a6e..b9ee471 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -876,6 +876,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      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;
@@ -2312,7 +2337,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 ())
@@ -3419,6 +3444,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"
@@ -3702,6 +3734,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
diff --git a/gdb/remote.c b/gdb/remote.c
index 92e3e6e..05fc4ee 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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)
@@ -14112,6 +14129,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);
 
diff --git a/gdb/testsuite/gdb.base/startup-with-shell.c b/gdb/testsuite/gdb.base/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.c
@@ -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
index 0000000..1284829
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.exp
@@ -0,0 +1,79 @@
+# 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
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+set unique_file [standard_output_file "unique-file.unique-extension"]
+
+# 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-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"unique-file\.unique-extension\"" \
+	"first argument expanded"
+}
+
+with_test_prefix "startup_with_shell = off; run_args = *.unique-extension" {
+    initial_setup_simple "off" "*.unique-extension"
+    gdb_test "print argv\[1\]" "\\\$$decimal = $hex \"\\\*\.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)
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
@ 2017-03-31 17:11     ` Pedro Alves
  2017-03-31 17:31       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-03-31 17:11 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
> gdb/gdbserver/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in (SFILE): Add "common/job-control.c".
> 	(OBS): Add "job-control.o".
> 	* terminal.h: Include "common-terminal.h".

Is there a reason the .h and the .c files are named differently?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver
  2017-03-30  1:50   ` [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
@ 2017-03-31 17:15     ` Pedro Alves
  2017-04-07  2:53       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-03-31 17:15 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
> +struct thread_info *
> +add_thread_silent (ptid_t ptid)
> +{
> +  pid_t pid = ptid_get_pid (ptid);
> +
> +  /* Check if there is a process already.  */
> +  if (find_process_pid (pid) == NULL)
> +    add_process (pid, 0);
> +
> +  return add_thread (ptid_build (pid, pid, 0), NULL);

This ptid_build here is always using the "pid" as
lwpid.  This suggests to me that "add_thread_silent" was not the
right function entry point to share, since we're adding a hack
to one of the implementations.  Either we need a new function,
like "add_initial_thread (pid_t pid)", or maybe we could move the
add_thread_silent call in fork_inferior to the gdb-side, only?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-31 17:11     ` Pedro Alves
@ 2017-03-31 17:31       ` Sergio Durigan Junior
  2017-03-31 18:21         ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-31 17:31 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 31 2017, Pedro Alves wrote:

> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>> gdb/gdbserver/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in (SFILE): Add "common/job-control.c".
>> 	(OBS): Add "job-control.o".
>> 	* terminal.h: Include "common-terminal.h".
>
> Is there a reason the .h and the .c files are named differently?

Hm, it's just because gdb_setpgid was defined on gdb/terminal.h, so I
thought it was better to move it to common-terminal.h (i.e., keep the
naming).  Do you want a common/job-control.h?

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-31 17:31       ` Sergio Durigan Junior
@ 2017-03-31 18:21         ` Pedro Alves
  2017-03-31 21:20           ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-03-31 18:21 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 03/31/2017 06:31 PM, Sergio Durigan Junior wrote:
> On Friday, March 31 2017, Pedro Alves wrote:
> 
>> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>>> gdb/gdbserver/ChangeLog:
>>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>
>>> 	* Makefile.in (SFILE): Add "common/job-control.c".
>>> 	(OBS): Add "job-control.o".
>>> 	* terminal.h: Include "common-terminal.h".
>>
>> Is there a reason the .h and the .c files are named differently?
> 
> Hm, it's just because gdb_setpgid was defined on gdb/terminal.h, so I
> thought it was better to move it to common-terminal.h (i.e., keep the
> naming).  Do you want a common/job-control.h?

So that .h file contains both definitions of symbols that
are the exported API of job-control.c, and also the whole
termios.h/termio.h #ifdefery mess.

It doesn't look like the termios.h stuff is needed by
the _clients_ of the functions defined in job-control.c?

So I think the best is to have two headers instead.

One with the termios.h/termio.h #ifdef-ery stuff,
called common/gdb_termios.h.  That's be similar in spirit
to gdb/gdb_curses.h.  That should only then be included
in files that actually need to see those bits defined.
Maybe job-control.c and inflow.c and not much else.

The "#include <sys/types.h>" include should probably not be
in the resulting gdb_termios.h.  I can't see why it's there
in your common-terminal.h.

And then add a new common/job-control.h header that matches the
new job-control.c file, that _only_ exports job-control.c's
public interface, like, these three declarations:

 extern int job_control;
 extern int gdb_setpgid ();
 extern void have_job_control ();

Also, it looks like gdbserver's terminal.h has all the same
termios goo that you were putting in common-terminal.h.
We should remove/undup all that.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-31 18:21         ` Pedro Alves
@ 2017-03-31 21:20           ` Sergio Durigan Junior
  2017-04-07 17:51             ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-03-31 21:20 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 31 2017, Pedro Alves wrote:

> On 03/31/2017 06:31 PM, Sergio Durigan Junior wrote:
>> On Friday, March 31 2017, Pedro Alves wrote:
>> 
>>> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>>>> gdb/gdbserver/ChangeLog:
>>>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>>>>
>>>> 	* Makefile.in (SFILE): Add "common/job-control.c".
>>>> 	(OBS): Add "job-control.o".
>>>> 	* terminal.h: Include "common-terminal.h".
>>>
>>> Is there a reason the .h and the .c files are named differently?
>> 
>> Hm, it's just because gdb_setpgid was defined on gdb/terminal.h, so I
>> thought it was better to move it to common-terminal.h (i.e., keep the
>> naming).  Do you want a common/job-control.h?
>
> So that .h file contains both definitions of symbols that
> are the exported API of job-control.c, and also the whole
> termios.h/termio.h #ifdefery mess.
>
> It doesn't look like the termios.h stuff is needed by
> the _clients_ of the functions defined in job-control.c?
>
> So I think the best is to have two headers instead.
>
> One with the termios.h/termio.h #ifdef-ery stuff,
> called common/gdb_termios.h.  That's be similar in spirit
> to gdb/gdb_curses.h.  That should only then be included
> in files that actually need to see those bits defined.
> Maybe job-control.c and inflow.c and not much else.
>
> The "#include <sys/types.h>" include should probably not be
> in the resulting gdb_termios.h.  I can't see why it's there
> in your common-terminal.h.
>
> And then add a new common/job-control.h header that matches the
> new job-control.c file, that _only_ exports job-control.c's
> public interface, like, these three declarations:
>
>  extern int job_control;
>  extern int gdb_setpgid ();
>  extern void have_job_control ();

Thanks, it makes sense to separate like this, indeed.

> Also, it looks like gdbserver's terminal.h has all the same
> termios goo that you were putting in common-terminal.h.
> We should remove/undup all that.

Yeah, after a closer look I noticed that the code is just a simplified
version of what's already done on the GDB side (now under common/).  So
I went ahead and deleted the gdbserver file.

Thanks for this review, I implemented everything you mentioned on this
message but will wait until you review the other parts before I send the
v6.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver
  2017-03-31 17:15     ` Pedro Alves
@ 2017-04-07  2:53       ` Sergio Durigan Junior
  2017-04-07 17:33         ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-07  2:53 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 31 2017, Pedro Alves wrote:

> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>> +struct thread_info *
>> +add_thread_silent (ptid_t ptid)
>> +{
>> +  pid_t pid = ptid_get_pid (ptid);
>> +
>> +  /* Check if there is a process already.  */
>> +  if (find_process_pid (pid) == NULL)
>> +    add_process (pid, 0);
>> +
>> +  return add_thread (ptid_build (pid, pid, 0), NULL);
>
> This ptid_build here is always using the "pid" as
> lwpid.  This suggests to me that "add_thread_silent" was not the
> right function entry point to share, since we're adding a hack
> to one of the implementations.  Either we need a new function,
> like "add_initial_thread (pid_t pid)", or maybe we could move the
> add_thread_silent call in fork_inferior to the gdb-side, only?

OOC, could you expand on why using pid as the lwpid means that this is a
hack?

On a side note, it seems from your comment that the best alternative
would be to move the add_thread_silent call to the GDB-specific
postfork_hook, and undo the changes on gdbserver/{linux,lynx}-low.c that
add the "*_update_process" functions.  This would mean that, on GDB, the
prefork_hook would always call add_thread_silent, but on gdbserver each
target would be responsible for adding the process/thread after calling
fork_inferior.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver
  2017-04-07  2:53       ` Sergio Durigan Junior
@ 2017-04-07 17:33         ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-04-07 17:33 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 04/07/2017 03:53 AM, Sergio Durigan Junior wrote:
> On Friday, March 31 2017, Pedro Alves wrote:
> 
>> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>>> +struct thread_info *
>>> +add_thread_silent (ptid_t ptid)
>>> +{
>>> +  pid_t pid = ptid_get_pid (ptid);
>>> +
>>> +  /* Check if there is a process already.  */
>>> +  if (find_process_pid (pid) == NULL)
>>> +    add_process (pid, 0);
>>> +
>>> +  return add_thread (ptid_build (pid, pid, 0), NULL);
>>
>> This ptid_build here is always using the "pid" as
>> lwpid.  This suggests to me that "add_thread_silent" was not the
>> right function entry point to share, since we're adding a hack
>> to one of the implementations.  Either we need a new function,
>> like "add_initial_thread (pid_t pid)", or maybe we could move the
>> add_thread_silent call in fork_inferior to the gdb-side, only?
> 
> OOC, could you expand on why using pid as the lwpid means that this is a
> hack?

Sure.  The function's purpose is creating a thread with a given
PTID, but while that is what currently happens on the gdb side, and
you're not changing it, the new implementation on the gdbserver side
ignores the ptid's fields except the PID.  It'd be reasonable for
some other future shared bits of code to call add_thread_silent on
other contexts with the lwp/tid fields of ptid filled in,
but it wouldn't work because of this hack.  Trying to fix that
issue when we stumble into this by making gdbserver's implementation
NOT ignore the passed-in ptid wouldn't work because it'd break the
fork-child path.  That's force us to fix it properly then and revisit
this exact issue we're discussing.  So I'd rather address it now,
upfront.

Note, while the right ptid for the initial thread for
Linux is "(pid,pid,0)", that's not the case for all/other ports.
So that hack above is also baking in a Linux-ism that happens to
work because gdbserver has fewer Unix-like ports than GDB.

> 
> On a side note, it seems from your comment that the best alternative
> would be to move the add_thread_silent call to the GDB-specific
> postfork_hook, and undo the changes on gdbserver/{linux,lynx}-low.c that
> add the "*_update_process" functions.  This would mean that, on GDB, the
> prefork_hook would always call add_thread_silent, but on gdbserver each
> target would be responsible for adding the process/thread after calling
> fork_inferior.

It'd be nice to be able to normalize the APIs between gdb and gdbserver.

It sounds like if we make each target responsible for adding the right main
thread after fork_inferior returns on the gdb side too, then we'll be able
to get rid of this hack in linux-nat.c:linux_nat_wait_1 while at it:

  /* The first time we get here after starting a new inferior, we may
     not have added it to the LWP list yet - this is the earliest
     moment at which we know its PID.  */
  if (ptid_is_pid (inferior_ptid))
    {
      /* Upgrade the main thread's ptid.  */
      thread_change_ptid (inferior_ptid,
			  ptid_build (ptid_get_pid (inferior_ptid),
				      ptid_get_pid (inferior_ptid), 0));

      lp = add_initial_lwp (inferior_ptid);
      lp->resumed = 1;
    }

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-03-31 21:20           ` Sergio Durigan Junior
@ 2017-04-07 17:51             ` Pedro Alves
  2017-04-12  0:25               ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-07 17:51 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 03/31/2017 10:20 PM, Sergio Durigan Junior wrote:
> On Friday, March 31 2017, Pedro Alves wrote:

>> So that .h file contains both definitions of symbols that
>> are the exported API of job-control.c, and also the whole
>> termios.h/termio.h #ifdefery mess.
>>
>> It doesn't look like the termios.h stuff is needed by
>> the _clients_ of the functions defined in job-control.c?
>>
>> So I think the best is to have two headers instead.
>>
>> One with the termios.h/termio.h #ifdef-ery stuff,
>> called common/gdb_termios.h.  That's be similar in spirit
>> to gdb/gdb_curses.h.  That should only then be included
>> in files that actually need to see those bits defined.
>> Maybe job-control.c and inflow.c and not much else.
>>
>> The "#include <sys/types.h>" include should probably not be
>> in the resulting gdb_termios.h.  I can't see why it's there
>> in your common-terminal.h.
>>
>> And then add a new common/job-control.h header that matches the
>> new job-control.c file, that _only_ exports job-control.c's
>> public interface, like, these three declarations:
>>
>>  extern int job_control;
>>  extern int gdb_setpgid ();
>>  extern void have_job_control ();
> 
> Thanks, it makes sense to separate like this, indeed.
> 
>> Also, it looks like gdbserver's terminal.h has all the same
>> termios goo that you were putting in common-terminal.h.
>> We should remove/undup all that.
> 
> Yeah, after a closer look I noticed that the code is just a simplified
> version of what's already done on the GDB side (now under common/).  So
> I went ahead and deleted the gdbserver file.
> 
> Thanks for this review, I implemented everything you mentioned on this
> message but will wait until you review the other parts before I send the
> v6.

Note that if you extract the
 gdb/terminal.h / gdbserver/terminal.h
   => common/gdb_termios.h 
part (including the corresponding common.m4 bits) into its own preparatory
patch, and post it separately, we can get that merged and out of the way
quickly.  That part stands on its own right.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior
  2017-03-30  1:50   ` [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior Sergio Durigan Junior
@ 2017-04-07 18:30     ` Pedro Alves
  2017-04-12  0:24       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-07 18:30 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
> As a preparation for the next patch, which will move fork_inferior
> from GDB to common/ (and therefore share it with gdbserver), it is
> interesting to convert a few functions to C++.

I've meanwhile realized that fork_inferior should move to "nat/",
not "common/" ...  This is code only used by the native targets.
Sorry for not pointing it out sooner...  :-/.

> This patch touches functions related to parsing command-line arguments
> to the inferior (see gdb/fork-child.c:breakup_args), the way the
> arguments are stored on fork_inferior (using std::vector instead of
> char **), and the code responsible for dealing with argv also on
> gdbserver.
> 
> I've taken this opportunity and decided to constify a few arguments to
> fork_inferior/create_inferior as well, in order to make the code
> cleaner.  And now, on gdbserver, we're using xstrdup everywhere and
> aren't checking for memory allocation failures anymore, as requested
> by Pedro.

It'd be good to say here _why_ that's the right thing to do.

I.e., write to the future hacker doing archaeology.

> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -1,4 +1,4 @@
> -/* Fork a Unix child process, and set up to debug it, for GDB.
> + /* Fork a Unix child process, and set up to debug it, for GDB.

Spurious whitespace change.

>  static void
> -breakup_args (char *scratch, char **argv)
> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>  {

...

> +
> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
> +

This creates a temporary string (heap allocates) ...

> +      argv.push_back (xstrdup (arg.c_str ()));

... and here you create yet another copy.

You should be able to avoid it by using e.g., savestring:

    char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
    argv.push_back (arg);

> +
> +      cur_pos = next_sep;
>      }
>  
> -  /* Null-terminate the vector.  */
> -  *argv = NULL;
> +  /* NULL-terminating the vector.  */

FYI, the non-gerund version of the text reads as more
natural English to me.

> +  argv.push_back (NULL);
>  }
>  


> --- a/gdb/go32-nat.c
> +++ b/gdb/go32-nat.c
> @@ -631,8 +631,9 @@ go32_kill_inferior (struct target_ops *ops)
>  }
>  
>  static void
> -go32_create_inferior (struct target_ops *ops, char *exec_file,
> -		      char *args, char **env, int from_tty)
> +go32_create_inferior (struct target_ops *ops,
> +		      const char *exec_file,
> +		      const std::string &allargs, char **env, int from_tty)
>  {
>    extern char **environ;
>    jmp_buf start_state;
> @@ -641,6 +642,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
>    size_t cmdlen;
>    struct inferior *inf;
>    int result;
> +  char *args = (char *) allargs.c_str ();

AFAICS, this could be const.


Note that when you really need to append a single character,
it's a tiny bit more efficient to write what you mean:

        shell_command += ' ';

instead of appending a string that happens to have one character:

+         shell_command += " ";
+         shell_command += "'";

because the later means you're calling the operator+= overload that
needs to handle / count the string length.


I saw a few of those in the patch.

Anyway, with those addressed and with any missing xstrdup
that -Wwrite-string may have flagged added, this is good to
go.

I believe this stands on its own and doesn't have any dependency
on the previous patches, so please go ahead and push.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior
  2017-04-07 18:30     ` Pedro Alves
@ 2017-04-12  0:24       ` Sergio Durigan Junior
  2017-04-12  5:04         ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12  0:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, April 07 2017, Pedro Alves wrote:

> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>> As a preparation for the next patch, which will move fork_inferior
>> from GDB to common/ (and therefore share it with gdbserver), it is
>> interesting to convert a few functions to C++.
>
> I've meanwhile realized that fork_inferior should move to "nat/",
> not "common/" ...  This is code only used by the native targets.
> Sorry for not pointing it out sooner...  :-/.

Alright.  I'll address that in the next version, thanks for the
heads-up.  I won't rename the file in this case, leaving it as
"nat/fork-child.c".

>> This patch touches functions related to parsing command-line arguments
>> to the inferior (see gdb/fork-child.c:breakup_args), the way the
>> arguments are stored on fork_inferior (using std::vector instead of
>> char **), and the code responsible for dealing with argv also on
>> gdbserver.
>> 
>> I've taken this opportunity and decided to constify a few arguments to
>> fork_inferior/create_inferior as well, in order to make the code
>> cleaner.  And now, on gdbserver, we're using xstrdup everywhere and
>> aren't checking for memory allocation failures anymore, as requested
>> by Pedro.
>
> It'd be good to say here _why_ that's the right thing to do.

Sure, I'll copy-and-adjust your rationale from the last message.

> I.e., write to the future hacker doing archaeology.
>
>> --- a/gdb/fork-child.c
>> +++ b/gdb/fork-child.c
>> @@ -1,4 +1,4 @@
>> -/* Fork a Unix child process, and set up to debug it, for GDB.
>> + /* Fork a Unix child process, and set up to debug it, for GDB.
>
> Spurious whitespace change.

Fixed.

>>  static void
>> -breakup_args (char *scratch, char **argv)
>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>  {
>
> ...
>
>> +
>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>> +
>
> This creates a temporary string (heap allocates) ...
>
>> +      argv.push_back (xstrdup (arg.c_str ()));
>
> ... and here you create yet another copy.
>
> You should be able to avoid it by using e.g., savestring:
>
>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>     argv.push_back (arg);

Fair enough.  I had my mind on "C++-only mode" when writing this code.

>> +
>> +      cur_pos = next_sep;
>>      }
>>  
>> -  /* Null-terminate the vector.  */
>> -  *argv = NULL;
>> +  /* NULL-terminating the vector.  */
>
> FYI, the non-gerund version of the text reads as more
> natural English to me.

Reverted.

>> +  argv.push_back (NULL);
>>  }
>>  
>
>
>> --- a/gdb/go32-nat.c
>> +++ b/gdb/go32-nat.c
>> @@ -631,8 +631,9 @@ go32_kill_inferior (struct target_ops *ops)
>>  }
>>  
>>  static void
>> -go32_create_inferior (struct target_ops *ops, char *exec_file,
>> -		      char *args, char **env, int from_tty)
>> +go32_create_inferior (struct target_ops *ops,
>> +		      const char *exec_file,
>> +		      const std::string &allargs, char **env, int from_tty)
>>  {
>>    extern char **environ;
>>    jmp_buf start_state;
>> @@ -641,6 +642,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
>>    size_t cmdlen;
>>    struct inferior *inf;
>>    int result;
>> +  char *args = (char *) allargs.c_str ();
>
> AFAICS, this could be const.

Right, fixed.

> Note that when you really need to append a single character,
> it's a tiny bit more efficient to write what you mean:
>
>         shell_command += ' ';
>
> instead of appending a string that happens to have one character:
>
> +         shell_command += " ";
> +         shell_command += "'";
>
> because the later means you're calling the operator+= overload that
> needs to handle / count the string length.
>
>
> I saw a few of those in the patch.

Hm, indeed.  Fixed.

> Anyway, with those addressed and with any missing xstrdup
> that -Wwrite-string may have flagged added, this is good to
> go.
>
> I believe this stands on its own and doesn't have any dependency
> on the previous patches, so please go ahead and push.

OK, thanks.  I'll work on patch 1/5 and get that out of the way first,
and the I'll push this in.

Thanks!

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 1/5] Move parts of inferior job control to common/
  2017-04-07 17:51             ` Pedro Alves
@ 2017-04-12  0:25               ` Sergio Durigan Junior
  2017-04-12  1:17                 ` [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h) Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12  0:25 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, April 07 2017, Pedro Alves wrote:

> On 03/31/2017 10:20 PM, Sergio Durigan Junior wrote:
>> On Friday, March 31 2017, Pedro Alves wrote:
>
>>> So that .h file contains both definitions of symbols that
>>> are the exported API of job-control.c, and also the whole
>>> termios.h/termio.h #ifdefery mess.
>>>
>>> It doesn't look like the termios.h stuff is needed by
>>> the _clients_ of the functions defined in job-control.c?
>>>
>>> So I think the best is to have two headers instead.
>>>
>>> One with the termios.h/termio.h #ifdef-ery stuff,
>>> called common/gdb_termios.h.  That's be similar in spirit
>>> to gdb/gdb_curses.h.  That should only then be included
>>> in files that actually need to see those bits defined.
>>> Maybe job-control.c and inflow.c and not much else.
>>>
>>> The "#include <sys/types.h>" include should probably not be
>>> in the resulting gdb_termios.h.  I can't see why it's there
>>> in your common-terminal.h.
>>>
>>> And then add a new common/job-control.h header that matches the
>>> new job-control.c file, that _only_ exports job-control.c's
>>> public interface, like, these three declarations:
>>>
>>>  extern int job_control;
>>>  extern int gdb_setpgid ();
>>>  extern void have_job_control ();
>> 
>> Thanks, it makes sense to separate like this, indeed.
>> 
>>> Also, it looks like gdbserver's terminal.h has all the same
>>> termios goo that you were putting in common-terminal.h.
>>> We should remove/undup all that.
>> 
>> Yeah, after a closer look I noticed that the code is just a simplified
>> version of what's already done on the GDB side (now under common/).  So
>> I went ahead and deleted the gdbserver file.
>> 
>> Thanks for this review, I implemented everything you mentioned on this
>> message but will wait until you review the other parts before I send the
>> v6.
>
> Note that if you extract the
>  gdb/terminal.h / gdbserver/terminal.h
>    => common/gdb_termios.h 
> part (including the corresponding common.m4 bits) into its own preparatory
> patch, and post it separately, we can get that merged and out of the way
> quickly.  That part stands on its own right.

OK, I'll do that now.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h)
  2017-04-12  0:25               ` Sergio Durigan Junior
@ 2017-04-12  1:17                 ` Sergio Durigan Junior
  2017-04-12 10:28                   ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12  1:17 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

As requested, I'm sending this as a separate patch because it is ready
to be included as-is.

The idea here is that both gdb/terminal.h and gdb/gdbserver/terminal.h
share the same code, which is responsible for setting a bunch of
defines on based on the presence of termios.h and a few other headers.
This simple patch just moves this common code to common/gdb_termios.h
and makes the necessary adjustments on both GDB and gdbserver so that
they can use this new header.  It also implements the some header
checks on common/common.m4.

As a bonus, gdb/gdbserver/terminal.h can be removed because it's now
empty.

Built on x86_64, no regressions found.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/gdb_termios.h".
	* common/common.m4: Check headers 'termios.h', 'termio.h' and
	'sgtty.h'.
	* common/gdb_termios.h: New file, with parts of "terminal.h".
	* inflow.c: Include "gdb_termios.h".
	* ser-unix.c: Include "gdb_termios.h".
	* terminal.h: Move terminal-related defines to
	"common/gdb_termios.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

        * remote-utils.c: Include "gdb_termios.h" instead of
        "terminal.h".
        * terminal.h: Delete file.
---
 gdb/Makefile.in              |  1 +
 gdb/common/common.m4         |  3 +-
 gdb/common/gdb_termios.h     | 78 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/remote-utils.c |  2 +-
 gdb/gdbserver/terminal.h     | 51 -----------------------------
 gdb/inflow.c                 |  1 +
 gdb/inflow.h                 |  2 +-
 gdb/ser-unix.c               |  1 +
 gdb/terminal.h               | 57 --------------------------------
 9 files changed, 85 insertions(+), 111 deletions(-)
 create mode 100644 gdb/common/gdb_termios.h
 delete mode 100644 gdb/gdbserver/terminal.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 23e4bed..847deb0 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1496,6 +1496,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_setjmp.h \
 	common/gdb_signals.h \
 	common/gdb_sys_time.h \
+	common/gdb_termios.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
 	common/host-defs.h \
diff --git a/gdb/common/common.m4 b/gdb/common/common.m4
index e21e6e5..45726ab 100644
--- a/gdb/common/common.m4
+++ b/gdb/common/common.m4
@@ -28,7 +28,8 @@ AC_DEFUN([GDB_AC_COMMON], [
   AC_CHECK_HEADERS(linux/perf_event.h locale.h memory.h signal.h dnl
 		   sys/resource.h sys/socket.h sys/syscall.h dnl
 		   sys/un.h sys/wait.h dnl
-		   thread_db.h wait.h)
+		   thread_db.h wait.h dnl
+		   termios.h termio.h sgtty.h)
 
   AC_CHECK_FUNCS([fdwalk getrlimit pipe pipe2 socketpair sigaction])
 
diff --git a/gdb/common/gdb_termios.h b/gdb/common/gdb_termios.h
new file mode 100644
index 0000000..1d0544d
--- /dev/null
+++ b/gdb/common/gdb_termios.h
@@ -0,0 +1,78 @@
+/* Common terminal interface definitions for GDB and gdbserver.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef GDB_TERMIOS_H
+#define GDB_TERMIOS_H
+
+/* If we're using autoconf, it will define HAVE_TERMIOS_H,
+   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
+   ser-unix.c and inflow.c to inspect those names instead of
+   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
+   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
+   nothing has already defined the one of the names, and do the right
+   thing.  */
+
+#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
+#if defined(HAVE_TERMIOS_H)
+#define HAVE_TERMIOS
+#else /* ! defined (HAVE_TERMIOS_H) */
+#if defined(HAVE_TERMIO_H)
+#define HAVE_TERMIO
+#else /* ! defined (HAVE_TERMIO_H) */
+#if defined(HAVE_SGTTY_H)
+#define HAVE_SGTTY
+#endif /* ! defined (HAVE_SGTTY_H) */
+#endif /* ! defined (HAVE_TERMIO_H) */
+#endif /* ! defined (HAVE_TERMIOS_H) */
+#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
+	  !defined (HAVE_SGTTY) */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
+
+/* Define a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  FIXME: serial.h and
+   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
+   is converted to use them, can get rid of this crap.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#else /* sgtty */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* sgtty */
+#endif
+
+#endif /* ! GDB_TERMIOS_H */
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 37a6402..25b7e41 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -17,7 +17,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
-#include "terminal.h"
+#include "gdb_termios.h"
 #include "target.h"
 #include "gdbthread.h"
 #include "tdesc.h"
diff --git a/gdb/gdbserver/terminal.h b/gdb/gdbserver/terminal.h
deleted file mode 100644
index 3bdd5f5..0000000
--- a/gdb/gdbserver/terminal.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Terminal interface definitions for the GDB remote server.
-   Copyright (C) 2002-2017 Free Software Foundation, Inc.
-
-   This file is part of GDB.
-
-   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/>.  */
-
-#if !defined (TERMINAL_H)
-#define TERMINAL_H 1
-
-/* Autoconf will have defined HAVE_TERMIOS_H, HAVE_TERMIO_H,
-   and HAVE_SGTTY_H for us as appropriate.  */
-
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#include <termios.h>
-#else /* ! HAVE_TERMIOS_H */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-#else /* ! HAVE_TERMIO_H */
-#ifdef HAVE_SGTTY_H
-#define HAVE_SGTTY
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-#endif
-#endif
-#endif
-
-#endif /* !defined (TERMINAL_H) */
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 7ffa83a..23dcc4d 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -31,6 +31,7 @@
 
 #include "inflow.h"
 #include "gdbcmd.h"
+#include "gdb_termios.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
diff --git a/gdb/inflow.h b/gdb/inflow.h
index 90ac4d6..428aed4 100644
--- a/gdb/inflow.h
+++ b/gdb/inflow.h
@@ -20,7 +20,7 @@
 #ifndef INFLOW_H
 #define INFLOW_H
 
-#include "terminal.h"		/* For HAVE_TERMIOS et.al.  */
+#include "gdb_termios.h"
 
 #ifdef HAVE_TERMIOS
 # define PROCESS_GROUP_TYPE pid_t
diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c
index 5c93891..54b0b75 100644
--- a/gdb/ser-unix.c
+++ b/gdb/ser-unix.c
@@ -31,6 +31,7 @@
 #include "gdb_select.h"
 #include "gdbcmd.h"
 #include "filestuff.h"
+#include "gdb_termios.h"
 
 #ifdef HAVE_TERMIOS
 
diff --git a/gdb/terminal.h b/gdb/terminal.h
index d8691b2..fb20ae0 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -19,63 +19,6 @@
 #if !defined (TERMINAL_H)
 #define TERMINAL_H 1
 
-
-/* If we're using autoconf, it will define HAVE_TERMIOS_H,
-   HAVE_TERMIO_H and HAVE_SGTTY_H for us.  One day we can rewrite
-   ser-unix.c and inflow.c to inspect those names instead of
-   HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither
-   HAVE_TERMIOS or HAVE_TERMIO is set).  Until then, make sure that
-   nothing has already defined the one of the names, and do the right
-   thing.  */
-
-#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY)
-#if defined(HAVE_TERMIOS_H)
-#define HAVE_TERMIOS
-#else /* ! defined (HAVE_TERMIOS_H) */
-#if defined(HAVE_TERMIO_H)
-#define HAVE_TERMIO
-#else /* ! defined (HAVE_TERMIO_H) */
-#if defined(HAVE_SGTTY_H)
-#define HAVE_SGTTY
-#endif /* ! defined (HAVE_SGTTY_H) */
-#endif /* ! defined (HAVE_TERMIO_H) */
-#endif /* ! defined (HAVE_TERMIOS_H) */
-#endif /* !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) &&
-	  !defined (HAVE_SGTTY) */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-
-#if !defined(_WIN32) && !defined (HAVE_TERMIOS)
-
-/* Define a common set of macros -- BSD based -- and redefine whatever
-   the system offers to make it look like that.  FIXME: serial.h and
-   ser-*.c deal with this in a much cleaner fashion; as soon as stuff
-   is converted to use them, can get rid of this crap.  */
-
-#ifdef HAVE_TERMIO
-
-#include <termio.h>
-
-#undef TIOCGETP
-#define TIOCGETP TCGETA
-#undef TIOCSETN
-#define TIOCSETN TCSETA
-#undef TIOCSETP
-#define TIOCSETP TCSETAF
-#define TERMINAL struct termio
-
-#else /* sgtty */
-
-#include <fcntl.h>
-#include <sgtty.h>
-#include <sys/ioctl.h>
-#define TERMINAL struct sgttyb
-
-#endif /* sgtty */
-#endif
-
 struct inferior;
 
 extern void new_tty_prefork (const char *);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior
  2017-04-12  0:24       ` Sergio Durigan Junior
@ 2017-04-12  5:04         ` Sergio Durigan Junior
  2017-04-12  5:19           ` [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior) Sergio Durigan Junior
                             ` (2 more replies)
  0 siblings, 3 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12  5:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

[-- Attachment #1: Type: text/plain, Size: 4548 bytes --]

On Tuesday, April 11 2017, I wrote:

> On Friday, April 07 2017, Pedro Alves wrote:
>
>> On 03/30/2017 02:49 AM, Sergio Durigan Junior wrote:
>>> As a preparation for the next patch, which will move fork_inferior
>>> from GDB to common/ (and therefore share it with gdbserver), it is
>>> interesting to convert a few functions to C++.
>>
>> I've meanwhile realized that fork_inferior should move to "nat/",
>> not "common/" ...  This is code only used by the native targets.
>> Sorry for not pointing it out sooner...  :-/.
>
> Alright.  I'll address that in the next version, thanks for the
> heads-up.  I won't rename the file in this case, leaving it as
> "nat/fork-child.c".
>
>>> This patch touches functions related to parsing command-line arguments
>>> to the inferior (see gdb/fork-child.c:breakup_args), the way the
>>> arguments are stored on fork_inferior (using std::vector instead of
>>> char **), and the code responsible for dealing with argv also on
>>> gdbserver.
>>> 
>>> I've taken this opportunity and decided to constify a few arguments to
>>> fork_inferior/create_inferior as well, in order to make the code
>>> cleaner.  And now, on gdbserver, we're using xstrdup everywhere and
>>> aren't checking for memory allocation failures anymore, as requested
>>> by Pedro.
>>
>> It'd be good to say here _why_ that's the right thing to do.
>
> Sure, I'll copy-and-adjust your rationale from the last message.
>
>> I.e., write to the future hacker doing archaeology.
>>
>>> --- a/gdb/fork-child.c
>>> +++ b/gdb/fork-child.c
>>> @@ -1,4 +1,4 @@
>>> -/* Fork a Unix child process, and set up to debug it, for GDB.
>>> + /* Fork a Unix child process, and set up to debug it, for GDB.
>>
>> Spurious whitespace change.
>
> Fixed.
>
>>>  static void
>>> -breakup_args (char *scratch, char **argv)
>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>  {
>>
>> ...
>>
>>> +
>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>> +
>>
>> This creates a temporary string (heap allocates) ...
>>
>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>
>> ... and here you create yet another copy.
>>
>> You should be able to avoid it by using e.g., savestring:
>>
>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>     argv.push_back (arg);
>
> Fair enough.  I had my mind on "C++-only mode" when writing this code.
>
>>> +
>>> +      cur_pos = next_sep;
>>>      }
>>>  
>>> -  /* Null-terminate the vector.  */
>>> -  *argv = NULL;
>>> +  /* NULL-terminating the vector.  */
>>
>> FYI, the non-gerund version of the text reads as more
>> natural English to me.
>
> Reverted.
>
>>> +  argv.push_back (NULL);
>>>  }
>>>  
>>
>>
>>> --- a/gdb/go32-nat.c
>>> +++ b/gdb/go32-nat.c
>>> @@ -631,8 +631,9 @@ go32_kill_inferior (struct target_ops *ops)
>>>  }
>>>  
>>>  static void
>>> -go32_create_inferior (struct target_ops *ops, char *exec_file,
>>> -		      char *args, char **env, int from_tty)
>>> +go32_create_inferior (struct target_ops *ops,
>>> +		      const char *exec_file,
>>> +		      const std::string &allargs, char **env, int from_tty)
>>>  {
>>>    extern char **environ;
>>>    jmp_buf start_state;
>>> @@ -641,6 +642,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
>>>    size_t cmdlen;
>>>    struct inferior *inf;
>>>    int result;
>>> +  char *args = (char *) allargs.c_str ();
>>
>> AFAICS, this could be const.
>
> Right, fixed.
>
>> Note that when you really need to append a single character,
>> it's a tiny bit more efficient to write what you mean:
>>
>>         shell_command += ' ';
>>
>> instead of appending a string that happens to have one character:
>>
>> +         shell_command += " ";
>> +         shell_command += "'";
>>
>> because the later means you're calling the operator+= overload that
>> needs to handle / count the string length.
>>
>>
>> I saw a few of those in the patch.
>
> Hm, indeed.  Fixed.
>
>> Anyway, with those addressed and with any missing xstrdup
>> that -Wwrite-string may have flagged added, this is good to
>> go.
>>
>> I believe this stands on its own and doesn't have any dependency
>> on the previous patches, so please go ahead and push.
>
> OK, thanks.  I'll work on patch 1/5 and get that out of the way first,
> and the I'll push this in.

Oh, well.  I went ahead and pushed it now.  No reason to wait.

Here's what I pushed.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-C-fy-and-prepare-for-sharing-fork_inferior.patch --]
[-- Type: text/x-patch, Size: 34520 bytes --]

From 7c5ded6a00c4817d56cdf04fbc1969bc33b2a930 Mon Sep 17 00:00:00 2001
From: Sergio Durigan Junior <sergiodj@redhat.com>
Date: Wed, 22 Mar 2017 21:54:49 -0400
Subject: [PATCH] C++-fy and prepare for sharing fork_inferior

As a preparation for the next patch, which will move fork_inferior
from GDB to common/ (and therefore share it with gdbserver), it is
interesting to convert a few functions to C++.

This patch touches functions related to parsing command-line arguments
to the inferior (see gdb/fork-child.c:breakup_args), the way the
arguments are stored on fork_inferior (using std::vector instead of
char **), and the code responsible for dealing with argv also on
gdbserver.

I've taken this opportunity and decided to constify a few arguments to
fork_inferior/create_inferior as well, in order to make the code
cleaner.  And now, on gdbserver, we're using xstrdup everywhere and
aren't checking for memory allocation failures anymore, as requested
by Pedro:

  <https://sourceware.org/ml/gdb-patches/2017-03/msg00191.html>
  Message-Id: <025ebdb9-90d9-d54a-c055-57ed2406b812@redhat.com>

  Pedro Alves wrote:

  > On the "== NULL" check: IIUC, the old NULL check was there to
  > handle strdup returning NULL due to out-of-memory.
  > See NULL checks and comments further above in this function.
  > Now that you're using a std::vector, that doesn't work or make
  > sense any longer, since if push_back fails to allocate space for
  > its internal buffer (with operator new), our operator new replacement
  > (common/new-op.c) calls malloc_failure, which aborts gdbserver.
  >
  > Not sure it makes sense to handle out-of-memory specially in
  > the gdb/rsp-facing functions nowadays (maybe git blame/log/patch
  > submission for that code shows some guidelines).  Maybe (or, probably)
  > it's OK to stop caring about it, but then we should consistently remove
  > left over code, by using xstrdup instead and remove the NULL checks.

IMO this refactoring was very good to increase the readability of the
code as well, because some parts of the argument handling were
unnecessarily confusing before.

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

	* common/common-utils.c (free_vector_argv): New function.
	* common/common-utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	* darwin-nat.c (darwin_create_inferior): Rewrite function
	prototype in order to constify "exec_file" and accept a
	"std::string" for "allargs".
	* fork-child.c: Include <vector>.
	(breakup_args): Rewrite function, using C++.
	(fork_inferior): Rewrite function header, constify "exec_file_arg"
	and accept "std::string" for "allargs".  Update the code to
	calculate "argv" based on "allargs".  Update calls to "exec_fun"
	and "execvp".
	* gnu-nat.c (gnu_create_inferior): Rewrite function prototype in
	order to constify "exec_file" and accept a "std::string" for
	"allargs".
	* go32-nat.c (go32_create_inferior): Likewise.
	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
	* infcmd.c (run_command_1): Constify "exec_file".  Use
	"std::string" for inferior arguments.
	* inferior.h (fork_inferior): Update prototype.
	* linux-nat.c (linux_nat_create_inferior): Rewrite function
	prototype in order to constify "exec_file" and accept a
	"std::string" for "allargs".
	* nto-procfs.c (procfs_create_inferior): Likewise.
	* procfs.c (procfs_create_inferior): Likewise.
	* remote-sim.c (gdbsim_create_inferior): Likewise.
	* remote.c (extended_remote_run): Update code to accept
	"std::string" as argument.
	(extended_remote_create_inferior): Rewrite function prototype in
	order to constify "exec_file" and accept a "std::string" for
	"allargs".
	* rs6000-nat.c (super_create_inferior): Likewise.
	(rs6000_create_inferior): Likewise.
	* target.h (struct target_ops) <to_create_inferior>: Likewise.
	* windows-nat.c (windows_create_inferior): Likewise.

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

	* server.c: Include <vector>.
	<program_argv, wrapper_argv>: Convert to std::vector.
	(start_inferior): Rewrite function to use C++.
	(handle_v_run): Likewise.  Update code that calculates the argv
	based on the vRun packet; use C++.
	(captured_main): Likewise.
---
 gdb/ChangeLog             |  38 +++++++++++++
 gdb/common/common-utils.c |  11 ++++
 gdb/common/common-utils.h |   5 ++
 gdb/darwin-nat.c          |  12 ++--
 gdb/fork-child.c          | 136 +++++++++++++++++++---------------------------
 gdb/gdbserver/ChangeLog   |   9 +++
 gdb/gdbserver/server.c    | 108 ++++++++++++++++--------------------
 gdb/gnu-nat.c             |   3 +-
 gdb/go32-nat.c            |   6 +-
 gdb/inf-ptrace.c          |   4 +-
 gdb/infcmd.c              |   7 ++-
 gdb/inferior.h            |   2 +-
 gdb/linux-nat.c           |   4 +-
 gdb/nto-procfs.c          |   9 +--
 gdb/procfs.c              |   4 +-
 gdb/remote-sim.c          |   7 ++-
 gdb/remote.c              |  12 ++--
 gdb/rs6000-nat.c          |  10 ++--
 gdb/target.h              |   3 +-
 gdb/windows-nat.c         |   6 +-
 20 files changed, 220 insertions(+), 176 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a5d07e6..c8f1bcf 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,41 @@
+2017-04-12  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	* common/common-utils.c (free_vector_argv): New function.
+	* common/common-utils.h: Include <vector>.
+	(free_vector_argv): New prototype.
+	* darwin-nat.c (darwin_create_inferior): Rewrite function
+	prototype in order to constify "exec_file" and accept a
+	"std::string" for "allargs".
+	* fork-child.c: Include <vector>.
+	(breakup_args): Rewrite function, using C++.
+	(fork_inferior): Rewrite function header, constify "exec_file_arg"
+	and accept "std::string" for "allargs".  Update the code to
+	calculate "argv" based on "allargs".  Update calls to "exec_fun"
+	and "execvp".
+	* gnu-nat.c (gnu_create_inferior): Rewrite function prototype in
+	order to constify "exec_file" and accept a "std::string" for
+	"allargs".
+	* go32-nat.c (go32_create_inferior): Likewise.
+	* inf-ptrace.c (inf_ptrace_create_inferior): Likewise.
+	* infcmd.c (run_command_1): Constify "exec_file".  Use
+	"std::string" for inferior arguments.
+	* inferior.h (fork_inferior): Update prototype.
+	* linux-nat.c (linux_nat_create_inferior): Rewrite function
+	prototype in order to constify "exec_file" and accept a
+	"std::string" for "allargs".
+	* nto-procfs.c (procfs_create_inferior): Likewise.
+	* procfs.c (procfs_create_inferior): Likewise.
+	* remote-sim.c (gdbsim_create_inferior): Likewise.
+	* remote.c (extended_remote_run): Update code to accept
+	"std::string" as argument.
+	(extended_remote_create_inferior): Rewrite function prototype in
+	order to constify "exec_file" and accept a "std::string" for
+	"allargs".
+	* rs6000-nat.c (super_create_inferior): Likewise.
+	(rs6000_create_inferior): Likewise.
+	* target.h (struct target_ops) <to_create_inferior>: Likewise.
+	* windows-nat.c (windows_create_inferior): Likewise.
+
 2017-04-11  Pedro Alves  <palves@redhat.com>
 
 	* thread.c: Fix whitespace throughout.
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index afc0af9..e94fdc4 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -317,3 +317,14 @@ skip_to_space_const (const char *chp)
     chp++;
   return chp;
 }
+
+/* See common/common-utils.h.  */
+
+void
+free_vector_argv (std::vector<char *> &v)
+{
+  for (char *el : v)
+    xfree (el);
+
+  v.clear ();
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 618d266..c331f0d 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -21,6 +21,7 @@
 #define COMMON_UTILS_H
 
 #include <string>
+#include <vector>
 
 /* If possible, define FUNCTION_NAME, a macro containing the name of
    the function being defined.  Since this macro may not always be
@@ -103,4 +104,8 @@ extern const char *skip_spaces_const (const char *inp);
 
 extern const char *skip_to_space_const (const char *inp);
 
+/* Assumes that V is an argv for a program, and iterates through
+   freeing all the elements.  */
+extern void free_vector_argv (std::vector<char *> &v);
+
 #endif
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index e509240..cba84ca 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -102,8 +102,10 @@ static void darwin_ptrace_me (void);
 
 static void darwin_ptrace_him (int pid);
 
-static void darwin_create_inferior (struct target_ops *ops, char *exec_file,
-				    char *allargs, char **env, int from_tty);
+static void darwin_create_inferior (struct target_ops *ops,
+				    const char *exec_file,
+				    const std::string &allargs,
+				    char **env, int from_tty);
 
 static void darwin_files_info (struct target_ops *ops);
 
@@ -1826,8 +1828,10 @@ darwin_execvp (const char *file, char * const argv[], char * const env[])
 }
 
 static void
-darwin_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+darwin_create_inferior (struct target_ops *ops,
+			const char *exec_file,
+			const std::string &allargs,
+			char **env, int from_tty)
 {
   /* Do the hard work.  */
   fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 04d2cdf..6b7386e 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -34,6 +34,7 @@
 #include "top.h"
 #include "signals-state-save-restore.h"
 #include <signal.h>
+#include <vector>
 
 /* This just gets used as a default if we can't find SHELL.  */
 #define SHELL_FILE "/bin/sh"
@@ -48,41 +49,32 @@ static char *exec_wrapper;
    fill in ARGV with the four arguments "a", "b", "c", "d".  */
 
 static void
-breakup_args (char *scratch, char **argv)
+breakup_args (const std::string &scratch, std::vector<char *> &argv)
 {
-  char *cp = scratch, *tmp;
-
-  for (;;)
+  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
     {
-      /* Scan past leading separators */
-      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
-	cp++;
-
-      /* Break if at end of string.  */
-      if (*cp == '\0')
-	break;
-
-      /* Take an arg.  */
-      *argv++ = cp;
-
-      /* Scan for next arg separator.  */
-      tmp = strchr (cp, ' ');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\t');
-      if (tmp == NULL)
-	tmp = strchr (cp, '\n');
-
-      /* No separators => end of string => break.  */
-      if (tmp == NULL)
-	break;
-      cp = tmp;
-
-      /* Replace the separator with a terminator.  */
-      *cp++ = '\0';
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
+
+      /* No separator found, which means this is the last
+	 argument.  */
+      if (next_sep == std::string::npos)
+	next_sep = scratch.size ();
+
+      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
+      argv.push_back (arg);
+
+      cur_pos = next_sep;
     }
 
-  /* Null-terminate the vector.  */
-  *argv = NULL;
+  /* NULL-terminate the vector.  */
+  argv.push_back (NULL);
 }
 
 /* When executing a command under the given shell, return non-zero if
@@ -145,9 +137,10 @@ trace_start_error_with_name (const char *string)
    made static to ensure that they survive the vfork call.  */
 
 int
-fork_inferior (char *exec_file_arg, char *allargs, char **env,
-	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg,
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (void),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
+	       char *shell_file_arg,
                void (*exec_fun)(const char *file, char * const *argv,
                                 char * const *env))
 {
@@ -159,10 +152,10 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
      to you in the parent process.  It's only used by humans for debugging.  */
   static int debug_setpgrp = 657473;
   static char *shell_file;
-  static char *exec_file;
+  static const char *exec_file;
   char **save_our_env;
   int shell = 0;
-  static char **argv;
+  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -171,9 +164,10 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   /* If no exec file handed to us, get it from the exec-file command
      -- with a good, common error message if none is specified.  */
-  exec_file = exec_file_arg;
-  if (exec_file == 0)
+  if (exec_file_arg == NULL)
     exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
 
   /* 'startup_with_shell' is declared in inferior.h and bound to the
      "set startup-with-shell" option.  If 0, we'll just do a
@@ -191,43 +185,26 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   if (!shell)
     {
-      /* We're going to call execvp.  Create argument vector.
-	 Calculate an upper bound on the length of the vector by
-	 assuming that every other character is a separate
-	 argument.  */
-      int argc = (strlen (allargs) + 1) / 2 + 2;
-
-      argv = XALLOCAVEC (char *, argc);
-      argv[0] = exec_file;
-      breakup_args (allargs, &argv[1]);
+      /* We're going to call execvp.  Create argument vector.  */
+      argv.push_back (xstrdup (exec_file));
+      breakup_args (allargs, argv);
     }
   else
     {
       /* We're going to call a shell.  */
-      char *shell_command;
-      int len;
-      char *p;
+      std::string shell_command;
+      const char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
-      /* Multiplying the length of exec_file by 4 is to account for the
-         fact that it may expand when quoted; it is a worst-case number
-         based on every character being '.  */
-      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-      if (exec_wrapper)
-        len += strlen (exec_wrapper) + 1;
-
-      shell_command = (char *) alloca (len);
-      shell_command[0] = '\0';
-
-      strcat (shell_command, "exec ");
+      shell_command = std::string ("exec ");
 
       /* Add any exec wrapper.  That may be a program name with arguments, so
 	 the user must handle quoting.  */
       if (exec_wrapper)
 	{
-	  strcat (shell_command, exec_wrapper);
-	  strcat (shell_command, " ");
+	  shell_command += exec_wrapper;
+	  shell_command += ' ';
 	}
 
       /* Now add exec_file, quoting as necessary.  */
@@ -268,33 +245,32 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
     end_scan:
       if (need_to_quote)
 	{
-	  strcat (shell_command, "'");
+	  shell_command += '\'';
 	  for (p = exec_file; *p != '\0'; ++p)
 	    {
 	      if (*p == '\'')
-		strcat (shell_command, "'\\''");
+		shell_command += "'\\''";
 	      else if (*p == '!' && escape_bang)
-		strcat (shell_command, "\\!");
+		shell_command += "\\!";
 	      else
-		strncat (shell_command, p, 1);
+		shell_command += *p;
 	    }
-	  strcat (shell_command, "'");
+	  shell_command += '\'';
 	}
       else
-	strcat (shell_command, exec_file);
+	shell_command += exec_file;
 
-      strcat (shell_command, " ");
-      strcat (shell_command, allargs);
+      shell_command += " " + allargs;
 
       /* If we decided above to start up with a shell, we exec the
 	 shell, "-c" says to interpret the next arg as a shell command
 	 to execute, and this command is "exec <target-program>
-	 <args>".  */
-      argv = (char **) alloca (4 * sizeof (char *));
-      argv[0] = shell_file;
-      argv[1] = (char *) "-c";
-      argv[2] = shell_command;
-      argv[3] = (char *) 0;
+	 <args>".  We xstrdup all the strings here because they will
+	 be free'd later in the code.  */
+      argv.push_back (xstrdup (shell_file));
+      argv.push_back (xstrdup ("-c"));
+      argv.push_back (xstrdup (shell_command.c_str ()));
+      argv.push_back (NULL);
     }
 
   /* Retain a copy of our environment variables, since the child will
@@ -401,9 +377,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       environ = env;
 
       if (exec_fun != NULL)
-        (*exec_fun) (argv[0], argv, env);
+        (*exec_fun) (argv[0], &argv[0], env);
       else
-        execvp (argv[0], argv);
+        execvp (argv[0], &argv[0]);
 
       /* If we get here, it's an error.  */
       save_errno = errno;
@@ -417,6 +393,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       _exit (0177);
     }
 
+  free_vector_argv (argv);
+
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 8b1adfe..1f8c593 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,12 @@
+2017-04-12  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	* server.c: Include <vector>.
+	<program_argv, wrapper_argv>: Convert to std::vector.
+	(start_inferior): Rewrite function to use C++.
+	(handle_v_run): Likewise.  Update code that calculates the argv
+	based on the vRun packet; use C++.
+	(captured_main): Likewise.
+
 2017-04-06  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* server.c (handle_v_cont): Initialize thread_resume::thread
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 9cc6145..69fcab1 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -35,6 +35,7 @@
 #include "tracepoint.h"
 #include "dll.h"
 #include "hostio.h"
+#include <vector>
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -78,7 +79,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static char **program_argv, **wrapper_argv;
+static std::vector<char *> program_argv;
+static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -239,29 +241,21 @@ target_running (void)
 static int
 start_inferior (char **argv)
 {
-  char **new_argv = argv;
+  std::vector<char *> new_argv;
 
-  if (wrapper_argv != NULL)
-    {
-      int i, count = 1;
-
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	count++;
-      for (i = 0; argv[i] != NULL; i++)
-	count++;
-      new_argv = XALLOCAVEC (char *, count);
-      count = 0;
-      for (i = 0; wrapper_argv[i] != NULL; i++)
-	new_argv[count++] = wrapper_argv[i];
-      for (i = 0; argv[i] != NULL; i++)
-	new_argv[count++] = argv[i];
-      new_argv[count] = NULL;
-    }
+  if (!wrapper_argv.empty ())
+    new_argv.insert (new_argv.begin (),
+		     wrapper_argv.begin (),
+		     wrapper_argv.end ());
+
+  for (int i = 0; argv[i] != NULL; ++i)
+    new_argv.push_back (argv[i]);
+
+  new_argv.push_back (NULL);
 
   if (debug_threads)
     {
-      int i;
-      for (i = 0; new_argv[i]; ++i)
+      for (int i = 0; i < new_argv.size (); ++i)
 	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
       debug_flush ();
     }
@@ -271,7 +265,7 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], new_argv);
+  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
 
   /* FIXME: we don't actually know at this point that the create
      actually succeeded.  We won't know that until we wait.  */
@@ -288,7 +282,7 @@ start_inferior (char **argv)
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (wrapper_argv != NULL)
+  if (!wrapper_argv.empty ())
     {
       ptid_t ptid = pid_to_ptid (signal_pid);
 
@@ -2852,7 +2846,8 @@ handle_v_attach (char *own_buf)
 static int
 handle_v_run (char *own_buf)
 {
-  char *p, *next_p, **new_argv;
+  char *p, *next_p;
+  std::vector<char *> new_argv;
   int i, new_argc;
 
   new_argc = 0;
@@ -2862,62 +2857,51 @@ handle_v_run (char *own_buf)
       new_argc++;
     }
 
-  new_argv = (char **) calloc (new_argc + 2, sizeof (char *));
-  if (new_argv == NULL)
-    {
-      write_enn (own_buf);
-      return 0;
-    }
-
-  i = 0;
-  for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
+  for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i)
     {
       next_p = strchr (p, ';');
       if (next_p == NULL)
 	next_p = p + strlen (p);
 
       if (i == 0 && p == next_p)
-	new_argv[i] = NULL;
+	{
+	  /* No program specified.  */
+	  new_argv.push_back (NULL);
+	}
       else
 	{
-	  /* FIXME: Fail request if out of memory instead of dying.  */
-	  new_argv[i] = (char *) xmalloc (1 + (next_p - p) / 2);
-	  hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
-	  new_argv[i][(next_p - p) / 2] = '\0';
+	  size_t len = (next_p - p) / 2;
+	  char *arg = (char *) xmalloc (len + 1);
+
+	  hex2bin (p, (gdb_byte *) arg, len);
+	  arg[len] = '\0';
+	  new_argv.push_back (arg);
 	}
 
       if (*next_p)
 	next_p++;
-      i++;
     }
-  new_argv[i] = NULL;
+  new_argv.push_back (NULL);
 
   if (new_argv[0] == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-
-      if (program_argv == NULL)
+      if (program_argv.empty ())
 	{
 	  write_enn (own_buf);
-	  freeargv (new_argv);
+	  free_vector_argv (new_argv);
 	  return 0;
 	}
 
-      new_argv[0] = strdup (program_argv[0]);
-      if (new_argv[0] == NULL)
-	{
-	  write_enn (own_buf);
-	  freeargv (new_argv);
-	  return 0;
-	}
+      new_argv.push_back (xstrdup (program_argv[0]));
     }
 
   /* Free the old argv and install the new one.  */
-  freeargv (program_argv);
+  free_vector_argv (program_argv);
   program_argv = new_argv;
 
-  start_inferior (program_argv);
+  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3536,13 +3520,18 @@ captured_main (int argc, char *argv[])
 	multi_mode = 1;
       else if (strcmp (*next_arg, "--wrapper") == 0)
 	{
+	  char **tmp;
+
 	  next_arg++;
 
-	  wrapper_argv = next_arg;
+	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
-	    next_arg++;
+	    {
+	      wrapper_argv.push_back (*next_arg);
+	      next_arg++;
+	    }
 
-	  if (next_arg == wrapper_argv || *next_arg == NULL)
+	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
 	      exit (1);
@@ -3692,13 +3681,12 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      program_argv = XNEWVEC (char *, n + 1);
       for (i = 0; i < n; i++)
-	program_argv[i] = xstrdup (next_arg[i]);
-      program_argv[i] = NULL;
+	program_argv.push_back (xstrdup (next_arg[i]));
+      program_argv.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (program_argv);
+      start_inferior (&program_argv[0]);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4313,9 +4301,9 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (program_argv != NULL)
+	  if (!program_argv.empty ())
 	    {
-	      start_inferior (program_argv);
+	      start_inferior (&program_argv[0]);
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index b2a975d..6298103 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2131,7 +2131,8 @@ gnu_ptrace_me (void)
 
 static void
 gnu_create_inferior (struct target_ops *ops, 
-		     char *exec_file, char *allargs, char **env,
+		     const char *exec_file, const std::string &allargs,
+		     char **env,
 		     int from_tty)
 {
   struct inf *inf = cur_inf ();
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index a20067e..4e609a8 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -631,8 +631,9 @@ go32_kill_inferior (struct target_ops *ops)
 }
 
 static void
-go32_create_inferior (struct target_ops *ops, char *exec_file,
-		      char *args, char **env, int from_tty)
+go32_create_inferior (struct target_ops *ops,
+		      const char *exec_file,
+		      const std::string &allargs, char **env, int from_tty)
 {
   extern char **environ;
   jmp_buf start_state;
@@ -641,6 +642,7 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
   size_t cmdlen;
   struct inferior *inf;
   int result;
+  const char *args = allargs.c_str ();
 
   /* If no exec file handed to us, get it from the exec-file command -- with
      a good, common error message if none is specified.  */
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index c911001..b19aaf9 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -90,8 +90,8 @@ inf_ptrace_me (void)
 
 static void
 inf_ptrace_create_inferior (struct target_ops *ops,
-			    char *exec_file, char *allargs, char **env,
-			    int from_tty)
+			    const char *exec_file, const std::string &allargs,
+			    char **env, int from_tty)
 {
   int pid;
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index f6ffb9b..22b2c7a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -526,7 +526,7 @@ prepare_execution_command (struct target_ops *target, int background)
 static void
 run_command_1 (char *args, int from_tty, int tbreak_at_main)
 {
-  char *exec_file;
+  const char *exec_file;
   struct cleanup *old_chain;
   ptid_t ptid;
   struct ui_out *uiout = current_uiout;
@@ -574,7 +574,7 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
   if (tbreak_at_main)
     tbreak_command (main_name (), 0);
 
-  exec_file = (char *) get_exec_file (0);
+  exec_file = get_exec_file (0);
 
   /* We keep symbols from add-symbol-file, on the grounds that the
      user might want to add some symbols before running the program
@@ -607,7 +607,8 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
 
   /* We call get_inferior_args() because we might need to compute
      the value now.  */
-  run_target->to_create_inferior (run_target, exec_file, get_inferior_args (),
+  run_target->to_create_inferior (run_target, exec_file,
+				  std::string (get_inferior_args ()),
 				  environ_vector (current_inferior ()->environment),
 				  from_tty);
   /* to_create_inferior should push the target, so after this point we
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7c0ddf3..bf06ac1 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -146,7 +146,7 @@ extern void trace_start_error (const char *fmt, ...)
 extern void trace_start_error_with_name (const char *string)
   ATTRIBUTE_NORETURN;
 
-extern int fork_inferior (char *, char *, char **,
+extern int fork_inferior (const char *, const std::string &, char **,
 			  void (*)(void),
 			  void (*)(int), void (*)(void), char *,
                           void (*)(const char *,
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 8dececf..b008df0 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1105,8 +1105,8 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *signalled)
 
 static void
 linux_nat_create_inferior (struct target_ops *ops, 
-			   char *exec_file, char *allargs, char **env,
-			   int from_tty)
+			   const char *exec_file, const std::string &allargs,
+			   char **env, int from_tty)
 {
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 75f92dc..7fb7095 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1163,8 +1163,9 @@ breakup_args (char *scratch, char **argv)
 }
 
 static void
-procfs_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+procfs_create_inferior (struct target_ops *ops, const char *exec_file,
+			const std::string &allargs,
+			char **env, int from_tty)
 {
   struct inheritance inherit;
   pid_t pid;
@@ -1176,7 +1177,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
 
-  argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) *
+  argv = xmalloc ((allargs.size () / (unsigned) 2 + 2) *
 		  sizeof (*argv));
   argv[0] = get_exec_file (1);
   if (!argv[0])
@@ -1187,7 +1188,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
 	return;
     }
 
-  args = xstrdup (allargs);
+  args = xstrdup (allargs.c_str ());
   breakup_args (args, (exec_file != NULL) ? &argv[1] : &argv[0]);
 
   argv = nto_parse_redirection (argv, &in, &out, &err);
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 87c317f..5d940dd 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4526,8 +4526,8 @@ procfs_set_exec_trap (void)
    inf-ptrace?  */
 
 static void
-procfs_create_inferior (struct target_ops *ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+procfs_create_inferior (struct target_ops *ops, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   char *shell_file = getenv ("SHELL");
   char *tryname;
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 4396d4b..fd1bc66 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -607,13 +607,14 @@ gdbsim_load (struct target_ops *self, const char *args, int fromtty)
    user types "run" after having attached.  */
 
 static void
-gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
-			char **env, int from_tty)
+gdbsim_create_inferior (struct target_ops *target, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   struct sim_inferior_data *sim_data
     = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
   int len;
   char *arg_buf, **argv;
+  const char *args = allargs.c_str ();
 
   if (exec_file == 0 || exec_bfd == 0)
     warning (_("No executable file specified."));
@@ -633,7 +634,7 @@ gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
 
   if (exec_file != NULL)
     {
-      len = strlen (exec_file) + 1 + strlen (args) + 1 + /*slop */ 10;
+      len = strlen (exec_file) + 1 + allargs.size () + 1 + /*slop */ 10;
       arg_buf = (char *) alloca (len);
       arg_buf[0] = '\0';
       strcat (arg_buf, exec_file);
diff --git a/gdb/remote.c b/gdb/remote.c
index a61469c..7c5fe87 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9526,7 +9526,7 @@ extended_remote_disable_randomization (int val)
 }
 
 static int
-extended_remote_run (char *args)
+extended_remote_run (const std::string &args)
 {
   struct remote_state *rs = get_remote_state ();
   int len;
@@ -9545,14 +9545,13 @@ extended_remote_run (char *args)
   len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
 		      strlen (remote_exec_file));
 
-  gdb_assert (args != NULL);
-  if (*args)
+  if (!args.empty ())
     {
       struct cleanup *back_to;
       int i;
       char **argv;
 
-      argv = gdb_buildargv (args);
+      argv = gdb_buildargv (args.c_str ());
       back_to = make_cleanup_freeargv (argv);
       for (i = 0; argv[i] != NULL; i++)
 	{
@@ -9597,7 +9596,8 @@ extended_remote_run (char *args)
 
 static void
 extended_remote_create_inferior (struct target_ops *ops,
-				 char *exec_file, char *args,
+				 const char *exec_file,
+				 const std::string &args,
 				 char **env, int from_tty)
 {
   int run_worked;
@@ -9622,7 +9622,7 @@ extended_remote_create_inferior (struct target_ops *ops,
 	 user requested.  */
       if (remote_exec_file[0])
 	error (_("Remote target does not support \"set remote exec-file\""));
-      if (args[0])
+      if (!args.empty ())
 	error (_("Remote target does not support \"set args\" or run <ARGS>"));
 
       /* Fall back to "R".  */
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index 8f5d25c..83e0693 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -524,11 +524,13 @@ rs6000_wait (struct target_ops *ops,
 /* Set the current architecture from the host running GDB.  Called when
    starting a child process.  */
 
-static void (*super_create_inferior) (struct target_ops *,char *exec_file, 
-				      char *allargs, char **env, int from_tty);
+static void (*super_create_inferior) (struct target_ops *,
+				      const char *exec_file,
+				      const std::string &allargs,
+				      char **env, int from_tty);
 static void
-rs6000_create_inferior (struct target_ops * ops, char *exec_file,
-			char *allargs, char **env, int from_tty)
+rs6000_create_inferior (struct target_ops * ops, const char *exec_file,
+			const std::string &allargs, char **env, int from_tty)
 {
   enum bfd_architecture arch;
   unsigned long mach;
diff --git a/gdb/target.h b/gdb/target.h
index fac9d51..a971adf 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -591,7 +591,8 @@ struct target_ops
        ENV is the environment vector to pass.  Errors reported with error().
        On VxWorks and various standalone systems, we ignore exec_file.  */
     void (*to_create_inferior) (struct target_ops *, 
-				char *, char *, char **, int);
+				const char *, const std::string &,
+				char **, int);
     void (*to_post_startup_inferior) (struct target_ops *, ptid_t)
       TARGET_DEFAULT_IGNORE ();
     int (*to_insert_fork_catchpoint) (struct target_ops *, int)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 21b5ebe..dd5cfe4 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2412,8 +2412,9 @@ redirect_inferior_handles (const char *cmd_orig, char *cmd,
    ENV is the environment vector to pass.  Errors reported with error().  */
 
 static void
-windows_create_inferior (struct target_ops *ops, char *exec_file,
-		       char *allargs, char **in_env, int from_tty)
+windows_create_inferior (struct target_ops *ops, const char *exec_file,
+			 const std::string &origallargs, char **in_env,
+			 int from_tty)
 {
   STARTUPINFO si;
 #ifdef __CYGWIN__
@@ -2432,6 +2433,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file,
   char real_path[__PMAX];
   char shell[__PMAX]; /* Path to shell */
   char *toexec;
+  const char *allargs = origallargs.c_str ();
   char *args, *allargs_copy;
   size_t args_len, allargs_len;
   int fd_inp = -1, fd_out = -1, fd_err = -1;
-- 
2.9.3


^ permalink raw reply	[flat|nested] 157+ messages in thread

* [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior)
  2017-04-12  5:04         ` Sergio Durigan Junior
@ 2017-04-12  5:19           ` Sergio Durigan Junior
  2017-04-12 10:14           ` [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior) Pedro Alves
  2017-04-14  1:03           ` [obv/commit] Fix build breakage on Cygwin (PR gdb/21385) Sergio Durigan Junior
  2 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12  5:19 UTC (permalink / raw)
  To: GDB Patches; +Cc: Sergio Durigan Junior

Forgot to declare the variable 'toexec' (from
window-nat.c:windows_create_inferior) as 'const char *', which caused
a build breakage.

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

	* windows-nat.c (windows_create_inferior): Declare 'toexec' as
	'const char *'.
---
 gdb/ChangeLog     | 5 +++++
 gdb/windows-nat.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c8f1bcf..087c0735 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
 2017-04-12  Sergio Durigan Junior  <sergiodj@redhat.com>
 
+	* windows-nat.c (windows_create_inferior): Declare 'toexec' as
+	'const char *'.
+
+2017-04-12  Sergio Durigan Junior  <sergiodj@redhat.com>
+
 	* common/common-utils.c (free_vector_argv): New function.
 	* common/common-utils.h: Include <vector>.
 	(free_vector_argv): New prototype.
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index dd5cfe4..d9a4f0a 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2432,7 +2432,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
 #else  /* !__CYGWIN__ */
   char real_path[__PMAX];
   char shell[__PMAX]; /* Path to shell */
-  char *toexec;
+  const char *toexec;
   const char *allargs = origallargs.c_str ();
   char *args, *allargs_copy;
   size_t args_len, allargs_len;
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-12  5:04         ` Sergio Durigan Junior
  2017-04-12  5:19           ` [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior) Sergio Durigan Junior
@ 2017-04-12 10:14           ` Pedro Alves
  2017-04-12 22:26             ` Sergio Durigan Junior
  2017-04-14  1:03           ` [obv/commit] Fix build breakage on Cygwin (PR gdb/21385) Sergio Durigan Junior
  2 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-12 10:14 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 04/12/2017 06:04 AM, Sergio Durigan Junior wrote:

>>>>  static void
>>>> -breakup_args (char *scratch, char **argv)
>>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>>  {
>>>
>>> ...
>>>
>>>> +
>>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>>> +
>>>
>>> This creates a temporary string (heap allocates) ...
>>>
>>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>>
>>> ... and here you create yet another copy.
>>>
>>> You should be able to avoid it by using e.g., savestring:
>>>
>>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>>     argv.push_back (arg);
>>
>> Fair enough.  I had my mind on "C++-only mode" when writing this code.

Yup, in C++, it's good to keep unnecessary temporaries
and hidden heap allocations in mind.  Actually, now that I look a bit
deeper, I think we can avoid a "premature pessimization" here, keeping
the same level of clarity.

I think it'd be good to push this patch below.  WDYT?

From 64d0035762344ed33858a3b8930a83e7071ea4a8 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 12 Apr 2017 10:55:36 +0100
Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
 copying

The previous patch converted the argv building from an
alloca-allocated array of non-owning arg pointers, to a std::vector of
owning pointers, which results in N string dups, with N being the
number of arguments in the vector, and then requires manually
releasing the pointers owned by the vector.

This patch makes the vector hold non-owning pointers, and avoids the
string dups, by doing one single string copy of the arguments upfront,
and replacing separators with NULL terminators in place, like we used
to.

With this, there's no need to remember to call free_vector_argv either.

Tested on x86_64 Fedora 23.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* fork-child.c (breakup_args): Make 'scratch' non-const.
	Replace separators with NULL terminators in place.  Change
	type of vector.  (fork_inferior): The argument vector now
	holds non-owning pointers.  Don't strdup strings into the
	vector.  Remove free_vector_argv call.
---
 gdb/fork-child.c | 57 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 6b7386e..8a6f9e6 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -46,10 +46,12 @@ static char *exec_wrapper;
 /* Break up SCRATCH into an argument vector suitable for passing to
    execvp and store it in ARGV.  E.g., on "run a b c d" this routine
    would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+   fill in ARGV with the four arguments "a", "b", "c", "d".  The
+   pointers pushed to ARGV point directly into SCRATCH, which is
+   modified in place with the necessary NULL terminators.  */
 
 static void
-breakup_args (const std::string &scratch, std::vector<char *> &argv)
+breakup_args (std::string &scratch, std::vector<const char *> &argv)
 {
   for (size_t cur_pos = 0; cur_pos < scratch.size ();)
     {
@@ -62,13 +64,19 @@ breakup_args (const std::string &scratch, std::vector<char *> &argv)
       /* Find the position of the next separator.  */
       std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
 
-      /* No separator found, which means this is the last
-	 argument.  */
       if (next_sep == std::string::npos)
-	next_sep = scratch.size ();
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = scratch.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  scratch[next_sep++] = '\0';
+	}
 
-      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
-      argv.push_back (arg);
+      argv.push_back (&scratch[cur_pos]);
 
       cur_pos = next_sep;
     }
@@ -155,7 +163,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   static const char *exec_file;
   char **save_our_env;
   int shell = 0;
-  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -183,21 +190,29 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       shell = 1;
     }
 
+  /* The argument vector.  Holds non-owning pointers.  */
+  std::vector<const char *> c_argv;
+
+  /* These must be live up to the exec call, because the arguments in
+     C_ARGV point inside them.  */
+  std::string broken_up_args;
+  std::string shell_command;
+
   if (!shell)
     {
       /* We're going to call execvp.  Create argument vector.  */
-      argv.push_back (xstrdup (exec_file));
-      breakup_args (allargs, argv);
+      c_argv.push_back (exec_file);
+      broken_up_args = allargs;
+      breakup_args (broken_up_args, c_argv);
     }
   else
     {
       /* We're going to call a shell.  */
-      std::string shell_command;
       const char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
-      shell_command = std::string ("exec ");
+      shell_command = "exec ";
 
       /* Add any exec wrapper.  That may be a program name with arguments, so
 	 the user must handle quoting.  */
@@ -265,12 +280,12 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       /* If we decided above to start up with a shell, we exec the
 	 shell, "-c" says to interpret the next arg as a shell command
 	 to execute, and this command is "exec <target-program>
-	 <args>".  We xstrdup all the strings here because they will
-	 be free'd later in the code.  */
-      argv.push_back (xstrdup (shell_file));
-      argv.push_back (xstrdup ("-c"));
-      argv.push_back (xstrdup (shell_command.c_str ()));
-      argv.push_back (NULL);
+	 <args>".  */
+      c_argv.reserve (4);
+      c_argv.push_back (shell_file);
+      c_argv.push_back ("-c");
+      c_argv.push_back (shell_command.c_str ());
+      c_argv.push_back (NULL);
     }
 
   /* Retain a copy of our environment variables, since the child will
@@ -376,6 +391,10 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
          path to find $SHELL.  Rich Pixley says so, and I agree.  */
       environ = env;
 
+      /* It is guaranteed that the exec functions do not modify the
+	 arguments, but they nevertheless expect "char **".  */
+      char **argv = const_cast<char **> (&c_argv[0]);
+
       if (exec_fun != NULL)
         (*exec_fun) (argv[0], &argv[0], env);
       else
@@ -393,8 +412,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       _exit (0177);
     }
 
-  free_vector_argv (argv);
-
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h)
  2017-04-12  1:17                 ` [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h) Sergio Durigan Junior
@ 2017-04-12 10:28                   ` Pedro Alves
  2017-04-12 22:00                     ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-12 10:28 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 04/12/2017 02:16 AM, Sergio Durigan Junior wrote:

> gdb/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/gdb_termios.h".
> 	* common/common.m4: Check headers 'termios.h', 'termio.h' and
> 	'sgtty.h'.
> 	* common/gdb_termios.h: New file, with parts of "terminal.h".
> 	* inflow.c: Include "gdb_termios.h".
> 	* ser-unix.c: Include "gdb_termios.h".
> 	* terminal.h: Move terminal-related defines to
> 	"common/gdb_termios.h".
> 
> gdb/gdbserver/ChangeLog:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
>         * remote-utils.c: Include "gdb_termios.h" instead of
>         "terminal.h".
>         * terminal.h: Delete file.

(Note leading tabs vs spaces in the gdbserver CL.)

OK.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h)
  2017-04-12 10:28                   ` Pedro Alves
@ 2017-04-12 22:00                     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12 22:00 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, April 12 2017, Pedro Alves wrote:

> On 04/12/2017 02:16 AM, Sergio Durigan Junior wrote:
>
>> gdb/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* Makefile.in (HFILES_NO_SRCDIR): Add "common/gdb_termios.h".
>> 	* common/common.m4: Check headers 'termios.h', 'termio.h' and
>> 	'sgtty.h'.
>> 	* common/gdb_termios.h: New file, with parts of "terminal.h".
>> 	* inflow.c: Include "gdb_termios.h".
>> 	* ser-unix.c: Include "gdb_termios.h".
>> 	* terminal.h: Move terminal-related defines to
>> 	"common/gdb_termios.h".
>> 
>> gdb/gdbserver/ChangeLog:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>>         * remote-utils.c: Include "gdb_termios.h" instead of
>>         "terminal.h".
>>         * terminal.h: Delete file.
>
> (Note leading tabs vs spaces in the gdbserver CL.)

Fixed.

> OK.

Pushed:

  be628ab814f1c90e185d7482d27aa8a991ab5837

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-12 10:14           ` [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior) Pedro Alves
@ 2017-04-12 22:26             ` Sergio Durigan Junior
  2017-04-13  3:42               ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-12 22:26 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, April 12 2017, Pedro Alves wrote:

> On 04/12/2017 06:04 AM, Sergio Durigan Junior wrote:
>
>>>>>  static void
>>>>> -breakup_args (char *scratch, char **argv)
>>>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>>>  {
>>>>
>>>> ...
>>>>
>>>>> +
>>>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>>>> +
>>>>
>>>> This creates a temporary string (heap allocates) ...
>>>>
>>>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>>>
>>>> ... and here you create yet another copy.
>>>>
>>>> You should be able to avoid it by using e.g., savestring:
>>>>
>>>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>>>     argv.push_back (arg);
>>>
>>> Fair enough.  I had my mind on "C++-only mode" when writing this code.
>
> Yup, in C++, it's good to keep unnecessary temporaries
> and hidden heap allocations in mind.  Actually, now that I look a bit
> deeper, I think we can avoid a "premature pessimization" here, keeping
> the same level of clarity.
>
> I think it'd be good to push this patch below.  WDYT?

Hm, I don't know.  I mean, I understand where you're coming from and
what you're trying to achieve, but somehow I thought the old code
(especially the part that modified the argument string in place, using
\0's as separators) was somewhat hacky.  Even though the new code uses
more memory, it it also more readable, at least IMNSHO.  And also more
const-correct, since we can make breakup_args_for_exec receive a const
as the first argument.

But I liked a few bits of your patch.  See below.

> From 64d0035762344ed33858a3b8930a83e7071ea4a8 Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Wed, 12 Apr 2017 10:55:36 +0100
> Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
>  copying
>
> The previous patch converted the argv building from an
> alloca-allocated array of non-owning arg pointers, to a std::vector of
> owning pointers, which results in N string dups, with N being the
> number of arguments in the vector, and then requires manually
> releasing the pointers owned by the vector.
>
> This patch makes the vector hold non-owning pointers, and avoids the
> string dups, by doing one single string copy of the arguments upfront,
> and replacing separators with NULL terminators in place, like we used
> to.
>
> With this, there's no need to remember to call free_vector_argv either.
>
> Tested on x86_64 Fedora 23.
>
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
>
> 	* fork-child.c (breakup_args): Make 'scratch' non-const.
> 	Replace separators with NULL terminators in place.  Change
> 	type of vector.  (fork_inferior): The argument vector now
> 	holds non-owning pointers.  Don't strdup strings into the
> 	vector.  Remove free_vector_argv call.
> ---
>  gdb/fork-child.c | 57 ++++++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 37 insertions(+), 20 deletions(-)
>
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 6b7386e..8a6f9e6 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -46,10 +46,12 @@ static char *exec_wrapper;
>  /* Break up SCRATCH into an argument vector suitable for passing to
>     execvp and store it in ARGV.  E.g., on "run a b c d" this routine
>     would get as input the string "a b c d", and as output it would
> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> +   fill in ARGV with the four arguments "a", "b", "c", "d".  The
> +   pointers pushed to ARGV point directly into SCRATCH, which is
> +   modified in place with the necessary NULL terminators.  */
>  
>  static void
> -breakup_args (const std::string &scratch, std::vector<char *> &argv)
> +breakup_args (std::string &scratch, std::vector<const char *> &argv)
>  {
>    for (size_t cur_pos = 0; cur_pos < scratch.size ();)
>      {
> @@ -62,13 +64,19 @@ breakup_args (const std::string &scratch, std::vector<char *> &argv)
>        /* Find the position of the next separator.  */
>        std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
>  
> -      /* No separator found, which means this is the last
> -	 argument.  */
>        if (next_sep == std::string::npos)
> -	next_sep = scratch.size ();
> +	{
> +	  /* No separator found, which means this is the last
> +	     argument.  */
> +	  next_sep = scratch.size ();
> +	}

This comment should really be inside the block.  Thanks.

> +      else
> +	{
> +	  /* Replace the separator with a terminator.  */
> +	  scratch[next_sep++] = '\0';
> +	}
>  
> -      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
> -      argv.push_back (arg);
> +      argv.push_back (&scratch[cur_pos]);
>  
>        cur_pos = next_sep;
>      }
> @@ -155,7 +163,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>    static const char *exec_file;
>    char **save_our_env;
>    int shell = 0;
> -  std::vector<char *> argv;
>    const char *inferior_io_terminal = get_inferior_io_terminal ();
>    struct inferior *inf;
>    int i;
> @@ -183,21 +190,29 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        shell = 1;
>      }
>  
> +  /* The argument vector.  Holds non-owning pointers.  */
> +  std::vector<const char *> c_argv;
> +
> +  /* These must be live up to the exec call, because the arguments in
> +     C_ARGV point inside them.  */
> +  std::string broken_up_args;
> +  std::string shell_command;
> +
>    if (!shell)
>      {
>        /* We're going to call execvp.  Create argument vector.  */
> -      argv.push_back (xstrdup (exec_file));
> -      breakup_args (allargs, argv);
> +      c_argv.push_back (exec_file);
> +      broken_up_args = allargs;
> +      breakup_args (broken_up_args, c_argv);
>      }
>    else
>      {
>        /* We're going to call a shell.  */
> -      std::string shell_command;
>        const char *p;
>        int need_to_quote;
>        const int escape_bang = escape_bang_in_quoted_argument (shell_file);
>  
> -      shell_command = std::string ("exec ");
> +      shell_command = "exec ";
>  
>        /* Add any exec wrapper.  That may be a program name with arguments, so
>  	 the user must handle quoting.  */
> @@ -265,12 +280,12 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        /* If we decided above to start up with a shell, we exec the
>  	 shell, "-c" says to interpret the next arg as a shell command
>  	 to execute, and this command is "exec <target-program>
> -	 <args>".  We xstrdup all the strings here because they will
> -	 be free'd later in the code.  */
> -      argv.push_back (xstrdup (shell_file));
> -      argv.push_back (xstrdup ("-c"));
> -      argv.push_back (xstrdup (shell_command.c_str ()));
> -      argv.push_back (NULL);
> +	 <args>".  */
> +      c_argv.reserve (4);

I liked the idea of reserving the exact amount of space needed in the
vector.

> +      c_argv.push_back (shell_file);
> +      c_argv.push_back ("-c");
> +      c_argv.push_back (shell_command.c_str ());
> +      c_argv.push_back (NULL);
>      }
>  
>    /* Retain a copy of our environment variables, since the child will
> @@ -376,6 +391,10 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>           path to find $SHELL.  Rich Pixley says so, and I agree.  */
>        environ = env;
>  
> +      /* It is guaranteed that the exec functions do not modify the
> +	 arguments, but they nevertheless expect "char **".  */
> +      char **argv = const_cast<char **> (&c_argv[0]);

Also, I liked your approach to this.

> +
>        if (exec_fun != NULL)
>          (*exec_fun) (argv[0], &argv[0], env);
>        else
> @@ -393,8 +412,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        _exit (0177);
>      }
>  
> -  free_vector_argv (argv);
> -
>    /* Restore our environment in case a vforked child clob'd it.  */
>    environ = save_our_env;
>  
> -- 
> 2.5.5

Anyway, long story short: I won't oppose if you want to go ahead and
push this patch, but it's not my preferred approach.

Cheers,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-12 22:26             ` Sergio Durigan Junior
@ 2017-04-13  3:42               ` Pedro Alves
  2017-04-13  4:33                 ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-13  3:42 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 04/12/2017 11:26 PM, Sergio Durigan Junior wrote:
> On Wednesday, April 12 2017, Pedro Alves wrote:
> 
>> On 04/12/2017 06:04 AM, Sergio Durigan Junior wrote:
>>
>>>>>>  static void
>>>>>> -breakup_args (char *scratch, char **argv)
>>>>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>>>>  {
>>>>>
>>>>> ...
>>>>>
>>>>>> +
>>>>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>>>>> +
>>>>>
>>>>> This creates a temporary string (heap allocates) ...
>>>>>
>>>>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>>>>
>>>>> ... and here you create yet another copy.
>>>>>
>>>>> You should be able to avoid it by using e.g., savestring:
>>>>>
>>>>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>>>>     argv.push_back (arg);
>>>>
>>>> Fair enough.  I had my mind on "C++-only mode" when writing this code.
>>
>> Yup, in C++, it's good to keep unnecessary temporaries
>> and hidden heap allocations in mind.  Actually, now that I look a bit
>> deeper, I think we can avoid a "premature pessimization" here, keeping
>> the same level of clarity.
>>
>> I think it'd be good to push this patch below.  WDYT?
> 
> Hm, I don't know.  I mean, I understand where you're coming from and
> what you're trying to achieve, but somehow I thought the old code
> (especially the part that modified the argument string in place, using
> \0's as separators) was somewhat hacky.  Even though the new code uses
> more memory, it it also more readable, at least IMNSHO.  And also more
> const-correct, since we can make breakup_args_for_exec receive a const
> as the first argument.

There's nothing wrong with writing to a string in place.  A std::string
is just a _container_ of chars with convenience methods.  It's
been designed to support embedded \0s.  And it's not a problem for a
function to take a copy of a value if it needs to modify it!
const-correct refers to when functions that _don't need to
modify an argument nevertheless declare non-const reference/pointer.

Effectively you can't avoid _some_ creating _some_ new string(s). 
But instead of taking one single copy (O(1)), the current code is making
many (N) tiny copies.  Trips to the generic allocator / malloc should
be one of the first things to avoid if easy to avoid, as a principle.

The patch I had posted is exactly equivalent to the one below, except
the state/storage in this one is moved to a class.  Maybe you'd
find this clearer?  (It'd need some cleaning up for comments
further at least, but it's getting quite late here...)

From 689a881839f9d4aeb36695676856db2eaf8e97ab Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 13 Apr 2017 04:13:22 +0100
Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
 copying

The previous patch converted the argv building from an
alloca-allocated array of non-owning arg pointers, to a std::vector of
owning pointers, which results in N string dups, with N being the
number of arguments in the vector, and then requires manually
releasing the pointers owned by the vector.

This patch makes the vector hold non-owning pointers, and avoids the
string dups, by doing one single string copy of the arguments upfront,
and replacing separators with NULL terminators in place, like we used
to.

With this, there's no need to remember to call free_vector_argv either.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* fork-child.c (breakup_args): Make 'scratch' non-const.
	Replace separators with NULL terminators in place.  Change
	type of vector.  (fork_inferior): The argument vector now
	holds non-owning pointers.  Don't strdup strings into the
	vector.  Remove free_vector_argv call.
---
 gdb/fork-child.c | 278 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 172 insertions(+), 106 deletions(-)

diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 6b7386e..91986f7 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -43,38 +43,96 @@ extern char **environ;
 
 static char *exec_wrapper;
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
+/* Build the argument vector for execv.  */
+
+class execv_argv_builder
+{
+public:
+  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
+     arguments to the program.  If starting with a shell, SHELL_FILE
+     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
+  execv_argv_builder (const char *exec_file,
+		      const std::string &allargs,
+		      const char *shell_file);
+
+  /* Return a pointer to the built argv, in the type expected by
+     execv.  */
+  char **argv ()
+  {
+    /* It is guaranteed that the exec functions do not modify the
+       arguments, but they nevertheless expect "char **", so that's
+       the type we return.  */
+    return const_cast<char **> (&m_argv[0]);
+  }
+
+private:
+  void build_no_shell (const char *exec_file,
+		       const std::string &allargs);
+
+  void build_shell (const char *exec_file,
+		    const std::string &allargs,
+		    const char *shell_file);
+
+  /* The argument vector built.  Holds non-owning pointers.  */
+  std::vector<const char *> m_argv;
+
+  /* Storage.  Arguments in C_ARGV point inside these.  */
+
+  /* For the !shell case.  */
+  std::string m_broke_up_args;
+
+  /* For the shell case.  */
+  std::string m_shell_command;
+};
+
+/* Break up allargs into an argument vector suitable for passing to
+   execvp and store it in M_ARGV.  E.g., on "run a b c d" this routine
    would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+   fill in M_ARGV with the four arguments "a", "b", "c", "d".  */
 
-static void
-breakup_args (const std::string &scratch, std::vector<char *> &argv)
+void
+execv_argv_builder::build_no_shell (const char *exec_file,
+				    const std::string &allargs)
 {
-  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
+  /* We're going to call execvp.  Create argument vector.  */
+
+  /* Save/work with a copy.  The pointers pushed to M_ARGV point
+     directly into M_BROKE_UP_ARGS, which is modified in place with
+     the necessary NULL terminators.  */
+  m_broke_up_args = allargs;
+
+  m_argv.push_back (exec_file);
+
+  for (size_t cur_pos = 0; cur_pos < m_broke_up_args.size ();)
     {
       /* Skip whitespace-like chars.  */
-      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
+      std::size_t pos = m_broke_up_args.find_first_not_of (" \t\n", cur_pos);
 
       if (pos != std::string::npos)
 	cur_pos = pos;
 
       /* Find the position of the next separator.  */
-      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
+      std::size_t next_sep = m_broke_up_args.find_first_of (" \t\n", cur_pos);
 
-      /* No separator found, which means this is the last
-	 argument.  */
       if (next_sep == std::string::npos)
-	next_sep = scratch.size ();
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = m_broke_up_args.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  m_broke_up_args[next_sep++] = '\0';
+	}
 
-      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
-      argv.push_back (arg);
+      m_argv.push_back (&m_broke_up_args[cur_pos]);
 
       cur_pos = next_sep;
     }
 
   /* NULL-terminate the vector.  */
-  argv.push_back (NULL);
+  m_argv.push_back (NULL);
 }
 
 /* When executing a command under the given shell, return non-zero if
@@ -101,6 +159,101 @@ escape_bang_in_quoted_argument (const char *shell_file)
   return 0;
 }
 
+execv_argv_builder::execv_argv_builder (const char *exec_file,
+					const std::string &allargs,
+					const char *shell_file)
+{
+  if (shell_file == NULL)
+    build_no_shell (exec_file, allargs);
+  else
+    build_shell (exec_file, allargs, shell_file);
+}
+
+void
+execv_argv_builder::build_shell (const char *exec_file,
+				 const std::string &allargs,
+				 const char *shell_file)
+{
+  /* We're going to call a shell.  */
+  const char *p;
+  int need_to_quote;
+  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  m_shell_command = "exec ";
+
+  /* Add any exec wrapper.  That may be a program name with arguments,
+     so the user must handle quoting.  */
+  if (exec_wrapper)
+    {
+      m_shell_command += exec_wrapper;
+      m_shell_command += ' ';
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But csh
+     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
+     to.  */
+  p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = 1;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = 0;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      m_shell_command += '\'';
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    m_shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    m_shell_command += "\\!";
+	  else
+	    m_shell_command += *p;
+	}
+      m_shell_command += '\'';
+    }
+  else
+    m_shell_command += exec_file;
+
+  m_shell_command += " " + allargs;
+
+  /* If we decided above to start up with a shell, we exec the shell,
+     "-c" says to interpret the next arg as a shell command to
+     execute, and this command is "exec <target-program> <args>".  */
+  m_argv.reserve (4);
+  m_argv.push_back (shell_file);
+  m_argv.push_back ("-c");
+  m_argv.push_back (m_shell_command.c_str ());
+  m_argv.push_back (NULL);
+}
+
 /* See inferior.h.  */
 
 void
@@ -155,7 +308,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   static const char *exec_file;
   char **save_our_env;
   int shell = 0;
-  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -183,95 +335,9 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       shell = 1;
     }
 
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.  */
-      argv.push_back (xstrdup (exec_file));
-      breakup_args (allargs, argv);
-    }
-  else
-    {
-      /* We're going to call a shell.  */
-      std::string shell_command;
-      const char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      shell_command = std::string ("exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  shell_command += exec_wrapper;
-	  shell_command += ' ';
-	}
-
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  shell_command += '\'';
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		shell_command += "'\\''";
-	      else if (*p == '!' && escape_bang)
-		shell_command += "\\!";
-	      else
-		shell_command += *p;
-	    }
-	  shell_command += '\'';
-	}
-      else
-	shell_command += exec_file;
-
-      shell_command += " " + allargs;
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  We xstrdup all the strings here because they will
-	 be free'd later in the code.  */
-      argv.push_back (xstrdup (shell_file));
-      argv.push_back (xstrdup ("-c"));
-      argv.push_back (xstrdup (shell_command.c_str ()));
-      argv.push_back (NULL);
-    }
+  /* Build the argument vector.  */
+  execv_argv_builder argv_builder (exec_file, allargs,
+				   shell ? shell_file : NULL);
 
   /* Retain a copy of our environment variables, since the child will
      replace the value of environ and if we're vforked, we have to
@@ -376,6 +442,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
          path to find $SHELL.  Rich Pixley says so, and I agree.  */
       environ = env;
 
+      char **argv = argv_builder.argv ();
+
       if (exec_fun != NULL)
         (*exec_fun) (argv[0], &argv[0], env);
       else
@@ -393,8 +461,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       _exit (0177);
     }
 
-  free_vector_argv (argv);
-
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
-- 
2.5.5


^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-13  3:42               ` Pedro Alves
@ 2017-04-13  4:33                 ` Sergio Durigan Junior
  2017-04-13 10:51                   ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-13  4:33 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, April 12 2017, Pedro Alves wrote:

> On 04/12/2017 11:26 PM, Sergio Durigan Junior wrote:
>> On Wednesday, April 12 2017, Pedro Alves wrote:
>> 
>>> On 04/12/2017 06:04 AM, Sergio Durigan Junior wrote:
>>>
>>>>>>>  static void
>>>>>>> -breakup_args (char *scratch, char **argv)
>>>>>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>>>>>  {
>>>>>>
>>>>>> ...
>>>>>>
>>>>>>> +
>>>>>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>>>>>> +
>>>>>>
>>>>>> This creates a temporary string (heap allocates) ...
>>>>>>
>>>>>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>>>>>
>>>>>> ... and here you create yet another copy.
>>>>>>
>>>>>> You should be able to avoid it by using e.g., savestring:
>>>>>>
>>>>>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>>>>>     argv.push_back (arg);
>>>>>
>>>>> Fair enough.  I had my mind on "C++-only mode" when writing this code.
>>>
>>> Yup, in C++, it's good to keep unnecessary temporaries
>>> and hidden heap allocations in mind.  Actually, now that I look a bit
>>> deeper, I think we can avoid a "premature pessimization" here, keeping
>>> the same level of clarity.
>>>
>>> I think it'd be good to push this patch below.  WDYT?
>> 
>> Hm, I don't know.  I mean, I understand where you're coming from and
>> what you're trying to achieve, but somehow I thought the old code
>> (especially the part that modified the argument string in place, using
>> \0's as separators) was somewhat hacky.  Even though the new code uses
>> more memory, it it also more readable, at least IMNSHO.  And also more
>> const-correct, since we can make breakup_args_for_exec receive a const
>> as the first argument.
>
> There's nothing wrong with writing to a string in place.  A std::string
> is just a _container_ of chars with convenience methods.  It's
> been designed to support embedded \0s.  And it's not a problem for a
> function to take a copy of a value if it needs to modify it!
> const-correct refers to when functions that _don't need to
> modify an argument nevertheless declare non-const reference/pointer.

Sorry, maybe I should have made myself clearer.  I did not mean to say
that there was anything actually wrong with modifying a string in-place;
I just meant that it seems somewhat hacky and more error-prone to me
than separate the string into substrings.

I totally understand that a std::string is just a container, and that it
is OK to modify it if needed.  But we're not talking about a generic
string manipulation here; we're talking about inserting \0's on the
string in order to split it.  Anyway, I totally understand this is valid
code.

About the const-correctness comment: you're right, I should have said
that the original function is better IMHO because it doesn't modify its
arguments.

> Effectively you can't avoid _some_ creating _some_ new string(s). 
> But instead of taking one single copy (O(1)), the current code is making
> many (N) tiny copies.  Trips to the generic allocator / malloc should
> be one of the first things to avoid if easy to avoid, as a principle.

Yep, I am aware that the code is more efficient using less strings, but
I thought "OK, how many args will we be dealing with here, usually?",
and I decided that it wasn't worth.

> The patch I had posted is exactly equivalent to the one below, except
> the state/storage in this one is moved to a class.  Maybe you'd
> find this clearer?  (It'd need some cleaning up for comments
> further at least, but it's getting quite late here...)

I liked your patch.  There are some things I'd like to comment, but
overall it is good and I think it does a nice job of separating things
on fork_inferior.  As I said before, I won't really make a fuss about
this approach if you think it is the right way to go; my comments were
solely based on my personal taste.

> From 689a881839f9d4aeb36695676856db2eaf8e97ab Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 13 Apr 2017 04:13:22 +0100
> Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
>  copying
>
> The previous patch converted the argv building from an
> alloca-allocated array of non-owning arg pointers, to a std::vector of
> owning pointers, which results in N string dups, with N being the
> number of arguments in the vector, and then requires manually
> releasing the pointers owned by the vector.
>
> This patch makes the vector hold non-owning pointers, and avoids the
> string dups, by doing one single string copy of the arguments upfront,
> and replacing separators with NULL terminators in place, like we used
> to.
>
> With this, there's no need to remember to call free_vector_argv either.
>
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
>
> 	* fork-child.c (breakup_args): Make 'scratch' non-const.
> 	Replace separators with NULL terminators in place.  Change
> 	type of vector.  (fork_inferior): The argument vector now
> 	holds non-owning pointers.  Don't strdup strings into the
> 	vector.  Remove free_vector_argv call.
> ---
>  gdb/fork-child.c | 278 ++++++++++++++++++++++++++++++++++---------------------
>  1 file changed, 172 insertions(+), 106 deletions(-)
>
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 6b7386e..91986f7 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -43,38 +43,96 @@ extern char **environ;
>  
>  static char *exec_wrapper;
>  
> -/* Break up SCRATCH into an argument vector suitable for passing to
> -   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> +/* Build the argument vector for execv.  */
> +
> +class execv_argv_builder
> +{
> +public:
> +  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
> +     arguments to the program.  If starting with a shell, SHELL_FILE
> +     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
> +  execv_argv_builder (const char *exec_file,
> +		      const std::string &allargs,
> +		      const char *shell_file);
> +
> +  /* Return a pointer to the built argv, in the type expected by
> +     execv.  */
> +  char **argv ()
> +  {
> +    /* It is guaranteed that the exec functions do not modify the
> +       arguments, but they nevertheless expect "char **", so that's
> +       the type we return.  */
> +    return const_cast<char **> (&m_argv[0]);
> +  }
> +
> +private:
> +  void build_no_shell (const char *exec_file,
> +		       const std::string &allargs);
> +
> +  void build_shell (const char *exec_file,
> +		    const std::string &allargs,
> +		    const char *shell_file);

Missing comments on the functions.

> +
> +  /* The argument vector built.  Holds non-owning pointers.  */
> +  std::vector<const char *> m_argv;

OOC, I notice you're prefixing a lot (if not all) of your class
variables with "m_".  I understand this is a code convention to signal
when a variable is a member of a class, but are we following this
officially?  Because (again!) I'm not really fond of this :-).

> +  /* Storage.  Arguments in C_ARGV point inside these.  */
> +
> +  /* For the !shell case.  */
> +  std::string m_broke_up_args;

If we're going this way, then I'd like to see this comment expanded to
explain how the args are split, i.e., using \0 as the delimiter.

> +
> +  /* For the shell case.  */
> +  std::string m_shell_command;

> +};
> +
> +/* Break up allargs into an argument vector suitable for passing to
> +   execvp and store it in M_ARGV.  E.g., on "run a b c d" this routine
>     would get as input the string "a b c d", and as output it would
> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> +   fill in M_ARGV with the four arguments "a", "b", "c", "d".  */
>  
> -static void
> -breakup_args (const std::string &scratch, std::vector<char *> &argv)
> +void
> +execv_argv_builder::build_no_shell (const char *exec_file,
> +				    const std::string &allargs)
>  {
> -  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
> +  /* We're going to call execvp.  Create argument vector.  */
> +
> +  /* Save/work with a copy.  The pointers pushed to M_ARGV point
> +     directly into M_BROKE_UP_ARGS, which is modified in place with
> +     the necessary NULL terminators.  */
> +  m_broke_up_args = allargs;
> +
> +  m_argv.push_back (exec_file);
> +
> +  for (size_t cur_pos = 0; cur_pos < m_broke_up_args.size ();)
>      {
>        /* Skip whitespace-like chars.  */
> -      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
> +      std::size_t pos = m_broke_up_args.find_first_not_of (" \t\n", cur_pos);
>  
>        if (pos != std::string::npos)
>  	cur_pos = pos;
>  
>        /* Find the position of the next separator.  */
> -      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
> +      std::size_t next_sep = m_broke_up_args.find_first_of (" \t\n", cur_pos);
>  
> -      /* No separator found, which means this is the last
> -	 argument.  */
>        if (next_sep == std::string::npos)
> -	next_sep = scratch.size ();
> +	{
> +	  /* No separator found, which means this is the last
> +	     argument.  */
> +	  next_sep = m_broke_up_args.size ();
> +	}
> +      else
> +	{
> +	  /* Replace the separator with a terminator.  */
> +	  m_broke_up_args[next_sep++] = '\0';
> +	}
>  
> -      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
> -      argv.push_back (arg);
> +      m_argv.push_back (&m_broke_up_args[cur_pos]);
>  
>        cur_pos = next_sep;
>      }
>  
>    /* NULL-terminate the vector.  */
> -  argv.push_back (NULL);
> +  m_argv.push_back (NULL);
>  }
>  
>  /* When executing a command under the given shell, return non-zero if
> @@ -101,6 +159,101 @@ escape_bang_in_quoted_argument (const char *shell_file)
>    return 0;
>  }

Missing a comment here explaining the function below (or pointing to the
right place).

> +execv_argv_builder::execv_argv_builder (const char *exec_file,
> +					const std::string &allargs,
> +					const char *shell_file)
> +{
> +  if (shell_file == NULL)
> +    build_no_shell (exec_file, allargs);
> +  else
> +    build_shell (exec_file, allargs, shell_file);
> +}

And here.

> +
> +void
> +execv_argv_builder::build_shell (const char *exec_file,
> +				 const std::string &allargs,
> +				 const char *shell_file)
> +{
> +  /* We're going to call a shell.  */
> +  const char *p;
> +  int need_to_quote;
> +  const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> +
> +  m_shell_command = "exec ";
> +
> +  /* Add any exec wrapper.  That may be a program name with arguments,
> +     so the user must handle quoting.  */
> +  if (exec_wrapper)
> +    {
> +      m_shell_command += exec_wrapper;
> +      m_shell_command += ' ';
> +    }
> +
> +  /* Now add exec_file, quoting as necessary.  */
> +
> +  /* Quoting in this style is said to work with all shells.  But csh
> +     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
> +     to.  */
> +  p = exec_file;
> +  while (1)
> +    {
> +      switch (*p)
> +	{
> +	case '\'':
> +	case '!':
> +	case '"':
> +	case '(':
> +	case ')':
> +	case '$':
> +	case '&':
> +	case ';':
> +	case '<':
> +	case '>':
> +	case ' ':
> +	case '\n':
> +	case '\t':
> +	  need_to_quote = 1;
> +	  goto end_scan;
> +
> +	case '\0':
> +	  need_to_quote = 0;
> +	  goto end_scan;
> +
> +	default:
> +	  break;
> +	}
> +      ++p;
> +    }
> + end_scan:
> +  if (need_to_quote)
> +    {
> +      m_shell_command += '\'';
> +      for (p = exec_file; *p != '\0'; ++p)
> +	{
> +	  if (*p == '\'')
> +	    m_shell_command += "'\\''";
> +	  else if (*p == '!' && escape_bang)
> +	    m_shell_command += "\\!";
> +	  else
> +	    m_shell_command += *p;
> +	}
> +      m_shell_command += '\'';
> +    }
> +  else
> +    m_shell_command += exec_file;
> +
> +  m_shell_command += " " + allargs;
> +
> +  /* If we decided above to start up with a shell, we exec the shell,
> +     "-c" says to interpret the next arg as a shell command to
> +     execute, and this command is "exec <target-program> <args>".  */
> +  m_argv.reserve (4);
> +  m_argv.push_back (shell_file);
> +  m_argv.push_back ("-c");
> +  m_argv.push_back (m_shell_command.c_str ());
> +  m_argv.push_back (NULL);
> +}
> +
>  /* See inferior.h.  */
>  
>  void
> @@ -155,7 +308,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>    static const char *exec_file;
>    char **save_our_env;
>    int shell = 0;
> -  std::vector<char *> argv;

I believe you can also remove the 'static' keyword from the 'shell_file'
declaration.

>    const char *inferior_io_terminal = get_inferior_io_terminal ();
>    struct inferior *inf;
>    int i;
> @@ -183,95 +335,9 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        shell = 1;
>      }
>  
> -  if (!shell)
> -    {
> -      /* We're going to call execvp.  Create argument vector.  */
> -      argv.push_back (xstrdup (exec_file));
> -      breakup_args (allargs, argv);
> -    }
> -  else
> -    {
> -      /* We're going to call a shell.  */
> -      std::string shell_command;
> -      const char *p;
> -      int need_to_quote;
> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> -
> -      shell_command = std::string ("exec ");
> -
> -      /* Add any exec wrapper.  That may be a program name with arguments, so
> -	 the user must handle quoting.  */
> -      if (exec_wrapper)
> -	{
> -	  shell_command += exec_wrapper;
> -	  shell_command += ' ';
> -	}
> -
> -      /* Now add exec_file, quoting as necessary.  */
> -
> -      /* Quoting in this style is said to work with all shells.  But
> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> -         we need to.  */
> -      p = exec_file;
> -      while (1)
> -	{
> -	  switch (*p)
> -	    {
> -	    case '\'':
> -	    case '!':
> -	    case '"':
> -	    case '(':
> -	    case ')':
> -	    case '$':
> -	    case '&':
> -	    case ';':
> -	    case '<':
> -	    case '>':
> -	    case ' ':
> -	    case '\n':
> -	    case '\t':
> -	      need_to_quote = 1;
> -	      goto end_scan;
> -
> -	    case '\0':
> -	      need_to_quote = 0;
> -	      goto end_scan;
> -
> -	    default:
> -	      break;
> -	    }
> -	  ++p;
> -	}
> -    end_scan:
> -      if (need_to_quote)
> -	{
> -	  shell_command += '\'';
> -	  for (p = exec_file; *p != '\0'; ++p)
> -	    {
> -	      if (*p == '\'')
> -		shell_command += "'\\''";
> -	      else if (*p == '!' && escape_bang)
> -		shell_command += "\\!";
> -	      else
> -		shell_command += *p;
> -	    }
> -	  shell_command += '\'';
> -	}
> -      else
> -	shell_command += exec_file;
> -
> -      shell_command += " " + allargs;
> -
> -      /* If we decided above to start up with a shell, we exec the
> -	 shell, "-c" says to interpret the next arg as a shell command
> -	 to execute, and this command is "exec <target-program>
> -	 <args>".  We xstrdup all the strings here because they will
> -	 be free'd later in the code.  */
> -      argv.push_back (xstrdup (shell_file));
> -      argv.push_back (xstrdup ("-c"));
> -      argv.push_back (xstrdup (shell_command.c_str ()));
> -      argv.push_back (NULL);
> -    }
> +  /* Build the argument vector.  */
> +  execv_argv_builder argv_builder (exec_file, allargs,
> +				   shell ? shell_file : NULL);

Good code cleanup!

BTW, it is possible to simplify this part and remove the "shell"
variable completely, using only "shell_file".

>  
>    /* Retain a copy of our environment variables, since the child will
>       replace the value of environ and if we're vforked, we have to
> @@ -376,6 +442,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>           path to find $SHELL.  Rich Pixley says so, and I agree.  */
>        environ = env;
>  
> +      char **argv = argv_builder.argv ();
> +
>        if (exec_fun != NULL)
>          (*exec_fun) (argv[0], &argv[0], env);
>        else
> @@ -393,8 +461,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        _exit (0177);
>      }
>  
> -  free_vector_argv (argv);
> -
>    /* Restore our environment in case a vforked child clob'd it.  */
>    environ = save_our_env;
>  
> -- 
> 2.5.5

Otherwise, LGTM.

Thanks for doing this,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-13  4:33                 ` Sergio Durigan Junior
@ 2017-04-13 10:51                   ` Pedro Alves
  2017-04-13 18:30                     ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-04-13 10:51 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 04/13/2017 05:31 AM, Sergio Durigan Junior wrote:
> On Wednesday, April 12 2017, Pedro Alves wrote:

> Missing comments on the functions.

Yup, it was a prototype patch, it was too late already.
I'd either finish it or not sleep.  :-)

>> +  /* The argument vector built.  Holds non-owning pointers.  */
>> +  std::vector<const char *> m_argv;
> 
> OOC, I notice you're prefixing a lot (if not all) of your class
> variables with "m_".  I understand this is a code convention to signal
> when a variable is a member of a class, but are we following this
> officially?  Because (again!) I'm not really fond of this :-).

Yes, we are:

https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#C.2B-.2B--specific_coding_conventions
 => 
   https://gcc.gnu.org/codingconventions.html

"When structs and/or classes have member functions, prefer to name data members with a leading m_ and static data members with a leading s_. "

> 
>> +  /* Storage.  Arguments in C_ARGV point inside these.  */
>> +
>> +  /* For the !shell case.  */
>> +  std::string m_broke_up_args;
> 
> If we're going this way, then I'd like to see this comment expanded to
> explain how the args are split, i.e., using \0 as the delimiter.

Done.

> Missing a comment here explaining the function below (or pointing to the
> right place).

Done.

>> @@ -155,7 +308,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>>    static const char *exec_file;
>>    char **save_our_env;
>>    int shell = 0;
>> -  std::vector<char *> argv;
> 
> I believe you can also remove the 'static' keyword from the 'shell_file'
> declaration.

And exec_file too.  It's not entirely clear to me why they
were ever made static.  The rationale about vfork looks bogus,
since the child does not modify these.  Anyway, better leave
that to a separate patch, IMO.

> Good code cleanup!
> 
> BTW, it is possible to simplify this part and remove the "shell"
> variable completely, using only "shell_file".

I did this.

> 

> Otherwise, LGTM.
> 
> Thanks for doing this,

Thanks.  Below's what I pushed, after another round of testing.

From 808480f667e41e2fdb66bfdc9d5e047f1aa34a68 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 13 Apr 2017 11:46:07 +0100
Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
 copying

The previous change to fork-child.c converted the argv building from
an alloca-allocated array of non-owning arg pointers, to a std::vector
of owning pointers, which results in N string dups, with N being the
number of arguments in the vector, and then requires manually
releasing the pointers owned by the vector.

This patch makes the vector hold non-owning pointers, and avoids the
string dups, by doing one single string copy of the arguments upfront,
and replacing separators with NULL terminators in place, like we used
to.  All the logic to do that is encapsulated in a new class.

With this, there's no need to remember to manually release the argv
elements with free_vector_argv either.

gdb/ChangeLog:
2017-04-13  Pedro Alves  <palves@redhat.com>

	* fork-child.c (execv_argv): New class.
	(breakup_args): Refactored as ...
	(execv_argv::init_for_no_shell): .. this method of execv_argv.
	Copy arguments to storage and replace separators with NULL
	terminators in place.
	(escape_bang_in_quoted_argument): Adjust to return bool.
	(execv_argv::execv_argv): New ctor.
	(execv_argv::init_for_shell): New method, factored out from
	fork_inferior.  Don't strdup strings into the vector.
	(fork_inferior): Eliminate "shell" local and use execv_argv.  Use
	Remove free_vector_argv call.
---
 gdb/ChangeLog    |  14 +++
 gdb/fork-child.c | 317 +++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 215 insertions(+), 116 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ed71880..90ed21c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@
+2017-04-13  Pedro Alves  <palves@redhat.com>
+
+	* fork-child.c (execv_argv): New class.
+	(breakup_args): Refactored as ...
+	(execv_argv::init_for_no_shell): .. this method of execv_argv.
+	Copy arguments to storage and replace separators with NULL
+	terminators in place.
+	(escape_bang_in_quoted_argument): Adjust to return bool.
+	(execv_argv::execv_argv): New ctor.
+	(execv_argv::init_for_shell): New method, factored out from
+	fork_inferior.  Don't strdup strings into the vector.
+	(fork_inferior): Eliminate "shell" local and use execv_argv.  Use
+	Remove free_vector_argv call.
+
 2017-04-13  Yao Qi  <yao.qi@linaro.org>
 
 	* rx-tdep.c (rx_fpsw_type): Check tdep->rx_fpsw_type instead of
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 6b7386e..11ffee9 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -43,62 +43,235 @@ extern char **environ;
 
 static char *exec_wrapper;
 
-/* Break up SCRATCH into an argument vector suitable for passing to
-   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
-   would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+/* Build the argument vector for execv(3).  */
 
-static void
-breakup_args (const std::string &scratch, std::vector<char *> &argv)
+class execv_argv
+{
+public:
+  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
+     arguments to the program.  If starting with a shell, SHELL_FILE
+     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
+  execv_argv (const char *exec_file, const std::string &allargs,
+	      const char *shell_file);
+
+  /* Return a pointer to the built argv, in the type expected by
+     execv.  The result is (only) valid for as long as this execv_argv
+     object is live.  We return a "char **" because that's the type
+     that the execv functions expect.  Note that it is guaranteed that
+     the execv functions do not modify the argv[] array nor the
+     strings to which the array point.  */
+  char **argv ()
+  {
+    return const_cast<char **> (&m_argv[0]);
+  }
+
+private:
+  /* Disable copying.  */
+  execv_argv (const execv_argv &) = delete;
+  void operator= (const execv_argv &) = delete;
+
+  /* Helper methods for constructing the argument vector.  */
+
+  /* Used when building an argv for a straight execv call, without
+     going via the shell.  */
+  void init_for_no_shell (const char *exec_file,
+			  const std::string &allargs);
+
+  /* Used when building an argv for execing a shell that execs the
+     child program.  */
+  void init_for_shell (const char *exec_file,
+		       const std::string &allargs,
+		       const char *shell_file);
+
+  /* The argument vector built.  Holds non-owning pointers.  Elements
+     either point to the strings passed to the execv_argv ctor, or
+     inside M_STORAGE.  */
+  std::vector<const char *> m_argv;
+
+  /* Storage.  In the no-shell case, this contains a copy of the
+     arguments passed to the ctor, split by '\0'.  In the shell case,
+     this contains the quoted shell command.  I.e., SHELL_COMMAND in
+     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
+  std::string m_storage;
+};
+
+/* Create argument vector for straight call to execvp.  Breaks up
+   ALLARGS into an argument vector suitable for passing to execvp and
+   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
+   as input the string "a b c d", and as output it would fill in
+   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
+   in M_ARGV points to a substring of a copy of ALLARGS stored in
+   M_STORAGE.  */
+
+void
+execv_argv::init_for_no_shell (const char *exec_file,
+			       const std::string &allargs)
 {
-  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
+
+  /* Save/work with a copy stored in our storage.  The pointers pushed
+     to M_ARGV point directly into M_STORAGE, which is modified in
+     place with the necessary NULL terminators.  This avoids N heap
+     allocations and string dups when 1 is sufficient.  */
+  std::string &args_copy = m_storage = allargs;
+
+  m_argv.push_back (exec_file);
+
+  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
     {
       /* Skip whitespace-like chars.  */
-      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
+      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
 
       if (pos != std::string::npos)
 	cur_pos = pos;
 
       /* Find the position of the next separator.  */
-      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
+      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
 
-      /* No separator found, which means this is the last
-	 argument.  */
       if (next_sep == std::string::npos)
-	next_sep = scratch.size ();
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = args_copy.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  args_copy[next_sep++] = '\0';
+	}
 
-      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
-      argv.push_back (arg);
+      m_argv.push_back (&args_copy[cur_pos]);
 
       cur_pos = next_sep;
     }
 
   /* NULL-terminate the vector.  */
-  argv.push_back (NULL);
+  m_argv.push_back (NULL);
 }
 
-/* When executing a command under the given shell, return non-zero if
-   the '!' character should be escaped when embedded in a quoted
+/* When executing a command under the given shell, return true if the
+   '!' character should be escaped when embedded in a quoted
    command-line argument.  */
 
-static int
+static bool
 escape_bang_in_quoted_argument (const char *shell_file)
 {
-  const int shell_file_len = strlen (shell_file);
+  size_t shell_file_len = strlen (shell_file);
 
   /* Bang should be escaped only in C Shells.  For now, simply check
      that the shell name ends with 'csh', which covers at least csh
      and tcsh.  This should be good enough for now.  */
 
   if (shell_file_len < 3)
-    return 0;
+    return false;
 
   if (shell_file[shell_file_len - 3] == 'c'
       && shell_file[shell_file_len - 2] == 's'
       && shell_file[shell_file_len - 1] == 'h')
-    return 1;
+    return true;
 
-  return 0;
+  return false;
+}
+
+/* See declaration.  */
+
+execv_argv::execv_argv (const char *exec_file,
+			const std::string &allargs,
+			const char *shell_file)
+{
+  if (shell_file == NULL)
+    init_for_no_shell (exec_file, allargs);
+  else
+    init_for_shell (exec_file, allargs, shell_file);
+}
+
+/* See declaration.  */
+
+void
+execv_argv::init_for_shell (const char *exec_file,
+			    const std::string &allargs,
+			    const char *shell_file)
+{
+  /* We're going to call a shell.  */
+  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  /* We need to build a new shell command string, and make argv point
+     to it.  So build it in the storage.  */
+  std::string &shell_command = m_storage;
+
+  shell_command = "exec ";
+
+  /* Add any exec wrapper.  That may be a program name with arguments,
+     so the user must handle quoting.  */
+  if (exec_wrapper)
+    {
+      shell_command += exec_wrapper;
+      shell_command += ' ';
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But csh
+     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
+     to.  */
+  bool need_to_quote;
+  const char *p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = true;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = false;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      shell_command += '\'';
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    shell_command += "\\!";
+	  else
+	    shell_command += *p;
+	}
+      shell_command += '\'';
+    }
+  else
+    shell_command += exec_file;
+
+  shell_command += ' ' + allargs;
+
+  /* If we decided above to start up with a shell, we exec the shell.
+     "-c" says to interpret the next arg as a shell command to
+     execute, and this command is "exec <target-program> <args>".  */
+  m_argv.reserve (4);
+  m_argv.push_back (shell_file);
+  m_argv.push_back ("-c");
+  m_argv.push_back (shell_command.c_str ());
+  m_argv.push_back (NULL);
 }
 
 /* See inferior.h.  */
@@ -154,8 +327,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   static char *shell_file;
   static const char *exec_file;
   char **save_our_env;
-  int shell = 0;
-  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -172,106 +343,20 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   /* 'startup_with_shell' is declared in inferior.h and bound to the
      "set startup-with-shell" option.  If 0, we'll just do a
      fork/exec, no shell, so don't bother figuring out what shell.  */
-  shell_file = shell_file_arg;
   if (startup_with_shell)
     {
+      shell_file = shell_file_arg;
       /* Figure out what shell to start up the user program under.  */
       if (shell_file == NULL)
 	shell_file = getenv ("SHELL");
       if (shell_file == NULL)
 	shell_file = default_shell_file;
-      shell = 1;
-    }
-
-  if (!shell)
-    {
-      /* We're going to call execvp.  Create argument vector.  */
-      argv.push_back (xstrdup (exec_file));
-      breakup_args (allargs, argv);
     }
   else
-    {
-      /* We're going to call a shell.  */
-      std::string shell_command;
-      const char *p;
-      int need_to_quote;
-      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-      shell_command = std::string ("exec ");
-
-      /* Add any exec wrapper.  That may be a program name with arguments, so
-	 the user must handle quoting.  */
-      if (exec_wrapper)
-	{
-	  shell_command += exec_wrapper;
-	  shell_command += ' ';
-	}
+    shell_file = NULL;
 
-      /* Now add exec_file, quoting as necessary.  */
-
-      /* Quoting in this style is said to work with all shells.  But
-         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
-         we need to.  */
-      p = exec_file;
-      while (1)
-	{
-	  switch (*p)
-	    {
-	    case '\'':
-	    case '!':
-	    case '"':
-	    case '(':
-	    case ')':
-	    case '$':
-	    case '&':
-	    case ';':
-	    case '<':
-	    case '>':
-	    case ' ':
-	    case '\n':
-	    case '\t':
-	      need_to_quote = 1;
-	      goto end_scan;
-
-	    case '\0':
-	      need_to_quote = 0;
-	      goto end_scan;
-
-	    default:
-	      break;
-	    }
-	  ++p;
-	}
-    end_scan:
-      if (need_to_quote)
-	{
-	  shell_command += '\'';
-	  for (p = exec_file; *p != '\0'; ++p)
-	    {
-	      if (*p == '\'')
-		shell_command += "'\\''";
-	      else if (*p == '!' && escape_bang)
-		shell_command += "\\!";
-	      else
-		shell_command += *p;
-	    }
-	  shell_command += '\'';
-	}
-      else
-	shell_command += exec_file;
-
-      shell_command += " " + allargs;
-
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  We xstrdup all the strings here because they will
-	 be free'd later in the code.  */
-      argv.push_back (xstrdup (shell_file));
-      argv.push_back (xstrdup ("-c"));
-      argv.push_back (xstrdup (shell_command.c_str ()));
-      argv.push_back (NULL);
-    }
+  /* Build the argument vector.  */
+  execv_argv child_argv (exec_file, allargs, shell_file);
 
   /* Retain a copy of our environment variables, since the child will
      replace the value of environ and if we're vforked, we have to
@@ -376,6 +461,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
          path to find $SHELL.  Rich Pixley says so, and I agree.  */
       environ = env;
 
+      char **argv = child_argv.argv ();
+
       if (exec_fun != NULL)
         (*exec_fun) (argv[0], &argv[0], env);
       else
@@ -393,8 +480,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       _exit (0177);
     }
 
-  free_vector_argv (argv);
-
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
-- 
2.5.5


^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
  2017-04-13 10:51                   ` Pedro Alves
@ 2017-04-13 18:30                     ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-13 18:30 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Thursday, April 13 2017, Pedro Alves wrote:

> On 04/13/2017 05:31 AM, Sergio Durigan Junior wrote:
>> On Wednesday, April 12 2017, Pedro Alves wrote:
>
>> Missing comments on the functions.
>
> Yup, it was a prototype patch, it was too late already.
> I'd either finish it or not sleep.  :-)

Yeah, I noticed, sorry for being picky.

>>> +  /* The argument vector built.  Holds non-owning pointers.  */
>>> +  std::vector<const char *> m_argv;
>> 
>> OOC, I notice you're prefixing a lot (if not all) of your class
>> variables with "m_".  I understand this is a code convention to signal
>> when a variable is a member of a class, but are we following this
>> officially?  Because (again!) I'm not really fond of this :-).
>
> Yes, we are:
>
> https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#C.2B-.2B--specific_coding_conventions
>  => 
>    https://gcc.gnu.org/codingconventions.html
>
> "When structs and/or classes have member functions, prefer to name data members with a leading m_ and static data members with a leading s_. "

OK, thanks for pointing that out.

>>> @@ -155,7 +308,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>>>    static const char *exec_file;
>>>    char **save_our_env;
>>>    int shell = 0;
>>> -  std::vector<char *> argv;
>> 
>> I believe you can also remove the 'static' keyword from the 'shell_file'
>> declaration.
>
> And exec_file too.  It's not entirely clear to me why they
> were ever made static.  The rationale about vfork looks bogus,
> since the child does not modify these.  Anyway, better leave
> that to a separate patch, IMO.

Yeah, the 'static' rationale got me thinking too.  I think this comes
from long time ago, maybe.

I'll send a patch to clean these up, then.

> Thanks.  Below's what I pushed, after another round of testing.

Awesome, thanks for doing that.

> From 808480f667e41e2fdb66bfdc9d5e047f1aa34a68 Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 13 Apr 2017 11:46:07 +0100
> Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
>  copying
>
> The previous change to fork-child.c converted the argv building from
> an alloca-allocated array of non-owning arg pointers, to a std::vector
> of owning pointers, which results in N string dups, with N being the
> number of arguments in the vector, and then requires manually
> releasing the pointers owned by the vector.
>
> This patch makes the vector hold non-owning pointers, and avoids the
> string dups, by doing one single string copy of the arguments upfront,
> and replacing separators with NULL terminators in place, like we used
> to.  All the logic to do that is encapsulated in a new class.
>
> With this, there's no need to remember to manually release the argv
> elements with free_vector_argv either.
>
> gdb/ChangeLog:
> 2017-04-13  Pedro Alves  <palves@redhat.com>
>
> 	* fork-child.c (execv_argv): New class.
> 	(breakup_args): Refactored as ...
> 	(execv_argv::init_for_no_shell): .. this method of execv_argv.
> 	Copy arguments to storage and replace separators with NULL
> 	terminators in place.
> 	(escape_bang_in_quoted_argument): Adjust to return bool.
> 	(execv_argv::execv_argv): New ctor.
> 	(execv_argv::init_for_shell): New method, factored out from
> 	fork_inferior.  Don't strdup strings into the vector.
> 	(fork_inferior): Eliminate "shell" local and use execv_argv.  Use
> 	Remove free_vector_argv call.
> ---
>  gdb/ChangeLog    |  14 +++
>  gdb/fork-child.c | 317 +++++++++++++++++++++++++++++++++++--------------------
>  2 files changed, 215 insertions(+), 116 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index ed71880..90ed21c 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,17 @@
> +2017-04-13  Pedro Alves  <palves@redhat.com>
> +
> +	* fork-child.c (execv_argv): New class.
> +	(breakup_args): Refactored as ...
> +	(execv_argv::init_for_no_shell): .. this method of execv_argv.
> +	Copy arguments to storage and replace separators with NULL
> +	terminators in place.
> +	(escape_bang_in_quoted_argument): Adjust to return bool.
> +	(execv_argv::execv_argv): New ctor.
> +	(execv_argv::init_for_shell): New method, factored out from
> +	fork_inferior.  Don't strdup strings into the vector.
> +	(fork_inferior): Eliminate "shell" local and use execv_argv.  Use
> +	Remove free_vector_argv call.
> +
>  2017-04-13  Yao Qi  <yao.qi@linaro.org>
>  
>  	* rx-tdep.c (rx_fpsw_type): Check tdep->rx_fpsw_type instead of
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 6b7386e..11ffee9 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -43,62 +43,235 @@ extern char **environ;
>  
>  static char *exec_wrapper;
>  
> -/* Break up SCRATCH into an argument vector suitable for passing to
> -   execvp and store it in ARGV.  E.g., on "run a b c d" this routine
> -   would get as input the string "a b c d", and as output it would
> -   fill in ARGV with the four arguments "a", "b", "c", "d".  */
> +/* Build the argument vector for execv(3).  */
>  
> -static void
> -breakup_args (const std::string &scratch, std::vector<char *> &argv)
> +class execv_argv
> +{
> +public:
> +  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
> +     arguments to the program.  If starting with a shell, SHELL_FILE
> +     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
> +  execv_argv (const char *exec_file, const std::string &allargs,
> +	      const char *shell_file);
> +
> +  /* Return a pointer to the built argv, in the type expected by
> +     execv.  The result is (only) valid for as long as this execv_argv
> +     object is live.  We return a "char **" because that's the type
> +     that the execv functions expect.  Note that it is guaranteed that
> +     the execv functions do not modify the argv[] array nor the
> +     strings to which the array point.  */
> +  char **argv ()
> +  {
> +    return const_cast<char **> (&m_argv[0]);
> +  }
> +
> +private:
> +  /* Disable copying.  */
> +  execv_argv (const execv_argv &) = delete;
> +  void operator= (const execv_argv &) = delete;
> +
> +  /* Helper methods for constructing the argument vector.  */
> +
> +  /* Used when building an argv for a straight execv call, without
> +     going via the shell.  */
> +  void init_for_no_shell (const char *exec_file,
> +			  const std::string &allargs);
> +
> +  /* Used when building an argv for execing a shell that execs the
> +     child program.  */
> +  void init_for_shell (const char *exec_file,
> +		       const std::string &allargs,
> +		       const char *shell_file);
> +
> +  /* The argument vector built.  Holds non-owning pointers.  Elements
> +     either point to the strings passed to the execv_argv ctor, or
> +     inside M_STORAGE.  */
> +  std::vector<const char *> m_argv;
> +
> +  /* Storage.  In the no-shell case, this contains a copy of the
> +     arguments passed to the ctor, split by '\0'.  In the shell case,
> +     this contains the quoted shell command.  I.e., SHELL_COMMAND in
> +     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
> +  std::string m_storage;
> +};
> +
> +/* Create argument vector for straight call to execvp.  Breaks up
> +   ALLARGS into an argument vector suitable for passing to execvp and
> +   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
> +   as input the string "a b c d", and as output it would fill in
> +   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
> +   in M_ARGV points to a substring of a copy of ALLARGS stored in
> +   M_STORAGE.  */
> +
> +void
> +execv_argv::init_for_no_shell (const char *exec_file,
> +			       const std::string &allargs)
>  {
> -  for (size_t cur_pos = 0; cur_pos < scratch.size ();)
> +
> +  /* Save/work with a copy stored in our storage.  The pointers pushed
> +     to M_ARGV point directly into M_STORAGE, which is modified in
> +     place with the necessary NULL terminators.  This avoids N heap
> +     allocations and string dups when 1 is sufficient.  */
> +  std::string &args_copy = m_storage = allargs;
> +
> +  m_argv.push_back (exec_file);
> +
> +  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
>      {
>        /* Skip whitespace-like chars.  */
> -      std::size_t pos = scratch.find_first_not_of (" \t\n", cur_pos);
> +      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
>  
>        if (pos != std::string::npos)
>  	cur_pos = pos;
>  
>        /* Find the position of the next separator.  */
> -      std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
> +      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
>  
> -      /* No separator found, which means this is the last
> -	 argument.  */
>        if (next_sep == std::string::npos)
> -	next_sep = scratch.size ();
> +	{
> +	  /* No separator found, which means this is the last
> +	     argument.  */
> +	  next_sep = args_copy.size ();
> +	}
> +      else
> +	{
> +	  /* Replace the separator with a terminator.  */
> +	  args_copy[next_sep++] = '\0';
> +	}
>  
> -      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
> -      argv.push_back (arg);
> +      m_argv.push_back (&args_copy[cur_pos]);
>  
>        cur_pos = next_sep;
>      }
>  
>    /* NULL-terminate the vector.  */
> -  argv.push_back (NULL);
> +  m_argv.push_back (NULL);
>  }
>  
> -/* When executing a command under the given shell, return non-zero if
> -   the '!' character should be escaped when embedded in a quoted
> +/* When executing a command under the given shell, return true if the
> +   '!' character should be escaped when embedded in a quoted
>     command-line argument.  */
>  
> -static int
> +static bool
>  escape_bang_in_quoted_argument (const char *shell_file)
>  {
> -  const int shell_file_len = strlen (shell_file);
> +  size_t shell_file_len = strlen (shell_file);
>  
>    /* Bang should be escaped only in C Shells.  For now, simply check
>       that the shell name ends with 'csh', which covers at least csh
>       and tcsh.  This should be good enough for now.  */
>  
>    if (shell_file_len < 3)
> -    return 0;
> +    return false;
>  
>    if (shell_file[shell_file_len - 3] == 'c'
>        && shell_file[shell_file_len - 2] == 's'
>        && shell_file[shell_file_len - 1] == 'h')
> -    return 1;
> +    return true;
>  
> -  return 0;
> +  return false;
> +}
> +
> +/* See declaration.  */
> +
> +execv_argv::execv_argv (const char *exec_file,
> +			const std::string &allargs,
> +			const char *shell_file)
> +{
> +  if (shell_file == NULL)
> +    init_for_no_shell (exec_file, allargs);
> +  else
> +    init_for_shell (exec_file, allargs, shell_file);
> +}
> +
> +/* See declaration.  */
> +
> +void
> +execv_argv::init_for_shell (const char *exec_file,
> +			    const std::string &allargs,
> +			    const char *shell_file)
> +{
> +  /* We're going to call a shell.  */
> +  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
> +
> +  /* We need to build a new shell command string, and make argv point
> +     to it.  So build it in the storage.  */
> +  std::string &shell_command = m_storage;
> +
> +  shell_command = "exec ";
> +
> +  /* Add any exec wrapper.  That may be a program name with arguments,
> +     so the user must handle quoting.  */
> +  if (exec_wrapper)
> +    {
> +      shell_command += exec_wrapper;
> +      shell_command += ' ';
> +    }
> +
> +  /* Now add exec_file, quoting as necessary.  */
> +
> +  /* Quoting in this style is said to work with all shells.  But csh
> +     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
> +     to.  */
> +  bool need_to_quote;
> +  const char *p = exec_file;
> +  while (1)
> +    {
> +      switch (*p)
> +	{
> +	case '\'':
> +	case '!':
> +	case '"':
> +	case '(':
> +	case ')':
> +	case '$':
> +	case '&':
> +	case ';':
> +	case '<':
> +	case '>':
> +	case ' ':
> +	case '\n':
> +	case '\t':
> +	  need_to_quote = true;
> +	  goto end_scan;
> +
> +	case '\0':
> +	  need_to_quote = false;
> +	  goto end_scan;
> +
> +	default:
> +	  break;
> +	}
> +      ++p;
> +    }
> + end_scan:
> +  if (need_to_quote)
> +    {
> +      shell_command += '\'';
> +      for (p = exec_file; *p != '\0'; ++p)
> +	{
> +	  if (*p == '\'')
> +	    shell_command += "'\\''";
> +	  else if (*p == '!' && escape_bang)
> +	    shell_command += "\\!";
> +	  else
> +	    shell_command += *p;
> +	}
> +      shell_command += '\'';
> +    }
> +  else
> +    shell_command += exec_file;
> +
> +  shell_command += ' ' + allargs;
> +
> +  /* If we decided above to start up with a shell, we exec the shell.
> +     "-c" says to interpret the next arg as a shell command to
> +     execute, and this command is "exec <target-program> <args>".  */
> +  m_argv.reserve (4);
> +  m_argv.push_back (shell_file);
> +  m_argv.push_back ("-c");
> +  m_argv.push_back (shell_command.c_str ());
> +  m_argv.push_back (NULL);
>  }
>  
>  /* See inferior.h.  */
> @@ -154,8 +327,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>    static char *shell_file;
>    static const char *exec_file;
>    char **save_our_env;
> -  int shell = 0;
> -  std::vector<char *> argv;
>    const char *inferior_io_terminal = get_inferior_io_terminal ();
>    struct inferior *inf;
>    int i;
> @@ -172,106 +343,20 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>    /* 'startup_with_shell' is declared in inferior.h and bound to the
>       "set startup-with-shell" option.  If 0, we'll just do a
>       fork/exec, no shell, so don't bother figuring out what shell.  */
> -  shell_file = shell_file_arg;
>    if (startup_with_shell)
>      {
> +      shell_file = shell_file_arg;
>        /* Figure out what shell to start up the user program under.  */
>        if (shell_file == NULL)
>  	shell_file = getenv ("SHELL");
>        if (shell_file == NULL)
>  	shell_file = default_shell_file;
> -      shell = 1;
> -    }
> -
> -  if (!shell)
> -    {
> -      /* We're going to call execvp.  Create argument vector.  */
> -      argv.push_back (xstrdup (exec_file));
> -      breakup_args (allargs, argv);
>      }
>    else
> -    {
> -      /* We're going to call a shell.  */
> -      std::string shell_command;
> -      const char *p;
> -      int need_to_quote;
> -      const int escape_bang = escape_bang_in_quoted_argument (shell_file);
> -
> -      shell_command = std::string ("exec ");
> -
> -      /* Add any exec wrapper.  That may be a program name with arguments, so
> -	 the user must handle quoting.  */
> -      if (exec_wrapper)
> -	{
> -	  shell_command += exec_wrapper;
> -	  shell_command += ' ';
> -	}
> +    shell_file = NULL;
>  
> -      /* Now add exec_file, quoting as necessary.  */
> -
> -      /* Quoting in this style is said to work with all shells.  But
> -         csh on IRIX 4.0.1 can't deal with it.  So we only quote it if
> -         we need to.  */
> -      p = exec_file;
> -      while (1)
> -	{
> -	  switch (*p)
> -	    {
> -	    case '\'':
> -	    case '!':
> -	    case '"':
> -	    case '(':
> -	    case ')':
> -	    case '$':
> -	    case '&':
> -	    case ';':
> -	    case '<':
> -	    case '>':
> -	    case ' ':
> -	    case '\n':
> -	    case '\t':
> -	      need_to_quote = 1;
> -	      goto end_scan;
> -
> -	    case '\0':
> -	      need_to_quote = 0;
> -	      goto end_scan;
> -
> -	    default:
> -	      break;
> -	    }
> -	  ++p;
> -	}
> -    end_scan:
> -      if (need_to_quote)
> -	{
> -	  shell_command += '\'';
> -	  for (p = exec_file; *p != '\0'; ++p)
> -	    {
> -	      if (*p == '\'')
> -		shell_command += "'\\''";
> -	      else if (*p == '!' && escape_bang)
> -		shell_command += "\\!";
> -	      else
> -		shell_command += *p;
> -	    }
> -	  shell_command += '\'';
> -	}
> -      else
> -	shell_command += exec_file;
> -
> -      shell_command += " " + allargs;
> -
> -      /* If we decided above to start up with a shell, we exec the
> -	 shell, "-c" says to interpret the next arg as a shell command
> -	 to execute, and this command is "exec <target-program>
> -	 <args>".  We xstrdup all the strings here because they will
> -	 be free'd later in the code.  */
> -      argv.push_back (xstrdup (shell_file));
> -      argv.push_back (xstrdup ("-c"));
> -      argv.push_back (xstrdup (shell_command.c_str ()));
> -      argv.push_back (NULL);
> -    }
> +  /* Build the argument vector.  */
> +  execv_argv child_argv (exec_file, allargs, shell_file);
>  
>    /* Retain a copy of our environment variables, since the child will
>       replace the value of environ and if we're vforked, we have to
> @@ -376,6 +461,8 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>           path to find $SHELL.  Rich Pixley says so, and I agree.  */
>        environ = env;
>  
> +      char **argv = child_argv.argv ();
> +
>        if (exec_fun != NULL)
>          (*exec_fun) (argv[0], &argv[0], env);
>        else
> @@ -393,8 +480,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>        _exit (0177);
>      }
>  
> -  free_vector_argv (argv);
> -
>    /* Restore our environment in case a vforked child clob'd it.  */
>    environ = save_our_env;
>  
> -- 
> 2.5.5

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [obv/commit] Fix build breakage on Cygwin (PR gdb/21385)
  2017-04-12  5:04         ` Sergio Durigan Junior
  2017-04-12  5:19           ` [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior) Sergio Durigan Junior
  2017-04-12 10:14           ` [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior) Pedro Alves
@ 2017-04-14  1:03           ` Sergio Durigan Junior
  2 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-04-14  1:03 UTC (permalink / raw)
  To: GDB Patches; +Cc: Sergio Durigan Junior

On gdb/windows-nat.c:windows_create_inferior, ALLARGS needs to be
declared independently of the host that we're building for.  This
fixes a build breakage on Cygwin.

2017-04-13  Sergio Durigan Junior  <sergiodj@redhat.com>

	PR gdb/21385
	* windows-nat.c (windows_create_inferior): Declare 'allargs'
	independently of the host, and fix build breakage on Cygwin.
---
 gdb/ChangeLog     | 6 ++++++
 gdb/windows-nat.c | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b739d8d..11d77be 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2017-04-13  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	PR gdb/21385
+	* windows-nat.c (windows_create_inferior): Declare 'allargs'
+	independently of the host, and fix build breakage on Cygwin.
+
 2017-04-13  Pedro Alves  <palves@redhat.com>
 
 	* inferior.c (free_inferior): Convert to ...
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index d9a4f0a..805fb43 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2433,7 +2433,6 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
   char real_path[__PMAX];
   char shell[__PMAX]; /* Path to shell */
   const char *toexec;
-  const char *allargs = origallargs.c_str ();
   char *args, *allargs_copy;
   size_t args_len, allargs_len;
   int fd_inp = -1, fd_out = -1, fd_err = -1;
@@ -2449,6 +2448,7 @@ windows_create_inferior (struct target_ops *ops, const char *exec_file,
   size_t envsize;
   char **env;
 #endif	/* !__CYGWIN__ */
+  const char *allargs = origallargs.c_str ();
   PROCESS_INFORMATION pi;
   BOOL ret;
   DWORD flags = 0;
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v6 0/4] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (8 preceding siblings ...)
  2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
@ 2017-05-04  5:31 ` Sergio Durigan Junior
  2017-05-04  5:32   ` [PATCH v6 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
                     ` (3 more replies)
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  10 siblings, 4 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-04  5:31 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves

Hi there,

This is the sixth iteration of the patch series.  You can see the last
version here:

  <https://sourceware.org/ml/gdb-patches/2017-03/msg00516.html>

Getting close, now!

Changes from v5:

- gdb_termios.h has been pushed.

- The "C++ifying" patch has been pushed.

- "common/common-fork-child.c" does not exist anymore.  fork_inferior
  and startup_inferior have been moved to a new "nat/fork-inferior.c"
  file.  The proper "gdb/config/*/*.mh" files have been updated to
  include "fork-inferior.o" as a NATDEPFILE.

- Targets on both GDB and gdbserver sides are now responsible for
  adding the thread/process to the respective lists after the call to
  fork_inferior..  This means that fork_inferior does not call
  add_thread_silent anymore.  I'm not submitting a fix to the hack
  mentioned by Pedro on
  <https://sourceware.org/ml/gdb-patches/2017-04/msg00176.html>; can
  do that in another patch.

No regressions found so far.

Thanks,

Sergio.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-05-04  5:32   ` [PATCH v6 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
@ 2017-05-04  5:32   ` Sergio Durigan Junior
  2017-05-05 19:04     ` Pedro Alves
  2017-05-04  5:32   ` [PATCH v6 3/4] Share fork_inferior et al " Sergio Durigan Junior
  2017-05-04  5:38   ` [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  3 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-04  5:32 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

GDB and gdbserver now share 'switch_to_thread' because of
fork_inferior.  To make things clear, I created a new file name
common/common-gdbthread.h, and left the implementation specific to
each part.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* gdbthread.h: Include "common-gdbthread.h".
	(switch_to_thread): Moved to "common/common-gdbthread.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (switch_to_thread): New function.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 27 +++++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     |  9 +++++++++
 gdb/gdbthread.h               |  5 +----
 4 files changed, 38 insertions(+), 4 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5f489e7..166fb1c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1492,6 +1492,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..3e2b991
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,27 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_GDBTHREAD_H
+#define COMMON_GDBTHREAD_H
+
+struct target_waitstatus;
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+#endif /* ! COMMON_GDBTHREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..5a4a0d1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,12 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 68427e9..3a66297 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -32,6 +32,7 @@ struct symtab;
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
 #include "common/refcounted-object.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -493,10 +494,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v6 1/4] Move parts of inferior job control to common/
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
@ 2017-05-04  5:32   ` Sergio Durigan Junior
  2017-05-04  5:32   ` [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-04  5:32 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This commit moves a few bits responsible for dealing with inferior job
control from GDB to common/, which makes them available to gdbserver.
This is necessary for the upcoming patches that will share
fork_inferior et al between GDB and gdbserver.

We move some parts of gdb/terminal.h to gdb/common/common-terminal.h,
especifically the code that checks terminal features and that are used
to set job_control accordingly.

After sharing parts of gdb/terminal.h, we also to share the two
functions on gdb/inflow.c that are going to be needed by the
fork_inferior rework.  They are 'gdb_setpgid' and the new
'have_job_control'.  I've also taken the opportunity to give a more
meaningful name to "inflow.c" on common/.  Now it is called
"job-control.c" (thanks Pedro for the suggestion).

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/job-control.c".
	(HFILES_NO_SRCDIR): Add "common/job-control.h" and
	"common/gdb_termios.h".
	(COMMON_OBS): Add "job-control.o".
	* common/job-control.c: New file, with contents from
	"gdb/inflow.c".
	* common/job-control.h: New file, with contents from "terminal.h".
	* fork-child.c: Include "job-control.h".
	* inflow.c: Include "job-control.h".
	(gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* terminal.h (job_control): Moved to "common/common-terminal.h".
	(gdb_setpgid): Likewise.
	* top.c: Include "job_control.h".
	* utils.c: Likewise.
	(job_control): Moved to "job-control.c".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILE): Add "common/job-control.c".
	(OBS): Add "job-control.o".
---
 gdb/Makefile.in           |  3 ++
 gdb/common/job-control.c  | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/common/job-control.h  | 38 +++++++++++++++++++
 gdb/fork-child.c          |  1 +
 gdb/gdbserver/Makefile.in |  2 +
 gdb/inflow.c              | 64 ++------------------------------
 gdb/terminal.h            | 12 ------
 gdb/top.c                 |  1 +
 gdb/utils.c               |  5 +--
 9 files changed, 142 insertions(+), 77 deletions(-)
 create mode 100644 gdb/common/job-control.c
 create mode 100644 gdb/common/job-control.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cc93485..5f489e7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1220,6 +1220,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/job-control.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1494,6 +1495,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/job-control.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
@@ -1648,6 +1650,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/job-control.c b/gdb/common/job-control.c
new file mode 100644
index 0000000..9b993df
--- /dev/null
+++ b/gdb/common/job-control.c
@@ -0,0 +1,93 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "job-control.h"
+#include "gdb_termios.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* Set the process group ID of the inferior.
+
+   Just using job_control only does part of it because setpgid or
+   setpgrp might not exist on a system without job control.
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid (void)
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control (void)
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/common/job-control.h b/gdb/common/job-control.h
new file mode 100644
index 0000000..187cd9f
--- /dev/null
+++ b/gdb/common/job-control.h
@@ -0,0 +1,38 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef JOB_CONTROL_H
+#define JOB_CONTROL_H
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid (void);
+
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  This function must be called before any use of
+   JOB_CONTROL.  */
+extern void have_job_control (void);
+
+#endif /* ! JOB_CONTROL_H */
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 11ffee9..c1b6f53 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -33,6 +33,7 @@
 #include "filestuff.h"
 #include "top.h"
 #include "signals-state-save-restore.h"
+#include "job-control.h"
 #include <signal.h>
 #include <vector>
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 01dfdc0..d9f55de 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/job-control.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 23dcc4d..01851f4 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -32,6 +32,7 @@
 #include "inflow.h"
 #include "gdbcmd.h"
 #include "gdb_termios.h"
+#include "job-control.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
@@ -804,43 +805,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -861,30 +825,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/terminal.h b/gdb/terminal.h
index fb20ae0..0027a3a 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -29,16 +29,8 @@ extern void new_tty_postfork (void);
 
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
 extern pid_t create_tty_session (void);
 
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
@@ -48,8 +40,4 @@ extern void gdb_save_tty_state (void);
    have had a chance to alter it.  */
 extern void set_initial_gdb_ttystate (void);
 
-/* Set the process group of the caller to its own pid, or do nothing
-   if we lack job control.  */
-extern int gdb_setpgid (void);
-
 #endif /* !defined (TERMINAL_H) */
diff --git a/gdb/top.c b/gdb/top.c
index 3de8a26..17261cc 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -35,6 +35,7 @@
 #include "value.h"
 #include "language.h"
 #include "terminal.h"		/* For job_control.  */
+#include "job-control.h"
 #include "annotate.h"
 #include "completer.h"
 #include "top.h"
diff --git a/gdb/utils.c b/gdb/utils.c
index b4332f8..c61557e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -65,6 +65,7 @@
 #include "gdb_usleep.h"
 #include "interps.h"
 #include "gdb_regex.h"
+#include "job-control.h"
 
 #if !HAVE_DECL_MALLOC
 extern PTR malloc ();		/* ARI: PTR */
@@ -102,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-05-04  5:32   ` [PATCH v6 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
  2017-05-04  5:32   ` [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
@ 2017-05-04  5:32   ` Sergio Durigan Junior
  2017-05-05 19:05     ` Pedro Alves
  2017-05-04  5:38   ` [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
  3 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-04  5:32 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-inferior.h"
	and "nat/fork-inferior.h".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* commom/common-utils.c: Include "common-utils.h".
	(stringify_argv): New function.
	(trace_start_error): Moved from "fork-child.c".
	(trace_start_error_with_name): Likewise.
	* config/aarch64/linux.mh (NATDEPFILES): Added "fork-inferior.o".
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	(stringify_argv): Likewise.
	(trace_start_error): Likewise.
	(trace_start_error_with_name): Likewise.
	* config/aarch64/linux.mh (NATDEPFILES): Add "fork-inferior.o".
	* config/alpha/alpha-linux.mh (NATDEPFILES): Likewise.
	* config/alpha/nbsd.mh (NATDEPFILES): Likewise.
	* config/arm/linux.mh (NATDEPFILES): Likewise.
	* config/arm/nbsdelf.mh (NATDEPFILES): Likewise.
	* config/i386/darwin.mh (NATDEPFILES): Likewise.
	* config/i386/fbsd.mh (NATDEPFILES): Likewise.
	* config/i386/fbsd64.mh (NATDEPFILES): Likewise.
	* config/i386/i386gnu.mh (NATDEPFILES): Likewise.
	* config/i386/i386sol2.mh (NATDEPFILES): Likewise.
	* config/i386/linux.mh (NATDEPFILES): Likewise.
	* config/i386/linux64.mh (NATDEPFILES): Likewise.
	* config/i386/nbsd64.mh (NATDEPFILES): Likewise.
	* config/i386/nbsdelf.mh (NATDEPFILES): Likewise.
	* config/i386/obsd.mh (NATDEPFILES): Likewise.
	* config/i386/obsd64.mh (NATDEPFILES): Likewise.
	* config/i386/sol2-64.mh (NATDEPFILES): Likewise.
	* config/ia64/linux.mh (NATDEPFILES): Likewise.
	* config/m32r/linux.mh (NATDEPFILES): Likewise.
	* config/m68k/linux.mh (NATDEPFILES): Likewise.
	* config/m68k/nbsdelf.mh (NATDEPFILES): Likewise.
	* config/m68k/obsd.mh (NATDEPFILES): Likewise.
	* config/m88k/obsd.mh (NATDEPFILES): Likewise.
	* config/mips/fbsd.mh (NATDEPFILES): Likewise.
	* config/mips/linux.mh (NATDEPFILES): Likewise.
	* config/mips/nbsd.mh (NATDEPFILES): Likewise.
	* config/mips/obsd64.mh (NATDEPFILES): Likewise.
	* config/mips/obsd64.mh (NATDEPFILES): Likewise.
	* config/pa/linux.mh (NATDEPFILES): Likewise.
	* config/pa/nbsd.mh (NATDEPFILES): Likewise.
	* config/pa/obsd.mh (NATDEPFILES): Likewise.
	* config/powerpc/aix.mh (NATDEPFILES): Likewise.
	* config/powerpc/fbsd.mh (NATDEPFILES): Likewise.
	* config/powerpc/linux.mh (NATDEPFILES): Likewise.
	* config/powerpc/nbsd.mh (NATDEPFILES): Likewise.
	* config/powerpc/obsd.mh (NATDEPFILES): Likewise.
	* config/powerpc/ppc64-linux.mh (NATDEPFILES): Likewise.
	* config/powerpc/spu-linux.mh (NATDEPFILES): Likewise.
	* config/s390/linux.mh (NATDEPFILES): Likewise.
	* config/sh/nbsd.mh (NATDEPFILES): Likewise.
	* config/sparc/fbsd.mh (NATDEPFILES): Likewise.
	* config/sparc/linux.mh (NATDEPFILES): Likewise.
	* config/sparc/linux64.mh (NATDEPFILES): Likewise.
	* config/sparc/nbsd64.mh (NATDEPFILES): Likewise.
	* config/sparc/nbsdelf.mh (NATDEPFILES): Likewise.
	* config/sparc/obsd64.mh (NATDEPFILES): Likewise.
	* config/sparc/sol2.mh (NATDEPFILES): Likewise.
	* config/tilegx/linux.mh (NATDEPFILES): Likewise.
	* config/vax/nbsdelf.mh (NATDEPFILES): Likewise.
	* config/vax/obsd.mh (NATDEPFILES): Likewise.
	* config/xtensa/linux.mh (NATDEPFILES): Likewise.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	(darwin_create_inferior): Call "add_thread_silent" after
	"fork_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(saved_ui): New variable.
	(prefork_hook): New function.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(gdb_startup_inferior): Likewise.
	(fork_inferior): Move to "common/common-fork-child.c".  Update
	function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inf-ptrace.c: Include "nat/fork-inferior.h" and "utils.h".
	(inf_ptrace_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inferior.h: Include "common-inferior.h".
	(trace_start_error): Move to "common/common-utils.h".
	(trace_start_error_with_name): Likewise.
	(fork_inferior): Move prototype to "nat/fork-inferior.h".
	(startup_inferior): Likewise.
	(gdb_startup_inferior): New prototype.
	* nat/fork-inferior.c: New file, with contents from "fork-child.c".
	* nat/fork-inferior.h: New file.
	* procfs.c (procfs_init_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "nat/fork-inferior.o".
	* configure: Regenerate.
	* configure.ac: Adding object file related to safe_strerror to
	IPA_DEPFILES.
	* configure.srv (srv_linux_obj): Add "fork-inferior.o".
	(i[34567]86-*-lynxos*): Likewise.
	(spu*-*-*): Likewise.
	* linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h"
	and "environ.h".
	(linux_ptrace_fun): New function.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".  Update comments.
	* server.c: Include "common-inferior.h", "nat/fork-inferior.h",
	"common-terminal.h" and "environ.h".
	(our_environ): New variable.
	(startup_with_shell): Likewise.
	(program_name): Likewise.
	(program_argv): Rename to...
	(program_args): ...this.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(prefork_hook): Likewise.
	(post_fork_inferior): Likewise.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(post_fork_inferior): New prototype.
	(get_environ): Likewise.
	* spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	* utils.h: Include <vector>.
	(free_vector_argv): New prototype.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   2 +
 gdb/common/common-inferior.h                      |  75 +++
 gdb/common/common-utils.c                         |  45 ++
 gdb/common/common-utils.h                         |  20 +
 gdb/config/aarch64/linux.mh                       |   2 +-
 gdb/config/alpha/alpha-linux.mh                   |   2 +-
 gdb/config/alpha/nbsd.mh                          |   2 +-
 gdb/config/arm/linux.mh                           |   2 +-
 gdb/config/arm/nbsdelf.mh                         |   2 +-
 gdb/config/i386/darwin.mh                         |   2 +-
 gdb/config/i386/fbsd.mh                           |   2 +-
 gdb/config/i386/fbsd64.mh                         |   2 +-
 gdb/config/i386/i386gnu.mh                        |   2 +-
 gdb/config/i386/i386sol2.mh                       |   2 +-
 gdb/config/i386/linux.mh                          |   2 +-
 gdb/config/i386/linux64.mh                        |   2 +-
 gdb/config/i386/nbsd64.mh                         |   2 +-
 gdb/config/i386/nbsdelf.mh                        |   2 +-
 gdb/config/i386/obsd.mh                           |   2 +-
 gdb/config/i386/obsd64.mh                         |   2 +-
 gdb/config/i386/sol2-64.mh                        |   2 +-
 gdb/config/ia64/linux.mh                          |   2 +-
 gdb/config/m32r/linux.mh                          |   2 +-
 gdb/config/m68k/linux.mh                          |   2 +-
 gdb/config/m68k/nbsdelf.mh                        |   2 +-
 gdb/config/m68k/obsd.mh                           |   2 +-
 gdb/config/m88k/obsd.mh                           |   2 +-
 gdb/config/mips/fbsd.mh                           |   2 +-
 gdb/config/mips/linux.mh                          |   2 +-
 gdb/config/mips/nbsd.mh                           |   2 +-
 gdb/config/mips/obsd64.mh                         |   2 +-
 gdb/config/pa/linux.mh                            |   2 +-
 gdb/config/pa/nbsd.mh                             |   2 +-
 gdb/config/pa/obsd.mh                             |   2 +-
 gdb/config/powerpc/aix.mh                         |   2 +-
 gdb/config/powerpc/fbsd.mh                        |   2 +-
 gdb/config/powerpc/linux.mh                       |   2 +-
 gdb/config/powerpc/nbsd.mh                        |   2 +-
 gdb/config/powerpc/obsd.mh                        |   2 +-
 gdb/config/powerpc/ppc64-linux.mh                 |   2 +-
 gdb/config/powerpc/spu-linux.mh                   |   2 +-
 gdb/config/s390/linux.mh                          |   2 +-
 gdb/config/sh/nbsd.mh                             |   2 +-
 gdb/config/sparc/fbsd.mh                          |   2 +-
 gdb/config/sparc/linux.mh                         |   2 +-
 gdb/config/sparc/linux64.mh                       |   2 +-
 gdb/config/sparc/nbsd64.mh                        |   2 +-
 gdb/config/sparc/nbsdelf.mh                       |   2 +-
 gdb/config/sparc/obsd64.mh                        |   2 +-
 gdb/config/sparc/sol2.mh                          |   2 +-
 gdb/config/tilegx/linux.mh                        |   2 +-
 gdb/config/vax/nbsdelf.mh                         |   2 +-
 gdb/config/vax/obsd.mh                            |   2 +-
 gdb/config/xtensa/linux.mh                        |   2 +-
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |  16 +-
 gdb/fork-child.c                                  | 637 +++-------------------
 gdb/gdbserver/Makefile.in                         |   1 +
 gdb/gdbserver/configure                           |   4 +-
 gdb/gdbserver/configure.ac                        |   4 +-
 gdb/gdbserver/configure.srv                       |   6 +-
 gdb/gdbserver/linux-low.c                         |  89 +--
 gdb/gdbserver/lynx-low.c                          |  51 +-
 gdb/gdbserver/nto-low.c                           |  10 +-
 gdb/gdbserver/server.c                            | 258 ++++++---
 gdb/gdbserver/server.h                            |  10 +
 gdb/gdbserver/spu-low.c                           |  45 +-
 gdb/gdbserver/target.c                            |  24 +
 gdb/gdbserver/target.h                            |  13 +-
 gdb/gdbserver/utils.c                             |   9 +
 gdb/gdbserver/utils.h                             |   2 +
 gdb/gdbserver/win32-low.c                         |  22 +-
 gdb/gnu-nat.c                                     |   8 +-
 gdb/inf-ptrace.c                                  |  15 +-
 gdb/inferior.h                                    |  27 +-
 gdb/nat/fork-inferior.c                           | 566 +++++++++++++++++++
 gdb/nat/fork-inferior.h                           |  51 ++
 gdb/procfs.c                                      |   7 +-
 gdb/target.h                                      |  17 -
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  12 +-
 gdb/utils.c                                       |   9 +
 82 files changed, 1313 insertions(+), 860 deletions(-)
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/nat/fork-inferior.c
 create mode 100644 gdb/nat/fork-inferior.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 166fb1c..b9ffc93 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1509,6 +1509,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_termios.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1549,6 +1550,7 @@ HFILES_NO_SRCDIR = \
 	nat/amd64-linux-siginfo.h \
 	nat/gdb_ptrace.h \
 	nat/gdb_thread_db.h \
+	nat/fork-inferior.h \
 	nat/linux-btrace.h \
 	nat/linux-namespaces.h \
 	nat/linux-nat.h \
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..206a36a
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,75 @@
+/* Variables that describe the inferior process running under GDB and
+   GDBserver: Where it is, why it stopped, and how to step it.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
+   is a string containing all the arguments received by the inferior.
+   This function is mainly used by fork_inferior.  */
+extern void prefork_hook (const char *args);
+
+/* Perform any necessary tasks after a fork/vfork takes place.  This
+   function is mainly used by fork_inferior.  */
+extern void postfork_hook (pid_t pid);
+
+/* Perform any necessary tasks *on the child* after a fork/vfork takes
+   place.  DEBUG_FORK is the number of seconds that we should sleep
+   before exec'ing (see fork_inferior).
+
+   This function is mainly used by fork_inferior.  */
+extern void postfork_child_hook (int debug_fork);
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern const char *get_exec_wrapper (void);
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index e94fdc4..d9fce66 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "common-defs.h"
+#include "common-utils.h"
 #include "host-defs.h"
 #include <ctype.h>
 
@@ -328,3 +329,47 @@ free_vector_argv (std::vector<char *> &v)
 
   v.clear ();
 }
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (const std::vector<char *> &args)
+{
+  std::string ret ("");
+
+  if (!args.empty ())
+    {
+      for (auto s : args)
+	if (s != NULL)
+	  ret += s + std::string (" ");
+
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+    }
+
+  return ret;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index c331f0d..0453844 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -108,4 +108,24 @@ extern const char *skip_to_space_const (const char *inp);
    freeing all the elements.  */
 extern void free_vector_argv (std::vector<char *> &v);
 
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments with a whitespace separating them.  */
+extern std::string stringify_argv (const std::vector<char *> &argv);
+
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err (void);
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
 #endif
diff --git a/gdb/config/aarch64/linux.mh b/gdb/config/aarch64/linux.mh
index d184a79..883489e 100644
--- a/gdb/config/aarch64/linux.mh
+++ b/gdb/config/aarch64/linux.mh
@@ -19,7 +19,7 @@
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o aarch32-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o aarch64-linux-nat.o aarch32-linux-nat.o \
 	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
 	linux-personality.o linux-namespaces.o aarch64-linux-hw-point.o \
diff --git a/gdb/config/alpha/alpha-linux.mh b/gdb/config/alpha/alpha-linux.mh
index 4991dd2..a56e123 100644
--- a/gdb/config/alpha/alpha-linux.mh
+++ b/gdb/config/alpha/alpha-linux.mh
@@ -1,7 +1,7 @@
 # Host: Little-endian Alpha running Linux
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o alpha-linux-nat.o \
-	fork-child.o proc-service.o linux-thread-db.o \
+	fork-child.o fork-inferior.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o linux-namespaces.o
 NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/config/alpha/nbsd.mh b/gdb/config/alpha/nbsd.mh
index a46739e..a2a064b 100644
--- a/gdb/config/alpha/nbsd.mh
+++ b/gdb/config/alpha/nbsd.mh
@@ -1,4 +1,4 @@
 # Host: NetBSD/alpha
-NATDEPFILES= fork-child.o inf-ptrace.o alpha-bsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o alpha-bsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/arm/linux.mh b/gdb/config/arm/linux.mh
index 003ca1f..ca69109 100644
--- a/gdb/config/arm/linux.mh
+++ b/gdb/config/arm/linux.mh
@@ -1,7 +1,7 @@
 # Host: ARM based machine running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o arm-linux-nat.o \
 	aarch32-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o linux-namespaces.o
diff --git a/gdb/config/arm/nbsdelf.mh b/gdb/config/arm/nbsdelf.mh
index 042b583..bf1074b 100644
--- a/gdb/config/arm/nbsdelf.mh
+++ b/gdb/config/arm/nbsdelf.mh
@@ -1,2 +1,2 @@
 # Host: NetBSD/arm
-NATDEPFILES= fork-child.o inf-ptrace.o arm-nbsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o arm-nbsd-nat.o
diff --git a/gdb/config/i386/darwin.mh b/gdb/config/i386/darwin.mh
index 16c1558..6eb1d69 100644
--- a/gdb/config/i386/darwin.mh
+++ b/gdb/config/i386/darwin.mh
@@ -1,4 +1,4 @@
 # Host: IA86 running Darwin
 
-NATDEPFILES = fork-child.o darwin-nat.o \
+NATDEPFILES = fork-child.o fork-inferior.o darwin-nat.o \
      i386-darwin-nat.o x86-nat.o x86-dregs.o amd64-nat.o darwin-nat-info.o
diff --git a/gdb/config/i386/fbsd.mh b/gdb/config/i386/fbsd.mh
index 69e0a8b..7304453 100644
--- a/gdb/config/i386/fbsd.mh
+++ b/gdb/config/i386/fbsd.mh
@@ -1,5 +1,5 @@
 # Host: FreeBSD/i386
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	fbsd-nat.o x86-nat.o x86-dregs.o x86-bsd-nat.o i386-bsd-nat.o \
 	i386-fbsd-nat.o bsd-kvm.o
 NAT_FILE= nm-fbsd.h
diff --git a/gdb/config/i386/fbsd64.mh b/gdb/config/i386/fbsd64.mh
index 461ff9a..7dfcf93 100644
--- a/gdb/config/i386/fbsd64.mh
+++ b/gdb/config/i386/fbsd64.mh
@@ -1,5 +1,5 @@
 # Host: FreeBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	fbsd-nat.o amd64-nat.o amd64-bsd-nat.o amd64-fbsd-nat.o \
 	bsd-kvm.o x86-nat.o x86-dregs.o x86-bsd-nat.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh
index 070497f..d73c28b 100644
--- a/gdb/config/i386/i386gnu.mh
+++ b/gdb/config/i386/i386gnu.mh
@@ -1,6 +1,6 @@
 # Host: Intel 386 running the GNU Hurd
 NATDEPFILES= i386-gnu-nat.o gnu-nat.o \
-	     x86-nat.o x86-dregs.o fork-child.o \
+	     x86-nat.o x86-dregs.o fork-child.o fork-inferior.o \
 	     notify_S.o process_reply_S.o msg_reply_S.o \
 	     msg_U.o exc_request_U.o exc_request_S.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/i386/i386sol2.mh b/gdb/config/i386/i386sol2.mh
index 787a3c1..18d0631 100644
--- a/gdb/config/i386/i386sol2.mh
+++ b/gdb/config/i386/i386sol2.mh
@@ -1,4 +1,4 @@
 # Host: Solaris x86
-NATDEPFILES= fork-child.o i386-v4-nat.o i386-sol2-nat.o \
+NATDEPFILES= fork-child.o fork-inferior.o i386-v4-nat.o i386-sol2-nat.o \
 	procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 421c56f..da03bc1 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -1,7 +1,7 @@
 # Host: Intel 386 running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	x86-nat.o x86-dregs.o i386-linux-nat.o x86-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index 42d8df5..df07959 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -1,5 +1,5 @@
 # Host: GNU/Linux x86-64
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	x86-nat.o x86-dregs.o amd64-nat.o amd64-linux-nat.o \
 	x86-linux-nat.o \
 	linux-nat.o linux-osdata.o \
diff --git a/gdb/config/i386/nbsd64.mh b/gdb/config/i386/nbsd64.mh
index 91d21f3..de679f1 100644
--- a/gdb/config/i386/nbsd64.mh
+++ b/gdb/config/i386/nbsd64.mh
@@ -1,3 +1,3 @@
 # Host: NetBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	nbsd-nat.o amd64-nat.o x86-bsd-nat.o amd64-bsd-nat.o amd64-nbsd-nat.o
diff --git a/gdb/config/i386/nbsdelf.mh b/gdb/config/i386/nbsdelf.mh
index 5954b3f..1504be2 100644
--- a/gdb/config/i386/nbsdelf.mh
+++ b/gdb/config/i386/nbsdelf.mh
@@ -1,5 +1,5 @@
 # Host: NetBSD/i386 ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	nbsd-nat.o x86-bsd-nat.o i386-bsd-nat.o i386-nbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/i386/obsd.mh b/gdb/config/i386/obsd.mh
index fac7282..3f1865d 100644
--- a/gdb/config/i386/obsd.mh
+++ b/gdb/config/i386/obsd.mh
@@ -1,5 +1,5 @@
 # Host: OpenBSD/i386 ELF
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o \
 	x86-bsd-nat.o i386-bsd-nat.o i386-obsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/i386/obsd64.mh b/gdb/config/i386/obsd64.mh
index 51deea7..a457c61 100644
--- a/gdb/config/i386/obsd64.mh
+++ b/gdb/config/i386/obsd64.mh
@@ -1,5 +1,5 @@
 # Host: OpenBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o \
 	amd64-nat.o x86-bsd-nat.o amd64-bsd-nat.o amd64-obsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/i386/sol2-64.mh b/gdb/config/i386/sol2-64.mh
index 7a3ab73..f9584b4 100644
--- a/gdb/config/i386/sol2-64.mh
+++ b/gdb/config/i386/sol2-64.mh
@@ -1,4 +1,4 @@
 # Host: Solaris x86_64
-NATDEPFILES= fork-child.o amd64-nat.o i386-v4-nat.o i386-sol2-nat.o \
+NATDEPFILES= fork-child.o fork-inferior.o amd64-nat.o i386-v4-nat.o i386-sol2-nat.o \
 	procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/ia64/linux.mh b/gdb/config/ia64/linux.mh
index b05f834..29714eb 100644
--- a/gdb/config/ia64/linux.mh
+++ b/gdb/config/ia64/linux.mh
@@ -1,7 +1,7 @@
 # Host: Intel IA-64 running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	ia64-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
diff --git a/gdb/config/m32r/linux.mh b/gdb/config/m32r/linux.mh
index 277d8bd..da95b18 100644
--- a/gdb/config/m32r/linux.mh
+++ b/gdb/config/m32r/linux.mh
@@ -1,7 +1,7 @@
 # Host: M32R based machine running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o				\
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o				\
 	m32r-linux-nat.o proc-service.o linux-thread-db.o	\
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o linux-namespaces.o
diff --git a/gdb/config/m68k/linux.mh b/gdb/config/m68k/linux.mh
index 7c1f4ac..ec729a1 100644
--- a/gdb/config/m68k/linux.mh
+++ b/gdb/config/m68k/linux.mh
@@ -1,7 +1,7 @@
 # Host: Motorola m68k running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	m68k-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
diff --git a/gdb/config/m68k/nbsdelf.mh b/gdb/config/m68k/nbsdelf.mh
index 1d00cbc..3ca06ce 100644
--- a/gdb/config/m68k/nbsdelf.mh
+++ b/gdb/config/m68k/nbsdelf.mh
@@ -1,4 +1,4 @@
 # Host: NetBSD/m68k ELF
-NATDEPFILES= m68k-bsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o
+NATDEPFILES= m68k-bsd-nat.o bsd-kvm.o fork-child.o fork-inferior.o inf-ptrace.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/m68k/obsd.mh b/gdb/config/m68k/obsd.mh
index 902a24b..64e715a 100644
--- a/gdb/config/m68k/obsd.mh
+++ b/gdb/config/m68k/obsd.mh
@@ -1,4 +1,4 @@
 # Host: OpenBSD/m68k
-NATDEPFILES= m68k-bsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o
+NATDEPFILES= m68k-bsd-nat.o bsd-kvm.o fork-child.o fork-inferior.o inf-ptrace.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/m88k/obsd.mh b/gdb/config/m88k/obsd.mh
index 3c4d8d5..2a46a0a 100644
--- a/gdb/config/m88k/obsd.mh
+++ b/gdb/config/m88k/obsd.mh
@@ -1,2 +1,2 @@
 # Host: OpenBSD/m88k
-NATDEPFILES= fork-child.o inf-ptrace.o m88k-bsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o m88k-bsd-nat.o
diff --git a/gdb/config/mips/fbsd.mh b/gdb/config/mips/fbsd.mh
index f433347..e6fb2fe 100644
--- a/gdb/config/mips/fbsd.mh
+++ b/gdb/config/mips/fbsd.mh
@@ -1,3 +1,3 @@
 # Host: FreeBSD/mips
-NATDEPFILES= fork-child.o inf-ptrace.o fbsd-nat.o mips-fbsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o fbsd-nat.o mips-fbsd-nat.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 11ff903..c279821 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -1,6 +1,6 @@
 # Host: Linux/MIPS
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/mips/nbsd.mh b/gdb/config/mips/nbsd.mh
index a80da95..ffcb865 100644
--- a/gdb/config/mips/nbsd.mh
+++ b/gdb/config/mips/nbsd.mh
@@ -1,2 +1,2 @@
 # Host: NetBSD/mips
-NATDEPFILES= fork-child.o inf-ptrace.o mips-nbsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o mips-nbsd-nat.o
diff --git a/gdb/config/mips/obsd64.mh b/gdb/config/mips/obsd64.mh
index 6aeac34..ec29639 100644
--- a/gdb/config/mips/obsd64.mh
+++ b/gdb/config/mips/obsd64.mh
@@ -1,2 +1,2 @@
 # Host: OpenBSD/mips64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o mips64-obsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o mips64-obsd-nat.o
diff --git a/gdb/config/pa/linux.mh b/gdb/config/pa/linux.mh
index 1b73ecd..54c4b21 100644
--- a/gdb/config/pa/linux.mh
+++ b/gdb/config/pa/linux.mh
@@ -1,6 +1,6 @@
 # Host: Hewlett-Packard PA-RISC machine, running Linux
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	hppa-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/pa/nbsd.mh b/gdb/config/pa/nbsd.mh
index 791cd9f..3fd205a 100644
--- a/gdb/config/pa/nbsd.mh
+++ b/gdb/config/pa/nbsd.mh
@@ -1,2 +1,2 @@
 # Host: NetBSD/hppa
-NATDEPFILES= fork-child.o inf-ptrace.o nbsd-nat.o hppa-nbsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o nbsd-nat.o hppa-nbsd-nat.o
diff --git a/gdb/config/pa/obsd.mh b/gdb/config/pa/obsd.mh
index 95dd416..10c7a46 100644
--- a/gdb/config/pa/obsd.mh
+++ b/gdb/config/pa/obsd.mh
@@ -1,2 +1,2 @@
 # Host: OpenBSD/hppa
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o hppa-obsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o hppa-obsd-nat.o
diff --git a/gdb/config/powerpc/aix.mh b/gdb/config/powerpc/aix.mh
index 141501d..0f6179e 100644
--- a/gdb/config/powerpc/aix.mh
+++ b/gdb/config/powerpc/aix.mh
@@ -1,7 +1,7 @@
 # Host: IBM PowerPC running AIX
 
 # aix-thread.o is not listed in NATDEPFILES as it is pulled in by configure.
-NATDEPFILES= fork-child.o inf-ptrace.o rs6000-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o rs6000-nat.o
 
 # When compiled with cc, for debugging, this argument should be passed.
 # We have no idea who our current compiler is though, so we skip it.
diff --git a/gdb/config/powerpc/fbsd.mh b/gdb/config/powerpc/fbsd.mh
index 9c2e6b4..f30d045 100644
--- a/gdb/config/powerpc/fbsd.mh
+++ b/gdb/config/powerpc/fbsd.mh
@@ -17,7 +17,7 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-NATDEPFILES= fbsd-nat.o fork-child.o inf-ptrace.o ppc-fbsd-nat.o bsd-kvm.o
+NATDEPFILES= fbsd-nat.o fork-child.o fork-inferior.o inf-ptrace.o ppc-fbsd-nat.o bsd-kvm.o
 HAVE_NATIVE_GCORE_HOST = 1
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/linux.mh b/gdb/config/powerpc/linux.mh
index f4a52c3..b0f5304 100644
--- a/gdb/config/powerpc/linux.mh
+++ b/gdb/config/powerpc/linux.mh
@@ -3,7 +3,7 @@
 XM_CLIBS=
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	ppc-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o linux-namespaces.o
diff --git a/gdb/config/powerpc/nbsd.mh b/gdb/config/powerpc/nbsd.mh
index f02a0f9..1ada620 100644
--- a/gdb/config/powerpc/nbsd.mh
+++ b/gdb/config/powerpc/nbsd.mh
@@ -1,4 +1,4 @@
 # Host: NetBSD/powerpc
-NATDEPFILES= fork-child.o inf-ptrace.o ppc-nbsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o ppc-nbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/obsd.mh b/gdb/config/powerpc/obsd.mh
index 3743254..da227f4 100644
--- a/gdb/config/powerpc/obsd.mh
+++ b/gdb/config/powerpc/obsd.mh
@@ -1,4 +1,4 @@
 # Host: OpenBSD/powerpc
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o ppc-obsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o ppc-obsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/ppc64-linux.mh b/gdb/config/powerpc/ppc64-linux.mh
index 8681d00..8cbe314 100644
--- a/gdb/config/powerpc/ppc64-linux.mh
+++ b/gdb/config/powerpc/ppc64-linux.mh
@@ -3,7 +3,7 @@
 XM_CLIBS=
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	ppc-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o ppc-linux.o linux-personality.o \
diff --git a/gdb/config/powerpc/spu-linux.mh b/gdb/config/powerpc/spu-linux.mh
index 9205b62..6b3b38a 100644
--- a/gdb/config/powerpc/spu-linux.mh
+++ b/gdb/config/powerpc/spu-linux.mh
@@ -3,6 +3,6 @@
 # This implements a 'pseudo-native' GDB running on the
 # PPU side of the Cell BE and debugging the SPU side.
 
-NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o \
+NATDEPFILES = spu-linux-nat.o fork-child.o fork-inferior.o inf-ptrace.o \
 	      linux-procfs.o linux-ptrace.o linux-waitpid.o \
 	      linux-personality.o linux-namespaces.o
diff --git a/gdb/config/s390/linux.mh b/gdb/config/s390/linux.mh
index 4a137cd..4353385 100644
--- a/gdb/config/s390/linux.mh
+++ b/gdb/config/s390/linux.mh
@@ -1,6 +1,6 @@
 # Host: S390, running Linux
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o s390-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o s390-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-personality.o \
diff --git a/gdb/config/sh/nbsd.mh b/gdb/config/sh/nbsd.mh
index 14d7e8c..c95e8fc 100644
--- a/gdb/config/sh/nbsd.mh
+++ b/gdb/config/sh/nbsd.mh
@@ -1,2 +1,2 @@
 # Host: NetBSD/sh
-NATDEPFILES= fork-child.o inf-ptrace.o sh-nbsd-nat.o
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o sh-nbsd-nat.o
diff --git a/gdb/config/sparc/fbsd.mh b/gdb/config/sparc/fbsd.mh
index bdc272c..b0adf2f 100644
--- a/gdb/config/sparc/fbsd.mh
+++ b/gdb/config/sparc/fbsd.mh
@@ -1,5 +1,5 @@
 # Host: FreeBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	fbsd-nat.o sparc-nat.o sparc64-nat.o sparc64-fbsd-nat.o \
 	bsd-kvm.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/sparc/linux.mh b/gdb/config/sparc/linux.mh
index 385f640..467d2f9 100644
--- a/gdb/config/sparc/linux.mh
+++ b/gdb/config/sparc/linux.mh
@@ -1,7 +1,7 @@
 # Host: GNU/Linux SPARC
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= sparc-nat.o sparc-linux-nat.o \
-	fork-child.o inf-ptrace.o \
+	fork-child.o fork-inferior.o inf-ptrace.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/sparc/linux64.mh b/gdb/config/sparc/linux64.mh
index 8df0de1..c0780ac 100644
--- a/gdb/config/sparc/linux64.mh
+++ b/gdb/config/sparc/linux64.mh
@@ -1,7 +1,7 @@
 # Host: GNU/Linux UltraSPARC
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= sparc-nat.o sparc64-nat.o sparc64-linux-nat.o \
-	fork-child.o inf-ptrace.o \
+	fork-child.o fork-inferior.o inf-ptrace.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/sparc/nbsd64.mh b/gdb/config/sparc/nbsd64.mh
index aa15b1d..f68bdf9 100644
--- a/gdb/config/sparc/nbsd64.mh
+++ b/gdb/config/sparc/nbsd64.mh
@@ -1,5 +1,5 @@
 # Host: NetBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	sparc64-nbsd-nat.o sparc-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/sparc/nbsdelf.mh b/gdb/config/sparc/nbsdelf.mh
index 97d07b3..34f6a43 100644
--- a/gdb/config/sparc/nbsdelf.mh
+++ b/gdb/config/sparc/nbsdelf.mh
@@ -1,5 +1,5 @@
 # Host: NetBSD/sparc ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	sparc-nat.o sparc-nbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/sparc/obsd64.mh b/gdb/config/sparc/obsd64.mh
index e9f2fb9..08c6318 100644
--- a/gdb/config/sparc/obsd64.mh
+++ b/gdb/config/sparc/obsd64.mh
@@ -1,5 +1,5 @@
 # Host: OpenBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o obsd-nat.o \
 	sparc64-obsd-nat.o sparc-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/sparc/sol2.mh b/gdb/config/sparc/sol2.mh
index 220c61f..dbeb2df 100644
--- a/gdb/config/sparc/sol2.mh
+++ b/gdb/config/sparc/sol2.mh
@@ -1,6 +1,6 @@
 # Host: Solaris SPARC & UltraSPARC
 NAT_FILE= nm-sol2.h
 NATDEPFILES= sparc-sol2-nat.o \
-	fork-child.o \
+	fork-child.o fork-inferior.o \
 	procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/tilegx/linux.mh b/gdb/config/tilegx/linux.mh
index ec648d3..c79e509 100644
--- a/gdb/config/tilegx/linux.mh
+++ b/gdb/config/tilegx/linux.mh
@@ -1,7 +1,7 @@
 # Host: Tilera TILE-Gx running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o \
 	tilegx-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
diff --git a/gdb/config/vax/nbsdelf.mh b/gdb/config/vax/nbsdelf.mh
index bf0f0b9..80f9b85 100644
--- a/gdb/config/vax/nbsdelf.mh
+++ b/gdb/config/vax/nbsdelf.mh
@@ -1,5 +1,5 @@
 # Host: NetBSD/vax ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	vax-bsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/vax/obsd.mh b/gdb/config/vax/obsd.mh
index cef99d3..c2dc5da 100644
--- a/gdb/config/vax/obsd.mh
+++ b/gdb/config/vax/obsd.mh
@@ -1,5 +1,5 @@
 # Host: OpenBSD/vax
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o fork-inferior.o inf-ptrace.o \
 	vax-bsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/xtensa/linux.mh b/gdb/config/xtensa/linux.mh
index d5b8f91..916838b 100644
--- a/gdb/config/xtensa/linux.mh
+++ b/gdb/config/xtensa/linux.mh
@@ -2,7 +2,7 @@
 
 NAT_FILE= config/nm-linux.h
 
-NATDEPFILES= inf-ptrace.o fork-child.o xtensa-linux-nat.o \
+NATDEPFILES= inf-ptrace.o fork-child.o fork-inferior.o xtensa-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o linux-namespaces.o
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 13a90b9..33eb4d1 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index cba84ca..4330a60 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1790,7 +1790,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 }
 
 static void
@@ -1833,13 +1833,23 @@ darwin_create_inferior (struct target_ops *ops,
 			const std::string &allargs,
 			char **env, int from_tty)
 {
+  pid_t pid;
+  ptid_t ptid;
+
   /* Do the hard work.  */
-  fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
-		 darwin_pre_ptrace, NULL, darwin_execvp);
+  pid = fork_inferior (exec_file, allargs, env, darwin_ptrace_me,
+		       darwin_ptrace_him, darwin_pre_ptrace, NULL,
+		       darwin_execvp);
 
+  ptid = pid_to_ptid (pid);
   /* Return now in case of error.  */
   if (ptid_equal (inferior_ptid, null_ptid))
     return;
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
 }
 \f
 
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index c1b6f53..21a296b 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,471 +21,54 @@
 
 #include "defs.h"
 #include "inferior.h"
+#include "gdbcmd.h"
 #include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
 #include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
-#include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
 #include "top.h"
-#include "signals-state-save-restore.h"
 #include "job-control.h"
-#include <signal.h>
-#include <vector>
-
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
-
-extern char **environ;
-
-static char *exec_wrapper;
-
-/* Build the argument vector for execv(3).  */
-
-class execv_argv
-{
-public:
-  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
-     arguments to the program.  If starting with a shell, SHELL_FILE
-     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
-  execv_argv (const char *exec_file, const std::string &allargs,
-	      const char *shell_file);
-
-  /* Return a pointer to the built argv, in the type expected by
-     execv.  The result is (only) valid for as long as this execv_argv
-     object is live.  We return a "char **" because that's the type
-     that the execv functions expect.  Note that it is guaranteed that
-     the execv functions do not modify the argv[] array nor the
-     strings to which the array point.  */
-  char **argv ()
-  {
-    return const_cast<char **> (&m_argv[0]);
-  }
-
-private:
-  /* Disable copying.  */
-  execv_argv (const execv_argv &) = delete;
-  void operator= (const execv_argv &) = delete;
-
-  /* Helper methods for constructing the argument vector.  */
-
-  /* Used when building an argv for a straight execv call, without
-     going via the shell.  */
-  void init_for_no_shell (const char *exec_file,
-			  const std::string &allargs);
-
-  /* Used when building an argv for execing a shell that execs the
-     child program.  */
-  void init_for_shell (const char *exec_file,
-		       const std::string &allargs,
-		       const char *shell_file);
-
-  /* The argument vector built.  Holds non-owning pointers.  Elements
-     either point to the strings passed to the execv_argv ctor, or
-     inside M_STORAGE.  */
-  std::vector<const char *> m_argv;
-
-  /* Storage.  In the no-shell case, this contains a copy of the
-     arguments passed to the ctor, split by '\0'.  In the shell case,
-     this contains the quoted shell command.  I.e., SHELL_COMMAND in
-     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
-  std::string m_storage;
-};
-
-/* Create argument vector for straight call to execvp.  Breaks up
-   ALLARGS into an argument vector suitable for passing to execvp and
-   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
-   as input the string "a b c d", and as output it would fill in
-   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
-   in M_ARGV points to a substring of a copy of ALLARGS stored in
-   M_STORAGE.  */
-
-void
-execv_argv::init_for_no_shell (const char *exec_file,
-			       const std::string &allargs)
-{
-
-  /* Save/work with a copy stored in our storage.  The pointers pushed
-     to M_ARGV point directly into M_STORAGE, which is modified in
-     place with the necessary NULL terminators.  This avoids N heap
-     allocations and string dups when 1 is sufficient.  */
-  std::string &args_copy = m_storage = allargs;
-
-  m_argv.push_back (exec_file);
+#include "filestuff.h"
+#include "nat/fork-inferior.h"
 
-  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
-    {
-      /* Skip whitespace-like chars.  */
-      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
-
-      if (pos != std::string::npos)
-	cur_pos = pos;
-
-      /* Find the position of the next separator.  */
-      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
-
-      if (next_sep == std::string::npos)
-	{
-	  /* No separator found, which means this is the last
-	     argument.  */
-	  next_sep = args_copy.size ();
-	}
-      else
-	{
-	  /* Replace the separator with a terminator.  */
-	  args_copy[next_sep++] = '\0';
-	}
-
-      m_argv.push_back (&args_copy[cur_pos]);
-
-      cur_pos = next_sep;
-    }
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-  /* NULL-terminate the vector.  */
-  m_argv.push_back (NULL);
-}
+static char *exec_wrapper = NULL;
 
-/* When executing a command under the given shell, return true if the
-   '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
+/* See common/common-inferior.h.  */
 
-static bool
-escape_bang_in_quoted_argument (const char *shell_file)
+const char *
+get_exec_wrapper (void)
 {
-  size_t shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return false;
-
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return true;
-
-  return false;
+  return exec_wrapper;
 }
 
-/* See declaration.  */
-
-execv_argv::execv_argv (const char *exec_file,
-			const std::string &allargs,
-			const char *shell_file)
-{
-  if (shell_file == NULL)
-    init_for_no_shell (exec_file, allargs);
-  else
-    init_for_shell (exec_file, allargs, shell_file);
-}
+/* The ui structure that will be saved on 'prefork_hook' and
+   restored on 'postfork_hook'.  */
+static struct ui *saved_ui = NULL;
 
-/* See declaration.  */
+/* See common/common-inferior.h.  */
 
 void
-execv_argv::init_for_shell (const char *exec_file,
-			    const std::string &allargs,
-			    const char *shell_file)
+prefork_hook (const char *args)
 {
-  /* We're going to call a shell.  */
-  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-  /* We need to build a new shell command string, and make argv point
-     to it.  So build it in the storage.  */
-  std::string &shell_command = m_storage;
-
-  shell_command = "exec ";
-
-  /* Add any exec wrapper.  That may be a program name with arguments,
-     so the user must handle quoting.  */
-  if (exec_wrapper)
-    {
-      shell_command += exec_wrapper;
-      shell_command += ' ';
-    }
-
-  /* Now add exec_file, quoting as necessary.  */
-
-  /* Quoting in this style is said to work with all shells.  But csh
-     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
-     to.  */
-  bool need_to_quote;
-  const char *p = exec_file;
-  while (1)
-    {
-      switch (*p)
-	{
-	case '\'':
-	case '!':
-	case '"':
-	case '(':
-	case ')':
-	case '$':
-	case '&':
-	case ';':
-	case '<':
-	case '>':
-	case ' ':
-	case '\n':
-	case '\t':
-	  need_to_quote = true;
-	  goto end_scan;
-
-	case '\0':
-	  need_to_quote = false;
-	  goto end_scan;
-
-	default:
-	  break;
-	}
-      ++p;
-    }
- end_scan:
-  if (need_to_quote)
-    {
-      shell_command += '\'';
-      for (p = exec_file; *p != '\0'; ++p)
-	{
-	  if (*p == '\'')
-	    shell_command += "'\\''";
-	  else if (*p == '!' && escape_bang)
-	    shell_command += "\\!";
-	  else
-	    shell_command += *p;
-	}
-      shell_command += '\'';
-    }
-  else
-    shell_command += exec_file;
-
-  shell_command += ' ' + allargs;
-
-  /* If we decided above to start up with a shell, we exec the shell.
-     "-c" says to interpret the next arg as a shell command to
-     execute, and this command is "exec <target-program> <args>".  */
-  m_argv.reserve (4);
-  m_argv.push_back (shell_file);
-  m_argv.push_back ("-c");
-  m_argv.push_back (shell_command.c_str ());
-  m_argv.push_back (NULL);
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
-		                  "process.\nError: ");
-  vfprintf_unfiltered (gdb_stderr, fmt, ap);
-  va_end (ap);
-
-  gdb_flush (gdb_stderr);
-  _exit (0177);
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error_with_name (const char *string)
-{
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (const char *exec_file_arg, const std::string &allargs,
-	       char **env, void (*traceme_fun) (void),
-	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
-	       char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static const char *exec_file;
-  char **save_our_env;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  if (exec_file_arg == NULL)
-    exec_file = get_exec_file (1);
-  else
-    exec_file = exec_file_arg;
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  if (startup_with_shell)
-    {
-      shell_file = shell_file_arg;
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-    }
-  else
-    shell_file = NULL;
-
-  /* Build the argument vector.  */
-  execv_argv child_argv (exec_file, allargs, shell_file);
 
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
+  gdb_assert (saved_ui == NULL);
+  /* Retain a copy of our UI, since the child will replace this value
+     and if we're vforked, we have to restore it.  */
+  saved_ui = current_ui;
 
   /* Tell the terminal handling subsystem what tty we plan to run on;
      it will just record the information for later.  */
   new_tty_prefork (inferior_io_terminal);
+}
 
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      char **argv = child_argv.argv ();
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], &argv[0], env);
-      else
-        execvp (argv[0], &argv[0]);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
+/* See common/common-inferior.h.  */
 
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
+void
+postfork_hook (pid_t pid)
+{
+  struct inferior *inf;
 
   if (!have_inferiors ())
     init_thread_list ();
@@ -494,147 +77,67 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
 
   inferior_appeared (inf, pid);
 
-  /* Needed for wait_for_inferior stuff below.  */
+  /* Needed for wait_for_inferior stuff.  */
   inferior_ptid = pid_to_ptid (pid);
 
-  new_tty_postfork ();
+  gdb_assert (saved_ui != NULL);
+  current_ui = saved_ui;
+  saved_ui = NULL;
 
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
+  new_tty_postfork ();
 }
 
-/* Accept NTRAPS traps from the inferior.  */
+/* See common/common-inferior.h.  */
 
 void
-startup_inferior (int ntraps)
+postfork_child_hook (int debug_fork)
 {
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
-
-  if (startup_with_shell)
-    {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
-    }
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
 
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
+  /* Make sure we switch to main_ui here in order to be able to
+     use the fprintf_unfiltered/warning/error functions.  */
+  current_ui = main_ui;
 
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
+  /* Close all file descriptors except those that gdb inherited
+     (usually 0/1/2), so they don't leak to the inferior.  Note
+     that this closes the file descriptors of all secondary
+     UIs.  */
+  close_most_fds ();
 
-  if (exec_wrapper)
-    pending_execs++;
+  if (debug_fork)
+    sleep (debug_fork);
 
-  while (1)
+  /* Create a new session for the inferior process, if necessary.
+     It will also place the inferior in a separate process group.  */
+  if (create_tty_session () <= 0)
     {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
+      /* No session was created, but we still want to run the inferior
+	 in a separate process group.  */
+      debug_setpgrp = gdb_setpgid ();
+      if (debug_setpgrp == -1)
+	perror (_("setpgrp failed in child"));
     }
 
+  /* Ask the tty subsystem to switch to the one we specified
+     earlier (or to share the current terminal, if none was
+     specified).  */
+  new_tty ();
+}
+
+/* See inferior.h.  */
+
+ptid_t
+gdb_startup_inferior (pid_t pid, int num_traps)
+{
+  ptid_t ptid = startup_inferior (pid, num_traps, NULL, NULL);
+
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  set_executing (ptid, 0);
+
+  return ptid;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d9f55de..834425d 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -218,6 +218,7 @@ SFILES = \
 	$(srcdir)/nat/linux-personality.c \
 	$(srcdir)/nat/mips-linux-watch.c \
 	$(srcdir)/nat/ppc-linux.c \
+	$(srcdir)/nat/fork-inferior.c \
 	$(srcdir)/target/waitstatus.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index d524ae4..715c209 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -8422,7 +8422,9 @@ fi
 
 if $want_ipa ; then
    if $have_ipa ; then
-     IPA_DEPFILES="$ipa_obj"
+     # Needed because safe_strerror's definition is host-dependent
+     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
+     IPA_DEPFILES="$ipa_obj $strerror_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      as_fn_error "inprocess agent not supported for this target" "$LINENO" 5
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 4ea7913..8aa85db 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -462,7 +462,9 @@ esac],
 
 if $want_ipa ; then
    if $have_ipa ; then
-     IPA_DEPFILES="$ipa_obj"
+     # Needed because safe_strerror's definition is host-dependent
+     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
+     IPA_DEPFILES="$ipa_obj $strerror_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      AC_MSG_ERROR([inprocess agent not supported for this target])
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index d00d9e2..056ac27 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
 
 # Linux object files.  This is so we don't have to repeat
 # these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-inferior.o"
 
 # Input is taken from the "${target}" variable.
 
@@ -131,7 +131,7 @@ case "${target}" in
 			ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
 			;;
   i[34567]86-*-lynxos*)	srv_regobj="i386.o"
-			srv_tgtobj="lynx-low.o lynx-i386-low.o"
+			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-inferior.o"
 			srv_xmlfiles="i386/i386.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
@@ -338,7 +338,7 @@ case "${target}" in
 			srv_linux_thread_db=yes
 			;;
   spu*-*-*)		srv_regobj=reg-spu.o
-			srv_tgtobj="spu-low.o"
+			srv_tgtobj="spu-low.o fork-inferior.o"
 			;;
   tic6x-*-uclinux)	srv_regobj="tic6x-c64xp-linux.o"
 			srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ea3c81b..5789ada 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,9 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -946,59 +949,57 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+	trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+	trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+	trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string str_program_args = stringify_argv (program_args);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
@@ -1008,6 +1009,8 @@ linux_create_inferior (char *program, char **allargs)
   new_lwp = add_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..59e8da3 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,8 @@
 #include "gdb_wait.h"
 #include <signal.h>
 #include "filestuff.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
 
 int using_threads = 1;
 
@@ -224,36 +226,43 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Callback used by fork_inferior to start tracing the inferior.  */
+
+static void
+lynx_ptrace_fun (void)
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  if (pgrp < 0)
+    trace_start_error_with_name ("pgrp");
+  if (setpgid (0, pgrp) < 0)
+    trace_start_error_with_name ("setpgid");
+  if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+    trace_start_error_with_name ("ioctl");
+  if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+    trace_start_error_with_name ("lynx_ptrace");
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (const char *program,
+		      const std::vector<char *> &program_args)
 {
   int pid;
+  std::string str_program_args = stringify_argv (program_args);
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program);
 
   lynx_add_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..a5f1543 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
+   arguments.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (const char *program,
+		     const std::vector<char *> &program_args)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string str_program_args = stringify_argv (program_args);
 
   TRACE ("%s %s\n", __func__, program);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
@@ -367,7 +370,8 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit,
+		(char *) str_program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 69fcab1..1402dea 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -36,6 +36,20 @@
 #include "dll.h"
 #include "hostio.h"
 #include <vector>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "job-control.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -79,7 +93,8 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static std::vector<char *> program_argv;
+static char *program_name = NULL;
+static std::vector<char *> program_args;
 static std::vector<char *> wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
@@ -238,25 +253,58 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+const char *
+get_exec_wrapper (void)
 {
-  std::vector<char *> new_argv;
+  static std::string ret;
+  static bool initialized_p = false;
 
-  if (!wrapper_argv.empty ())
-    new_argv.insert (new_argv.begin (),
-		     wrapper_argv.begin (),
-		     wrapper_argv.end ());
+  if (wrapper_argv.empty ())
+    return NULL;
 
-  for (int i = 0; argv[i] != NULL; ++i)
-    new_argv.push_back (argv[i]);
+  if (!initialized_p)
+    {
+      for (auto s : wrapper_argv)
+	ret += s + std::string (" ");
 
-  new_argv.push_back (NULL);
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+
+      initialized_p = true;
+    }
+
+  return ret.c_str ();
+}
+
+/* See common/common-inferior.h.  */
+
+char *
+get_exec_file (int err)
+{
+  if (err && program_name == NULL)
+    error (_("No executable file specified."));
+
+  return program_name;
+}
+
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ (void)
+{
+  return our_environ;
+}
+
+/* See common-inferior.h.  */
 
+void
+prefork_hook (const char *args)
+{
   if (debug_threads)
     {
-      for (int i = 0; i < new_argv.size (); ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      debug_printf ("args: %s\n", args);
       debug_flush ();
     }
 
@@ -265,67 +313,64 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, const char *program)
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (!wrapper_argv.empty ())
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
+  startup_inferior (pid, num_traps, &last_status, &last_ptid);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = last_status;
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
+}
 
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
+/* See common/common-inferior.h.  */
 
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+void
+postfork_hook (pid_t pid)
+{
+}
 
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
+/* See common/common-inferior.h.  */
 
-  return signal_pid;
+void
+postfork_child_hook (int debug_fork)
+{
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  /* Close all file descriptors except those that gdb inherited
+     (usually 0/1/2), so they don't leak to the inferior.  Note
+     that this closes the file descriptors of all secondary
+     UIs.  */
+  close_most_fds ();
+
+  debug_setpgrp = gdb_setpgid ();
+  if (debug_setpgrp == -1)
+    perror (_("setpgrp failed in child"));
 }
 
 static int
@@ -2848,6 +2893,7 @@ handle_v_run (char *own_buf)
 {
   char *p, *next_p;
   std::vector<char *> new_argv;
+  char *new_program_name = NULL;
   int i, new_argc;
 
   new_argc = 0;
@@ -2866,42 +2912,95 @@ handle_v_run (char *own_buf)
       if (i == 0 && p == next_p)
 	{
 	  /* No program specified.  */
-	  new_argv.push_back (NULL);
+	  new_program_name = NULL;
+	}
+      else if (p == next_p)
+	{
+	  /* Empty argument.  */
+	  new_argv.push_back (xstrdup ("''"));
 	}
       else
 	{
+	  /* FIXME: Fail request if out of memory instead of dying.  */
 	  size_t len = (next_p - p) / 2;
+	  /* ARG is the unquoted argument received via the RSP.  */
 	  char *arg = (char *) xmalloc (len + 1);
+	  /* FULL_ARGS will contain the quoted version of ARG.  */
+	  char *full_arg = (char *) xmalloc ((len + 1) * 2);
+	  /* These are pointers used to navigate the strings above.  */
+	  char *tmp_arg = arg;
+	  char *tmp_full_arg = full_arg;
+	  int need_quote = 0;
 
 	  hex2bin (p, (gdb_byte *) arg, len);
 	  arg[len] = '\0';
-	  new_argv.push_back (arg);
-	}
 
+	  while (*tmp_arg != '\0')
+	    {
+	      switch (*tmp_arg)
+		{
+		case '\n':
+		  /* Quote \n.  */
+		  *tmp_full_arg = '\'';
+		  ++tmp_full_arg;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  /* Quote single quote.  */
+		  *tmp_full_arg = '\\';
+		  ++tmp_full_arg;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_full_arg = *tmp_arg;
+	      ++tmp_full_arg;
+	      ++tmp_arg;
+	    }
+
+	  if (need_quote)
+	    *tmp_full_arg++ = '\'';
+
+	  /* Finish FULL_ARG and push it into the vector containing
+	     the argv.  */
+	  *tmp_full_arg = '\0';
+	  if (i == 0)
+	    new_program_name = full_arg;
+	  else
+	    new_argv.push_back (full_arg);
+	  xfree (arg);
+	}
       if (*next_p)
 	next_p++;
     }
   new_argv.push_back (NULL);
 
-  if (new_argv[0] == NULL)
+  if (new_program_name == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-      if (program_argv.empty ())
+      if (program_name == NULL)
 	{
 	  write_enn (own_buf);
 	  free_vector_argv (new_argv);
 	  return 0;
 	}
-
-      new_argv.push_back (xstrdup (program_argv[0]));
+    }
+  else
+    {
+      xfree (program_name);
+      program_name = new_program_name;
     }
 
   /* Free the old argv and install the new one.  */
-  free_vector_argv (program_argv);
-  program_argv = new_argv;
+  free_vector_argv (program_args);
+  program_args = new_argv;
+
+  create_inferior (program_name, program_args);
 
-  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3666,8 +3765,13 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3681,12 +3785,13 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      for (i = 0; i < n; i++)
-	program_argv.push_back (xstrdup (next_arg[i]));
-      program_argv.push_back (NULL);
+      program_name = xstrdup (next_arg[0]);
+      for (i = 1; i < n; i++)
+	program_args.push_back (xstrdup (next_arg[i]));
+      program_args.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (&program_argv[0]);
+      create_inferior (program_name, program_args);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4301,9 +4406,10 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (!program_argv.empty ())
+	  if (program_name != NULL)
 	    {
-	      start_inferior (&program_argv[0]);
+	      create_inferior (program_name, program_args);
+
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..5087614 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #include "utils.h"
 #include "debug.h"
 #include "gdb_vecs.h"
+#include <vector>
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
@@ -148,4 +149,13 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, and PROGRAM is its name.  */
+extern void post_fork_inferior (int pid, const char *program);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ (void);
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..6c45f88 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,8 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
 
 /* Some older glibc versions do not define this.  */
 #ifndef __WNOTHREAD
@@ -261,36 +263,37 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun (void)
+{
+  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
+
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (const char *program,
+		     const std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string str_program_args = stringify_argv (program_args);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program);
 
   proc = add_process (pid, 0);
   proc->tdesc = tdesc_spu;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..1e1d193 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,27 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior (void)
+{
+  /* To be implemented.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours (void)
+{
+  /* To be implemented.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..be89258 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -67,13 +68,13 @@ struct target_ops
   /* Start a new process.
 
      PROGRAM is a path to the program to execute.
-     ARGS is a standard NULL-terminated array of arguments,
-     to be passed to the inferior as ``argv''.
+     PROGRAM_ARGS is a standard NULL-terminated array of arguments,
+     to be passed to the inferior as ``argv'' (along with PROGRAM).
 
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
-
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (const char *program,
+			  const std::vector<char *> &program_args);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_args)	\
+  (*the_target->create_inferior) (program, program_args)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..a7a5f81 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,12 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  fflush (stdout);
+  fflush (stderr);
+}
diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
index b4ded31..48804c5 100644
--- a/gdb/gdbserver/utils.h
+++ b/gdb/gdbserver/utils.h
@@ -19,6 +19,8 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <vector>
+
 char *paddress (CORE_ADDR addr);
 char *pfildes (gdb_fildes_t fd);
 
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7b09f4b..4e47ba9 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,13 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM is the program name.
+   PROGRAM_ARGS is the vector containing the inferior's args.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -627,6 +627,8 @@ win32_create_inferior (char *program, char **program_args)
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string str_program_args = stringify_argv (program_argv);
+  char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -652,18 +654,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 6298103..d5e3841 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2143,6 +2143,11 @@ gnu_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, gnu_ptrace_me,
                        NULL, NULL, NULL, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   /* Attach to the now stopped child, which is actually a shell...  */
   inf_debug (inf, "attaching to child: %d", pid);
 
@@ -2162,7 +2167,8 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
+
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index b19aaf9..2a01dd2 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -31,6 +31,8 @@
 #include "inf-ptrace.h"
 #include "inf-child.h"
 #include "gdbthread.h"
+#include "nat/fork-inferior.h"
+#include "utils.h"
 
 \f
 
@@ -93,7 +95,8 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 			    const char *exec_file, const std::string &allargs,
 			    char **env, int from_tty)
 {
-  int pid;
+  pid_t pid;
+  ptid_t ptid;  
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
@@ -110,13 +113,19 @@ inf_ptrace_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
 		       NULL, NULL, NULL);
 
+  ptid = pid_to_ptid (pid);
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
+
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
-  target_post_startup_inferior (pid_to_ptid (pid));
+  target_post_startup_inferior (ptid);
 }
 
 #ifdef PT_GET_PROCESS_STATE
diff --git a/gdb/inferior.h b/gdb/inferior.h
index c6fb9d3..4bab079 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -45,6 +45,7 @@ struct inferior;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 #include "common/refcounted-object.h"
@@ -136,28 +137,10 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
-extern int fork_inferior (const char *, const std::string &, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
+/* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
+   This function already calls set_executing.  Return the ptid_t from
+   STARTUP_INFERIOR.  */
+extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
 
 extern char *construct_inferior_arguments (int, char **);
 
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
new file mode 100644
index 0000000..9311736
--- /dev/null
+++ b/gdb/nat/fork-inferior.c
@@ -0,0 +1,566 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "fork-inferior.h"
+#include "target/waitstatus.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "signals-state-save-restore.h"
+#include <vector>
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Build the argument vector for execv(3).  */
+
+class execv_argv
+{
+public:
+  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
+     arguments to the program.  If starting with a shell, SHELL_FILE
+     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
+  execv_argv (const char *exec_file, const std::string &allargs,
+	      const char *shell_file);
+
+  /* Return a pointer to the built argv, in the type expected by
+     execv.  The result is (only) valid for as long as this execv_argv
+     object is live.  We return a "char **" because that's the type
+     that the execv functions expect.  Note that it is guaranteed that
+     the execv functions do not modify the argv[] array nor the
+     strings to which the array point.  */
+  char **argv ()
+  {
+    return const_cast<char **> (&m_argv[0]);
+  }
+
+private:
+  /* Disable copying.  */
+  execv_argv (const execv_argv &) = delete;
+  void operator= (const execv_argv &) = delete;
+
+  /* Helper methods for constructing the argument vector.  */
+
+  /* Used when building an argv for a straight execv call, without
+     going via the shell.  */
+  void init_for_no_shell (const char *exec_file,
+			  const std::string &allargs);
+
+  /* Used when building an argv for execing a shell that execs the
+     child program.  */
+  void init_for_shell (const char *exec_file,
+		       const std::string &allargs,
+		       const char *shell_file);
+
+  /* The argument vector built.  Holds non-owning pointers.  Elements
+     either point to the strings passed to the execv_argv ctor, or
+     inside M_STORAGE.  */
+  std::vector<const char *> m_argv;
+
+  /* Storage.  In the no-shell case, this contains a copy of the
+     arguments passed to the ctor, split by '\0'.  In the shell case,
+     this contains the quoted shell command.  I.e., SHELL_COMMAND in
+     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
+  std::string m_storage;
+};
+
+/* Create argument vector for straight call to execvp.  Breaks up
+   ALLARGS into an argument vector suitable for passing to execvp and
+   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
+   as input the string "a b c d", and as output it would fill in
+   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
+   in M_ARGV points to a substring of a copy of ALLARGS stored in
+   M_STORAGE.  */
+
+void
+execv_argv::init_for_no_shell (const char *exec_file,
+			       const std::string &allargs)
+{
+
+  /* Save/work with a copy stored in our storage.  The pointers pushed
+     to M_ARGV point directly into M_STORAGE, which is modified in
+     place with the necessary NULL terminators.  This avoids N heap
+     allocations and string dups when 1 is sufficient.  */
+  std::string &args_copy = m_storage = allargs;
+
+  m_argv.push_back (exec_file);
+
+  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
+    {
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
+
+      if (next_sep == std::string::npos)
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = args_copy.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  args_copy[next_sep++] = '\0';
+	}
+
+      m_argv.push_back (&args_copy[cur_pos]);
+
+      cur_pos = next_sep;
+    }
+
+  /* NULL-terminate the vector.  */
+  m_argv.push_back (NULL);
+}
+
+/* When executing a command under the given shell, return non-zero if
+   the '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static int
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  const int shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return 0;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return 1;
+
+  return 0;
+}
+
+/* See declaration.  */
+
+execv_argv::execv_argv (const char *exec_file,
+			const std::string &allargs,
+			const char *shell_file)
+{
+  if (shell_file == NULL)
+    init_for_no_shell (exec_file, allargs);
+  else
+    init_for_shell (exec_file, allargs, shell_file);
+}
+
+/* See declaration.  */
+
+void
+execv_argv::init_for_shell (const char *exec_file,
+			    const std::string &allargs,
+			    const char *shell_file)
+{
+  const char *exec_wrapper = get_exec_wrapper ();
+
+  /* We're going to call a shell.  */
+  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  /* We need to build a new shell command string, and make argv point
+     to it.  So build it in the storage.  */
+  std::string &shell_command = m_storage;
+
+  shell_command = "exec ";
+
+  /* Add any exec wrapper.  That may be a program name with arguments,
+     so the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      shell_command += exec_wrapper;
+      shell_command += ' ';
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But csh
+     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
+     to.  */
+  bool need_to_quote;
+  const char *p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = true;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = false;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      shell_command += '\'';
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    shell_command += "\\!";
+	  else
+	    shell_command += *p;
+	}
+      shell_command += '\'';
+    }
+  else
+    shell_command += exec_file;
+
+  shell_command += ' ' + allargs;
+
+  /* If we decided above to start up with a shell, we exec the shell.
+     "-c" says to interpret the next arg as a shell command to
+     execute, and this command is "exec <target-program> <args>".  */
+  m_argv.reserve (4);
+  m_argv.push_back (shell_file);
+  m_argv.push_back ("-c");
+  m_argv.push_back (shell_command.c_str ());
+  m_argv.push_back (NULL);
+}
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+
+static const char *
+get_startup_shell (void)
+{
+  static const char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* See common/common-inferior.h.  */
+
+pid_t
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (void),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
+	       const char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
+{
+  pid_t pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  int debug_fork = 0;
+  const char *shell_file;
+  const char *exec_file;
+  char **save_our_env;
+  int i;
+  int save_errno;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  if (exec_file_arg == NULL)
+    exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  if (startup_with_shell)
+    {
+      shell_file = shell_file_arg;
+
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+    }
+  else
+    shell_file = NULL;
+
+  /* Build the argument vector.  */
+  execv_argv child_argv (exec_file, allargs, shell_file);
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Perform any necessary actions regarding to TTY before the
+     fork/vfork call.  */
+  prefork_hook (allargs.c_str ());
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Execute any necessary post-fork actions before we exec.  */
+      postfork_child_hook (debug_fork);
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      char **argv = child_argv.argv ();
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], &argv[0], env);
+      else
+        execvp (argv[0], &argv[0]);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  postfork_hook (pid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See common/common-inferior.h.  */
+
+ptid_t
+startup_inferior (pid_t pid, int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (pid);
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	  case TARGET_WAITKIND_VFORK_DONE:
+	  case TARGET_WAITKIND_IGNORE:
+	  case TARGET_WAITKIND_NO_HISTORY:
+	  case TARGET_WAITKIND_NO_RESUMED:
+	  case TARGET_WAITKIND_THREAD_CREATED:
+	  case TARGET_WAITKIND_THREAD_EXITED:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  return resume_ptid;
+}
diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
new file mode 100644
index 0000000..6a8528e
--- /dev/null
+++ b/gdb/nat/fork-inferior.h
@@ -0,0 +1,51 @@
+/* Functions and data responsible for forking the inferior process.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef FORK_CHILD_H
+#define FORK_CHILD_H
+
+#include <vector>
+
+/* Accept NTRAPS traps from the inferior.
+
+   Return the ptid of the inferior being started.  */
+extern ptid_t startup_inferior (pid_t pid, int ntraps,
+				struct target_waitstatus *mystatus,
+				ptid_t *myptid);
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern pid_t fork_inferior (const char *exec_file_arg,
+			    const std::string &allargs,
+			    char **env, void (*traceme_fun) (void),
+			    void (*init_trace_fun) (int),
+			    void (*pre_trace_fun) (void),
+			    const char *shell_file_arg,
+			    void (*exec_fun) (const char *file,
+					      char * const *argv,
+					      char * const *env));
+
+#endif /* ! FORK_CHILD_H */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 5d940dd..b8a92be 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4377,7 +4377,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
@@ -4604,6 +4604,11 @@ procfs_create_inferior (struct target_ops *ops, const char *exec_file,
   pid = fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
 		       NULL, NULL, shell_file, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   procfs_init_inferior (ops, pid);
 }
 
diff --git a/gdb/target.h b/gdb/target.h
index a971adf..6c995a1 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1538,17 +1538,6 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
-
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
    so that no input is discarded.  This is a no-op if terminal_ours
@@ -1557,12 +1546,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..f12262e 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init (void);
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior (void);
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours (void);
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..68d4d53 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,16 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled (e.g., when the SHELL variable is
+    # unset).
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled, which is the
+    # default behaviour.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/utils.c b/gdb/utils.c
index c61557e..ab23be8 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3391,6 +3391,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err (void)
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
                     ` (2 preceding siblings ...)
  2017-05-04  5:32   ` [PATCH v6 3/4] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-05-04  5:38   ` Sergio Durigan Junior
  2017-05-05 19:21     ` Pedro Alves
  3 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-04  5:38 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS (Changes in 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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
yyyy-mm-dd  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/NEWS                                      | 12 ++++
 gdb/doc/gdb.texinfo                           | 39 +++++++++++++
 gdb/gdbserver/server.c                        | 38 ++++++++++++-
 gdb/remote.c                                  | 20 +++++++
 gdb/testsuite/gdb.base/startup-with-shell.c   | 29 ++++++++++
 gdb/testsuite/gdb.base/startup-with-shell.exp | 82 +++++++++++++++++++++++++++
 6 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index eb1a589..995e523 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -5,6 +5,15 @@
 
 *** Changes in 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.
+
 * GDB now supports access to the PKU register on GNU/Linux. The register is
   added by the Memory Protection Keys for Userspace feature which will be
   available in future Intel CPUs.
@@ -410,6 +419,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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f2e6156..b2e72c7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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}
@@ -36422,6 +36427,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
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 1402dea..e698cc2 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -877,6 +877,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QStartupWithShell:"))
+    {
+      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;
@@ -2313,7 +2338,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 ())
@@ -3420,6 +3445,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"
@@ -3705,6 +3737,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
diff --git a/gdb/remote.c b/gdb/remote.c
index 2cd9850..f2cf821 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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)
@@ -14105,6 +14122,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);
 
diff --git a/gdb/testsuite/gdb.base/startup-with-shell.c b/gdb/testsuite/gdb.base/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.c
@@ -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
index 0000000..064134a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.exp
@@ -0,0 +1,82 @@
+# 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
+}
+
+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)
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver
  2017-05-04  5:32   ` [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
@ 2017-05-05 19:04     ` Pedro Alves
  2017-05-06 14:15       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-05-05 19:04 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 05/04/2017 06:29 AM, Sergio Durigan Junior wrote:

> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
> new file mode 100644
> index 0000000..3e2b991
> --- /dev/null
> +++ b/gdb/common/common-gdbthread.h
> @@ -0,0 +1,27 @@

> +#ifndef COMMON_GDBTHREAD_H
> +#define COMMON_GDBTHREAD_H
> +
> +struct target_waitstatus;

Why add this here?  Nothing uses it in this file.

> +
> +/* Switch from one thread to another.  */
> +extern void switch_to_thread (ptid_t ptid);
> +
> +#endif /* ! COMMON_GDBTHREAD_H */

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-05-04  5:32   ` [PATCH v6 3/4] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-05-05 19:05     ` Pedro Alves
  2017-05-31  3:43       ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-05-05 19:05 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 05/04/2017 06:29 AM, Sergio Durigan Junior wrote:

> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
> new file mode 100644
> index 0000000..206a36a
> --- /dev/null
> +++ b/gdb/common/common-inferior.h
> @@ -0,0 +1,75 @@
> +/* Variables that describe the inferior process running under GDB and
> +   GDBserver: Where it is, why it stopped, and how to step it.

Stale comment.

> +
> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef COMMON_INFERIOR_H
> +#define COMMON_INFERIOR_H
> +
> +/* Number of traps that happen between exec'ing the shell to run an
> +   inferior and when we finally get to the inferior code, not counting
> +   the exec for the shell.  This is 1 on all supported
> +   implementations.  */
> +#define START_INFERIOR_TRAPS_EXPECTED 1

The copy in gdb/inferior.h should be removed instead of being left
duplicated.

> +
> +/* Whether to start up the debuggee under a shell.
> +
> +   If startup-with-shell is set, GDB's "run" will attempt to start up
> +   the debuggee under a shell.  This also happens when using GDBserver
> +   under extended remote mode.
> +
> +   This is in order for argument-expansion to occur.  E.g.,
> +
> +   (gdb) run *
> +
> +   The "*" gets expanded by the shell into a list of files.
> +
> +   While this is a nice feature, it may be handy to bypass the shell
> +   in some cases.  To disable this feature, do "set startup-with-shell
> +   false".
> +
> +   The catch-exec traps expected during start-up will be one more if
> +   the target is started up with a shell.  */
> +extern int startup_with_shell;
> +
> +/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
> +   is a string containing all the arguments received by the inferior.
> +   This function is mainly used by fork_inferior.  */
> +extern void prefork_hook (const char *args);
> +
> +/* Perform any necessary tasks after a fork/vfork takes place.  This
> +   function is mainly used by fork_inferior.  */
> +extern void postfork_hook (pid_t pid);
> +
> +/* Perform any necessary tasks *on the child* after a fork/vfork takes
> +   place.  DEBUG_FORK is the number of seconds that we should sleep
> +   before exec'ing (see fork_inferior).
> +
> +   This function is mainly used by fork_inferior.  */
> +extern void postfork_child_hook (int debug_fork);

Wouldn't it better to put these in nat/fork-inferior.h instead?
Likewise START_INFERIOR_TRAPS_EXPECTED, maybe?

> +
> +/* Return the exec wrapper to be used when starting the inferior, or NULL
> +   otherwise.  */
> +extern const char *get_exec_wrapper (void);

Should really drop the "(void)" in all new code throughout the series.

> +
> +/* Return the name of the executable file as a string.
> +   ERR nonzero means get error if there is none specified;
> +   otherwise return 0 in that case.  */
> +extern char *get_exec_file (int err);
> +
> +#endif /* ! COMMON_INFERIOR_H */


> +/* See common/common-utils.h.  */
> +
> +std::string
> +stringify_argv (const std::vector<char *> &args)
> +{
> +  std::string ret ("");

  std::string ret;

> +
> +  if (!args.empty ())
> +    {
> +      for (auto s : args)
> +	if (s != NULL)
> +	  ret += s + std::string (" ");

Avoid unnecessary temporaries:

          {
	    ret += s;
            ret += ' ';
          }

> +
> +      /* Erase the last whitespace.  */
> +      ret.erase (ret.end () - 1);
> +    }
> +
> +  return ret;
> +}



>  
> -/* Accept NTRAPS traps from the inferior.  */
> +/* See common/common-inferior.h.  */
>  
>  void
> -startup_inferior (int ntraps)
> +postfork_child_hook (int debug_fork)
>  {
> -  int pending_execs = ntraps;
> -  int terminal_initted = 0;
> -  ptid_t resume_ptid;
> -
> -  if (startup_with_shell)
> -    {
> -      /* One trap extra for exec'ing the shell.  */
> -      pending_execs++;
> -    }
> +  /* This is set to the result of setpgrp, which if vforked, will be
> +     visible to you in the parent process.  It's only used by humans
> +     for debugging.  */
> +  static int debug_setpgrp = 657473;
>  
> -  if (target_supports_multi_process ())
> -    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
> -  else
> -    resume_ptid = minus_one_ptid;
> +  /* Make sure we switch to main_ui here in order to be able to
> +     use the fprintf_unfiltered/warning/error functions.  */
> +  current_ui = main_ui;
>  
> -  /* The process was started by the fork that created it, but it will
> -     have stopped one instruction after execing the shell.  Here we
> -     must get it up to actual execution of the real program.  */
> +  /* Close all file descriptors except those that gdb inherited
> +     (usually 0/1/2), so they don't leak to the inferior.  Note
> +     that this closes the file descriptors of all secondary
> +     UIs.  */
> +  close_most_fds ();

Any reason this closing isn't done in the common code instead of
having it done on both hook implementations?

>  
> -  if (exec_wrapper)
> -    pending_execs++;
> +  if (debug_fork)
> +    sleep (debug_fork);

Similarly, why not leave this sleep to the common code?  It's
missing on the gdbserver side, AFAICS.

> +	  case TARGET_WAITKIND_SPURIOUS:
> +	  case TARGET_WAITKIND_LOADED:
> +	  case TARGET_WAITKIND_FORKED:
> +	  case TARGET_WAITKIND_VFORKED:
> +	  case TARGET_WAITKIND_SYSCALL_ENTRY:
> +	  case TARGET_WAITKIND_SYSCALL_RETURN:
> +	  case TARGET_WAITKIND_VFORK_DONE:
> +	  case TARGET_WAITKIND_IGNORE:
> +	  case TARGET_WAITKIND_NO_HISTORY:
> +	  case TARGET_WAITKIND_NO_RESUMED:
> +	  case TARGET_WAITKIND_THREAD_CREATED:
> +	  case TARGET_WAITKIND_THREAD_EXITED:

You added several of these at the same time (but they don't really
make sense here).  Did you run into some of them in gdbserver?

> index 4ea7913..8aa85db 100644
> --- a/gdb/gdbserver/configure.ac
> +++ b/gdb/gdbserver/configure.ac
> @@ -462,7 +462,9 @@ esac],
>  
>  if $want_ipa ; then
>     if $have_ipa ; then
> -     IPA_DEPFILES="$ipa_obj"
> +     # Needed because safe_strerror's definition is host-dependent

Why do we end up needing safe_strerror in the IPA in the first place?

> +     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
> +     IPA_DEPFILES="$ipa_obj $strerror_obj"
>       extra_libraries="$extra_libraries libinproctrace.so"
>     else
>       AC_MSG_ERROR([inprocess agent not supported for this target])



> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
> -  pid = vfork ();

Does fork_inferior end up always using vfork on no-MMU
ports somehow?

> -#else
> -  pid = fork ();
> -#endif

> +const char *
> +get_exec_wrapper (void)
>  {
> -  std::vector<char *> new_argv;
> +  static std::string ret;
> +  static bool initialized_p = false;
>  
> -  if (!wrapper_argv.empty ())
> -    new_argv.insert (new_argv.begin (),
> -		     wrapper_argv.begin (),
> -		     wrapper_argv.end ());
> +  if (wrapper_argv.empty ())
> +    return NULL;
>  
> -  for (int i = 0; argv[i] != NULL; ++i)
> -    new_argv.push_back (argv[i]);
> +  if (!initialized_p)
> +    {
> +      for (auto s : wrapper_argv)
> +	ret += s + std::string (" ");

Avoid unnecessary temporaries.

>  
> -  new_argv.push_back (NULL);
> +      /* Erase the last whitespace.  */
> +      ret.erase (ret.end () - 1);
> +
> +      initialized_p = true;
> +    }
> +
> +  return ret.c_str ();
> +}

I'm actually having a bit of trouble understanding
why do we need the wrapper_argv global plus this initialized_p
indirection, instead of just building the exec wrapper string
in captured_main.


> @@ -2848,6 +2893,7 @@ handle_v_run (char *own_buf)
>  {


> +	  /* FIXME: Fail request if out of memory instead of dying.  */
>  	  size_t len = (next_p - p) / 2;

Did you really mean to add that comment?


> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index d5fee38..5087614 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  #include "utils.h"
>  #include "debug.h"
>  #include "gdb_vecs.h"
> +#include <vector>
>  

Why?

>  /* Maximum number of bytes to read/write at once.  The value here
>     is chosen to fill up a packet (the headers account for the 32).  */
> @@ -148,4 +149,13 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  /* Definition for any syscall, used for unfiltered syscall reporting.  */
>  #define ANY_SYSCALL (-2)
>  
> +/* After fork_inferior has been called, we need to adjust a few
> +   signals and call startup_inferior.  This is done here.  PID is the
> +   pid of the new inferior, and PROGRAM is its name.  */
> +extern void post_fork_inferior (int pid, const char *program);
> +
> +/* Get the 'struct gdb_environ *' being used in the current
> +   session.  */
> +extern struct gdb_environ *get_environ (void);
> +
>  #endif /* SERVER_H */

> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_init (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_inferior (void)
> +{
> +  /* To be implemented.  */
> +}
> +
> +/* See target/target.h.  */
> +
> +void
> +target_terminal_ours (void)
> +{
> +  /* To be implemented.  */
> +}

s/To be implemented/Not necessary/ or some such.

> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
> index b4ded31..48804c5 100644
> --- a/gdb/gdbserver/utils.h
> +++ b/gdb/gdbserver/utils.h
> @@ -19,6 +19,8 @@
>  #ifndef UTILS_H
>  #define UTILS_H
>  
> +#include <vector>
> +

Why?

>  char *paddress (CORE_ADDR addr);
>  char *pfildes (gdb_fildes_t fd);
>  

>  static int
> -win32_create_inferior (char *program, char **program_args)
> +win32_create_inferior (const char *program,
> +		       const std::vector<char *> &program_args)
>  {
>  #ifndef USE_WIN32API
>    char real_path[PATH_MAX];
> @@ -627,6 +627,8 @@ win32_create_inferior (char *program, char **program_args)
>    int argc;
>    PROCESS_INFORMATION pi;
>    DWORD err;
> +  std::string str_program_args = stringify_argv (program_argv);
> +  char *args = (char *) str_program_args.c_str ();

Can it be const?

> +
> +/* When executing a command under the given shell, return non-zero if
> +   the '!' character should be escaped when embedded in a quoted
> +   command-line argument.  */
> +
> +static int
> +escape_bang_in_quoted_argument (const char *shell_file)
> +{
> +  const int shell_file_len = strlen (shell_file);
> +
> +  /* Bang should be escaped only in C Shells.  For now, simply check
> +     that the shell name ends with 'csh', which covers at least csh
> +     and tcsh.  This should be good enough for now.  */
> +
> +  if (shell_file_len < 3)
> +    return 0;
> +
> +  if (shell_file[shell_file_len - 3] == 'c'
> +      && shell_file[shell_file_len - 2] == 's'
> +      && shell_file[shell_file_len - 1] == 'h')
> +    return 1;
> +
> +  return 0;
> +}

This function lost some edits done in the execv_argv patch.

bool + size_t.

Please run a diff of the old gdb/fork-child.c against the
new nat/fork-inferior.c to make sure nothing else was lost.


> diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
> new file mode 100644
> index 0000000..6a8528e
> --- /dev/null
> +++ b/gdb/nat/fork-inferior.h
> @@ -0,0 +1,51 @@
...

> +
> +#ifndef FORK_CHILD_H
> +#define FORK_CHILD_H

Incorrectly named multiple-inclusion guard.

> +
> +#include <vector>

Why?  Nothing uses std::vector here.

> +
> +/* Accept NTRAPS traps from the inferior.
> +
> +   Return the ptid of the inferior being started.  */
> +extern ptid_t startup_inferior (pid_t pid, int ntraps,
> +				struct target_waitstatus *mystatus,
> +				ptid_t *myptid);
> +
> +/* Start an inferior Unix child process and sets inferior_ptid to its
> +   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
> +   the arguments to the program.  ENV is the environment vector to
> +   pass.  SHELL_FILE is the shell file, or NULL if we should pick
> +   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
> +   one.  */
> +
> +/* This function is NOT reentrant.  Some of the variables have been
> +   made static to ensure that they survive the vfork call.  */
> +extern pid_t fork_inferior (const char *exec_file_arg,
> +			    const std::string &allargs,

Should include <string>.

> +			    char **env, void (*traceme_fun) (void),
> +			    void (*init_trace_fun) (int),
> +			    void (*pre_trace_fun) (void),
> +			    const char *shell_file_arg,
> +			    void (*exec_fun) (const char *file,
> +					      char * const *argv,
> +					      char * const *env));
> +
> +#endif /* ! FORK_CHILD_H */

>  
> diff --git a/gdb/target.h b/gdb/target.h
> index a971adf..6c995a1 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -1538,17 +1538,6 @@ extern int target_terminal_is_inferior (void);
>  
>  extern int target_terminal_is_ours (void);
>  
> -/* Initialize the terminal settings we record for the inferior,
> -   before we actually run the inferior.  */
> -
> -extern void target_terminal_init (void);
> -
> -/* Put the inferior's terminal settings into effect.  This is
> -   preparation for starting or resuming the inferior.  This is a no-op
> -   unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_inferior (void);
> -
>  /* Put some of our terminal settings into effect, enough to get proper
>     results from our output, but do not change into or out of RAW mode
>     so that no input is discarded.  This is a no-op if terminal_ours
> @@ -1557,12 +1546,6 @@ extern void target_terminal_inferior (void);
>  
>  extern void target_terminal_ours_for_output (void);
>  
> -/* Put our terminal settings into effect.  First record the inferior's
> -   terminal settings so they can be restored properly later.  This is
> -   a no-op unless called with the main UI as current UI.  */
> -
> -extern void target_terminal_ours (void);
> -

Please leave breakcrumb comments behind.

>  /* Return true if the target stack has a non-default
>    "to_terminal_ours" method.  */
>  

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver
  2017-05-04  5:38   ` [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
@ 2017-05-05 19:21     ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-05-05 19:21 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

On 05/04/2017 06:29 AM, Sergio Durigan Junior wrote:

> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -877,6 +877,31 @@ handle_general_set (char *own_buf)
>        return;
>      }
>  
> +  if (startswith (own_buf, "QStartupWithShell:"))
> +    {
> +      char *value = own_buf + strlen ("QStartupWithShell:");

const.

> +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"
> +

This may require some tweaking or disabling when tested against
a remote host.  Not sure.  Could you check whether the test runs
with  testsuite/boards/local-remote-host-native.exp?

Otherwise this one LGTM.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver
  2017-05-05 19:04     ` Pedro Alves
@ 2017-05-06 14:15       ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-06 14:15 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, May 05 2017, Pedro Alves wrote:

> On 05/04/2017 06:29 AM, Sergio Durigan Junior wrote:
>
>> diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
>> new file mode 100644
>> index 0000000..3e2b991
>> --- /dev/null
>> +++ b/gdb/common/common-gdbthread.h
>> @@ -0,0 +1,27 @@
>
>> +#ifndef COMMON_GDBTHREAD_H
>> +#define COMMON_GDBTHREAD_H
>> +
>> +struct target_waitstatus;
>
> Why add this here?  Nothing uses it in this file.

Leftover from previous commits.  Sorry about that.  Removed locally.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-05-05 19:05     ` Pedro Alves
@ 2017-05-31  3:43       ` Sergio Durigan Junior
  2017-06-07 10:16         ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-05-31  3:43 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

Hey Pedro,

Sorry for the long delay in getting back to this.  Comments below.

On Friday, May 05 2017, Pedro Alves wrote:

> On 05/04/2017 06:29 AM, Sergio Durigan Junior wrote:
>
>> diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
>> new file mode 100644
>> index 0000000..206a36a
>> --- /dev/null
>> +++ b/gdb/common/common-inferior.h
>> @@ -0,0 +1,75 @@
>> +/* Variables that describe the inferior process running under GDB and
>> +   GDBserver: Where it is, why it stopped, and how to step it.
>
> Stale comment.

Replaced by:

/* Functions to deal with the inferior being executed on GDB or
   GDBserver.

Sorry, couldn't think of a better description.

>> +
>> +   Copyright (C) 1986-2017 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef COMMON_INFERIOR_H
>> +#define COMMON_INFERIOR_H
>> +
>> +/* Number of traps that happen between exec'ing the shell to run an
>> +   inferior and when we finally get to the inferior code, not counting
>> +   the exec for the shell.  This is 1 on all supported
>> +   implementations.  */
>> +#define START_INFERIOR_TRAPS_EXPECTED 1
>
> The copy in gdb/inferior.h should be removed instead of being left
> duplicated.

Sorry, a mistake here.  Removed the copy in gdb/inferior.h.

>> +
>> +/* Whether to start up the debuggee under a shell.
>> +
>> +   If startup-with-shell is set, GDB's "run" will attempt to start up
>> +   the debuggee under a shell.  This also happens when using GDBserver
>> +   under extended remote mode.
>> +
>> +   This is in order for argument-expansion to occur.  E.g.,
>> +
>> +   (gdb) run *
>> +
>> +   The "*" gets expanded by the shell into a list of files.
>> +
>> +   While this is a nice feature, it may be handy to bypass the shell
>> +   in some cases.  To disable this feature, do "set startup-with-shell
>> +   false".
>> +
>> +   The catch-exec traps expected during start-up will be one more if
>> +   the target is started up with a shell.  */
>> +extern int startup_with_shell;
>> +
>> +/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
>> +   is a string containing all the arguments received by the inferior.
>> +   This function is mainly used by fork_inferior.  */
>> +extern void prefork_hook (const char *args);
>> +
>> +/* Perform any necessary tasks after a fork/vfork takes place.  This
>> +   function is mainly used by fork_inferior.  */
>> +extern void postfork_hook (pid_t pid);
>> +
>> +/* Perform any necessary tasks *on the child* after a fork/vfork takes
>> +   place.  DEBUG_FORK is the number of seconds that we should sleep
>> +   before exec'ing (see fork_inferior).
>> +
>> +   This function is mainly used by fork_inferior.  */
>> +extern void postfork_child_hook (int debug_fork);
>
> Wouldn't it better to put these in nat/fork-inferior.h instead?
> Likewise START_INFERIOR_TRAPS_EXPECTED, maybe?

I remember struggling to decide where to put these functions.  In the
end, I decided to put them on commom/common-inferior.h for a very good
reason that I now do not remember anymore :-/.  Anyway, since I can't
really argue against your point, I will do what you're suggesting.  Only
get_exec_wrapper and get_exec_file will remain in common-inferior.h

>> +
>> +/* Return the exec wrapper to be used when starting the inferior, or NULL
>> +   otherwise.  */
>> +extern const char *get_exec_wrapper (void);
>
> Should really drop the "(void)" in all new code throughout the series.

Oh, OK.  I wasn't sure if we were following this practice for all
functions or only for methods.

>> +
>> +/* Return the name of the executable file as a string.
>> +   ERR nonzero means get error if there is none specified;
>> +   otherwise return 0 in that case.  */
>> +extern char *get_exec_file (int err);
>> +
>> +#endif /* ! COMMON_INFERIOR_H */
>
>
>> +/* See common/common-utils.h.  */
>> +
>> +std::string
>> +stringify_argv (const std::vector<char *> &args)
>> +{
>> +  std::string ret ("");
>
>   std::string ret;

Done.

>> +
>> +  if (!args.empty ())
>> +    {
>> +      for (auto s : args)
>> +	if (s != NULL)
>> +	  ret += s + std::string (" ");
>
> Avoid unnecessary temporaries:
>
>           {
> 	    ret += s;
>             ret += ' ';
>           }

Done.

>> +
>> +      /* Erase the last whitespace.  */
>> +      ret.erase (ret.end () - 1);
>> +    }
>> +
>> +  return ret;
>> +}
>
>
>
>>  
>> -/* Accept NTRAPS traps from the inferior.  */
>> +/* See common/common-inferior.h.  */
>>  
>>  void
>> -startup_inferior (int ntraps)
>> +postfork_child_hook (int debug_fork)
>>  {
>> -  int pending_execs = ntraps;
>> -  int terminal_initted = 0;
>> -  ptid_t resume_ptid;
>> -
>> -  if (startup_with_shell)
>> -    {
>> -      /* One trap extra for exec'ing the shell.  */
>> -      pending_execs++;
>> -    }
>> +  /* This is set to the result of setpgrp, which if vforked, will be
>> +     visible to you in the parent process.  It's only used by humans
>> +     for debugging.  */
>> +  static int debug_setpgrp = 657473;
>>  
>> -  if (target_supports_multi_process ())
>> -    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
>> -  else
>> -    resume_ptid = minus_one_ptid;
>> +  /* Make sure we switch to main_ui here in order to be able to
>> +     use the fprintf_unfiltered/warning/error functions.  */
>> +  current_ui = main_ui;
>>  
>> -  /* The process was started by the fork that created it, but it will
>> -     have stopped one instruction after execing the shell.  Here we
>> -     must get it up to actual execution of the real program.  */
>> +  /* Close all file descriptors except those that gdb inherited
>> +     (usually 0/1/2), so they don't leak to the inferior.  Note
>> +     that this closes the file descriptors of all secondary
>> +     UIs.  */
>> +  close_most_fds ();
>
> Any reason this closing isn't done in the common code instead of
> having it done on both hook implementations?

You're right, close_most_fds can be shared between them.

>>  
>> -  if (exec_wrapper)
>> -    pending_execs++;
>> +  if (debug_fork)
>> +    sleep (debug_fork);
>
> Similarly, why not leave this sleep to the common code?  It's
> missing on the gdbserver side, AFAICS.

Right, I clearly got confused about debug_fork and its usefulness on
gdbserver.  Moved to common code, and removed the "debug_fork" parameter
from postfork_child_hook.

>> +	  case TARGET_WAITKIND_SPURIOUS:
>> +	  case TARGET_WAITKIND_LOADED:
>> +	  case TARGET_WAITKIND_FORKED:
>> +	  case TARGET_WAITKIND_VFORKED:
>> +	  case TARGET_WAITKIND_SYSCALL_ENTRY:
>> +	  case TARGET_WAITKIND_SYSCALL_RETURN:
>> +	  case TARGET_WAITKIND_VFORK_DONE:
>> +	  case TARGET_WAITKIND_IGNORE:
>> +	  case TARGET_WAITKIND_NO_HISTORY:
>> +	  case TARGET_WAITKIND_NO_RESUMED:
>> +	  case TARGET_WAITKIND_THREAD_CREATED:
>> +	  case TARGET_WAITKIND_THREAD_EXITED:
>
> You added several of these at the same time (but they don't really
> make sense here).  Did you run into some of them in gdbserver?

No.  At the time I thought it would be better to cover all the
TARGET_WAITKIND_* entries here.  Some of them seemed to make sense to
me, like the TARGET_WAITKIND_THREAD_* ones.

Based on your comment, I removed the ones that I had added:

  case TARGET_WAITKIND_VFORK_DONE:
  case TARGET_WAITKIND_IGNORE:
  case TARGET_WAITKIND_NO_HISTORY:
  case TARGET_WAITKIND_NO_RESUMED:
  case TARGET_WAITKIND_THREAD_CREATED:
  case TARGET_WAITKIND_THREAD_EXITED:

>> index 4ea7913..8aa85db 100644
>> --- a/gdb/gdbserver/configure.ac
>> +++ b/gdb/gdbserver/configure.ac
>> @@ -462,7 +462,9 @@ esac],
>>  
>>  if $want_ipa ; then
>>     if $have_ipa ; then
>> -     IPA_DEPFILES="$ipa_obj"
>> +     # Needed because safe_strerror's definition is host-dependent
>
> Why do we end up needing safe_strerror in the IPA in the first place?

This is needed because I moved the definition of
trace_start_error_with_name from the old gdb/fork-child.c to
common/common-utils.c.  This function which uses safe_strerror, and
common/common-utils.c is compiled by IPA.

An option would be to keep these trace_start_error.* functions in
nat/fork-inferior.c, but I think it is more logical to keep them on
common-utils.c.

Now, I can obviously expand the comment if that's what you meant.

>> +     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
>> +     IPA_DEPFILES="$ipa_obj $strerror_obj"
>>       extra_libraries="$extra_libraries libinproctrace.so"
>>     else
>>       AC_MSG_ERROR([inprocess agent not supported for this target])
>
>
>
>> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>> -  pid = vfork ();
>
> Does fork_inferior end up always using vfork on no-MMU
> ports somehow?

Sorry, I am not sure.  How would I go about finding that?

>
>> -#else
>> -  pid = fork ();
>> -#endif
>
>> +const char *
>> +get_exec_wrapper (void)
>>  {
>> -  std::vector<char *> new_argv;
>> +  static std::string ret;
>> +  static bool initialized_p = false;
>>  
>> -  if (!wrapper_argv.empty ())
>> -    new_argv.insert (new_argv.begin (),
>> -		     wrapper_argv.begin (),
>> -		     wrapper_argv.end ());
>> +  if (wrapper_argv.empty ())
>> +    return NULL;
>>  
>> -  for (int i = 0; argv[i] != NULL; ++i)
>> -    new_argv.push_back (argv[i]);
>> +  if (!initialized_p)
>> +    {
>> +      for (auto s : wrapper_argv)
>> +	ret += s + std::string (" ");
>
> Avoid unnecessary temporaries.

Done.

>>  
>> -  new_argv.push_back (NULL);
>> +      /* Erase the last whitespace.  */
>> +      ret.erase (ret.end () - 1);
>> +
>> +      initialized_p = true;
>> +    }
>> +
>> +  return ret.c_str ();
>> +}
>
> I'm actually having a bit of trouble understanding
> why do we need the wrapper_argv global plus this initialized_p
> indirection, instead of just building the exec wrapper string
> in captured_main.

Alright, I'm now using a global std::string wrapper_argv which is
constructed on captured_main, and get_exec_wrapper now just returns the
c_str () version of it, or NULL if the wrapper_argv.size () is zero.

>
>> @@ -2848,6 +2893,7 @@ handle_v_run (char *own_buf)
>>  {
>
>
>> +	  /* FIXME: Fail request if out of memory instead of dying.  */
>>  	  size_t len = (next_p - p) / 2;
>
> Did you really mean to add that comment?

No.  Removed.

>
>> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
>> index d5fee38..5087614 100644
>> --- a/gdb/gdbserver/server.h
>> +++ b/gdb/gdbserver/server.h
>> @@ -132,6 +132,7 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  #include "utils.h"
>>  #include "debug.h"
>>  #include "gdb_vecs.h"
>> +#include <vector>
>>  
>
> Why?

Leftover from a previous patch.  Removed.

>>  /* Maximum number of bytes to read/write at once.  The value here
>>     is chosen to fill up a packet (the headers account for the 32).  */
>> @@ -148,4 +149,13 @@ extern int in_queued_stop_replies (ptid_t ptid);
>>  /* Definition for any syscall, used for unfiltered syscall reporting.  */
>>  #define ANY_SYSCALL (-2)
>>  
>> +/* After fork_inferior has been called, we need to adjust a few
>> +   signals and call startup_inferior.  This is done here.  PID is the
>> +   pid of the new inferior, and PROGRAM is its name.  */
>> +extern void post_fork_inferior (int pid, const char *program);
>> +
>> +/* Get the 'struct gdb_environ *' being used in the current
>> +   session.  */
>> +extern struct gdb_environ *get_environ (void);
>> +
>>  #endif /* SERVER_H */
>
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_init (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_inferior (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>> +
>> +/* See target/target.h.  */
>> +
>> +void
>> +target_terminal_ours (void)
>> +{
>> +  /* To be implemented.  */
>> +}
>
> s/To be implemented/Not necessary/ or some such.

Changed to:

  /* Placeholder needed because of fork_inferior.  Not necessary on
     GDBserver.  */

>> diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h
>> index b4ded31..48804c5 100644
>> --- a/gdb/gdbserver/utils.h
>> +++ b/gdb/gdbserver/utils.h
>> @@ -19,6 +19,8 @@
>>  #ifndef UTILS_H
>>  #define UTILS_H
>>  
>> +#include <vector>
>> +
>
> Why?

Sigh...  Leftover.  Removed.  Thanks, and sorry.

>>  char *paddress (CORE_ADDR addr);
>>  char *pfildes (gdb_fildes_t fd);
>>  
>
>>  static int
>> -win32_create_inferior (char *program, char **program_args)
>> +win32_create_inferior (const char *program,
>> +		       const std::vector<char *> &program_args)
>>  {
>>  #ifndef USE_WIN32API
>>    char real_path[PATH_MAX];
>> @@ -627,6 +627,8 @@ win32_create_inferior (char *program, char **program_args)
>>    int argc;
>>    PROCESS_INFORMATION pi;
>>    DWORD err;
>> +  std::string str_program_args = stringify_argv (program_argv);
>> +  char *args = (char *) str_program_args.c_str ();
>
> Can it be const?

It can, but then I'd have to cast it to "char *" when passing to
create_process.  CreateProcessA's second argument is of the type LPSTR,
which translates to "char *".  So I'd rather keep args as "char *".

>> +
>> +/* When executing a command under the given shell, return non-zero if
>> +   the '!' character should be escaped when embedded in a quoted
>> +   command-line argument.  */
>> +
>> +static int
>> +escape_bang_in_quoted_argument (const char *shell_file)
>> +{
>> +  const int shell_file_len = strlen (shell_file);
>> +
>> +  /* Bang should be escaped only in C Shells.  For now, simply check
>> +     that the shell name ends with 'csh', which covers at least csh
>> +     and tcsh.  This should be good enough for now.  */
>> +
>> +  if (shell_file_len < 3)
>> +    return 0;
>> +
>> +  if (shell_file[shell_file_len - 3] == 'c'
>> +      && shell_file[shell_file_len - 2] == 's'
>> +      && shell_file[shell_file_len - 1] == 'h')
>> +    return 1;
>> +
>> +  return 0;
>> +}
>
> This function lost some edits done in the execv_argv patch.
>
> bool + size_t.
>
> Please run a diff of the old gdb/fork-child.c against the
> new nat/fork-inferior.c to make sure nothing else was lost.

Thanks, I'll make sure that nothing else is missed.

>
>> diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
>> new file mode 100644
>> index 0000000..6a8528e
>> --- /dev/null
>> +++ b/gdb/nat/fork-inferior.h
>> @@ -0,0 +1,51 @@
> ...
>
>> +
>> +#ifndef FORK_CHILD_H
>> +#define FORK_CHILD_H
>
> Incorrectly named multiple-inclusion guard.

Fixed.

>> +
>> +#include <vector>
>
> Why?  Nothing uses std::vector here.

Removed.

>> +
>> +/* Accept NTRAPS traps from the inferior.
>> +
>> +   Return the ptid of the inferior being started.  */
>> +extern ptid_t startup_inferior (pid_t pid, int ntraps,
>> +				struct target_waitstatus *mystatus,
>> +				ptid_t *myptid);
>> +
>> +/* Start an inferior Unix child process and sets inferior_ptid to its
>> +   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
>> +   the arguments to the program.  ENV is the environment vector to
>> +   pass.  SHELL_FILE is the shell file, or NULL if we should pick
>> +   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
>> +   one.  */
>> +
>> +/* This function is NOT reentrant.  Some of the variables have been
>> +   made static to ensure that they survive the vfork call.  */
>> +extern pid_t fork_inferior (const char *exec_file_arg,
>> +			    const std::string &allargs,
>
> Should include <string>.

Should it?  It's compiling fine without it.  I included just for the
sake of clarity anyway.

>> +			    char **env, void (*traceme_fun) (void),
>> +			    void (*init_trace_fun) (int),
>> +			    void (*pre_trace_fun) (void),
>> +			    const char *shell_file_arg,
>> +			    void (*exec_fun) (const char *file,
>> +					      char * const *argv,
>> +					      char * const *env));
>> +
>> +#endif /* ! FORK_CHILD_H */
>
>>  
>> diff --git a/gdb/target.h b/gdb/target.h
>> index a971adf..6c995a1 100644
>> --- a/gdb/target.h
>> +++ b/gdb/target.h
>> @@ -1538,17 +1538,6 @@ extern int target_terminal_is_inferior (void);
>>  
>>  extern int target_terminal_is_ours (void);
>>  
>> -/* Initialize the terminal settings we record for the inferior,
>> -   before we actually run the inferior.  */
>> -
>> -extern void target_terminal_init (void);
>> -
>> -/* Put the inferior's terminal settings into effect.  This is
>> -   preparation for starting or resuming the inferior.  This is a no-op
>> -   unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_inferior (void);
>> -
>>  /* Put some of our terminal settings into effect, enough to get proper
>>     results from our output, but do not change into or out of RAW mode
>>     so that no input is discarded.  This is a no-op if terminal_ours
>> @@ -1557,12 +1546,6 @@ extern void target_terminal_inferior (void);
>>  
>>  extern void target_terminal_ours_for_output (void);
>>  
>> -/* Put our terminal settings into effect.  First record the inferior's
>> -   terminal settings so they can be restored properly later.  This is
>> -   a no-op unless called with the main UI as current UI.  */
>> -
>> -extern void target_terminal_ours (void);
>> -
>
> Please leave breakcrumb comments behind.

Will do.

Now, something that came up while I was testing things with mingw here.
gdb/gdbserver/server.c now calls startup_inferior (define in
nat/fork-inferior.c) directly, instead of doing things on its own.  This
is one of the goals of this series, but for targets that don't compile
fork-inferior.c (like Windows) this is an obvious problem.  So here's
what I'm doing for the new version of the series: I'll move
startup_inferior to common/ (probably common/common-fork-inferior.c or
some such), so that all targets can have access to it (it's
target-agnostic anyway).  If you have any comments about this, please
let me know.

Expect a new version of the series tomorrow.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
                     ` (2 preceding siblings ...)
  2017-06-04 22:18   ` [PATCH v7 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
@ 2017-06-04 22:18   ` Sergio Durigan Junior
  2017-06-07 12:29     ` Pedro Alves
                       ` (2 more replies)
  3 siblings, 3 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-04 22:18 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-inferior.h"
	and "nat/fork-inferior.h".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* commom/common-utils.c: Include "common-utils.h".
	(stringify_argv): New function.
	(trace_start_error): Moved from "fork-child.c".
	(trace_start_error_with_name): Likewise.
	* configure.nat: Add "fork-inferior.o" as a dependency for
	"*linux*", "fbsd*" and "nbsd*" hosts.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	(darwin_create_inferior): Call "add_thread_silent" after
	"fork_inferior".
	* common/common-utils.h (gdb_flush_out_err): New prototype.
	(stringify_argv): Likewise.
	(trace_start_error): Likewise.
	(trace_start_error_with_name): Likewise.
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(saved_ui): New variable.
	(prefork_hook): New function.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(gdb_startup_inferior): Likewise.
	(fork_inferior): Move to "common/common-fork-child.c".  Update
	function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inf-ptrace.c: Include "nat/fork-inferior.h" and "utils.h".
	(inf_ptrace_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inferior.h: Include "common-inferior.h".
	(trace_start_error): Move to "common/common-utils.h".
	(trace_start_error_with_name): Likewise.
	(fork_inferior): Move prototype to "nat/fork-inferior.h".
	(startup_inferior): Likewise.
	(gdb_startup_inferior): New prototype.
	* nat/fork-inferior.c: New file, with contents from "fork-child.c".
	* nat/fork-inferior.h: New file.
	* procfs.c (procfs_init_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "nat/fork-inferior.o".
	* configure: Regenerate.
	* configure.ac: Adding object file related to safe_strerror to
	IPA_DEPFILES.
	* configure.srv (srv_linux_obj): Add "fork-inferior.o".
	(i[34567]86-*-lynxos*): Likewise.
	(spu*-*-*): Likewise.
	* linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h"
	and "environ.h".
	(linux_ptrace_fun): New function.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".  Update comments.
	* server.c: Include "common-inferior.h", "nat/fork-inferior.h",
	"common-terminal.h" and "environ.h".
	(our_environ): New variable.
	(startup_with_shell): Likewise.
	(program_name): Likewise.
	(program_argv): Rename to...
	(program_args): ...this.
	(wrapper_argv): New variable.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(prefork_hook): Likewise.
	(post_fork_inferior): Likewise.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h: Include <vector>.
	(post_fork_inferior): New prototype.
	(get_environ): Likewise.
	* spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   2 +
 gdb/common/common-inferior.h                      |  33 ++
 gdb/common/common-utils.c                         |  48 ++
 gdb/common/common-utils.h                         |  20 +
 gdb/configure.nat                                 |   8 +-
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |  16 +-
 gdb/fork-child.c                                  | 629 +++-------------------
 gdb/gdbserver/Makefile.in                         |   1 +
 gdb/gdbserver/configure                           |   4 +-
 gdb/gdbserver/configure.ac                        |   4 +-
 gdb/gdbserver/configure.srv                       |   6 +-
 gdb/gdbserver/linux-low.c                         |  89 +--
 gdb/gdbserver/lynx-low.c                          |  51 +-
 gdb/gdbserver/nto-low.c                           |  10 +-
 gdb/gdbserver/server.c                            | 250 ++++++---
 gdb/gdbserver/server.h                            |  16 +
 gdb/gdbserver/spu-low.c                           |  45 +-
 gdb/gdbserver/target.c                            |  27 +
 gdb/gdbserver/target.h                            |  13 +-
 gdb/gdbserver/utils.c                             |   9 +
 gdb/gdbserver/win32-low.c                         |  23 +-
 gdb/gnu-nat.c                                     |   8 +-
 gdb/inf-ptrace.c                                  |  15 +-
 gdb/inferior.h                                    |  33 +-
 gdb/nat/fork-inferior.c                           | 569 +++++++++++++++++++
 gdb/nat/fork-inferior.h                           |  90 ++++
 gdb/procfs.c                                      |   7 +-
 gdb/target.h                                      |  18 +-
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  12 +-
 gdb/utils.c                                       |   9 +
 32 files changed, 1261 insertions(+), 822 deletions(-)
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/nat/fork-inferior.c
 create mode 100644 gdb/nat/fork-inferior.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6bb44d7..642b711 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1524,6 +1524,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_termios.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1564,6 +1565,7 @@ HFILES_NO_SRCDIR = \
 	nat/amd64-linux-siginfo.h \
 	nat/gdb_ptrace.h \
 	nat/gdb_thread_db.h \
+	nat/fork-inferior.h \
 	nat/linux-btrace.h \
 	nat/linux-namespaces.h \
 	nat/linux-nat.h \
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..87c1300
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,33 @@
+/* Functions to deal with the inferior being executed on GDB or
+   GDBserver.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern const char *get_exec_wrapper ();
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index e94fdc4..fbec0da 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "common-defs.h"
+#include "common-utils.h"
 #include "host-defs.h"
 #include <ctype.h>
 
@@ -328,3 +329,50 @@ free_vector_argv (std::vector<char *> &v)
 
   v.clear ();
 }
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (const std::vector<char *> &args)
+{
+  std::string ret;
+
+  if (!args.empty ())
+    {
+      for (auto s : args)
+	if (s != NULL)
+	  {
+	    ret += s;
+	    ret += ' ';
+	  }
+
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+    }
+
+  return ret;
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See common/common-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index c331f0d..38505e0 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -108,4 +108,24 @@ extern const char *skip_to_space_const (const char *inp);
    freeing all the elements.  */
 extern void free_vector_argv (std::vector<char *> &v);
 
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments with a whitespace separating them.  */
+extern std::string stringify_argv (const std::vector<char *> &argv);
+
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err ();
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
 #endif
diff --git a/gdb/configure.nat b/gdb/configure.nat
index e6c96da..e6da599 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -54,7 +54,7 @@
 case ${gdb_host} in
     *linux*)
 	NAT_FILE='config/nm-linux.h'
-	NATDEPFILES='inf-ptrace.o fork-child.o proc-service.o \
+	NATDEPFILES='inf-ptrace.o fork-child.o fork-inferior.o proc-service.o \
 		linux-thread-db.o linux-nat.o linux-osdata.o linux-fork.o \
 		linux-procfs.o linux-ptrace.o linux-waitpid.o \
 		linux-personality.o linux-namespaces.o'
@@ -62,15 +62,15 @@ case ${gdb_host} in
 	LOADLIBES='-ldl $(RDYNAMIC)'
 	;;
     fbsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o fbsd-nat.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o fbsd-nat.o'
 	HAVE_NATIVE_GCORE_HOST=1
 	LOADLIBES='-lkvm'
 	;;
     nbsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o'
 	;;
     obsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o'
 	;;
     cygwin*)
 	NATDEPFILES='x86-nat.o x86-dregs.o windows-nat.o'
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 13a90b9..33eb4d1 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index cba84ca..4330a60 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1790,7 +1790,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 }
 
 static void
@@ -1833,13 +1833,23 @@ darwin_create_inferior (struct target_ops *ops,
 			const std::string &allargs,
 			char **env, int from_tty)
 {
+  pid_t pid;
+  ptid_t ptid;
+
   /* Do the hard work.  */
-  fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
-		 darwin_pre_ptrace, NULL, darwin_execvp);
+  pid = fork_inferior (exec_file, allargs, env, darwin_ptrace_me,
+		       darwin_ptrace_him, darwin_pre_ptrace, NULL,
+		       darwin_execvp);
 
+  ptid = pid_to_ptid (pid);
   /* Return now in case of error.  */
   if (ptid_equal (inferior_ptid, null_ptid))
     return;
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
 }
 \f
 
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index c1b6f53..39e49b5 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,471 +21,55 @@
 
 #include "defs.h"
 #include "inferior.h"
+#include "gdbcmd.h"
 #include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
 #include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
-#include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
 #include "top.h"
-#include "signals-state-save-restore.h"
 #include "job-control.h"
-#include <signal.h>
-#include <vector>
-
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
-
-extern char **environ;
+#include "filestuff.h"
+#include "nat/fork-inferior.h"
+#include "common/common-inferior.h"
 
-static char *exec_wrapper;
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-/* Build the argument vector for execv(3).  */
+static char *exec_wrapper = NULL;
 
-class execv_argv
-{
-public:
-  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
-     arguments to the program.  If starting with a shell, SHELL_FILE
-     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
-  execv_argv (const char *exec_file, const std::string &allargs,
-	      const char *shell_file);
-
-  /* Return a pointer to the built argv, in the type expected by
-     execv.  The result is (only) valid for as long as this execv_argv
-     object is live.  We return a "char **" because that's the type
-     that the execv functions expect.  Note that it is guaranteed that
-     the execv functions do not modify the argv[] array nor the
-     strings to which the array point.  */
-  char **argv ()
-  {
-    return const_cast<char **> (&m_argv[0]);
-  }
-
-private:
-  /* Disable copying.  */
-  execv_argv (const execv_argv &) = delete;
-  void operator= (const execv_argv &) = delete;
-
-  /* Helper methods for constructing the argument vector.  */
-
-  /* Used when building an argv for a straight execv call, without
-     going via the shell.  */
-  void init_for_no_shell (const char *exec_file,
-			  const std::string &allargs);
-
-  /* Used when building an argv for execing a shell that execs the
-     child program.  */
-  void init_for_shell (const char *exec_file,
-		       const std::string &allargs,
-		       const char *shell_file);
-
-  /* The argument vector built.  Holds non-owning pointers.  Elements
-     either point to the strings passed to the execv_argv ctor, or
-     inside M_STORAGE.  */
-  std::vector<const char *> m_argv;
-
-  /* Storage.  In the no-shell case, this contains a copy of the
-     arguments passed to the ctor, split by '\0'.  In the shell case,
-     this contains the quoted shell command.  I.e., SHELL_COMMAND in
-     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
-  std::string m_storage;
-};
-
-/* Create argument vector for straight call to execvp.  Breaks up
-   ALLARGS into an argument vector suitable for passing to execvp and
-   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
-   as input the string "a b c d", and as output it would fill in
-   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
-   in M_ARGV points to a substring of a copy of ALLARGS stored in
-   M_STORAGE.  */
+/* See common/common-inferior.h.  */
 
-void
-execv_argv::init_for_no_shell (const char *exec_file,
-			       const std::string &allargs)
+const char *
+get_exec_wrapper ()
 {
-
-  /* Save/work with a copy stored in our storage.  The pointers pushed
-     to M_ARGV point directly into M_STORAGE, which is modified in
-     place with the necessary NULL terminators.  This avoids N heap
-     allocations and string dups when 1 is sufficient.  */
-  std::string &args_copy = m_storage = allargs;
-
-  m_argv.push_back (exec_file);
-
-  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
-    {
-      /* Skip whitespace-like chars.  */
-      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
-
-      if (pos != std::string::npos)
-	cur_pos = pos;
-
-      /* Find the position of the next separator.  */
-      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
-
-      if (next_sep == std::string::npos)
-	{
-	  /* No separator found, which means this is the last
-	     argument.  */
-	  next_sep = args_copy.size ();
-	}
-      else
-	{
-	  /* Replace the separator with a terminator.  */
-	  args_copy[next_sep++] = '\0';
-	}
-
-      m_argv.push_back (&args_copy[cur_pos]);
-
-      cur_pos = next_sep;
-    }
-
-  /* NULL-terminate the vector.  */
-  m_argv.push_back (NULL);
+  return exec_wrapper;
 }
 
-/* When executing a command under the given shell, return true if the
-   '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static bool
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  size_t shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return false;
+/* The ui structure that will be saved on 'prefork_hook' and
+   restored on 'postfork_hook'.  */
+static struct ui *saved_ui = NULL;
 
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return true;
-
-  return false;
-}
-
-/* See declaration.  */
-
-execv_argv::execv_argv (const char *exec_file,
-			const std::string &allargs,
-			const char *shell_file)
-{
-  if (shell_file == NULL)
-    init_for_no_shell (exec_file, allargs);
-  else
-    init_for_shell (exec_file, allargs, shell_file);
-}
-
-/* See declaration.  */
+/* See nat/fork-inferior.h.  */
 
 void
-execv_argv::init_for_shell (const char *exec_file,
-			    const std::string &allargs,
-			    const char *shell_file)
+prefork_hook (const char *args)
 {
-  /* We're going to call a shell.  */
-  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-  /* We need to build a new shell command string, and make argv point
-     to it.  So build it in the storage.  */
-  std::string &shell_command = m_storage;
-
-  shell_command = "exec ";
-
-  /* Add any exec wrapper.  That may be a program name with arguments,
-     so the user must handle quoting.  */
-  if (exec_wrapper)
-    {
-      shell_command += exec_wrapper;
-      shell_command += ' ';
-    }
-
-  /* Now add exec_file, quoting as necessary.  */
-
-  /* Quoting in this style is said to work with all shells.  But csh
-     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
-     to.  */
-  bool need_to_quote;
-  const char *p = exec_file;
-  while (1)
-    {
-      switch (*p)
-	{
-	case '\'':
-	case '!':
-	case '"':
-	case '(':
-	case ')':
-	case '$':
-	case '&':
-	case ';':
-	case '<':
-	case '>':
-	case ' ':
-	case '\n':
-	case '\t':
-	  need_to_quote = true;
-	  goto end_scan;
-
-	case '\0':
-	  need_to_quote = false;
-	  goto end_scan;
-
-	default:
-	  break;
-	}
-      ++p;
-    }
- end_scan:
-  if (need_to_quote)
-    {
-      shell_command += '\'';
-      for (p = exec_file; *p != '\0'; ++p)
-	{
-	  if (*p == '\'')
-	    shell_command += "'\\''";
-	  else if (*p == '!' && escape_bang)
-	    shell_command += "\\!";
-	  else
-	    shell_command += *p;
-	}
-      shell_command += '\'';
-    }
-  else
-    shell_command += exec_file;
-
-  shell_command += ' ' + allargs;
-
-  /* If we decided above to start up with a shell, we exec the shell.
-     "-c" says to interpret the next arg as a shell command to
-     execute, and this command is "exec <target-program> <args>".  */
-  m_argv.reserve (4);
-  m_argv.push_back (shell_file);
-  m_argv.push_back ("-c");
-  m_argv.push_back (shell_command.c_str ());
-  m_argv.push_back (NULL);
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
-		                  "process.\nError: ");
-  vfprintf_unfiltered (gdb_stderr, fmt, ap);
-  va_end (ap);
-
-  gdb_flush (gdb_stderr);
-  _exit (0177);
-}
-
-/* See inferior.h.  */
-
-void
-trace_start_error_with_name (const char *string)
-{
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (const char *exec_file_arg, const std::string &allargs,
-	       char **env, void (*traceme_fun) (void),
-	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
-	       char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static const char *exec_file;
-  char **save_our_env;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  if (exec_file_arg == NULL)
-    exec_file = get_exec_file (1);
-  else
-    exec_file = exec_file_arg;
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  if (startup_with_shell)
-    {
-      shell_file = shell_file_arg;
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-    }
-  else
-    shell_file = NULL;
-
-  /* Build the argument vector.  */
-  execv_argv child_argv (exec_file, allargs, shell_file);
 
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
+  gdb_assert (saved_ui == NULL);
+  /* Retain a copy of our UI, since the child will replace this value
+     and if we're vforked, we have to restore it.  */
+  saved_ui = current_ui;
 
   /* Tell the terminal handling subsystem what tty we plan to run on;
      it will just record the information for later.  */
   new_tty_prefork (inferior_io_terminal);
+}
 
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      char **argv = child_argv.argv ();
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], &argv[0], env);
-      else
-        execvp (argv[0], &argv[0]);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
+/* See nat/fork-inferior.h.  */
 
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
+void
+postfork_hook (pid_t pid)
+{
+  struct inferior *inf;
 
   if (!have_inferiors ())
     init_thread_list ();
@@ -494,147 +78,58 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
 
   inferior_appeared (inf, pid);
 
-  /* Needed for wait_for_inferior stuff below.  */
+  /* Needed for wait_for_inferior stuff.  */
   inferior_ptid = pid_to_ptid (pid);
 
-  new_tty_postfork ();
+  gdb_assert (saved_ui != NULL);
+  current_ui = saved_ui;
+  saved_ui = NULL;
 
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
+  new_tty_postfork ();
 }
 
-/* Accept NTRAPS traps from the inferior.  */
+/* See nat/fork-inferior.h.  */
 
 void
-startup_inferior (int ntraps)
+postfork_child_hook ()
 {
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  /* Make sure we switch to main_ui here in order to be able to
+     use the fprintf_unfiltered/warning/error functions.  */
+  current_ui = main_ui;
 
-  if (startup_with_shell)
+  /* Create a new session for the inferior process, if necessary.
+     It will also place the inferior in a separate process group.  */
+  if (create_tty_session () <= 0)
     {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
+      /* No session was created, but we still want to run the inferior
+	 in a separate process group.  */
+      debug_setpgrp = gdb_setpgid ();
+      if (debug_setpgrp == -1)
+	perror (_("setpgrp failed in child"));
     }
 
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
+  /* Ask the tty subsystem to switch to the one we specified
+     earlier (or to share the current terminal, if none was
+     specified).  */
+  new_tty ();
+}
 
-  if (exec_wrapper)
-    pending_execs++;
+/* See inferior.h.  */
 
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
+ptid_t
+gdb_startup_inferior (pid_t pid, int num_traps)
+{
+  ptid_t ptid = startup_inferior (pid, num_traps, NULL, NULL);
 
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  set_executing (ptid, 0);
+
+  return ptid;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d9f55de..834425d 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -218,6 +218,7 @@ SFILES = \
 	$(srcdir)/nat/linux-personality.c \
 	$(srcdir)/nat/mips-linux-watch.c \
 	$(srcdir)/nat/ppc-linux.c \
+	$(srcdir)/nat/fork-inferior.c \
 	$(srcdir)/target/waitstatus.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index b314c41..96befef 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -8422,7 +8422,9 @@ fi
 
 if $want_ipa ; then
    if $have_ipa ; then
-     IPA_DEPFILES="$ipa_obj"
+     # Needed because safe_strerror's definition is host-dependent
+     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
+     IPA_DEPFILES="$ipa_obj $strerror_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      as_fn_error "inprocess agent not supported for this target" "$LINENO" 5
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 4ea7913..8aa85db 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -462,7 +462,9 @@ esac],
 
 if $want_ipa ; then
    if $have_ipa ; then
-     IPA_DEPFILES="$ipa_obj"
+     # Needed because safe_strerror's definition is host-dependent
+     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
+     IPA_DEPFILES="$ipa_obj $strerror_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      AC_MSG_ERROR([inprocess agent not supported for this target])
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index d00d9e2..056ac27 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
 
 # Linux object files.  This is so we don't have to repeat
 # these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-inferior.o"
 
 # Input is taken from the "${target}" variable.
 
@@ -131,7 +131,7 @@ case "${target}" in
 			ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
 			;;
   i[34567]86-*-lynxos*)	srv_regobj="i386.o"
-			srv_tgtobj="lynx-low.o lynx-i386-low.o"
+			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-inferior.o"
 			srv_xmlfiles="i386/i386.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
@@ -338,7 +338,7 @@ case "${target}" in
 			srv_linux_thread_db=yes
 			;;
   spu*-*-*)		srv_regobj=reg-spu.o
-			srv_tgtobj="spu-low.o"
+			srv_tgtobj="spu-low.o fork-inferior.o"
 			;;
   tic6x-*-uclinux)	srv_regobj="tic6x-c64xp-linux.o"
 			srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ea3c81b..ab6670b 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,9 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -946,59 +949,57 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun ()
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+	trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+	trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+	trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string str_program_args = stringify_argv (program_args);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
@@ -1008,6 +1009,8 @@ linux_create_inferior (char *program, char **allargs)
   new_lwp = add_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program, startup_inferior);
+
   return pid;
 }
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..382d71c 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,8 @@
 #include "gdb_wait.h"
 #include <signal.h>
 #include "filestuff.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
 
 int using_threads = 1;
 
@@ -224,36 +226,43 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Callback used by fork_inferior to start tracing the inferior.  */
+
+static void
+lynx_ptrace_fun ()
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  if (pgrp < 0)
+    trace_start_error_with_name ("pgrp");
+  if (setpgid (0, pgrp) < 0)
+    trace_start_error_with_name ("setpgid");
+  if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+    trace_start_error_with_name ("ioctl");
+  if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+    trace_start_error_with_name ("lynx_ptrace");
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (const char *program,
+		      const std::vector<char *> &program_args)
 {
   int pid;
+  std::string str_program_args = stringify_argv (program_args);
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program, startup_inferior);
 
   lynx_add_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..a5f1543 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
+   arguments.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (const char *program,
+		     const std::vector<char *> &program_args)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string str_program_args = stringify_argv (program_args);
 
   TRACE ("%s %s\n", __func__, program);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
@@ -367,7 +370,8 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit,
+		(char *) str_program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 69fcab1..5a76927 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -36,6 +36,20 @@
 #include "dll.h"
 #include "hostio.h"
 #include <vector>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "job-control.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -79,8 +93,9 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static std::vector<char *> program_argv;
-static std::vector<char *> wrapper_argv;
+static char *program_name = NULL;
+static std::vector<char *> program_args;
+static std::string wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -238,25 +253,41 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
+/* See common/common-inferior.h.  */
+
+const char *
+get_exec_wrapper ()
 {
-  std::vector<char *> new_argv;
+  return wrapper_argv.size () > 0 ? wrapper_argv.c_str () : NULL;
+}
+
+/* See common/common-inferior.h.  */
 
-  if (!wrapper_argv.empty ())
-    new_argv.insert (new_argv.begin (),
-		     wrapper_argv.begin (),
-		     wrapper_argv.end ());
+char *
+get_exec_file (int err)
+{
+  if (err && program_name == NULL)
+    error (_("No executable file specified."));
 
-  for (int i = 0; argv[i] != NULL; ++i)
-    new_argv.push_back (argv[i]);
+  return program_name;
+}
 
-  new_argv.push_back (NULL);
+/* See server.h.  */
+
+struct gdb_environ *
+get_environ ()
+{
+  return our_environ;
+}
+
+/* See nat/fork-inferior.h.  */
 
+void
+prefork_hook (const char *args)
+{
   if (debug_threads)
     {
-      for (int i = 0; i < new_argv.size (); ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      debug_printf ("args: %s\n", args);
       debug_flush ();
     }
 
@@ -265,67 +296,63 @@ start_inferior (char **argv)
   signal (SIGTTIN, SIG_DFL);
 #endif
 
-  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
 
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, const char *program,
+		    ptid_t (*my_startup_inferior) (pid_t pid, int ntraps,
+						   struct target_waitstatus
+						   *mystatus,
+						   ptid_t *myptid))
+
+{
+  /* Number of traps to be expected by startup_inferior.  We always
+     expect at least one trap for the main executable.  */
+  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
 
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_IGN);
   signal (SIGTTIN, SIG_IGN);
   terminal_fd = fileno (stderr);
   old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
+  tcsetpgrp (terminal_fd, pid);
   atexit (restore_old_foreground_pgrp);
 #endif
 
-  if (!wrapper_argv.empty ())
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
-
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
+  my_startup_inferior (pid, num_traps, &last_status, &last_ptid);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = last_status;
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
+}
 
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
+/* See nat/fork-inferior.h.  */
 
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+void
+postfork_hook (pid_t pid)
+{
+}
 
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
+/* See nat/fork-inferior.h.  */
 
-  return signal_pid;
+void
+postfork_child_hook ()
+{
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  debug_setpgrp = gdb_setpgid ();
+  if (debug_setpgrp == -1)
+    perror (_("setpgrp failed in child"));
 }
 
 static int
@@ -2848,6 +2875,7 @@ handle_v_run (char *own_buf)
 {
   char *p, *next_p;
   std::vector<char *> new_argv;
+  char *new_program_name = NULL;
   int i, new_argc;
 
   new_argc = 0;
@@ -2866,42 +2894,94 @@ handle_v_run (char *own_buf)
       if (i == 0 && p == next_p)
 	{
 	  /* No program specified.  */
-	  new_argv.push_back (NULL);
+	  new_program_name = NULL;
+	}
+      else if (p == next_p)
+	{
+	  /* Empty argument.  */
+	  new_argv.push_back (xstrdup ("''"));
 	}
       else
 	{
 	  size_t len = (next_p - p) / 2;
+	  /* ARG is the unquoted argument received via the RSP.  */
 	  char *arg = (char *) xmalloc (len + 1);
+	  /* FULL_ARGS will contain the quoted version of ARG.  */
+	  char *full_arg = (char *) xmalloc ((len + 1) * 2);
+	  /* These are pointers used to navigate the strings above.  */
+	  char *tmp_arg = arg;
+	  char *tmp_full_arg = full_arg;
+	  int need_quote = 0;
 
 	  hex2bin (p, (gdb_byte *) arg, len);
 	  arg[len] = '\0';
-	  new_argv.push_back (arg);
-	}
 
+	  while (*tmp_arg != '\0')
+	    {
+	      switch (*tmp_arg)
+		{
+		case '\n':
+		  /* Quote \n.  */
+		  *tmp_full_arg = '\'';
+		  ++tmp_full_arg;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  /* Quote single quote.  */
+		  *tmp_full_arg = '\\';
+		  ++tmp_full_arg;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_full_arg = *tmp_arg;
+	      ++tmp_full_arg;
+	      ++tmp_arg;
+	    }
+
+	  if (need_quote)
+	    *tmp_full_arg++ = '\'';
+
+	  /* Finish FULL_ARG and push it into the vector containing
+	     the argv.  */
+	  *tmp_full_arg = '\0';
+	  if (i == 0)
+	    new_program_name = full_arg;
+	  else
+	    new_argv.push_back (full_arg);
+	  xfree (arg);
+	}
       if (*next_p)
 	next_p++;
     }
   new_argv.push_back (NULL);
 
-  if (new_argv[0] == NULL)
+  if (new_program_name == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-      if (program_argv.empty ())
+      if (program_name == NULL)
 	{
 	  write_enn (own_buf);
 	  free_vector_argv (new_argv);
 	  return 0;
 	}
-
-      new_argv.push_back (xstrdup (program_argv[0]));
+    }
+  else
+    {
+      xfree (program_name);
+      program_name = new_program_name;
     }
 
   /* Free the old argv and install the new one.  */
-  free_vector_argv (program_argv);
-  program_argv = new_argv;
+  free_vector_argv (program_args);
+  program_args = new_argv;
+
+  create_inferior (program_name, program_args);
 
-  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3527,10 +3607,17 @@ captured_main (int argc, char *argv[])
 	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
 	    {
-	      wrapper_argv.push_back (*next_arg);
+	      wrapper_argv += *next_arg;
+	      wrapper_argv += ' ';
 	      next_arg++;
 	    }
 
+	  if (wrapper_argv.size () > 0)
+	    {
+	      /* Erase the last whitespace.  */
+	      wrapper_argv.erase (wrapper_argv.end () - 1);
+	    }
+
 	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
@@ -3666,8 +3753,13 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3681,12 +3773,13 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      for (i = 0; i < n; i++)
-	program_argv.push_back (xstrdup (next_arg[i]));
-      program_argv.push_back (NULL);
+      program_name = xstrdup (next_arg[0]);
+      for (i = 1; i < n; i++)
+	program_args.push_back (xstrdup (next_arg[i]));
+      program_args.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (&program_argv[0]);
+      create_inferior (program_name, program_args);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4301,9 +4394,10 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (!program_argv.empty ())
+	  if (program_name != NULL)
 	    {
-	      start_inferior (&program_argv[0]);
+	      create_inferior (program_name, program_args);
+
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..96566fe 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -148,4 +148,20 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior.  This is done here.  PID is the
+   pid of the new inferior, PROGRAM is its name, and
+   MY_STARTUP_INFERIOR is the function that should be called to start
+   the inferior and consume its first events.  In most cases, this
+   function should be "startup_inferior" itself.  */
+extern void post_fork_inferior (int pid, const char *program,
+				ptid_t (*my_startup_inferior)
+				(pid_t pid, int ntraps,
+				 struct target_waitstatus *mystatus,
+				 ptid_t *myptid));
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ ();
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..c71e8ba 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,8 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
 
 /* Some older glibc versions do not define this.  */
 #ifndef __WNOTHREAD
@@ -261,36 +263,37 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun ()
+{
+  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
+
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (const char *program,
+		     const std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string str_program_args = stringify_argv (program_args);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program, startup_inferior);
 
   proc = add_process (pid, 0);
   proc->tdesc = tdesc_spu;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..7526463 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,30 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..be89258 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -67,13 +68,13 @@ struct target_ops
   /* Start a new process.
 
      PROGRAM is a path to the program to execute.
-     ARGS is a standard NULL-terminated array of arguments,
-     to be passed to the inferior as ``argv''.
+     PROGRAM_ARGS is a standard NULL-terminated array of arguments,
+     to be passed to the inferior as ``argv'' (along with PROGRAM).
 
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
-
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (const char *program,
+			  const std::vector<char *> &program_args);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_args)	\
+  (*the_target->create_inferior) (program, program_args)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 307d15a..3f96a6c 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,3 +137,12 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
+
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err ()
+{
+  fflush (stdout);
+  fflush (stderr);
+}
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7b09f4b..88f6911 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,13 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM is the program name.
+   PROGRAM_ARGS is the vector containing the inferior's args.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -622,11 +622,12 @@ win32_create_inferior (char *program, char **program_args)
 #endif
   BOOL ret;
   DWORD flags;
-  char *args;
   int argslen;
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string str_program_args = stringify_argv (program_args);
+  char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -652,18 +653,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 6298103..d5e3841 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2143,6 +2143,11 @@ gnu_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, gnu_ptrace_me,
                        NULL, NULL, NULL, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   /* Attach to the now stopped child, which is actually a shell...  */
   inf_debug (inf, "attaching to child: %d", pid);
 
@@ -2162,7 +2167,8 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
+
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index b19aaf9..2a01dd2 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -31,6 +31,8 @@
 #include "inf-ptrace.h"
 #include "inf-child.h"
 #include "gdbthread.h"
+#include "nat/fork-inferior.h"
+#include "utils.h"
 
 \f
 
@@ -93,7 +95,8 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 			    const char *exec_file, const std::string &allargs,
 			    char **env, int from_tty)
 {
-  int pid;
+  pid_t pid;
+  ptid_t ptid;  
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
@@ -110,13 +113,19 @@ inf_ptrace_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
 		       NULL, NULL, NULL);
 
+  ptid = pid_to_ptid (pid);
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
+
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
-  target_post_startup_inferior (pid_to_ptid (pid));
+  target_post_startup_inferior (ptid);
 }
 
 #ifdef PT_GET_PROCESS_STATE
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7ee92ed..cdaeb11 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -45,6 +45,7 @@ struct inferior;
 
 #include "progspace.h"
 #include "registry.h"
+#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 #include "common/refcounted-object.h"
@@ -136,28 +137,10 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
-extern int fork_inferior (const char *, const std::string &, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
+/* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
+   This function already calls set_executing.  Return the ptid_t from
+   STARTUP_INFERIOR.  */
+extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
 
 extern char *construct_inferior_arguments (int, char **);
 
@@ -282,12 +265,6 @@ enum stop_kind
 #define ON_STACK 1
 #define AT_ENTRY_POINT 4
 
-/* Number of traps that happen between exec'ing the shell to run an
-   inferior and when we finally get to the inferior code, not counting
-   the exec for the shell.  This is 1 on all supported
-   implementations.  */
-#define START_INFERIOR_TRAPS_EXPECTED	1
-
 struct private_inferior;
 
 /* Inferior process specific part of `struct infcall_control_state'.
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
new file mode 100644
index 0000000..7fd93ef
--- /dev/null
+++ b/gdb/nat/fork-inferior.c
@@ -0,0 +1,569 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "fork-inferior.h"
+#include "target/waitstatus.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "signals-state-save-restore.h"
+#include <vector>
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Build the argument vector for execv(3).  */
+
+class execv_argv
+{
+public:
+  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
+     arguments to the program.  If starting with a shell, SHELL_FILE
+     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
+  execv_argv (const char *exec_file, const std::string &allargs,
+	      const char *shell_file);
+
+  /* Return a pointer to the built argv, in the type expected by
+     execv.  The result is (only) valid for as long as this execv_argv
+     object is live.  We return a "char **" because that's the type
+     that the execv functions expect.  Note that it is guaranteed that
+     the execv functions do not modify the argv[] array nor the
+     strings to which the array point.  */
+  char **argv ()
+  {
+    return const_cast<char **> (&m_argv[0]);
+  }
+
+private:
+  /* Disable copying.  */
+  execv_argv (const execv_argv &) = delete;
+  void operator= (const execv_argv &) = delete;
+
+  /* Helper methods for constructing the argument vector.  */
+
+  /* Used when building an argv for a straight execv call, without
+     going via the shell.  */
+  void init_for_no_shell (const char *exec_file,
+			  const std::string &allargs);
+
+  /* Used when building an argv for execing a shell that execs the
+     child program.  */
+  void init_for_shell (const char *exec_file,
+		       const std::string &allargs,
+		       const char *shell_file);
+
+  /* The argument vector built.  Holds non-owning pointers.  Elements
+     either point to the strings passed to the execv_argv ctor, or
+     inside M_STORAGE.  */
+  std::vector<const char *> m_argv;
+
+  /* Storage.  In the no-shell case, this contains a copy of the
+     arguments passed to the ctor, split by '\0'.  In the shell case,
+     this contains the quoted shell command.  I.e., SHELL_COMMAND in
+     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
+  std::string m_storage;
+};
+
+/* Create argument vector for straight call to execvp.  Breaks up
+   ALLARGS into an argument vector suitable for passing to execvp and
+   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
+   as input the string "a b c d", and as output it would fill in
+   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
+   in M_ARGV points to a substring of a copy of ALLARGS stored in
+   M_STORAGE.  */
+
+void
+execv_argv::init_for_no_shell (const char *exec_file,
+			       const std::string &allargs)
+{
+
+  /* Save/work with a copy stored in our storage.  The pointers pushed
+     to M_ARGV point directly into M_STORAGE, which is modified in
+     place with the necessary NULL terminators.  This avoids N heap
+     allocations and string dups when 1 is sufficient.  */
+  std::string &args_copy = m_storage = allargs;
+
+  m_argv.push_back (exec_file);
+
+  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
+    {
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
+
+      if (next_sep == std::string::npos)
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = args_copy.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  args_copy[next_sep++] = '\0';
+	}
+
+      m_argv.push_back (&args_copy[cur_pos]);
+
+      cur_pos = next_sep;
+    }
+
+  /* NULL-terminate the vector.  */
+  m_argv.push_back (NULL);
+}
+
+/* When executing a command under the given shell, return true if the
+   '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static bool
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  size_t shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return false;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return true;
+
+  return false;
+}
+
+/* See declaration.  */
+
+execv_argv::execv_argv (const char *exec_file,
+			const std::string &allargs,
+			const char *shell_file)
+{
+  if (shell_file == NULL)
+    init_for_no_shell (exec_file, allargs);
+  else
+    init_for_shell (exec_file, allargs, shell_file);
+}
+
+/* See declaration.  */
+
+void
+execv_argv::init_for_shell (const char *exec_file,
+			    const std::string &allargs,
+			    const char *shell_file)
+{
+  const char *exec_wrapper = get_exec_wrapper ();
+
+  /* We're going to call a shell.  */
+  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  /* We need to build a new shell command string, and make argv point
+     to it.  So build it in the storage.  */
+  std::string &shell_command = m_storage;
+
+  shell_command = "exec ";
+
+  /* Add any exec wrapper.  That may be a program name with arguments,
+     so the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      shell_command += exec_wrapper;
+      shell_command += ' ';
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But csh
+     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
+     to.  */
+  bool need_to_quote;
+  const char *p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = true;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = false;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      shell_command += '\'';
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    shell_command += "\\!";
+	  else
+	    shell_command += *p;
+	}
+      shell_command += '\'';
+    }
+  else
+    shell_command += exec_file;
+
+  shell_command += ' ' + allargs;
+
+  /* If we decided above to start up with a shell, we exec the shell.
+     "-c" says to interpret the next arg as a shell command to
+     execute, and this command is "exec <target-program> <args>".  */
+  m_argv.reserve (4);
+  m_argv.push_back (shell_file);
+  m_argv.push_back ("-c");
+  m_argv.push_back (shell_command.c_str ());
+  m_argv.push_back (NULL);
+}
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+
+static const char *
+get_startup_shell ()
+{
+  static const char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* See nat/fork-inferior.h.  */
+
+pid_t
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (),
+	       const char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
+{
+  pid_t pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  int debug_fork = 0;
+  const char *shell_file;
+  const char *exec_file;
+  char **save_our_env;
+  int i;
+  int save_errno;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  if (exec_file_arg == NULL)
+    exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  if (startup_with_shell)
+    {
+      shell_file = shell_file_arg;
+
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+    }
+  else
+    shell_file = NULL;
+
+  /* Build the argument vector.  */
+  execv_argv child_argv (exec_file, allargs, shell_file);
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Perform any necessary actions regarding to TTY before the
+     fork/vfork call.  */
+  prefork_hook (allargs.c_str ());
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
+      close_most_fds ();
+
+      if (debug_fork)
+	sleep (debug_fork);
+
+      /* Execute any necessary post-fork actions before we exec.  */
+      postfork_child_hook ();
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      char **argv = child_argv.argv ();
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], &argv[0], env);
+      else
+        execvp (argv[0], &argv[0]);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  postfork_hook (pid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See nat/fork-inferior.h.  */
+
+ptid_t
+startup_inferior (pid_t pid, int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (pid);
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  return resume_ptid;
+}
diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
new file mode 100644
index 0000000..39bdd8d
--- /dev/null
+++ b/gdb/nat/fork-inferior.h
@@ -0,0 +1,90 @@
+/* Functions and data responsible for forking the inferior process.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef FORK_INFERIOR_H
+#define FORK_INFERIOR_H
+
+#include <string>
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern pid_t fork_inferior (const char *exec_file_arg,
+			    const std::string &allargs,
+			    char **env, void (*traceme_fun) (),
+			    void (*init_trace_fun) (int),
+			    void (*pre_trace_fun) (),
+			    const char *shell_file_arg,
+			    void (*exec_fun) (const char *file,
+					      char * const *argv,
+					      char * const *env));
+
+/* Accept NTRAPS traps from the inferior.
+
+   Return the ptid of the inferior being started.  */
+extern ptid_t startup_inferior (pid_t pid, int ntraps,
+				struct target_waitstatus *mystatus,
+				ptid_t *myptid);
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
+   is a string containing all the arguments received by the inferior.
+   This function is mainly used by fork_inferior.  */
+extern void prefork_hook (const char *args);
+
+/* Perform any necessary tasks after a fork/vfork takes place.  This
+   function is mainly used by fork_inferior.  */
+extern void postfork_hook (pid_t pid);
+
+/* Perform any necessary tasks *on the child* after a fork/vfork takes
+   place.  This function is mainly used by fork_inferior.  */
+extern void postfork_child_hook ();
+
+#endif /* ! FORK_INFERIOR_H */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index adb2e84..b03809c 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4377,7 +4377,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
@@ -4604,6 +4604,11 @@ procfs_create_inferior (struct target_ops *ops, const char *exec_file,
   pid = fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
 		       NULL, NULL, shell_file, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   procfs_init_inferior (ops, pid);
 }
 
diff --git a/gdb/target.h b/gdb/target.h
index a971adf..083d2bc 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1538,16 +1538,8 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
+/* For target_terminal_init, target_terminal_inferior and
+   target_terminal_ours, see target/target.h.  */
 
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
@@ -1557,12 +1549,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..0528766 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init ();
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior ();
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours ();
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..68d4d53 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,16 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled (e.g., when the SHELL variable is
+    # unset).
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled, which is the
+    # default behaviour.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
diff --git a/gdb/utils.c b/gdb/utils.c
index c61557e..bd0a0d8 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3391,6 +3391,15 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
+/* See common/common-utils.h.  */
+
+void
+gdb_flush_out_err ()
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v7 4/4] Implement proper "startup-with-shell" support on gdbserver
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
@ 2017-06-04 22:18   ` Sergio Durigan Junior
  2017-06-05  2:31     ` Eli Zaretskii
  2017-06-04 22:18   ` [PATCH v7 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-04 22:18 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

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:
yyyy-mm-dd  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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

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

gdb/doc/ChangeLog:
yyyy-mm-dd  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/NEWS                                      | 17 +++++
 gdb/doc/gdb.texinfo                           | 39 ++++++++++++
 gdb/gdbserver/server.c                        | 38 +++++++++++-
 gdb/remote.c                                  | 20 ++++++
 gdb/testsuite/gdb.base/startup-with-shell.c   | 29 +++++++++
 gdb/testsuite/gdb.base/startup-with-shell.exp | 89 +++++++++++++++++++++++++++
 6 files changed, 231 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.c
 create mode 100644 gdb/testsuite/gdb.base/startup-with-shell.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 112aa2f..8dab5d3 100644
--- 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.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9fb70f6..8d7a1c9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 5a76927..c2acb9e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -859,6 +859,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;
@@ -2295,7 +2320,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 ())
@@ -3401,6 +3426,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"
@@ -3693,6 +3725,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
diff --git a/gdb/remote.c b/gdb/remote.c
index 1f86079..b66ecee 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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);
 
diff --git a/gdb/testsuite/gdb.base/startup-with-shell.c b/gdb/testsuite/gdb.base/startup-with-shell.c
new file mode 100644
index 0000000..6278447
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.c
@@ -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
index 0000000..af06c88
--- /dev/null
+++ b/gdb/testsuite/gdb.base/startup-with-shell.exp
@@ -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)
+}
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v7 0/4] Implement the ability to start inferiors with a shell on gdbserver
  2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
                   ` (9 preceding siblings ...)
  2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
@ 2017-06-04 22:18 ` Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
                     ` (3 more replies)
  10 siblings, 4 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-04 22:18 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves

Hi,

This is the seventh iteration of the patch series.  You can see the
last version here:

  <https://sourceware.org/ml/gdb-patches/2017-05/msg00098.html>

Changes from v6:

- Several small cleanups/fixes caught by Pedro.

- The testcase now doesn't run when using a remote target board.  This
  is because it is not trivial to set environment variables via
  ssh/dejagnu, so one testcase fails.

- Using the new gdb/configure.nat file.

- The post_fork_inferior function on gdb/gdbserver/server.c now takes
  a "my_startup_inferior" function pointer as argument.  This is done
  to avoid using startup_inferior directly, which is not declared on
  all targets (e.g., win32).


Other than that, the patch hasn't changed.

Thanks,

Sergio.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v7 2/4] Share parts of gdb/gdbthread.h with gdbserver
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
@ 2017-06-04 22:18   ` Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
  3 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-04 22:18 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

GDB and gdbserver now share 'switch_to_thread' because of
fork_inferior.  To make things clear, I created a new file name
common/common-gdbthread.h, and left the implementation specific to
each part.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-gdbthread.h".
	* common/common-gdbthread.h: New file, with parts from
	"gdb/gdbthread.h".
	* gdbthread.h: Include "common-gdbthread.h".
	(switch_to_thread): Moved to "common/common-gdbthread.h".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* inferiors.c (switch_to_thread): New function.
---
 gdb/Makefile.in               |  1 +
 gdb/common/common-gdbthread.h | 25 +++++++++++++++++++++++++
 gdb/gdbserver/inferiors.c     |  9 +++++++++
 gdb/gdbthread.h               |  5 +----
 4 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 gdb/common/common-gdbthread.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 25777f2..6bb44d7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1507,6 +1507,7 @@ HFILES_NO_SRCDIR = \
 	common/common-debug.h \
 	common/common-defs.h \
 	common/common-exceptions.h \
+	common/common-gdbthread.h \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
diff --git a/gdb/common/common-gdbthread.h b/gdb/common/common-gdbthread.h
new file mode 100644
index 0000000..d8635e7
--- /dev/null
+++ b/gdb/common/common-gdbthread.h
@@ -0,0 +1,25 @@
+/* Common multi-process/thread control defs for GDB and gdbserver.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_GDBTHREAD_H
+#define COMMON_GDBTHREAD_H
+
+/* Switch from one thread to another.  */
+extern void switch_to_thread (ptid_t ptid);
+
+#endif /* ! COMMON_GDBTHREAD_H */
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index b65a726..5a4a0d1 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -468,3 +468,12 @@ make_cleanup_restore_current_thread (void)
 {
   return make_cleanup (do_restore_current_thread_cleanup, current_thread);
 }
+
+/* See common/common-gdbthread.h.  */
+
+void
+switch_to_thread (ptid_t ptid)
+{
+  if (!ptid_equal (ptid, minus_one_ptid))
+    current_thread = find_thread_ptid (ptid);
+}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 7bf2070..046bf95 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -32,6 +32,7 @@ struct symtab;
 #include "target/waitstatus.h"
 #include "cli/cli-utils.h"
 #include "common/refcounted-object.h"
+#include "common-gdbthread.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -493,10 +494,6 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  Also sets the STOP_PC
-   global.  */
-extern void switch_to_thread (ptid_t ptid);
-
 /* Switch from one thread to another.  Does not read registers and
    sets STOP_PC to -1.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [PATCH v7 1/4] Move parts of inferior job control to common/
  2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
@ 2017-06-04 22:18   ` Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
  2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
  3 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-04 22:18 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This commit moves a few bits responsible for dealing with inferior job
control from GDB to common/, which makes them available to gdbserver.
This is necessary for the upcoming patches that will share
fork_inferior et al between GDB and gdbserver.

We move some parts of gdb/terminal.h to gdb/common/common-terminal.h,
especifically the code that checks terminal features and that are used
to set job_control accordingly.

After sharing parts of gdb/terminal.h, we also to share the two
functions on gdb/inflow.c that are going to be needed by the
fork_inferior rework.  They are 'gdb_setpgid' and the new
'have_job_control'.  I've also taken the opportunity to give a more
meaningful name to "inflow.c" on common/.  Now it is called
"job-control.c" (thanks Pedro for the suggestion).

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILES): Add "common/job-control.c".
	(HFILES_NO_SRCDIR): Add "common/job-control.h".
	(COMMON_OBS): Add "job-control.o".
	* common/job-control.c: New file, with contents from
	"gdb/inflow.c".
	* common/job-control.h: New file, with contents from "terminal.h".
	* fork-child.c: Include "job-control.h".
	* inflow.c: Include "job-control.h".
	(gdb_setpgid): Move to "common/common-inflow.c".
	(_initialize_inflow): Move setting of "job_control" to
	"handle_job_control".
	* terminal.h (job_control): Moved to "common/common-terminal.h".
	(gdb_setpgid): Likewise.
	* top.c: Include "job_control.h".
	* utils.c: Likewise.
	(job_control): Moved to "job-control.c".

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* Makefile.in (SFILE): Add "common/job-control.c".
	(OBS): Add "job-control.o".
---
 gdb/Makefile.in           |  3 ++
 gdb/common/job-control.c  | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/common/job-control.h  | 38 +++++++++++++++++++
 gdb/fork-child.c          |  1 +
 gdb/gdbserver/Makefile.in |  2 +
 gdb/inflow.c              | 64 ++------------------------------
 gdb/terminal.h            | 12 ------
 gdb/top.c                 |  1 +
 gdb/utils.c               |  5 +--
 9 files changed, 142 insertions(+), 77 deletions(-)
 create mode 100644 gdb/common/job-control.c
 create mode 100644 gdb/common/job-control.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8be73ba..25777f2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1234,6 +1234,7 @@ SFILES = \
 	common/fileio.c \
 	common/filestuff.c \
 	common/format.c \
+	common/job-control.c \
 	common/gdb_vecs.c \
 	common/new-op.c \
 	common/print-utils.c \
@@ -1509,6 +1510,7 @@ HFILES_NO_SRCDIR = \
 	common/common-regcache.h \
 	common/common-types.h \
 	common/common-utils.h \
+	common/job-control.h \
 	common/errors.h \
 	common/environ.h \
 	common/fileio.h \
@@ -1663,6 +1665,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-agent.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	complaints.o \
diff --git a/gdb/common/job-control.c b/gdb/common/job-control.c
new file mode 100644
index 0000000..d76bc57
--- /dev/null
+++ b/gdb/common/job-control.c
@@ -0,0 +1,93 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "job-control.h"
+#include "gdb_termios.h"
+
+/* Nonzero if we have job control.  */
+int job_control;
+
+/* Set the process group ID of the inferior.
+
+   Just using job_control only does part of it because setpgid or
+   setpgrp might not exist on a system without job control.
+
+   For a more clean implementation, in libiberty, put a setpgid which merely
+   calls setpgrp and a setpgrp which does nothing (any system with job control
+   will have one or the other).  */
+
+int
+gdb_setpgid ()
+{
+  int retval = 0;
+
+  if (job_control)
+    {
+#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
+#ifdef HAVE_SETPGID
+      /* The call setpgid (0, 0) is supposed to work and mean the same
+         thing as this, but on Ultrix 4.2A it fails with EPERM (and
+         setpgid (getpid (), getpid ()) succeeds).  */
+      retval = setpgid (getpid (), getpid ());
+#else
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+      retval = setpgrp ();
+#else
+      retval = setpgrp (getpid (), getpid ());
+#endif
+#endif /* HAVE_SETPGRP */
+#endif /* HAVE_SETPGID */
+#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
+    }
+
+  return retval;
+}
+
+/* See common/common-terminal.h.  */
+
+void
+have_job_control ()
+{
+  /* OK, figure out whether we have job control.  If neither termios nor
+     sgtty (i.e. termio or go32), leave job_control 0.  */
+#if defined (HAVE_TERMIOS)
+  /* Do all systems with termios have the POSIX way of identifying job
+     control?  I hope so.  */
+#ifdef _POSIX_JOB_CONTROL
+  job_control = 1;
+#else
+#ifdef _SC_JOB_CONTROL
+  job_control = sysconf (_SC_JOB_CONTROL);
+#else
+  job_control = 0;		/* Have to assume the worst.  */
+#endif /* _SC_JOB_CONTROL */
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SGTTY
+#ifdef TIOCGPGRP
+  job_control = 1;
+#else
+  job_control = 0;
+#endif /* TIOCGPGRP */
+#endif /* sgtty */
+}
diff --git a/gdb/common/job-control.h b/gdb/common/job-control.h
new file mode 100644
index 0000000..9e284aa
--- /dev/null
+++ b/gdb/common/job-control.h
@@ -0,0 +1,38 @@
+/* Job control and terminal related functions, for GDB and gdbserver
+   when running under Unix.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef JOB_CONTROL_H
+#define JOB_CONTROL_H
+
+/* Do we have job control?  Can be assumed to always be the same
+   within a given run of GDB.  Use in gdb/inflow.c and
+   common/common-inflow.c.  */
+extern int job_control;
+
+/* Set the process group of the caller to its own pid, or do nothing
+   if we lack job control.  */
+extern int gdb_setpgid ();
+
+/* Determine whether we have job control, and set variable JOB_CONTROL
+   accordingly.  This function must be called before any use of
+   JOB_CONTROL.  */
+extern void have_job_control ();
+
+#endif /* ! JOB_CONTROL_H */
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 11ffee9..c1b6f53 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -33,6 +33,7 @@
 #include "filestuff.h"
 #include "top.h"
 #include "signals-state-save-restore.h"
+#include "job-control.h"
 #include <signal.h>
 #include <vector>
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 01dfdc0..d9f55de 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -204,6 +204,7 @@ SFILES = \
 	$(srcdir)/common/environ.c \
 	$(srcdir)/common/fileio.c \
 	$(srcdir)/common/filestuff.c \
+	$(srcdir)/common/job-control.c \
 	$(srcdir)/common/gdb_vecs.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/print-utils.c \
@@ -234,6 +235,7 @@ OBS = \
 	cleanups.o \
 	common-debug.o \
 	common-exceptions.o \
+	job-control.o \
 	common-regcache.o \
 	common-utils.o \
 	debug.o \
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 23dcc4d..01851f4 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -32,6 +32,7 @@
 #include "inflow.h"
 #include "gdbcmd.h"
 #include "gdb_termios.h"
+#include "job-control.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
@@ -804,43 +805,6 @@ create_tty_session (void)
 #endif /* HAVE_SETSID */
 }
 
-/* This is here because this is where we figure out whether we (probably)
-   have job control.  Just using job_control only does part of it because
-   setpgid or setpgrp might not exist on a system without job control.
-   It might be considered misplaced (on the other hand, process groups and
-   job control are closely related to ttys).
-
-   For a more clean implementation, in libiberty, put a setpgid which merely
-   calls setpgrp and a setpgrp which does nothing (any system with job control
-   will have one or the other).  */
-int
-gdb_setpgid (void)
-{
-  int retval = 0;
-
-  if (job_control)
-    {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
-      /* The call setpgid (0, 0) is supposed to work and mean the same
-         thing as this, but on Ultrix 4.2A it fails with EPERM (and
-         setpgid (getpid (), getpid ()) succeeds).  */
-      retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID 
-      retval = setpgrp ();
-#else
-      retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
-    }
-
-  return retval;
-}
-
 /* Get all the current tty settings (including whether we have a
    tty at all!).  We can't do this in _initialize_inflow because
    serial_fdopen() won't work until the serial_ops_list is
@@ -861,30 +825,8 @@ _initialize_inflow (void)
 
   terminal_is_ours = 1;
 
-  /* OK, figure out whether we have job control.  If neither termios nor
-     sgtty (i.e. termio or go32), leave job_control 0.  */
-
-#if defined (HAVE_TERMIOS)
-  /* Do all systems with termios have the POSIX way of identifying job
-     control?  I hope so.  */
-#ifdef _POSIX_JOB_CONTROL
-  job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
-  job_control = sysconf (_SC_JOB_CONTROL);
-#else
-  job_control = 0;		/* Have to assume the worst.  */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
-  job_control = 1;
-#else
-  job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+  /* OK, figure out whether we have job control.  */
+  have_job_control ();
 
   observer_attach_inferior_exit (inflow_inferior_exit);
 
diff --git a/gdb/terminal.h b/gdb/terminal.h
index fb20ae0..0027a3a 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -29,16 +29,8 @@ extern void new_tty_postfork (void);
 
 extern void copy_terminal_info (struct inferior *to, struct inferior *from);
 
-/* Do we have job control?  Can be assumed to always be the same within
-   a given run of GDB.  In inflow.c.  */
-extern int job_control;
-
 extern pid_t create_tty_session (void);
 
-/* Set the process group of the caller to its own pid, or do nothing if
-   we lack job control.  */
-extern int gdb_setpgid (void);
-
 /* Set up a serial structure describing standard input.  In inflow.c.  */
 extern void initialize_stdin_serial (void);
 
@@ -48,8 +40,4 @@ extern void gdb_save_tty_state (void);
    have had a chance to alter it.  */
 extern void set_initial_gdb_ttystate (void);
 
-/* Set the process group of the caller to its own pid, or do nothing
-   if we lack job control.  */
-extern int gdb_setpgid (void);
-
 #endif /* !defined (TERMINAL_H) */
diff --git a/gdb/top.c b/gdb/top.c
index 3de8a26..17261cc 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -35,6 +35,7 @@
 #include "value.h"
 #include "language.h"
 #include "terminal.h"		/* For job_control.  */
+#include "job-control.h"
 #include "annotate.h"
 #include "completer.h"
 #include "top.h"
diff --git a/gdb/utils.c b/gdb/utils.c
index b4332f8..c61557e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -65,6 +65,7 @@
 #include "gdb_usleep.h"
 #include "interps.h"
 #include "gdb_regex.h"
+#include "job-control.h"
 
 #if !HAVE_DECL_MALLOC
 extern PTR malloc ();		/* ARI: PTR */
@@ -102,10 +103,6 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 static int debug_timestamp = 0;
 
-/* Nonzero if we have job control.  */
-
-int job_control;
-
 /* Nonzero means that strings with character values >0x7F should be printed
    as octal escapes.  Zero means just print the value (e.g. it's an
    international character, and the terminal or window can cope.)  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 4/4] Implement proper "startup-with-shell" support on gdbserver
  2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
@ 2017-06-05  2:31     ` Eli Zaretskii
  0 siblings, 0 replies; 157+ messages in thread
From: Eli Zaretskii @ 2017-06-05  2:31 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, palves

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>,	Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Sun,  4 Jun 2017 18:18:03 -0400
> 
> A documentation patch is included, along with a new testcase for the
> feature.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  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:
> yyyy-mm-dd  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:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* gdb.base/startup-with-shell.c: New file.
> 	* gdb.base/startup-with-shell.exp: Likewise.
> 
> gdb/doc/ChangeLog:
> yyyy-mm-dd  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.

OK for the documentation parts.

Thanks.

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-05-31  3:43       ` Sergio Durigan Junior
@ 2017-06-07 10:16         ` Pedro Alves
  2017-06-07 12:23           ` Pedro Alves
  2017-06-07 21:00           ` Sergio Durigan Junior
  0 siblings, 2 replies; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 10:16 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 05/31/2017 04:43 AM, Sergio Durigan Junior wrote:
> 
>>> >> index 4ea7913..8aa85db 100644
>>> >> --- a/gdb/gdbserver/configure.ac
>>> >> +++ b/gdb/gdbserver/configure.ac
>>> >> @@ -462,7 +462,9 @@ esac],
>>> >>  
>>> >>  if $want_ipa ; then
>>> >>     if $have_ipa ; then
>>> >> -     IPA_DEPFILES="$ipa_obj"
>>> >> +     # Needed because safe_strerror's definition is host-dependent
>> >
>> > Why do we end up needing safe_strerror in the IPA in the first place?
> This is needed because I moved the definition of
> trace_start_error_with_name from the old gdb/fork-child.c to
> common/common-utils.c.  This function which uses safe_strerror, and
> common/common-utils.c is compiled by IPA.
> 
> An option would be to keep these trace_start_error.* functions in
> nat/fork-inferior.c, but I think it is more logical to keep them on
> common-utils.c.

I'd rather not add them to the IPA.  The least unnecessary code
is included in that library the better, because it is injected
into the target process.  So keeping them in fork-inferior.c
sounds better.

> 
> Now, I can obviously expand the comment if that's what you meant.
> 
>>> >> +     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
>>> >> +     IPA_DEPFILES="$ipa_obj $strerror_obj"
>>> >>       extra_libraries="$extra_libraries libinproctrace.so"
>>> >>     else
>>> >>       AC_MSG_ERROR([inprocess agent not supported for this target])
>> >
>> >
>> >
>>> >> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>>> >> -  pid = vfork ();
>> >
>> > Does fork_inferior end up always using vfork on no-MMU
>> > ports somehow?
> Sorry, I am not sure.  How would I go about finding that?

I'm not sure either.  configure.ac for anything fork related?
Look at git blame history around those lines, see what other
bits were touched at the same time?  gdbserver clearly cares about
being built for no-MMU ports, so the new code must too.  We can't
just delete that support without an alternative.

>>> >> +
>>> >> +/* This function is NOT reentrant.  Some of the variables have been
>>> >> +   made static to ensure that they survive the vfork call.  */
>>> >> +extern pid_t fork_inferior (const char *exec_file_arg,
>>> >> +			    const std::string &allargs,
>> >
>> > Should include <string>.
> Should it?  It's compiling fine without it.  I included just for the
> sake of clarity anyway.

Yes, headers should include what they depend on directly.

> Now, something that came up while I was testing things with mingw here.
> gdb/gdbserver/server.c now calls startup_inferior (define in
> nat/fork-inferior.c) directly, instead of doing things on its own.  This
> is one of the goals of this series, but for targets that don't compile
> fork-inferior.c (like Windows) this is an obvious problem.  So here's
> what I'm doing for the new version of the series: I'll move
> startup_inferior to common/ (probably common/common-fork-inferior.c or
> some such), so that all targets can have access to it (it's
> target-agnostic anyway).  If you have any comments about this, please
> let me know.

This sounds quite contorted, but I'll take a better look at it in v7.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 10:16         ` Pedro Alves
@ 2017-06-07 12:23           ` Pedro Alves
  2017-06-07 21:01             ` Sergio Durigan Junior
  2017-06-07 21:00           ` Sergio Durigan Junior
  1 sibling, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 12:23 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 06/07/2017 11:15 AM, Pedro Alves wrote:
> On 05/31/2017 04:43 AM, Sergio Durigan Junior wrote:
>>
>>>>>> index 4ea7913..8aa85db 100644
>>>>>> --- a/gdb/gdbserver/configure.ac
>>>>>> +++ b/gdb/gdbserver/configure.ac
>>>>>> @@ -462,7 +462,9 @@ esac],
>>>>>>  
>>>>>>  if $want_ipa ; then
>>>>>>     if $have_ipa ; then
>>>>>> -     IPA_DEPFILES="$ipa_obj"
>>>>>> +     # Needed because safe_strerror's definition is host-dependent
>>>>
>>>> Why do we end up needing safe_strerror in the IPA in the first place?
>> This is needed because I moved the definition of
>> trace_start_error_with_name from the old gdb/fork-child.c to
>> common/common-utils.c.  This function which uses safe_strerror, and
>> common/common-utils.c is compiled by IPA.
>>
>> An option would be to keep these trace_start_error.* functions in
>> nat/fork-inferior.c, but I think it is more logical to keep them on
>> common-utils.c.
> 
> I'd rather not add them to the IPA.  The least unnecessary code
> is included in that library the better, because it is injected
> into the target process.  So keeping them in fork-inferior.c
> sounds better.
> 

I tried it against v7, and that works.  The think to keep
in mind is that these trace_start_error functions
are only called from the fork child, so they're very much
fork-inferior.c related.

>>>>
>>>>>> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>>>>>> -  pid = vfork ();
>>>>
>>>> Does fork_inferior end up always using vfork on no-MMU
>>>> ports somehow?
>> Sorry, I am not sure.  How would I go about finding that?
> 
> I'm not sure either.  configure.ac for anything fork related?
> Look at git blame history around those lines, see what other
> bits were touched at the same time?  gdbserver clearly cares about
> being built for no-MMU ports, so the new code must too.  We can't
> just delete that support without an alternative.

I think we just need to add the HAVE_MMU etc. check around
vfork in fork-inferior.c.

> 
>> Now, something that came up while I was testing things with mingw here.
>> gdb/gdbserver/server.c now calls startup_inferior (define in
>> nat/fork-inferior.c) directly, instead of doing things on its own.  This
>> is one of the goals of this series, but for targets that don't compile
>> fork-inferior.c (like Windows) this is an obvious problem.  So here's
>> what I'm doing for the new version of the series: I'll move
>> startup_inferior to common/ (probably common/common-fork-inferior.c or
>> some such), so that all targets can have access to it (it's
>> target-agnostic anyway).  If you have any comments about this, please
>> let me know.
> 
> This sounds quite contorted, but I'll take a better look at it in v7.

I think that we just need to create a gdbserver/fork-child.c that is
very much like gdb's own gdb/fork-child.c ends up looking like,
and then only building fork-child.o on hosts that also build
nat/fork-inferior.o.  We can get rid of the function pointer
parameter this way.

I'll send you a patch on top of v7 in reply to v7, to show
what I mean.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
@ 2017-06-07 12:29     ` Pedro Alves
  2017-06-07 21:06       ` Sergio Durigan Junior
  2017-06-08 16:40     ` Yao Qi
  2017-06-21 17:01     ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Simon Marchi
  2 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 12:29 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

So here's the patch showing what I meant in:
 https://sourceware.org/ml/gdb-patches/2017-06/msg00169.html

I'll be happy with the resulting patch once if you fold this in.
Could you do that, retest and repost?

I think we could get rid of the new common-inferior.h
header too, but I'll leave that as is, for now at least.

From 1d66adbd79ab97415d519f18906257e99ce49706 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 7 Jun 2017 13:18:14 +0100
Subject: [PATCH] Fixes

---
 gdb/common/common-utils.c   |  24 ----------
 gdb/common/common-utils.h   |  16 -------
 gdb/fork-child.c            |   9 ++++
 gdb/gdbserver/configure     |   4 +-
 gdb/gdbserver/configure.ac  |   4 +-
 gdb/gdbserver/configure.srv |   6 +--
 gdb/gdbserver/fork-child.c  | 113 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/linux-low.c   |   4 +-
 gdb/gdbserver/lynx-low.c    |   2 +-
 gdb/gdbserver/server.c      | 100 ++-------------------------------------
 gdb/gdbserver/server.h      |  18 ++++---
 gdb/gdbserver/spu-low.c     |   3 +-
 gdb/gdbserver/utils.c       |   9 ----
 gdb/inf-ptrace.c            |   2 +-
 gdb/inferior.h              |   1 -
 gdb/nat/fork-inferior.c     |  26 ++++++++++
 gdb/nat/fork-inferior.h     |  16 +++++++
 gdb/utils.c                 |   9 ----
 18 files changed, 185 insertions(+), 181 deletions(-)
 create mode 100644 gdb/gdbserver/fork-child.c

diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index fbec0da..793ab3b 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -352,27 +352,3 @@ stringify_argv (const std::vector<char *> &args)
 
   return ret;
 }
-
-/* See common/common-inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  warning ("Could not trace the inferior process.\nError: ");
-  vwarning (fmt, ap);
-  va_end (ap);
-
-  gdb_flush_out_err ();
-  _exit (0177);
-}
-
-/* See common/common-inferior.h.  */
-
-void
-trace_start_error_with_name (const char *string)
-{
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 38505e0..787bac9 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -112,20 +112,4 @@ extern void free_vector_argv (std::vector<char *> &v);
    joining all the arguments with a whitespace separating them.  */
 extern std::string stringify_argv (const std::vector<char *> &argv);
 
-/* Flush both stdout and stderr.  This function needs to be
-   implemented differently on GDB and GDBserver.  */
-extern void gdb_flush_out_err ();
-
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
 #endif
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 39e49b5..60985d8 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -43,6 +43,15 @@ get_exec_wrapper ()
   return exec_wrapper;
 }
 
+/* See nat/fork-inferior.h.  */
+
+void
+gdb_flush_out_err ()
+{
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
+}
+
 /* The ui structure that will be saved on 'prefork_hook' and
    restored on 'postfork_hook'.  */
 static struct ui *saved_ui = NULL;
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index 96befef..b314c41 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -8422,9 +8422,7 @@ fi
 
 if $want_ipa ; then
    if $have_ipa ; then
-     # Needed because safe_strerror's definition is host-dependent
-     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
-     IPA_DEPFILES="$ipa_obj $strerror_obj"
+     IPA_DEPFILES="$ipa_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      as_fn_error "inprocess agent not supported for this target" "$LINENO" 5
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 8aa85db..4ea7913 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -462,9 +462,7 @@ esac],
 
 if $want_ipa ; then
    if $have_ipa ; then
-     # Needed because safe_strerror's definition is host-dependent
-     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
-     IPA_DEPFILES="$ipa_obj $strerror_obj"
+     IPA_DEPFILES="$ipa_obj"
      extra_libraries="$extra_libraries libinproctrace.so"
    else
      AC_MSG_ERROR([inprocess agent not supported for this target])
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 056ac27..43f90c9 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
 
 # Linux object files.  This is so we don't have to repeat
 # these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-inferior.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-child.o fork-inferior.o"
 
 # Input is taken from the "${target}" variable.
 
@@ -131,7 +131,7 @@ case "${target}" in
 			ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
 			;;
   i[34567]86-*-lynxos*)	srv_regobj="i386.o"
-			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-inferior.o"
+			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o fork-inferior.o"
 			srv_xmlfiles="i386/i386.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
@@ -338,7 +338,7 @@ case "${target}" in
 			srv_linux_thread_db=yes
 			;;
   spu*-*-*)		srv_regobj=reg-spu.o
-			srv_tgtobj="spu-low.o fork-inferior.o"
+			srv_tgtobj="spu-low.o fork-child.o fork-inferior.o"
 			;;
   tic6x-*-uclinux)	srv_regobj="tic6x-c64xp-linux.o"
 			srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
new file mode 100644
index 0000000..a1a8ff1
--- /dev/null
+++ b/gdb/gdbserver/fork-child.c
@@ -0,0 +1,113 @@
+/* Fork a Unix child process, and set up to debug it, for GDBserver.
+   Copyright (C) 1989-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "job-control.h"
+#include "nat/fork-inferior.h"
+
+#ifdef SIGTTOU
+/* A file descriptor for the controlling terminal.  */
+static int terminal_fd;
+
+/* TERMINAL_FD's original foreground group.  */
+static pid_t old_foreground_pgrp;
+
+/* Hand back terminal ownership to the original foreground group.  */
+
+static void
+restore_old_foreground_pgrp (void)
+{
+  tcsetpgrp (terminal_fd, old_foreground_pgrp);
+}
+#endif
+
+/* See nat/fork-inferior.h.  */
+
+void
+prefork_hook (const char *args)
+{
+  if (debug_threads)
+    {
+      debug_printf ("args: %s\n", args);
+      debug_flush ();
+    }
+
+#ifdef SIGTTOU
+  signal (SIGTTOU, SIG_DFL);
+  signal (SIGTTIN, SIG_DFL);
+#endif
+
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+postfork_hook (pid_t pid)
+{
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+postfork_child_hook ()
+{
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  debug_setpgrp = gdb_setpgid ();
+  if (debug_setpgrp == -1)
+    perror (_("setpgrp failed in child"));
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+gdb_flush_out_err ()
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, const char *program)
+{
+#ifdef SIGTTOU
+  signal (SIGTTOU, SIG_IGN);
+  signal (SIGTTIN, SIG_IGN);
+  terminal_fd = fileno (stderr);
+  old_foreground_pgrp = tcgetpgrp (terminal_fd);
+  tcsetpgrp (terminal_fd, pid);
+  atexit (restore_old_foreground_pgrp);
+#endif
+
+  startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
+		    &last_status, &last_ptid);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = last_status;
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ab6670b..7fbf744 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -1009,7 +1009,7 @@ linux_create_inferior (const char *program,
   new_lwp = add_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
-  post_fork_inferior (pid, program, startup_inferior);
+  post_fork_inferior (pid, program);
 
   return pid;
 }
@@ -6058,8 +6058,6 @@ linux_look_up_symbols (void)
 static void
 linux_request_interrupt (void)
 {
-  extern unsigned long signal_pid;
-
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  */
   kill (-signal_pid, SIGINT);
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 382d71c..35160d6 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -262,7 +262,7 @@ lynx_create_inferior (const char *program,
 		       environ_vector (get_environ ()), lynx_ptrace_fun,
 		       NULL, NULL, NULL, NULL);
 
-  post_fork_inferior (pid, program, startup_inferior);
+  post_fork_inferior (pid, program);
 
   lynx_add_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 5a76927..3ab042d 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -37,7 +37,6 @@
 #include "hostio.h"
 #include <vector>
 #include "common-inferior.h"
-#include "nat/fork-inferior.h"
 #include "job-control.h"
 #include "environ.h"
 
@@ -108,22 +107,6 @@ int program_signals_p;
 
 unsigned long signal_pid;
 
-#ifdef SIGTTOU
-/* A file descriptor for the controlling terminal.  */
-int terminal_fd;
-
-/* TERMINAL_FD's original foreground group.  */
-pid_t old_foreground_pgrp;
-
-/* Hand back terminal ownership to the original foreground group.  */
-
-static void
-restore_old_foreground_pgrp (void)
-{
-  tcsetpgrp (terminal_fd, old_foreground_pgrp);
-}
-#endif
-
 /* Set if you want to disable optional thread related packets support
    in gdbserver, for the sake of testing GDB against stubs that don't
    support them.  */
@@ -133,8 +116,8 @@ int disable_packet_qC;
 int disable_packet_qfThreadInfo;
 
 /* Last status reported to GDB.  */
-static struct target_waitstatus last_status;
-static ptid_t last_ptid;
+struct target_waitstatus last_status;
+ptid_t last_ptid;
 
 char *own_buf;
 static unsigned char *mem_buf;
@@ -258,7 +241,7 @@ target_running (void)
 const char *
 get_exec_wrapper ()
 {
-  return wrapper_argv.size () > 0 ? wrapper_argv.c_str () : NULL;
+  return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL;
 }
 
 /* See common/common-inferior.h.  */
@@ -280,81 +263,6 @@ get_environ ()
   return our_environ;
 }
 
-/* See nat/fork-inferior.h.  */
-
-void
-prefork_hook (const char *args)
-{
-  if (debug_threads)
-    {
-      debug_printf ("args: %s\n", args);
-      debug_flush ();
-    }
-
-#ifdef SIGTTOU
-  signal (SIGTTOU, SIG_DFL);
-  signal (SIGTTIN, SIG_DFL);
-#endif
-
-  /* Clear this so the backend doesn't get confused, thinking
-     CONT_THREAD died, and it needs to resume all threads.  */
-  cont_thread = null_ptid;
-}
-
-/* See server.h.  */
-
-void
-post_fork_inferior (int pid, const char *program,
-		    ptid_t (*my_startup_inferior) (pid_t pid, int ntraps,
-						   struct target_waitstatus
-						   *mystatus,
-						   ptid_t *myptid))
-
-{
-  /* Number of traps to be expected by startup_inferior.  We always
-     expect at least one trap for the main executable.  */
-  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
-
-#ifdef SIGTTOU
-  signal (SIGTTOU, SIG_IGN);
-  signal (SIGTTIN, SIG_IGN);
-  terminal_fd = fileno (stderr);
-  old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, pid);
-  atexit (restore_old_foreground_pgrp);
-#endif
-
-  my_startup_inferior (pid, num_traps, &last_status, &last_ptid);
-  current_thread->last_resume_kind = resume_stop;
-  current_thread->last_status = last_status;
-  signal_pid = pid;
-  target_post_create_inferior ();
-  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
-  fflush (stderr);
-}
-
-/* See nat/fork-inferior.h.  */
-
-void
-postfork_hook (pid_t pid)
-{
-}
-
-/* See nat/fork-inferior.h.  */
-
-void
-postfork_child_hook ()
-{
-  /* This is set to the result of setpgrp, which if vforked, will be
-     visible to you in the parent process.  It's only used by humans
-     for debugging.  */
-  static int debug_setpgrp = 657473;
-
-  debug_setpgrp = gdb_setpgid ();
-  if (debug_setpgrp == -1)
-    perror (_("setpgrp failed in child"));
-}
-
 static int
 attach_inferior (int pid)
 {
@@ -3612,7 +3520,7 @@ captured_main (int argc, char *argv[])
 	      next_arg++;
 	    }
 
-	  if (wrapper_argv.size () > 0)
+	  if (!wrapper_argv.empty ())
 	    {
 	      /* Erase the last whitespace.  */
 	      wrapper_argv.erase (wrapper_argv.end () - 1);
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 96566fe..4de4244 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -149,19 +149,17 @@ extern int in_queued_stop_replies (ptid_t ptid);
 #define ANY_SYSCALL (-2)
 
 /* After fork_inferior has been called, we need to adjust a few
-   signals and call startup_inferior.  This is done here.  PID is the
-   pid of the new inferior, PROGRAM is its name, and
-   MY_STARTUP_INFERIOR is the function that should be called to start
-   the inferior and consume its first events.  In most cases, this
-   function should be "startup_inferior" itself.  */
-extern void post_fork_inferior (int pid, const char *program,
-				ptid_t (*my_startup_inferior)
-				(pid_t pid, int ntraps,
-				 struct target_waitstatus *mystatus,
-				 ptid_t *myptid));
+   signals and call startup_inferior to start the inferior and consume
+   its first events.  This is done here.  PID is the pid of the new
+   inferior and PROGRAM is its name.  */
+extern void post_fork_inferior (int pid, const char *program);
 
 /* Get the 'struct gdb_environ *' being used in the current
    session.  */
 extern struct gdb_environ *get_environ ();
 
+extern target_waitstatus last_status;
+extern ptid_t last_ptid;
+extern unsigned long signal_pid;
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index c71e8ba..0f770a0 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,7 +27,6 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
-#include "common-inferior.h"
 #include "nat/fork-inferior.h"
 
 /* Some older glibc versions do not define this.  */
@@ -293,7 +292,7 @@ spu_create_inferior (const char *program,
 		       environ_vector (get_environ ()), spu_ptrace_fun,
 		       NULL, NULL, NULL, NULL);
 
-  post_fork_inferior (pid, program, startup_inferior);
+  post_fork_inferior (pid, program);
 
   proc = add_process (pid, 0);
   proc->tdesc = tdesc_spu;
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 3f96a6c..307d15a 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -137,12 +137,3 @@ pfildes (gdb_fildes_t fd)
   return plongest (fd);
 #endif
 }
-
-/* See common/common-utils.h.  */
-
-void
-gdb_flush_out_err ()
-{
-  fflush (stdout);
-  fflush (stderr);
-}
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 2a01dd2..af181f0 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -96,7 +96,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 			    char **env, int from_tty)
 {
   pid_t pid;
-  ptid_t ptid;  
+  ptid_t ptid;
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
diff --git a/gdb/inferior.h b/gdb/inferior.h
index cdaeb11..6376952 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -45,7 +45,6 @@ struct inferior;
 
 #include "progspace.h"
 #include "registry.h"
-#include "common-inferior.h"
 
 #include "symfile-add-flags.h"
 #include "common/refcounted-object.h"
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 7fd93ef..0913409 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -358,9 +358,11 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
      state, this doesn't work.  Also note that the vfork(2) call might
      actually be a call to fork(2) due to the fact that autoconf will
      ``#define vfork fork'' on certain platforms.  */
+#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
   if (pre_trace_fun || debug_fork)
     pid = fork ();
   else
+#endif
     pid = vfork ();
 
   if (pid < 0)
@@ -567,3 +569,27 @@ startup_inferior (pid_t pid, int ntraps,
 
   return resume_ptid;
 }
+
+/* See nat/fork-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
index 39bdd8d..10e3832 100644
--- a/gdb/nat/fork-inferior.h
+++ b/gdb/nat/fork-inferior.h
@@ -87,4 +87,20 @@ extern void postfork_hook (pid_t pid);
    place.  This function is mainly used by fork_inferior.  */
 extern void postfork_child_hook ();
 
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err ();
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
 #endif /* ! FORK_INFERIOR_H */
diff --git a/gdb/utils.c b/gdb/utils.c
index bd0a0d8..c61557e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3391,15 +3391,6 @@ strip_leading_path_elements (const char *path, int n)
   return p;
 }
 
-/* See common/common-utils.h.  */
-
-void
-gdb_flush_out_err ()
-{
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-}
-
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
-- 
2.5.5


^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 10:16         ` Pedro Alves
  2017-06-07 12:23           ` Pedro Alves
@ 2017-06-07 21:00           ` Sergio Durigan Junior
  1 sibling, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 21:00 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, Pedro Alves wrote:

> On 05/31/2017 04:43 AM, Sergio Durigan Junior wrote:
>> 
>>>> >> index 4ea7913..8aa85db 100644
>>>> >> --- a/gdb/gdbserver/configure.ac
>>>> >> +++ b/gdb/gdbserver/configure.ac
>>>> >> @@ -462,7 +462,9 @@ esac],
>>>> >>  
>>>> >>  if $want_ipa ; then
>>>> >>     if $have_ipa ; then
>>>> >> -     IPA_DEPFILES="$ipa_obj"
>>>> >> +     # Needed because safe_strerror's definition is host-dependent
>>> >
>>> > Why do we end up needing safe_strerror in the IPA in the first place?
>> This is needed because I moved the definition of
>> trace_start_error_with_name from the old gdb/fork-child.c to
>> common/common-utils.c.  This function which uses safe_strerror, and
>> common/common-utils.c is compiled by IPA.
>> 
>> An option would be to keep these trace_start_error.* functions in
>> nat/fork-inferior.c, but I think it is more logical to keep them on
>> common-utils.c.
>
> I'd rather not add them to the IPA.  The least unnecessary code
> is included in that library the better, because it is injected
> into the target process.  So keeping them in fork-inferior.c
> sounds better.

OK, fair enough.

>> Now, I can obviously expand the comment if that's what you meant.
>> 
>>>> >> +     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
>>>> >> +     IPA_DEPFILES="$ipa_obj $strerror_obj"
>>>> >>       extra_libraries="$extra_libraries libinproctrace.so"
>>>> >>     else
>>>> >>       AC_MSG_ERROR([inprocess agent not supported for this target])
>>> >
>>> >
>>> >
>>>> >> -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
>>>> >> -  pid = vfork ();
>>> >
>>> > Does fork_inferior end up always using vfork on no-MMU
>>> > ports somehow?
>> Sorry, I am not sure.  How would I go about finding that?
>
> I'm not sure either.  configure.ac for anything fork related?
> Look at git blame history around those lines, see what other
> bits were touched at the same time?  gdbserver clearly cares about
> being built for no-MMU ports, so the new code must too.  We can't
> just delete that support without an alternative.

As explained earlier in private, I'm sorry for the confusion.  I totally
misunderstood your question; I thought you were suggesting to *remove*
the defines, but you actually wants to know why they were removed from
the code...  Obviously!

Well, as I said, I totally agree that they should be kept and I will put
them back.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 12:23           ` Pedro Alves
@ 2017-06-07 21:01             ` Sergio Durigan Junior
  2017-06-07 21:06               ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 21:01 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, Pedro Alves wrote:

> On 06/07/2017 11:15 AM, Pedro Alves wrote:
>> On 05/31/2017 04:43 AM, Sergio Durigan Junior wrote:
>>>
>>>>>>> index 4ea7913..8aa85db 100644
>>>>>>> --- a/gdb/gdbserver/configure.ac
>>>>>>> +++ b/gdb/gdbserver/configure.ac
>>>>>>> @@ -462,7 +462,9 @@ esac],
>>>>>>>  
>>>>>>>  if $want_ipa ; then
>>>>>>>     if $have_ipa ; then
>>>>>>> -     IPA_DEPFILES="$ipa_obj"
>>>>>>> +     # Needed because safe_strerror's definition is host-dependent
>>>>>
>>>>> Why do we end up needing safe_strerror in the IPA in the first place?
>>> This is needed because I moved the definition of
>>> trace_start_error_with_name from the old gdb/fork-child.c to
>>> common/common-utils.c.  This function which uses safe_strerror, and
>>> common/common-utils.c is compiled by IPA.
>>>
>>> An option would be to keep these trace_start_error.* functions in
>>> nat/fork-inferior.c, but I think it is more logical to keep them on
>>> common-utils.c.
>> 
>> I'd rather not add them to the IPA.  The least unnecessary code
>> is included in that library the better, because it is injected
>> into the target process.  So keeping them in fork-inferior.c
>> sounds better.
>> 
>
> I tried it against v7, and that works.  The think to keep
> in mind is that these trace_start_error functions
> are only called from the fork child, so they're very much
> fork-inferior.c related.

They're actually being used by some -nat.c files on gdb/, and -low.c
files on gdbserver.  But as I said, I'm OK with your suggestion.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 12:29     ` Pedro Alves
@ 2017-06-07 21:06       ` Sergio Durigan Junior
  2017-06-07 21:41         ` Sergio Durigan Junior
  2017-06-07 22:15         ` Sergio Durigan Junior
  0 siblings, 2 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 21:06 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, Pedro Alves wrote:

> So here's the patch showing what I meant in:
>  https://sourceware.org/ml/gdb-patches/2017-06/msg00169.html
>
> I'll be happy with the resulting patch once if you fold this in.
> Could you do that, retest and repost?

Thanks for the patch, it makes sense to me in light of the discussions
we had.  I'll apply it and resubmit this specific patch of the series
(instead of resubmitting everything), if that's OK with you.

> I think we could get rid of the new common-inferior.h
> header too, but I'll leave that as is, for now at least.

And move get_exec_{wrapper,file} to fork-inferior.h and fork-child.c,
you mean?

> From 1d66adbd79ab97415d519f18906257e99ce49706 Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Wed, 7 Jun 2017 13:18:14 +0100
> Subject: [PATCH] Fixes
>
> ---
>  gdb/common/common-utils.c   |  24 ----------
>  gdb/common/common-utils.h   |  16 -------
>  gdb/fork-child.c            |   9 ++++
>  gdb/gdbserver/configure     |   4 +-
>  gdb/gdbserver/configure.ac  |   4 +-
>  gdb/gdbserver/configure.srv |   6 +--
>  gdb/gdbserver/fork-child.c  | 113 ++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbserver/linux-low.c   |   4 +-
>  gdb/gdbserver/lynx-low.c    |   2 +-
>  gdb/gdbserver/server.c      | 100 ++-------------------------------------
>  gdb/gdbserver/server.h      |  18 ++++---
>  gdb/gdbserver/spu-low.c     |   3 +-
>  gdb/gdbserver/utils.c       |   9 ----
>  gdb/inf-ptrace.c            |   2 +-
>  gdb/inferior.h              |   1 -
>  gdb/nat/fork-inferior.c     |  26 ++++++++++
>  gdb/nat/fork-inferior.h     |  16 +++++++
>  gdb/utils.c                 |   9 ----
>  18 files changed, 185 insertions(+), 181 deletions(-)
>  create mode 100644 gdb/gdbserver/fork-child.c
>
> diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
> index fbec0da..793ab3b 100644
> --- a/gdb/common/common-utils.c
> +++ b/gdb/common/common-utils.c
> @@ -352,27 +352,3 @@ stringify_argv (const std::vector<char *> &args)
>  
>    return ret;
>  }
> -
> -/* See common/common-inferior.h.  */
> -
> -void
> -trace_start_error (const char *fmt, ...)
> -{
> -  va_list ap;
> -
> -  va_start (ap, fmt);
> -  warning ("Could not trace the inferior process.\nError: ");
> -  vwarning (fmt, ap);
> -  va_end (ap);
> -
> -  gdb_flush_out_err ();
> -  _exit (0177);
> -}
> -
> -/* See common/common-inferior.h.  */
> -
> -void
> -trace_start_error_with_name (const char *string)
> -{
> -  trace_start_error ("%s: %s", string, safe_strerror (errno));
> -}
> diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
> index 38505e0..787bac9 100644
> --- a/gdb/common/common-utils.h
> +++ b/gdb/common/common-utils.h
> @@ -112,20 +112,4 @@ extern void free_vector_argv (std::vector<char *> &v);
>     joining all the arguments with a whitespace separating them.  */
>  extern std::string stringify_argv (const std::vector<char *> &argv);
>  
> -/* Flush both stdout and stderr.  This function needs to be
> -   implemented differently on GDB and GDBserver.  */
> -extern void gdb_flush_out_err ();
> -
> -/* Report an error that happened when starting to trace the inferior
> -   (i.e., when the "traceme_fun" callback is called on fork_inferior)
> -   and bail out.  This function does not return.  */
> -extern void trace_start_error (const char *fmt, ...)
> -  ATTRIBUTE_NORETURN;
> -
> -/* Like "trace_start_error", but the error message is constructed by
> -   combining STRING with the system error message for errno.  This
> -   function does not return.  */
> -extern void trace_start_error_with_name (const char *string)
> -  ATTRIBUTE_NORETURN;
> -
>  #endif
> diff --git a/gdb/fork-child.c b/gdb/fork-child.c
> index 39e49b5..60985d8 100644
> --- a/gdb/fork-child.c
> +++ b/gdb/fork-child.c
> @@ -43,6 +43,15 @@ get_exec_wrapper ()
>    return exec_wrapper;
>  }
>  
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +gdb_flush_out_err ()
> +{
> +  gdb_flush (main_ui->m_gdb_stdout);
> +  gdb_flush (main_ui->m_gdb_stderr);
> +}
> +
>  /* The ui structure that will be saved on 'prefork_hook' and
>     restored on 'postfork_hook'.  */
>  static struct ui *saved_ui = NULL;
> diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
> index 96befef..b314c41 100755
> --- a/gdb/gdbserver/configure
> +++ b/gdb/gdbserver/configure
> @@ -8422,9 +8422,7 @@ fi
>  
>  if $want_ipa ; then
>     if $have_ipa ; then
> -     # Needed because safe_strerror's definition is host-dependent
> -     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
> -     IPA_DEPFILES="$ipa_obj $strerror_obj"
> +     IPA_DEPFILES="$ipa_obj"
>       extra_libraries="$extra_libraries libinproctrace.so"
>     else
>       as_fn_error "inprocess agent not supported for this target" "$LINENO" 5
> diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
> index 8aa85db..4ea7913 100644
> --- a/gdb/gdbserver/configure.ac
> +++ b/gdb/gdbserver/configure.ac
> @@ -462,9 +462,7 @@ esac],
>  
>  if $want_ipa ; then
>     if $have_ipa ; then
> -     # Needed because safe_strerror's definition is host-dependent
> -     strerror_obj="`echo $srv_host_obs | sed 's/\(.*-strerror\)\.o/\1-ipa.o/'`"
> -     IPA_DEPFILES="$ipa_obj $strerror_obj"
> +     IPA_DEPFILES="$ipa_obj"
>       extra_libraries="$extra_libraries libinproctrace.so"
>     else
>       AC_MSG_ERROR([inprocess agent not supported for this target])
> diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
> index 056ac27..43f90c9 100644
> --- a/gdb/gdbserver/configure.srv
> +++ b/gdb/gdbserver/configure.srv
> @@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
>  
>  # Linux object files.  This is so we don't have to repeat
>  # these files over and over again.
> -srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-inferior.o"
> +srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-child.o fork-inferior.o"
>  
>  # Input is taken from the "${target}" variable.
>  
> @@ -131,7 +131,7 @@ case "${target}" in
>  			ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
>  			;;
>    i[34567]86-*-lynxos*)	srv_regobj="i386.o"
> -			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-inferior.o"
> +			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o fork-inferior.o"
>  			srv_xmlfiles="i386/i386.xml"
>  			srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
>  			srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
> @@ -338,7 +338,7 @@ case "${target}" in
>  			srv_linux_thread_db=yes
>  			;;
>    spu*-*-*)		srv_regobj=reg-spu.o
> -			srv_tgtobj="spu-low.o fork-inferior.o"
> +			srv_tgtobj="spu-low.o fork-child.o fork-inferior.o"
>  			;;
>    tic6x-*-uclinux)	srv_regobj="tic6x-c64xp-linux.o"
>  			srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
> diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
> new file mode 100644
> index 0000000..a1a8ff1
> --- /dev/null
> +++ b/gdb/gdbserver/fork-child.c
> @@ -0,0 +1,113 @@
> +/* Fork a Unix child process, and set up to debug it, for GDBserver.
> +   Copyright (C) 1989-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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 "server.h"
> +#include "job-control.h"
> +#include "nat/fork-inferior.h"
> +
> +#ifdef SIGTTOU
> +/* A file descriptor for the controlling terminal.  */
> +static int terminal_fd;
> +
> +/* TERMINAL_FD's original foreground group.  */
> +static pid_t old_foreground_pgrp;
> +
> +/* Hand back terminal ownership to the original foreground group.  */
> +
> +static void
> +restore_old_foreground_pgrp (void)
> +{
> +  tcsetpgrp (terminal_fd, old_foreground_pgrp);
> +}
> +#endif
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +prefork_hook (const char *args)
> +{
> +  if (debug_threads)
> +    {
> +      debug_printf ("args: %s\n", args);
> +      debug_flush ();
> +    }
> +
> +#ifdef SIGTTOU
> +  signal (SIGTTOU, SIG_DFL);
> +  signal (SIGTTIN, SIG_DFL);
> +#endif
> +
> +  /* Clear this so the backend doesn't get confused, thinking
> +     CONT_THREAD died, and it needs to resume all threads.  */
> +  cont_thread = null_ptid;
> +}
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +postfork_hook (pid_t pid)
> +{
> +}
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +postfork_child_hook ()
> +{
> +  /* This is set to the result of setpgrp, which if vforked, will be
> +     visible to you in the parent process.  It's only used by humans
> +     for debugging.  */
> +  static int debug_setpgrp = 657473;
> +
> +  debug_setpgrp = gdb_setpgid ();
> +  if (debug_setpgrp == -1)
> +    perror (_("setpgrp failed in child"));
> +}
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +gdb_flush_out_err ()
> +{
> +  fflush (stdout);
> +  fflush (stderr);
> +}
> +
> +/* See server.h.  */
> +
> +void
> +post_fork_inferior (int pid, const char *program)
> +{
> +#ifdef SIGTTOU
> +  signal (SIGTTOU, SIG_IGN);
> +  signal (SIGTTIN, SIG_IGN);
> +  terminal_fd = fileno (stderr);
> +  old_foreground_pgrp = tcgetpgrp (terminal_fd);
> +  tcsetpgrp (terminal_fd, pid);
> +  atexit (restore_old_foreground_pgrp);
> +#endif
> +
> +  startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
> +		    &last_status, &last_ptid);
> +  current_thread->last_resume_kind = resume_stop;
> +  current_thread->last_status = last_status;
> +  signal_pid = pid;
> +  target_post_create_inferior ();
> +  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
> +  fflush (stderr);
> +}
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index ab6670b..7fbf744 100644
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -1009,7 +1009,7 @@ linux_create_inferior (const char *program,
>    new_lwp = add_lwp (ptid);
>    new_lwp->must_set_ptrace_flags = 1;
>  
> -  post_fork_inferior (pid, program, startup_inferior);
> +  post_fork_inferior (pid, program);
>  
>    return pid;
>  }
> @@ -6058,8 +6058,6 @@ linux_look_up_symbols (void)
>  static void
>  linux_request_interrupt (void)
>  {
> -  extern unsigned long signal_pid;
> -
>    /* Send a SIGINT to the process group.  This acts just like the user
>       typed a ^C on the controlling terminal.  */
>    kill (-signal_pid, SIGINT);
> diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
> index 382d71c..35160d6 100644
> --- a/gdb/gdbserver/lynx-low.c
> +++ b/gdb/gdbserver/lynx-low.c
> @@ -262,7 +262,7 @@ lynx_create_inferior (const char *program,
>  		       environ_vector (get_environ ()), lynx_ptrace_fun,
>  		       NULL, NULL, NULL, NULL);
>  
> -  post_fork_inferior (pid, program, startup_inferior);
> +  post_fork_inferior (pid, program);
>  
>    lynx_add_process (pid, 0);
>    /* Do not add the process thread just yet, as we do not know its tid.
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 5a76927..3ab042d 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -37,7 +37,6 @@
>  #include "hostio.h"
>  #include <vector>
>  #include "common-inferior.h"
> -#include "nat/fork-inferior.h"
>  #include "job-control.h"
>  #include "environ.h"
>  
> @@ -108,22 +107,6 @@ int program_signals_p;
>  
>  unsigned long signal_pid;
>  
> -#ifdef SIGTTOU
> -/* A file descriptor for the controlling terminal.  */
> -int terminal_fd;
> -
> -/* TERMINAL_FD's original foreground group.  */
> -pid_t old_foreground_pgrp;
> -
> -/* Hand back terminal ownership to the original foreground group.  */
> -
> -static void
> -restore_old_foreground_pgrp (void)
> -{
> -  tcsetpgrp (terminal_fd, old_foreground_pgrp);
> -}
> -#endif
> -
>  /* Set if you want to disable optional thread related packets support
>     in gdbserver, for the sake of testing GDB against stubs that don't
>     support them.  */
> @@ -133,8 +116,8 @@ int disable_packet_qC;
>  int disable_packet_qfThreadInfo;
>  
>  /* Last status reported to GDB.  */
> -static struct target_waitstatus last_status;
> -static ptid_t last_ptid;
> +struct target_waitstatus last_status;
> +ptid_t last_ptid;
>  
>  char *own_buf;
>  static unsigned char *mem_buf;
> @@ -258,7 +241,7 @@ target_running (void)
>  const char *
>  get_exec_wrapper ()
>  {
> -  return wrapper_argv.size () > 0 ? wrapper_argv.c_str () : NULL;
> +  return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL;
>  }
>  
>  /* See common/common-inferior.h.  */
> @@ -280,81 +263,6 @@ get_environ ()
>    return our_environ;
>  }
>  
> -/* See nat/fork-inferior.h.  */
> -
> -void
> -prefork_hook (const char *args)
> -{
> -  if (debug_threads)
> -    {
> -      debug_printf ("args: %s\n", args);
> -      debug_flush ();
> -    }
> -
> -#ifdef SIGTTOU
> -  signal (SIGTTOU, SIG_DFL);
> -  signal (SIGTTIN, SIG_DFL);
> -#endif
> -
> -  /* Clear this so the backend doesn't get confused, thinking
> -     CONT_THREAD died, and it needs to resume all threads.  */
> -  cont_thread = null_ptid;
> -}
> -
> -/* See server.h.  */
> -
> -void
> -post_fork_inferior (int pid, const char *program,
> -		    ptid_t (*my_startup_inferior) (pid_t pid, int ntraps,
> -						   struct target_waitstatus
> -						   *mystatus,
> -						   ptid_t *myptid))
> -
> -{
> -  /* Number of traps to be expected by startup_inferior.  We always
> -     expect at least one trap for the main executable.  */
> -  int num_traps = START_INFERIOR_TRAPS_EXPECTED;
> -
> -#ifdef SIGTTOU
> -  signal (SIGTTOU, SIG_IGN);
> -  signal (SIGTTIN, SIG_IGN);
> -  terminal_fd = fileno (stderr);
> -  old_foreground_pgrp = tcgetpgrp (terminal_fd);
> -  tcsetpgrp (terminal_fd, pid);
> -  atexit (restore_old_foreground_pgrp);
> -#endif
> -
> -  my_startup_inferior (pid, num_traps, &last_status, &last_ptid);
> -  current_thread->last_resume_kind = resume_stop;
> -  current_thread->last_status = last_status;
> -  signal_pid = pid;
> -  target_post_create_inferior ();
> -  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
> -  fflush (stderr);
> -}
> -
> -/* See nat/fork-inferior.h.  */
> -
> -void
> -postfork_hook (pid_t pid)
> -{
> -}
> -
> -/* See nat/fork-inferior.h.  */
> -
> -void
> -postfork_child_hook ()
> -{
> -  /* This is set to the result of setpgrp, which if vforked, will be
> -     visible to you in the parent process.  It's only used by humans
> -     for debugging.  */
> -  static int debug_setpgrp = 657473;
> -
> -  debug_setpgrp = gdb_setpgid ();
> -  if (debug_setpgrp == -1)
> -    perror (_("setpgrp failed in child"));
> -}
> -
>  static int
>  attach_inferior (int pid)
>  {
> @@ -3612,7 +3520,7 @@ captured_main (int argc, char *argv[])
>  	      next_arg++;
>  	    }
>  
> -	  if (wrapper_argv.size () > 0)
> +	  if (!wrapper_argv.empty ())
>  	    {
>  	      /* Erase the last whitespace.  */
>  	      wrapper_argv.erase (wrapper_argv.end () - 1);
> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index 96566fe..4de4244 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -149,19 +149,17 @@ extern int in_queued_stop_replies (ptid_t ptid);
>  #define ANY_SYSCALL (-2)
>  
>  /* After fork_inferior has been called, we need to adjust a few
> -   signals and call startup_inferior.  This is done here.  PID is the
> -   pid of the new inferior, PROGRAM is its name, and
> -   MY_STARTUP_INFERIOR is the function that should be called to start
> -   the inferior and consume its first events.  In most cases, this
> -   function should be "startup_inferior" itself.  */
> -extern void post_fork_inferior (int pid, const char *program,
> -				ptid_t (*my_startup_inferior)
> -				(pid_t pid, int ntraps,
> -				 struct target_waitstatus *mystatus,
> -				 ptid_t *myptid));
> +   signals and call startup_inferior to start the inferior and consume
> +   its first events.  This is done here.  PID is the pid of the new
> +   inferior and PROGRAM is its name.  */
> +extern void post_fork_inferior (int pid, const char *program);
>  
>  /* Get the 'struct gdb_environ *' being used in the current
>     session.  */
>  extern struct gdb_environ *get_environ ();
>  
> +extern target_waitstatus last_status;
> +extern ptid_t last_ptid;
> +extern unsigned long signal_pid;
> +
>  #endif /* SERVER_H */
> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
> index c71e8ba..0f770a0 100644
> --- a/gdb/gdbserver/spu-low.c
> +++ b/gdb/gdbserver/spu-low.c
> @@ -27,7 +27,6 @@
>  #include <sys/syscall.h>
>  #include "filestuff.h"
>  #include "hostio.h"
> -#include "common-inferior.h"
>  #include "nat/fork-inferior.h"
>  
>  /* Some older glibc versions do not define this.  */
> @@ -293,7 +292,7 @@ spu_create_inferior (const char *program,
>  		       environ_vector (get_environ ()), spu_ptrace_fun,
>  		       NULL, NULL, NULL, NULL);
>  
> -  post_fork_inferior (pid, program, startup_inferior);
> +  post_fork_inferior (pid, program);
>  
>    proc = add_process (pid, 0);
>    proc->tdesc = tdesc_spu;
> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
> index 3f96a6c..307d15a 100644
> --- a/gdb/gdbserver/utils.c
> +++ b/gdb/gdbserver/utils.c
> @@ -137,12 +137,3 @@ pfildes (gdb_fildes_t fd)
>    return plongest (fd);
>  #endif
>  }
> -
> -/* See common/common-utils.h.  */
> -
> -void
> -gdb_flush_out_err ()
> -{
> -  fflush (stdout);
> -  fflush (stderr);
> -}
> diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
> index 2a01dd2..af181f0 100644
> --- a/gdb/inf-ptrace.c
> +++ b/gdb/inf-ptrace.c
> @@ -96,7 +96,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
>  			    char **env, int from_tty)
>  {
>    pid_t pid;
> -  ptid_t ptid;  
> +  ptid_t ptid;
>  
>    /* Do not change either targets above or the same target if already present.
>       The reason is the target stack is shared across multiple inferiors.  */
> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index cdaeb11..6376952 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -45,7 +45,6 @@ struct inferior;
>  
>  #include "progspace.h"
>  #include "registry.h"
> -#include "common-inferior.h"
>  
>  #include "symfile-add-flags.h"
>  #include "common/refcounted-object.h"
> diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
> index 7fd93ef..0913409 100644
> --- a/gdb/nat/fork-inferior.c
> +++ b/gdb/nat/fork-inferior.c
> @@ -358,9 +358,11 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
>       state, this doesn't work.  Also note that the vfork(2) call might
>       actually be a call to fork(2) due to the fact that autoconf will
>       ``#define vfork fork'' on certain platforms.  */
> +#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
>    if (pre_trace_fun || debug_fork)
>      pid = fork ();
>    else
> +#endif
>      pid = vfork ();
>  
>    if (pid < 0)
> @@ -567,3 +569,27 @@ startup_inferior (pid_t pid, int ntraps,
>  
>    return resume_ptid;
>  }
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +trace_start_error (const char *fmt, ...)
> +{
> +  va_list ap;
> +
> +  va_start (ap, fmt);
> +  warning ("Could not trace the inferior process.\nError: ");
> +  vwarning (fmt, ap);
> +  va_end (ap);
> +
> +  gdb_flush_out_err ();
> +  _exit (0177);
> +}
> +
> +/* See nat/fork-inferior.h.  */
> +
> +void
> +trace_start_error_with_name (const char *string)
> +{
> +  trace_start_error ("%s: %s", string, safe_strerror (errno));
> +}
> diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
> index 39bdd8d..10e3832 100644
> --- a/gdb/nat/fork-inferior.h
> +++ b/gdb/nat/fork-inferior.h
> @@ -87,4 +87,20 @@ extern void postfork_hook (pid_t pid);
>     place.  This function is mainly used by fork_inferior.  */
>  extern void postfork_child_hook ();
>  
> +/* Flush both stdout and stderr.  This function needs to be
> +   implemented differently on GDB and GDBserver.  */
> +extern void gdb_flush_out_err ();
> +
> +/* Report an error that happened when starting to trace the inferior
> +   (i.e., when the "traceme_fun" callback is called on fork_inferior)
> +   and bail out.  This function does not return.  */
> +extern void trace_start_error (const char *fmt, ...)
> +  ATTRIBUTE_NORETURN;
> +
> +/* Like "trace_start_error", but the error message is constructed by
> +   combining STRING with the system error message for errno.  This
> +   function does not return.  */
> +extern void trace_start_error_with_name (const char *string)
> +  ATTRIBUTE_NORETURN;
> +
>  #endif /* ! FORK_INFERIOR_H */
> diff --git a/gdb/utils.c b/gdb/utils.c
> index bd0a0d8..c61557e 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -3391,15 +3391,6 @@ strip_leading_path_elements (const char *path, int n)
>    return p;
>  }
>  
> -/* See common/common-utils.h.  */
> -
> -void
> -gdb_flush_out_err ()
> -{
> -  gdb_flush (main_ui->m_gdb_stdout);
> -  gdb_flush (main_ui->m_gdb_stderr);
> -}
> -
>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>  extern initialize_file_ftype _initialize_utils;
>  
> -- 
> 2.5.5

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v6 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 21:01             ` Sergio Durigan Junior
@ 2017-06-07 21:06               ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 21:06 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 06/07/2017 10:01 PM, Sergio Durigan Junior wrote:
>> >
>> > I tried it against v7, and that works.  The think to keep
>> > in mind is that these trace_start_error functions
>> > are only called from the fork child, so they're very much
>> > fork-inferior.c related.
> They're actually being used by some -nat.c files on gdb/, and -low.c
> files on gdbserver.  But as I said, I'm OK with your suggestion.

Sure, but that's exactly the code that is related to forking
a child, and which runs on the fork child, after it forks,
and before it execs.

It'd never make sense to call those functions on the fork
parent, which is GDB, because they'd cause GDB to exit!

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 21:06       ` Sergio Durigan Junior
@ 2017-06-07 21:41         ` Sergio Durigan Junior
  2017-06-07 22:05           ` Pedro Alves
  2017-06-07 22:15         ` Sergio Durigan Junior
  1 sibling, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 21:41 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, I wrote:

> On Wednesday, June 07 2017, Pedro Alves wrote:
>> I think we could get rid of the new common-inferior.h
>> header too, but I'll leave that as is, for now at least.
>
> And move get_exec_{wrapper,file} to fork-inferior.h and fork-child.c,
> you mean?

Probably not, because get_exec_file is used by Windows targets as well.
I'll wait for your reply before submitting the next patch.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 21:41         ` Sergio Durigan Junior
@ 2017-06-07 22:05           ` Pedro Alves
  2017-06-07 22:08             ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 22:05 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 06/07/2017 10:41 PM, Sergio Durigan Junior wrote:
> On Wednesday, June 07 2017, I wrote:
> 
>> On Wednesday, June 07 2017, Pedro Alves wrote:
>>> I think we could get rid of the new common-inferior.h
>>> header too, but I'll leave that as is, for now at least.
>>
>> And move get_exec_{wrapper,file} to fork-inferior.h and fork-child.c,
>> you mean?
> 
> Probably not, because get_exec_file is used by Windows targets as well.
> I'll wait for your reply before submitting the next patch.
> 

Considering exec_file for instance:  fork_inferior calls
get_exec_file if exec_file is NULL.  But, we could just
pass down the right exec_file to fork_inferior in the first
place.  We could do that by e.g., adding fork_child
wrapper functions to both gdb and gdbserver's fork-child.c that
would call the shared fork_inferior function, and then adjust
targets to call that instead.  For the exec wrapper, we could
add a new "const char *exec_wrapper" parameter to fork_inferior.

Since it's arguable which approach is better in this case,
I'm totally fine with leaving things as is.

I notice now that get_exec_file is still declared
in gdbcore.h, however.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 22:05           ` Pedro Alves
@ 2017-06-07 22:08             ` Sergio Durigan Junior
  2017-06-07 22:14               ` Pedro Alves
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 22:08 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, Pedro Alves wrote:

> On 06/07/2017 10:41 PM, Sergio Durigan Junior wrote:
>> On Wednesday, June 07 2017, I wrote:
>> 
>>> On Wednesday, June 07 2017, Pedro Alves wrote:
>>>> I think we could get rid of the new common-inferior.h
>>>> header too, but I'll leave that as is, for now at least.
>>>
>>> And move get_exec_{wrapper,file} to fork-inferior.h and fork-child.c,
>>> you mean?
>> 
>> Probably not, because get_exec_file is used by Windows targets as well.
>> I'll wait for your reply before submitting the next patch.
>> 
>
> Considering exec_file for instance:  fork_inferior calls
> get_exec_file if exec_file is NULL.  But, we could just
> pass down the right exec_file to fork_inferior in the first
> place.  We could do that by e.g., adding fork_child
> wrapper functions to both gdb and gdbserver's fork-child.c that
> would call the shared fork_inferior function, and then adjust
> targets to call that instead.  For the exec wrapper, we could
> add a new "const char *exec_wrapper" parameter to fork_inferior.
>
> Since it's arguable which approach is better in this case,
> I'm totally fine with leaving things as is.
>
> I notice now that get_exec_file is still declared
> in gdbcore.h, however.

OK, I'll leave things as is then, and will tackle this problem at a
later date.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 22:08             ` Sergio Durigan Junior
@ 2017-06-07 22:14               ` Pedro Alves
  0 siblings, 0 replies; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 22:14 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 06/07/2017 11:08 PM, Sergio Durigan Junior wrote:
> On Wednesday, June 07 2017, Pedro Alves wrote:

>> I notice now that get_exec_file is still declared
>> in gdbcore.h, however.
> 
> OK, I'll leave things as is then, and will tackle this problem at a
> later date.

TBC, please remove the redundant declaration in gdbcore.h
(and add back the common-inferior.h inclusion from inferior.h,
I guess).

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 21:06       ` Sergio Durigan Junior
  2017-06-07 21:41         ` Sergio Durigan Junior
@ 2017-06-07 22:15         ` Sergio Durigan Junior
  2017-06-07 22:29           ` Pedro Alves
  1 sibling, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-07 22:15 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, I wrote:

> On Wednesday, June 07 2017, Pedro Alves wrote:
>
>> So here's the patch showing what I meant in:
>>  https://sourceware.org/ml/gdb-patches/2017-06/msg00169.html
>>
>> I'll be happy with the resulting patch once if you fold this in.
>> Could you do that, retest and repost?
>
> Thanks for the patch, it makes sense to me in light of the discussions
> we had.  I'll apply it and resubmit this specific patch of the series
> (instead of resubmitting everything), if that's OK with you.

And here it is.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

From 84c62a570ac067b83a547063f0487e98a5900af0 Mon Sep 17 00:00:00 2001
From: Sergio Durigan Junior <sergiodj@redhat.com>
Date: Thu, 22 Dec 2016 21:11:11 -0500
Subject: [PATCH v7 3/4] Share fork_inferior et al with gdbserver

This is the most important (and the biggest, sorry) patch of the
series.  It moves fork_inferior from gdb/fork-child.c to
common/common-fork-child.c and makes all the necessary adjustments to
both GDB and gdbserver to make sure everything works OK.

There is no "most important change" with this patch; all changes are
made in a progressive way, making sure that gdbserver had the
necessary features while not breaking GDB at the same time.

I decided to go ahead and implement a partial support for starting the
inferior with a shell on gdbserver, although the full feature comes in
the next patch.  The user won't have the option to disable the
startup-with-shell, and also won't be able to change which shell
gdbserver will use (other than setting the $SHELL environment
variable, that is).

Everything is working as expected, and no regressions were present
during the tests.

gdb/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Pedro Alves  <palves@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-inferior.h"
	and "nat/fork-inferior.h".
	* common/common-inferior.h: New file, with contents from
	"gdb/inferior.h".
	* commom/common-utils.c: Include "common-utils.h".
	(stringify_argv): New function.
	* common/common-utils.h (stringify_argv): New prototype.
	* configure.nat: Add "fork-inferior.o" as a dependency for
	"*linux*", "fbsd*" and "nbsd*" hosts.
	* corefile.c (get_exec_file): Update comment.
	* darwin-nat.c (darwin_ptrace_him): Call "gdb_startup_inferior"
	instead of "startup_inferior".
	(darwin_create_inferior): Call "add_thread_silent" after
	"fork_inferior".
	* fork-child.c: Cleanup unnecessary includes.
	(SHELL_FILE): Move to "common/common-fork-child.c".
	(environ): Likewise.
	(exec_wrapper): Initialize.
	(get_exec_wrapper): New function.
	(breakup_args): Move to "common/common-fork-child.c"; rename to
	"breakup_args_for_exec".
	(escape_bang_in_quoted_argument): Move to
	"common/common-fork-child.c".
	(saved_ui): New variable.
	(prefork_hook): New function.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(gdb_startup_inferior): Likewise.
	(fork_inferior): Move to "common/common-fork-child.c".  Update
	function to support gdbserver.
	(startup_inferior): Likewise.
	* gnu-nat.c (gnu_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inf-ptrace.c: Include "nat/fork-inferior.h" and "utils.h".
	(inf_ptrace_create_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* inferior.h: Include "common-inferior.h".
	(trace_start_error): Move to "common/common-utils.h".
	(trace_start_error_with_name): Likewise.
	(fork_inferior): Move prototype to "nat/fork-inferior.h".
	(startup_inferior): Likewise.
	(gdb_startup_inferior): New prototype.
	* nat/fork-inferior.c: New file, with contents from "fork-child.c".
	* nat/fork-inferior.h: New file.
	* procfs.c (procfs_init_inferior): Call "gdb_startup_inferior"
	instead of "startup_inferior".  Call "add_thread_silent" after
	"fork_inferior".
	* target.h (target_terminal_init): Move prototype to
	"target/target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target/target.h (target_terminal_init): New prototype, moved
	from "target.h".
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* utils.c (gdb_flush_out_err): New function.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Pedro Alves  <palves@redhat.com>

	* Makefile.in (SFILES): Add "nat/fork-inferior.o".
	* configure: Regenerate.
	* configure.ac: Adding object file related to safe_strerror to
	IPA_DEPFILES.
	* configure.srv (srv_linux_obj): Add "fork-child.o" and
	"fork-inferior.o".
	(i[34567]86-*-lynxos*): Likewise.
	(spu*-*-*): Likewise.
	* fork-child.c: New file.
	* linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h"
	and "environ.h".
	(linux_ptrace_fun): New function.
	(linux_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	(linux_request_interrupt): Delete "signal_pid".
	* lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(lynx_ptrace_fun): New function.
	(lynx_create_inferior): Adjust function prototype to reflect
	change on "target.h".  Adjust function code to use
	"fork_inferior".
	* nto-low.c (nto_create_inferior): Adjust function prototype and
	code to reflect change on "target.h".  Update comments.
	* server.c: Include "common-inferior.h", "nat/fork-inferior.h",
	"common-terminal.h" and "environ.h".
	(terminal_fd): Moved to fork-child.c.
	(old_foreground_pgrp): Likewise.
	(restore_old_foreground_pgrp): Likewise.
	(last_status): Make it global.
	(last_ptid): Likewise.
	(our_environ): New variable.
	(startup_with_shell): Likewise.
	(program_name): Likewise.
	(program_argv): Rename to...
	(program_args): ...this.
	(wrapper_argv): New variable.
	(start_inferior): Delete function.
	(get_exec_wrapper): New function.
	(get_exec_file): Likewise.
	(get_environ): Likewise.
	(prefork_hook): Likewise.
	(post_fork_inferior): Likewise.
	(postfork_hook): Likewise.
	(postfork_child_hook): Likewise.
	(handle_v_run): Update code to deal with arguments coming from the
	remote host.  Update calls from "start_inferior" to
	"create_inferior".
	(captured_main): Likewise.  Initialize environment variable.  Call
	"have_job_control".
	* server.h (post_fork_inferior): New prototype.
	(get_environ): Likewise.
	(last_status): Declare.
	(last_ptid): Likewise.
	(signal_pid): Likewise.
	* spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
	(spu_ptrace_fun): New function.
	(spu_create_inferior): Adjust function prototype to reflect change
	on "target.h".  Adjust function code to use "fork_inferior".
	* target.c (target_terminal_init): New function.
	(target_terminal_inferior): Likewise.
	(target_terminal_ours): Likewise.
	* target.h: Include <vector>.
	(struct target_ops) <create_inferior>: Update prototype.
	(create_inferior): Update macro.
	* utils.c (gdb_flush_out_err): New function.
	* win32-low.c (win32_create_inferior): Adjust function prototype
	and code to reflect change on "target.h".

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

	* gdb.server/non-existing-program.exp: Update regex in order to
	reflect the fact that gdbserver is now using fork_inferior (with a
	shell) to startup the inferior.
---
 gdb/Makefile.in                                   |   2 +
 gdb/common/common-inferior.h                      |  33 ++
 gdb/common/common-utils.c                         |  24 +
 gdb/common/common-utils.h                         |   4 +
 gdb/configure.nat                                 |   8 +-
 gdb/corefile.c                                    |   4 +-
 gdb/darwin-nat.c                                  |  16 +-
 gdb/fork-child.c                                  | 628 +++-------------------
 gdb/gdbserver/Makefile.in                         |   1 +
 gdb/gdbserver/configure.srv                       |   6 +-
 gdb/gdbserver/fork-child.c                        | 113 ++++
 gdb/gdbserver/linux-low.c                         |  91 ++--
 gdb/gdbserver/lynx-low.c                          |  51 +-
 gdb/gdbserver/nto-low.c                           |  10 +-
 gdb/gdbserver/server.c                            | 240 +++++----
 gdb/gdbserver/server.h                            |  14 +
 gdb/gdbserver/spu-low.c                           |  44 +-
 gdb/gdbserver/target.c                            |  27 +
 gdb/gdbserver/target.h                            |  13 +-
 gdb/gdbserver/win32-low.c                         |  23 +-
 gdb/gnu-nat.c                                     |   8 +-
 gdb/inf-ptrace.c                                  |  15 +-
 gdb/inferior.h                                    |  32 +-
 gdb/nat/fork-inferior.c                           | 595 ++++++++++++++++++++
 gdb/nat/fork-inferior.h                           | 106 ++++
 gdb/procfs.c                                      |   7 +-
 gdb/target.h                                      |  18 +-
 gdb/target/target.h                               |  14 +
 gdb/testsuite/gdb.server/non-existing-program.exp |  12 +-
 29 files changed, 1301 insertions(+), 858 deletions(-)
 create mode 100644 gdb/common/common-inferior.h
 create mode 100644 gdb/gdbserver/fork-child.c
 create mode 100644 gdb/nat/fork-inferior.c
 create mode 100644 gdb/nat/fork-inferior.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2b47d29..5e5fcaa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1525,6 +1525,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_termios.h \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
+	common/common-inferior.h \
 	common/host-defs.h \
 	common/print-utils.h \
 	common/ptid.h \
@@ -1565,6 +1566,7 @@ HFILES_NO_SRCDIR = \
 	nat/amd64-linux-siginfo.h \
 	nat/gdb_ptrace.h \
 	nat/gdb_thread_db.h \
+	nat/fork-inferior.h \
 	nat/linux-btrace.h \
 	nat/linux-namespaces.h \
 	nat/linux-nat.h \
diff --git a/gdb/common/common-inferior.h b/gdb/common/common-inferior.h
new file mode 100644
index 0000000..87c1300
--- /dev/null
+++ b/gdb/common/common-inferior.h
@@ -0,0 +1,33 @@
+/* Functions to deal with the inferior being executed on GDB or
+   GDBserver.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef COMMON_INFERIOR_H
+#define COMMON_INFERIOR_H
+
+/* Return the exec wrapper to be used when starting the inferior, or NULL
+   otherwise.  */
+extern const char *get_exec_wrapper ();
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+extern char *get_exec_file (int err);
+
+#endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index e94fdc4..793ab3b 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "common-defs.h"
+#include "common-utils.h"
 #include "host-defs.h"
 #include <ctype.h>
 
@@ -328,3 +329,26 @@ free_vector_argv (std::vector<char *> &v)
 
   v.clear ();
 }
+
+/* See common/common-utils.h.  */
+
+std::string
+stringify_argv (const std::vector<char *> &args)
+{
+  std::string ret;
+
+  if (!args.empty ())
+    {
+      for (auto s : args)
+	if (s != NULL)
+	  {
+	    ret += s;
+	    ret += ' ';
+	  }
+
+      /* Erase the last whitespace.  */
+      ret.erase (ret.end () - 1);
+    }
+
+  return ret;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index c331f0d..787bac9 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -108,4 +108,8 @@ extern const char *skip_to_space_const (const char *inp);
    freeing all the elements.  */
 extern void free_vector_argv (std::vector<char *> &v);
 
+/* Given a vector of arguments ARGV, return a string equivalent to
+   joining all the arguments with a whitespace separating them.  */
+extern std::string stringify_argv (const std::vector<char *> &argv);
+
 #endif
diff --git a/gdb/configure.nat b/gdb/configure.nat
index e6c96da..e6da599 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -54,7 +54,7 @@
 case ${gdb_host} in
     *linux*)
 	NAT_FILE='config/nm-linux.h'
-	NATDEPFILES='inf-ptrace.o fork-child.o proc-service.o \
+	NATDEPFILES='inf-ptrace.o fork-child.o fork-inferior.o proc-service.o \
 		linux-thread-db.o linux-nat.o linux-osdata.o linux-fork.o \
 		linux-procfs.o linux-ptrace.o linux-waitpid.o \
 		linux-personality.o linux-namespaces.o'
@@ -62,15 +62,15 @@ case ${gdb_host} in
 	LOADLIBES='-ldl $(RDYNAMIC)'
 	;;
     fbsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o fbsd-nat.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o fbsd-nat.o'
 	HAVE_NATIVE_GCORE_HOST=1
 	LOADLIBES='-lkvm'
 	;;
     nbsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o'
 	;;
     obsd*)
-	NATDEPFILES='fork-child.o inf-ptrace.o'
+	NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o'
 	;;
     cygwin*)
 	NATDEPFILES='x86-nat.o x86-dregs.o windows-nat.o'
diff --git a/gdb/corefile.c b/gdb/corefile.c
index 13a90b9..33eb4d1 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -170,9 +170,7 @@ validate_files (void)
     }
 }
 
-/* Return the name of the executable file as a string.
-   ERR nonzero means get error if there is none specified;
-   otherwise return 0 in that case.  */
+/* See common/common-inferior.h.  */
 
 char *
 get_exec_file (int err)
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index cba84ca..4330a60 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -1790,7 +1790,7 @@ darwin_ptrace_him (int pid)
 
   darwin_init_thread_list (inf);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 }
 
 static void
@@ -1833,13 +1833,23 @@ darwin_create_inferior (struct target_ops *ops,
 			const std::string &allargs,
 			char **env, int from_tty)
 {
+  pid_t pid;
+  ptid_t ptid;
+
   /* Do the hard work.  */
-  fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
-		 darwin_pre_ptrace, NULL, darwin_execvp);
+  pid = fork_inferior (exec_file, allargs, env, darwin_ptrace_me,
+		       darwin_ptrace_him, darwin_pre_ptrace, NULL,
+		       darwin_execvp);
 
+  ptid = pid_to_ptid (pid);
   /* Return now in case of error.  */
   if (ptid_equal (inferior_ptid, null_ptid))
     return;
+
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
 }
 \f
 
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index c1b6f53..60985d8 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -21,471 +21,64 @@
 
 #include "defs.h"
 #include "inferior.h"
+#include "gdbcmd.h"
 #include "terminal.h"
-#include "target.h"
-#include "gdb_wait.h"
-#include "gdb_vfork.h"
-#include "gdbcore.h"
 #include "gdbthread.h"
-#include "command.h" /* for dont_repeat () */
-#include "gdbcmd.h"
-#include "solib.h"
-#include "filestuff.h"
 #include "top.h"
-#include "signals-state-save-restore.h"
 #include "job-control.h"
-#include <signal.h>
-#include <vector>
-
-/* This just gets used as a default if we can't find SHELL.  */
-#define SHELL_FILE "/bin/sh"
-
-extern char **environ;
-
-static char *exec_wrapper;
-
-/* Build the argument vector for execv(3).  */
-
-class execv_argv
-{
-public:
-  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
-     arguments to the program.  If starting with a shell, SHELL_FILE
-     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
-  execv_argv (const char *exec_file, const std::string &allargs,
-	      const char *shell_file);
-
-  /* Return a pointer to the built argv, in the type expected by
-     execv.  The result is (only) valid for as long as this execv_argv
-     object is live.  We return a "char **" because that's the type
-     that the execv functions expect.  Note that it is guaranteed that
-     the execv functions do not modify the argv[] array nor the
-     strings to which the array point.  */
-  char **argv ()
-  {
-    return const_cast<char **> (&m_argv[0]);
-  }
-
-private:
-  /* Disable copying.  */
-  execv_argv (const execv_argv &) = delete;
-  void operator= (const execv_argv &) = delete;
-
-  /* Helper methods for constructing the argument vector.  */
-
-  /* Used when building an argv for a straight execv call, without
-     going via the shell.  */
-  void init_for_no_shell (const char *exec_file,
-			  const std::string &allargs);
-
-  /* Used when building an argv for execing a shell that execs the
-     child program.  */
-  void init_for_shell (const char *exec_file,
-		       const std::string &allargs,
-		       const char *shell_file);
-
-  /* The argument vector built.  Holds non-owning pointers.  Elements
-     either point to the strings passed to the execv_argv ctor, or
-     inside M_STORAGE.  */
-  std::vector<const char *> m_argv;
-
-  /* Storage.  In the no-shell case, this contains a copy of the
-     arguments passed to the ctor, split by '\0'.  In the shell case,
-     this contains the quoted shell command.  I.e., SHELL_COMMAND in
-     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
-  std::string m_storage;
-};
-
-/* Create argument vector for straight call to execvp.  Breaks up
-   ALLARGS into an argument vector suitable for passing to execvp and
-   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
-   as input the string "a b c d", and as output it would fill in
-   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
-   in M_ARGV points to a substring of a copy of ALLARGS stored in
-   M_STORAGE.  */
-
-void
-execv_argv::init_for_no_shell (const char *exec_file,
-			       const std::string &allargs)
-{
-
-  /* Save/work with a copy stored in our storage.  The pointers pushed
-     to M_ARGV point directly into M_STORAGE, which is modified in
-     place with the necessary NULL terminators.  This avoids N heap
-     allocations and string dups when 1 is sufficient.  */
-  std::string &args_copy = m_storage = allargs;
-
-  m_argv.push_back (exec_file);
-
-  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
-    {
-      /* Skip whitespace-like chars.  */
-      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
-
-      if (pos != std::string::npos)
-	cur_pos = pos;
-
-      /* Find the position of the next separator.  */
-      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
-
-      if (next_sep == std::string::npos)
-	{
-	  /* No separator found, which means this is the last
-	     argument.  */
-	  next_sep = args_copy.size ();
-	}
-      else
-	{
-	  /* Replace the separator with a terminator.  */
-	  args_copy[next_sep++] = '\0';
-	}
-
-      m_argv.push_back (&args_copy[cur_pos]);
-
-      cur_pos = next_sep;
-    }
-
-  /* NULL-terminate the vector.  */
-  m_argv.push_back (NULL);
-}
-
-/* When executing a command under the given shell, return true if the
-   '!' character should be escaped when embedded in a quoted
-   command-line argument.  */
-
-static bool
-escape_bang_in_quoted_argument (const char *shell_file)
-{
-  size_t shell_file_len = strlen (shell_file);
-
-  /* Bang should be escaped only in C Shells.  For now, simply check
-     that the shell name ends with 'csh', which covers at least csh
-     and tcsh.  This should be good enough for now.  */
-
-  if (shell_file_len < 3)
-    return false;
+#include "filestuff.h"
+#include "nat/fork-inferior.h"
+#include "common/common-inferior.h"
 
-  if (shell_file[shell_file_len - 3] == 'c'
-      && shell_file[shell_file_len - 2] == 's'
-      && shell_file[shell_file_len - 1] == 'h')
-    return true;
+/* The exec-wrapper, if any, that will be used when starting the
+   inferior.  */
 
-  return false;
-}
+static char *exec_wrapper = NULL;
 
-/* See declaration.  */
+/* See common/common-inferior.h.  */
 
-execv_argv::execv_argv (const char *exec_file,
-			const std::string &allargs,
-			const char *shell_file)
+const char *
+get_exec_wrapper ()
 {
-  if (shell_file == NULL)
-    init_for_no_shell (exec_file, allargs);
-  else
-    init_for_shell (exec_file, allargs, shell_file);
+  return exec_wrapper;
 }
 
-/* See declaration.  */
+/* See nat/fork-inferior.h.  */
 
 void
-execv_argv::init_for_shell (const char *exec_file,
-			    const std::string &allargs,
-			    const char *shell_file)
+gdb_flush_out_err ()
 {
-  /* We're going to call a shell.  */
-  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
-
-  /* We need to build a new shell command string, and make argv point
-     to it.  So build it in the storage.  */
-  std::string &shell_command = m_storage;
-
-  shell_command = "exec ";
-
-  /* Add any exec wrapper.  That may be a program name with arguments,
-     so the user must handle quoting.  */
-  if (exec_wrapper)
-    {
-      shell_command += exec_wrapper;
-      shell_command += ' ';
-    }
-
-  /* Now add exec_file, quoting as necessary.  */
-
-  /* Quoting in this style is said to work with all shells.  But csh
-     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
-     to.  */
-  bool need_to_quote;
-  const char *p = exec_file;
-  while (1)
-    {
-      switch (*p)
-	{
-	case '\'':
-	case '!':
-	case '"':
-	case '(':
-	case ')':
-	case '$':
-	case '&':
-	case ';':
-	case '<':
-	case '>':
-	case ' ':
-	case '\n':
-	case '\t':
-	  need_to_quote = true;
-	  goto end_scan;
-
-	case '\0':
-	  need_to_quote = false;
-	  goto end_scan;
-
-	default:
-	  break;
-	}
-      ++p;
-    }
- end_scan:
-  if (need_to_quote)
-    {
-      shell_command += '\'';
-      for (p = exec_file; *p != '\0'; ++p)
-	{
-	  if (*p == '\'')
-	    shell_command += "'\\''";
-	  else if (*p == '!' && escape_bang)
-	    shell_command += "\\!";
-	  else
-	    shell_command += *p;
-	}
-      shell_command += '\'';
-    }
-  else
-    shell_command += exec_file;
-
-  shell_command += ' ' + allargs;
-
-  /* If we decided above to start up with a shell, we exec the shell.
-     "-c" says to interpret the next arg as a shell command to
-     execute, and this command is "exec <target-program> <args>".  */
-  m_argv.reserve (4);
-  m_argv.push_back (shell_file);
-  m_argv.push_back ("-c");
-  m_argv.push_back (shell_command.c_str ());
-  m_argv.push_back (NULL);
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
 }
 
-/* See inferior.h.  */
-
-void
-trace_start_error (const char *fmt, ...)
-{
-  va_list ap;
-
-  va_start (ap, fmt);
-  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
-		                  "process.\nError: ");
-  vfprintf_unfiltered (gdb_stderr, fmt, ap);
-  va_end (ap);
+/* The ui structure that will be saved on 'prefork_hook' and
+   restored on 'postfork_hook'.  */
+static struct ui *saved_ui = NULL;
 
-  gdb_flush (gdb_stderr);
-  _exit (0177);
-}
-
-/* See inferior.h.  */
+/* See nat/fork-inferior.h.  */
 
 void
-trace_start_error_with_name (const char *string)
+prefork_hook (const char *args)
 {
-  trace_start_error ("%s: %s", string, safe_strerror (errno));
-}
-
-/* Start an inferior Unix child process and sets inferior_ptid to its
-   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
-   the arguments to the program.  ENV is the environment vector to
-   pass.  SHELL_FILE is the shell file, or NULL if we should pick
-   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
-   one.  */
-
-/* This function is NOT reentrant.  Some of the variables have been
-   made static to ensure that they survive the vfork call.  */
-
-int
-fork_inferior (const char *exec_file_arg, const std::string &allargs,
-	       char **env, void (*traceme_fun) (void),
-	       void (*init_trace_fun) (int), void (*pre_trace_fun) (void),
-	       char *shell_file_arg,
-               void (*exec_fun)(const char *file, char * const *argv,
-                                char * const *env))
-{
-  int pid;
-  static char default_shell_file[] = SHELL_FILE;
-  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
-  static int debug_fork = 0;
-  /* This is set to the result of setpgrp, which if vforked, will be visible
-     to you in the parent process.  It's only used by humans for debugging.  */
-  static int debug_setpgrp = 657473;
-  static char *shell_file;
-  static const char *exec_file;
-  char **save_our_env;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
-  struct inferior *inf;
-  int i;
-  int save_errno;
-  struct ui *save_ui;
-
-  /* If no exec file handed to us, get it from the exec-file command
-     -- with a good, common error message if none is specified.  */
-  if (exec_file_arg == NULL)
-    exec_file = get_exec_file (1);
-  else
-    exec_file = exec_file_arg;
-
-  /* 'startup_with_shell' is declared in inferior.h and bound to the
-     "set startup-with-shell" option.  If 0, we'll just do a
-     fork/exec, no shell, so don't bother figuring out what shell.  */
-  if (startup_with_shell)
-    {
-      shell_file = shell_file_arg;
-      /* Figure out what shell to start up the user program under.  */
-      if (shell_file == NULL)
-	shell_file = getenv ("SHELL");
-      if (shell_file == NULL)
-	shell_file = default_shell_file;
-    }
-  else
-    shell_file = NULL;
 
-  /* Build the argument vector.  */
-  execv_argv child_argv (exec_file, allargs, shell_file);
-
-  /* Retain a copy of our environment variables, since the child will
-     replace the value of environ and if we're vforked, we have to
-     restore it.  */
-  save_our_env = environ;
-
-  /* Likewise the current UI.  */
-  save_ui = current_ui;
+  gdb_assert (saved_ui == NULL);
+  /* Retain a copy of our UI, since the child will replace this value
+     and if we're vforked, we have to restore it.  */
+  saved_ui = current_ui;
 
   /* Tell the terminal handling subsystem what tty we plan to run on;
      it will just record the information for later.  */
   new_tty_prefork (inferior_io_terminal);
+}
 
-  /* It is generally good practice to flush any possible pending stdio
-     output prior to doing a fork, to avoid the possibility of both
-     the parent and child flushing the same data after the fork.  */
-  gdb_flush (main_ui->m_gdb_stdout);
-  gdb_flush (main_ui->m_gdb_stderr);
-
-  /* If there's any initialization of the target layers that must
-     happen to prepare to handle the child we're about fork, do it
-     now...  */
-  if (pre_trace_fun != NULL)
-    (*pre_trace_fun) ();
-
-  /* Create the child process.  Since the child process is going to
-     exec(3) shortly afterwards, try to reduce the overhead by
-     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
-     likely that this optimization won't work since there's too much
-     work to do between the vfork(2) and the exec(3).  This is known
-     to be the case on ttrace(2)-based HP-UX, where some handshaking
-     between parent and child needs to happen between fork(2) and
-     exec(2).  However, since the parent is suspended in the vforked
-     state, this doesn't work.  Also note that the vfork(2) call might
-     actually be a call to fork(2) due to the fact that autoconf will
-     ``#define vfork fork'' on certain platforms.  */
-  if (pre_trace_fun || debug_fork)
-    pid = fork ();
-  else
-    pid = vfork ();
-
-  if (pid < 0)
-    perror_with_name (("vfork"));
-
-  if (pid == 0)
-    {
-      /* Switch to the main UI, so that gdb_std{in/out/err} in the
-	 child are mapped to std{in/out/err}.  This makes it possible
-	 to use fprintf_unfiltered/warning/error/etc. in the child
-	 from here on.  */
-      current_ui = main_ui;
-
-      /* Close all file descriptors except those that gdb inherited
-	 (usually 0/1/2), so they don't leak to the inferior.  Note
-	 that this closes the file descriptors of all secondary
-	 UIs.  */
-      close_most_fds ();
-
-      if (debug_fork)
-	sleep (debug_fork);
-
-      /* Create a new session for the inferior process, if necessary.
-         It will also place the inferior in a separate process group.  */
-      if (create_tty_session () <= 0)
-	{
-	  /* No session was created, but we still want to run the inferior
-	     in a separate process group.  */
-	  debug_setpgrp = gdb_setpgid ();
-	  if (debug_setpgrp == -1)
-	    perror (_("setpgrp failed in child"));
-	}
-
-      /* Ask the tty subsystem to switch to the one we specified
-         earlier (or to share the current terminal, if none was
-         specified).  */
-      new_tty ();
-
-      /* Changing the signal handlers for the inferior after
-         a vfork can also change them for the superior, so we don't mess
-         with signals here.  See comments in
-         initialize_signals for how we get the right signal handlers
-         for the inferior.  */
-
-      /* "Trace me, Dr. Memory!"  */
-      (*traceme_fun) ();
-
-      /* The call above set this process (the "child") as debuggable
-        by the original gdb process (the "parent").  Since processes
-        (unlike people) can have only one parent, if you are debugging
-        gdb itself (and your debugger is thus _already_ the
-        controller/parent for this child), code from here on out is
-        undebuggable.  Indeed, you probably got an error message
-        saying "not parent".  Sorry; you'll have to use print
-        statements!  */
-
-      restore_original_signals_state ();
-
-      /* There is no execlpe call, so we have to set the environment
-         for our child in the global variable.  If we've vforked, this
-         clobbers the parent, but environ is restored a few lines down
-         in the parent.  By the way, yes we do need to look down the
-         path to find $SHELL.  Rich Pixley says so, and I agree.  */
-      environ = env;
-
-      char **argv = child_argv.argv ();
-
-      if (exec_fun != NULL)
-        (*exec_fun) (argv[0], &argv[0], env);
-      else
-        execvp (argv[0], &argv[0]);
-
-      /* If we get here, it's an error.  */
-      save_errno = errno;
-      fprintf_unfiltered (gdb_stderr, "Cannot exec %s", argv[0]);
-      for (i = 1; argv[i] != NULL; i++)
-	fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
-      fprintf_unfiltered (gdb_stderr, ".\n");
-      fprintf_unfiltered (gdb_stderr, "Error: %s\n",
-			  safe_strerror (save_errno));
-      gdb_flush (gdb_stderr);
-      _exit (0177);
-    }
-
-  /* Restore our environment in case a vforked child clob'd it.  */
-  environ = save_our_env;
+/* See nat/fork-inferior.h.  */
 
-  /* Likewise the current UI.  */
-  current_ui = save_ui;
+void
+postfork_hook (pid_t pid)
+{
+  struct inferior *inf;
 
   if (!have_inferiors ())
     init_thread_list ();
@@ -494,147 +87,58 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
 
   inferior_appeared (inf, pid);
 
-  /* Needed for wait_for_inferior stuff below.  */
+  /* Needed for wait_for_inferior stuff.  */
   inferior_ptid = pid_to_ptid (pid);
 
-  new_tty_postfork ();
+  gdb_assert (saved_ui != NULL);
+  current_ui = saved_ui;
+  saved_ui = NULL;
 
-  /* We have something that executes now.  We'll be running through
-     the shell at this point, but the pid shouldn't change.  Targets
-     supporting MT should fill this task's ptid with more data as soon
-     as they can.  */
-  add_thread_silent (inferior_ptid);
-
-  /* Now that we have a child process, make it our target, and
-     initialize anything target-vector-specific that needs
-     initializing.  */
-  if (init_trace_fun)
-    (*init_trace_fun) (pid);
-
-  /* We are now in the child process of interest, having exec'd the
-     correct program, and are poised at the first instruction of the
-     new program.  */
-  return pid;
+  new_tty_postfork ();
 }
 
-/* Accept NTRAPS traps from the inferior.  */
+/* See nat/fork-inferior.h.  */
 
 void
-startup_inferior (int ntraps)
+postfork_child_hook ()
 {
-  int pending_execs = ntraps;
-  int terminal_initted = 0;
-  ptid_t resume_ptid;
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  /* Make sure we switch to main_ui here in order to be able to
+     use the fprintf_unfiltered/warning/error functions.  */
+  current_ui = main_ui;
 
-  if (startup_with_shell)
+  /* Create a new session for the inferior process, if necessary.
+     It will also place the inferior in a separate process group.  */
+  if (create_tty_session () <= 0)
     {
-      /* One trap extra for exec'ing the shell.  */
-      pending_execs++;
+      /* No session was created, but we still want to run the inferior
+	 in a separate process group.  */
+      debug_setpgrp = gdb_setpgid ();
+      if (debug_setpgrp == -1)
+	perror (_("setpgrp failed in child"));
     }
 
-  if (target_supports_multi_process ())
-    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
-  else
-    resume_ptid = minus_one_ptid;
-
-  /* The process was started by the fork that created it, but it will
-     have stopped one instruction after execing the shell.  Here we
-     must get it up to actual execution of the real program.  */
+  /* Ask the tty subsystem to switch to the one we specified
+     earlier (or to share the current terminal, if none was
+     specified).  */
+  new_tty ();
+}
 
-  if (exec_wrapper)
-    pending_execs++;
+/* See inferior.h.  */
 
-  while (1)
-    {
-      enum gdb_signal resume_signal = GDB_SIGNAL_0;
-      ptid_t event_ptid;
-
-      struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
-      event_ptid = target_wait (resume_ptid, &ws, 0);
-
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
-	/* The inferior didn't really stop, keep waiting.  */
-	continue;
-
-      switch (ws.kind)
-	{
-	  case TARGET_WAITKIND_SPURIOUS:
-	  case TARGET_WAITKIND_LOADED:
-	  case TARGET_WAITKIND_FORKED:
-	  case TARGET_WAITKIND_VFORKED:
-	  case TARGET_WAITKIND_SYSCALL_ENTRY:
-	  case TARGET_WAITKIND_SYSCALL_RETURN:
-	    /* Ignore gracefully during startup of the inferior.  */
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_SIGNALLED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
-	    return;
-
-	  case TARGET_WAITKIND_EXITED:
-	    target_terminal_ours ();
-	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
-	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
-	    else
-	      error (_("During startup program exited normally."));
-	    return;
-
-	  case TARGET_WAITKIND_EXECD:
-	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    xfree (ws.value.execd_pathname);
-	    resume_signal = GDB_SIGNAL_TRAP;
-	    switch_to_thread (event_ptid);
-	    break;
-
-	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
-	    switch_to_thread (event_ptid);
-	    break;
-	}
-
-      if (resume_signal != GDB_SIGNAL_TRAP)
-	{
-	  /* Let shell child handle its own signals in its own way.  */
-	  target_continue (resume_ptid, resume_signal);
-	}
-      else
-	{
-	  /* We handle SIGTRAP, however; it means child did an exec.  */
-	  if (!terminal_initted)
-	    {
-	      /* Now that the child has exec'd we know it has already
-	         set its process group.  On POSIX systems, tcsetpgrp
-	         will fail with EPERM if we try it before the child's
-	         setpgid.  */
-
-	      /* Set up the "saved terminal modes" of the inferior
-	         based on what modes we are starting it with.  */
-	      target_terminal_init ();
-
-	      /* Install inferior's terminal modes.  */
-	      target_terminal_inferior ();
-
-	      terminal_initted = 1;
-	    }
-
-	  if (--pending_execs == 0)
-	    break;
-
-	  /* Just make it go on.  */
-	  target_continue_no_signal (resume_ptid);
-	}
-    }
+ptid_t
+gdb_startup_inferior (pid_t pid, int num_traps)
+{
+  ptid_t ptid = startup_inferior (pid, num_traps, NULL, NULL);
 
   /* Mark all threads non-executing.  */
-  set_executing (resume_ptid, 0);
+  set_executing (ptid, 0);
+
+  return ptid;
 }
 
 /* Implement the "unset exec-wrapper" command.  */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d9f55de..834425d 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -218,6 +218,7 @@ SFILES = \
 	$(srcdir)/nat/linux-personality.c \
 	$(srcdir)/nat/mips-linux-watch.c \
 	$(srcdir)/nat/ppc-linux.c \
+	$(srcdir)/nat/fork-inferior.c \
 	$(srcdir)/target/waitstatus.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index d00d9e2..43f90c9 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
 
 # Linux object files.  This is so we don't have to repeat
 # these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-child.o fork-inferior.o"
 
 # Input is taken from the "${target}" variable.
 
@@ -131,7 +131,7 @@ case "${target}" in
 			ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
 			;;
   i[34567]86-*-lynxos*)	srv_regobj="i386.o"
-			srv_tgtobj="lynx-low.o lynx-i386-low.o"
+			srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o fork-inferior.o"
 			srv_xmlfiles="i386/i386.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
@@ -338,7 +338,7 @@ case "${target}" in
 			srv_linux_thread_db=yes
 			;;
   spu*-*-*)		srv_regobj=reg-spu.o
-			srv_tgtobj="spu-low.o"
+			srv_tgtobj="spu-low.o fork-child.o fork-inferior.o"
 			;;
   tic6x-*-uclinux)	srv_regobj="tic6x-c64xp-linux.o"
 			srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
new file mode 100644
index 0000000..a1a8ff1
--- /dev/null
+++ b/gdb/gdbserver/fork-child.c
@@ -0,0 +1,113 @@
+/* Fork a Unix child process, and set up to debug it, for GDBserver.
+   Copyright (C) 1989-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "server.h"
+#include "job-control.h"
+#include "nat/fork-inferior.h"
+
+#ifdef SIGTTOU
+/* A file descriptor for the controlling terminal.  */
+static int terminal_fd;
+
+/* TERMINAL_FD's original foreground group.  */
+static pid_t old_foreground_pgrp;
+
+/* Hand back terminal ownership to the original foreground group.  */
+
+static void
+restore_old_foreground_pgrp (void)
+{
+  tcsetpgrp (terminal_fd, old_foreground_pgrp);
+}
+#endif
+
+/* See nat/fork-inferior.h.  */
+
+void
+prefork_hook (const char *args)
+{
+  if (debug_threads)
+    {
+      debug_printf ("args: %s\n", args);
+      debug_flush ();
+    }
+
+#ifdef SIGTTOU
+  signal (SIGTTOU, SIG_DFL);
+  signal (SIGTTIN, SIG_DFL);
+#endif
+
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+postfork_hook (pid_t pid)
+{
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+postfork_child_hook ()
+{
+  /* This is set to the result of setpgrp, which if vforked, will be
+     visible to you in the parent process.  It's only used by humans
+     for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  debug_setpgrp = gdb_setpgid ();
+  if (debug_setpgrp == -1)
+    perror (_("setpgrp failed in child"));
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+gdb_flush_out_err ()
+{
+  fflush (stdout);
+  fflush (stderr);
+}
+
+/* See server.h.  */
+
+void
+post_fork_inferior (int pid, const char *program)
+{
+#ifdef SIGTTOU
+  signal (SIGTTOU, SIG_IGN);
+  signal (SIGTTIN, SIG_IGN);
+  terminal_fd = fileno (stderr);
+  old_foreground_pgrp = tcgetpgrp (terminal_fd);
+  tcsetpgrp (terminal_fd, pid);
+  atexit (restore_old_foreground_pgrp);
+#endif
+
+  startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
+		    &last_status, &last_ptid);
+  current_thread->last_resume_kind = resume_stop;
+  current_thread->last_status = last_status;
+  signal_pid = pid;
+  target_post_create_inferior ();
+  fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+  fflush (stderr);
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ea3c81b..7fbf744 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,9 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -946,59 +949,57 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun ()
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+	trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+	trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+	trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+		 sizeof ("stdin/stdout redirected\n") - 1) < 0)
+	{
+	  /* Errors ignored.  */;
+	}
+    }
+}
+
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string str_program_args = stringify_argv (program_args);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-	 stdout to stderr so that inferior i/o doesn't corrupt the connection.
-	 Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-	{
-	  close (0);
-	  open ("/dev/null", O_RDONLY);
-	  dup2 (2, 1);
-	  if (write (2, "stdin/stdout redirected\n",
-		     sizeof ("stdin/stdout redirected\n") - 1) < 0)
-	    {
-	      /* Errors ignored.  */;
-	    }
-	}
-
-      restore_original_signals_state ();
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), linux_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
@@ -1008,6 +1009,8 @@ linux_create_inferior (char *program, char **allargs)
   new_lwp = add_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program);
+
   return pid;
 }
 
@@ -6055,8 +6058,6 @@ linux_look_up_symbols (void)
 static void
 linux_request_interrupt (void)
 {
-  extern unsigned long signal_pid;
-
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  */
   kill (-signal_pid, SIGINT);
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..35160d6 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,8 @@
 #include "gdb_wait.h"
 #include <signal.h>
 #include "filestuff.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
 
 int using_threads = 1;
 
@@ -224,36 +226,43 @@ lynx_add_process (int pid, int attached)
   return proc;
 }
 
+/* Callback used by fork_inferior to start tracing the inferior.  */
+
+static void
+lynx_ptrace_fun ()
+{
+  int pgrp;
+
+  /* Switch child to its own process group so that signals won't
+     directly affect GDBserver. */
+  pgrp = getpid();
+  if (pgrp < 0)
+    trace_start_error_with_name ("pgrp");
+  if (setpgid (0, pgrp) < 0)
+    trace_start_error_with_name ("setpgid");
+  if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+    trace_start_error_with_name ("ioctl");
+  if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+    trace_start_error_with_name ("lynx_ptrace");
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (const char *program,
+		      const std::vector<char *> &program_args)
 {
   int pid;
+  std::string str_program_args = stringify_argv (program_args);
 
   lynx_debug ("lynx_create_inferior ()");
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), lynx_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-  if (pid == 0)
-    {
-      int pgrp;
-
-      close_most_fds ();
-
-      /* Switch child to its own process group so that signals won't
-         directly affect gdbserver. */
-      pgrp = getpid();
-      setpgid (0, pgrp);
-      ioctl (0, TIOCSPGRP, &pgrp);
-      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
-      execv (program, allargs);
-      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program);
 
   lynx_add_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..a5f1543 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
   return len_read;
 }
 
-/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
+   arguments.  */
 
 static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (const char *program,
+		     const std::vector<char *> &program_args)
 {
   struct inheritance inherit;
   pid_t pid;
   sigset_t set;
+  std::string str_program_args = stringify_argv (program_args);
 
   TRACE ("%s %s\n", __func__, program);
   /* Clear any pending SIGUSR1's but keep the behavior the same.  */
@@ -367,7 +370,8 @@ nto_create_inferior (char *program, char **allargs)
   memset (&inherit, 0, sizeof (inherit));
   inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
   inherit.pgroup = SPAWN_NEWPGROUP;
-  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  pid = spawnp (program, 0, NULL, &inherit,
+		(char *) str_program_args.c_str (), 0);
   sigprocmask (SIG_BLOCK, &set, NULL);
 
   if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 69fcab1..3ab042d 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -36,6 +36,19 @@
 #include "dll.h"
 #include "hostio.h"
 #include <vector>
+#include "common-inferior.h"
+#include "job-control.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it.  */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell.  */
+
+/* We always try to start the inferior using a shell.  */
+
+int startup_with_shell = 1;
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -79,8 +92,9 @@ static int vCont_supported;
    space randomization feature before starting an inferior.  */
 int disable_randomization = 1;
 
-static std::vector<char *> program_argv;
-static std::vector<char *> wrapper_argv;
+static char *program_name = NULL;
+static std::vector<char *> program_args;
+static std::string wrapper_argv;
 
 int pass_signals[GDB_SIGNAL_LAST];
 int program_signals[GDB_SIGNAL_LAST];
@@ -93,22 +107,6 @@ int program_signals_p;
 
 unsigned long signal_pid;
 
-#ifdef SIGTTOU
-/* A file descriptor for the controlling terminal.  */
-int terminal_fd;
-
-/* TERMINAL_FD's original foreground group.  */
-pid_t old_foreground_pgrp;
-
-/* Hand back terminal ownership to the original foreground group.  */
-
-static void
-restore_old_foreground_pgrp (void)
-{
-  tcsetpgrp (terminal_fd, old_foreground_pgrp);
-}
-#endif
-
 /* Set if you want to disable optional thread related packets support
    in gdbserver, for the sake of testing GDB against stubs that don't
    support them.  */
@@ -118,8 +116,8 @@ int disable_packet_qC;
 int disable_packet_qfThreadInfo;
 
 /* Last status reported to GDB.  */
-static struct target_waitstatus last_status;
-static ptid_t last_ptid;
+struct target_waitstatus last_status;
+ptid_t last_ptid;
 
 char *own_buf;
 static unsigned char *mem_buf;
@@ -238,94 +236,31 @@ target_running (void)
   return get_first_thread () != NULL;
 }
 
-static int
-start_inferior (char **argv)
-{
-  std::vector<char *> new_argv;
-
-  if (!wrapper_argv.empty ())
-    new_argv.insert (new_argv.begin (),
-		     wrapper_argv.begin (),
-		     wrapper_argv.end ());
-
-  for (int i = 0; argv[i] != NULL; ++i)
-    new_argv.push_back (argv[i]);
-
-  new_argv.push_back (NULL);
+/* See common/common-inferior.h.  */
 
-  if (debug_threads)
-    {
-      for (int i = 0; i < new_argv.size (); ++i)
-	debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
-      debug_flush ();
-    }
-
-#ifdef SIGTTOU
-  signal (SIGTTOU, SIG_DFL);
-  signal (SIGTTIN, SIG_DFL);
-#endif
-
-  signal_pid = create_inferior (new_argv[0], &new_argv[0]);
-
-  /* FIXME: we don't actually know at this point that the create
-     actually succeeded.  We won't know that until we wait.  */
-  fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
-	   signal_pid);
-  fflush (stderr);
-
-#ifdef SIGTTOU
-  signal (SIGTTOU, SIG_IGN);
-  signal (SIGTTIN, SIG_IGN);
-  terminal_fd = fileno (stderr);
-  old_foreground_pgrp = tcgetpgrp (terminal_fd);
-  tcsetpgrp (terminal_fd, signal_pid);
-  atexit (restore_old_foreground_pgrp);
-#endif
-
-  if (!wrapper_argv.empty ())
-    {
-      ptid_t ptid = pid_to_ptid (signal_pid);
-
-      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
-      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-	{
-	  do
-	    {
-	      target_continue_no_signal (ptid);
+const char *
+get_exec_wrapper ()
+{
+  return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL;
+}
 
-	      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-	      if (last_status.kind != TARGET_WAITKIND_STOPPED)
-		break;
+/* See common/common-inferior.h.  */
 
-	      current_thread->last_resume_kind = resume_stop;
-	      current_thread->last_status = last_status;
-	    }
-	  while (last_status.value.sig != GDB_SIGNAL_TRAP);
-	}
-      target_post_create_inferior ();
-      return signal_pid;
-    }
+char *
+get_exec_file (int err)
+{
+  if (err && program_name == NULL)
+    error (_("No executable file specified."));
 
-  /* Wait till we are at 1st instruction in program, return new pid
-     (assuming success).  */
-  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+  return program_name;
+}
 
-  /* At this point, the target process, if it exits, is stopped.  Do not call
-     the function target_post_create_inferior if the process has already
-     exited, as the target implementation of the routine may rely on the
-     process being live. */
-  if (last_status.kind != TARGET_WAITKIND_EXITED
-      && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-    {
-      target_post_create_inferior ();
-      current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
-    }
-  else
-    target_mourn_inferior (last_ptid);
+/* See server.h.  */
 
-  return signal_pid;
+struct gdb_environ *
+get_environ ()
+{
+  return our_environ;
 }
 
 static int
@@ -2848,6 +2783,7 @@ handle_v_run (char *own_buf)
 {
   char *p, *next_p;
   std::vector<char *> new_argv;
+  char *new_program_name = NULL;
   int i, new_argc;
 
   new_argc = 0;
@@ -2866,42 +2802,94 @@ handle_v_run (char *own_buf)
       if (i == 0 && p == next_p)
 	{
 	  /* No program specified.  */
-	  new_argv.push_back (NULL);
+	  new_program_name = NULL;
+	}
+      else if (p == next_p)
+	{
+	  /* Empty argument.  */
+	  new_argv.push_back (xstrdup ("''"));
 	}
       else
 	{
 	  size_t len = (next_p - p) / 2;
+	  /* ARG is the unquoted argument received via the RSP.  */
 	  char *arg = (char *) xmalloc (len + 1);
+	  /* FULL_ARGS will contain the quoted version of ARG.  */
+	  char *full_arg = (char *) xmalloc ((len + 1) * 2);
+	  /* These are pointers used to navigate the strings above.  */
+	  char *tmp_arg = arg;
+	  char *tmp_full_arg = full_arg;
+	  int need_quote = 0;
 
 	  hex2bin (p, (gdb_byte *) arg, len);
 	  arg[len] = '\0';
-	  new_argv.push_back (arg);
-	}
 
+	  while (*tmp_arg != '\0')
+	    {
+	      switch (*tmp_arg)
+		{
+		case '\n':
+		  /* Quote \n.  */
+		  *tmp_full_arg = '\'';
+		  ++tmp_full_arg;
+		  need_quote = 1;
+		  break;
+
+		case '\'':
+		  /* Quote single quote.  */
+		  *tmp_full_arg = '\\';
+		  ++tmp_full_arg;
+		  break;
+
+		default:
+		  break;
+		}
+
+	      *tmp_full_arg = *tmp_arg;
+	      ++tmp_full_arg;
+	      ++tmp_arg;
+	    }
+
+	  if (need_quote)
+	    *tmp_full_arg++ = '\'';
+
+	  /* Finish FULL_ARG and push it into the vector containing
+	     the argv.  */
+	  *tmp_full_arg = '\0';
+	  if (i == 0)
+	    new_program_name = full_arg;
+	  else
+	    new_argv.push_back (full_arg);
+	  xfree (arg);
+	}
       if (*next_p)
 	next_p++;
     }
   new_argv.push_back (NULL);
 
-  if (new_argv[0] == NULL)
+  if (new_program_name == NULL)
     {
       /* GDB didn't specify a program to run.  Use the program from the
 	 last run with the new argument list.  */
-      if (program_argv.empty ())
+      if (program_name == NULL)
 	{
 	  write_enn (own_buf);
 	  free_vector_argv (new_argv);
 	  return 0;
 	}
-
-      new_argv.push_back (xstrdup (program_argv[0]));
+    }
+  else
+    {
+      xfree (program_name);
+      program_name = new_program_name;
     }
 
   /* Free the old argv and install the new one.  */
-  free_vector_argv (program_argv);
-  program_argv = new_argv;
+  free_vector_argv (program_args);
+  program_args = new_argv;
+
+  create_inferior (program_name, program_args);
 
-  start_inferior (&program_argv[0]);
   if (last_status.kind == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3527,10 +3515,17 @@ captured_main (int argc, char *argv[])
 	  tmp = next_arg;
 	  while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
 	    {
-	      wrapper_argv.push_back (*next_arg);
+	      wrapper_argv += *next_arg;
+	      wrapper_argv += ' ';
 	      next_arg++;
 	    }
 
+	  if (!wrapper_argv.empty ())
+	    {
+	      /* Erase the last whitespace.  */
+	      wrapper_argv.erase (wrapper_argv.end () - 1);
+	    }
+
 	  if (next_arg == tmp || *next_arg == NULL)
 	    {
 	      gdbserver_usage (stderr);
@@ -3666,8 +3661,13 @@ captured_main (int argc, char *argv[])
       exit (1);
     }
 
+  /* Gather information about the environment.  */
+  our_environ = make_environ ();
+  init_environ (our_environ);
+
   initialize_async_io ();
   initialize_low ();
+  have_job_control ();
   initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
@@ -3681,12 +3681,13 @@ captured_main (int argc, char *argv[])
       int i, n;
 
       n = argc - (next_arg - argv);
-      for (i = 0; i < n; i++)
-	program_argv.push_back (xstrdup (next_arg[i]));
-      program_argv.push_back (NULL);
+      program_name = xstrdup (next_arg[0]);
+      for (i = 1; i < n; i++)
+	program_args.push_back (xstrdup (next_arg[i]));
+      program_args.push_back (NULL);
 
       /* Wait till we are at first instruction in program.  */
-      start_inferior (&program_argv[0]);
+      create_inferior (program_name, program_args);
 
       /* We are now (hopefully) stopped at the first instruction of
 	 the target process.  This assumes that the target process was
@@ -4301,9 +4302,10 @@ process_serial_event (void)
 	  fprintf (stderr, "GDBserver restarting\n");
 
 	  /* Wait till we are at 1st instruction in prog.  */
-	  if (!program_argv.empty ())
+	  if (program_name != NULL)
 	    {
-	      start_inferior (&program_argv[0]);
+	      create_inferior (program_name, program_args);
+
 	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..4de4244 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -148,4 +148,18 @@ extern int in_queued_stop_replies (ptid_t ptid);
 /* Definition for any syscall, used for unfiltered syscall reporting.  */
 #define ANY_SYSCALL (-2)
 
+/* After fork_inferior has been called, we need to adjust a few
+   signals and call startup_inferior to start the inferior and consume
+   its first events.  This is done here.  PID is the pid of the new
+   inferior and PROGRAM is its name.  */
+extern void post_fork_inferior (int pid, const char *program);
+
+/* Get the 'struct gdb_environ *' being used in the current
+   session.  */
+extern struct gdb_environ *get_environ ();
+
+extern target_waitstatus last_status;
+extern ptid_t last_ptid;
+extern unsigned long signal_pid;
+
 #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..0f770a0 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include "filestuff.h"
 #include "hostio.h"
+#include "nat/fork-inferior.h"
 
 /* Some older glibc versions do not define this.  */
 #ifndef __WNOTHREAD
@@ -261,36 +262,37 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
   return ret;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+spu_ptrace_fun ()
+{
+  if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+}
 
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
+
 static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (const char *program,
+		     const std::vector<char *> &program_argv)
 {
   int pid;
   ptid_t ptid;
   struct process_info *proc;
+  std::string str_program_args = stringify_argv (program_args);
 
-  pid = fork ();
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, 0, 0);
-
-      setpgid (0, 0);
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-	execvp (program, allargs);
+  pid = fork_inferior (program,
+		       str_program_args.c_str (),
+		       environ_vector (get_environ ()), spu_ptrace_fun,
+		       NULL, NULL, NULL, NULL);
 
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-	       strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  post_fork_inferior (pid, program);
 
   proc = add_process (pid, 0);
   proc->tdesc = tdesc_spu;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..7526463 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,30 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
   (*the_target->sw_breakpoint_from_kind) (0, &size);
   return size;
 }
+
+/* See target/target.h.  */
+
+void
+target_terminal_init ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_inferior ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal_ours ()
+{
+  /* Placeholder needed because of fork_inferior.  Not necessary on
+     GDBserver.  */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..be89258 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
 #include "target/waitstatus.h"
 #include "mem-break.h"
 #include "btrace-common.h"
+#include <vector>
 
 struct emit_ops;
 struct buffer;
@@ -67,13 +68,13 @@ struct target_ops
   /* Start a new process.
 
      PROGRAM is a path to the program to execute.
-     ARGS is a standard NULL-terminated array of arguments,
-     to be passed to the inferior as ``argv''.
+     PROGRAM_ARGS is a standard NULL-terminated array of arguments,
+     to be passed to the inferior as ``argv'' (along with PROGRAM).
 
      Returns the new PID on success, -1 on failure.  Registers the new
      process with the process list.  */
-
-  int (*create_inferior) (char *program, char **args);
+  int (*create_inferior) (const char *program,
+			  const std::vector<char *> &program_args);
 
   /* Do additional setup after a new process is created, including
      exec-wrapper completion.  */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
 
 void set_target_ops (struct target_ops *);
 
-#define create_inferior(program, args) \
-  (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_args)	\
+  (*the_target->create_inferior) (program, program_args)
 
 #define target_post_create_inferior()			 \
   do							 \
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7b09f4b..88f6911 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,13 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   PROGRAM is the program name.
+   PROGRAM_ARGS is the vector containing the inferior's args.
    Returns the new PID on success, -1 on failure.  Registers the new
    process with the process list.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+		       const std::vector<char *> &program_args)
 {
 #ifndef USE_WIN32API
   char real_path[PATH_MAX];
@@ -622,11 +622,12 @@ win32_create_inferior (char *program, char **program_args)
 #endif
   BOOL ret;
   DWORD flags;
-  char *args;
   int argslen;
   int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string str_program_args = stringify_argv (program_args);
+  char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -652,18 +653,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = (char *) alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-	 handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 6298103..d5e3841 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2143,6 +2143,11 @@ gnu_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, gnu_ptrace_me,
                        NULL, NULL, NULL, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   /* Attach to the now stopped child, which is actually a shell...  */
   inf_debug (inf, "attaching to child: %d", pid);
 
@@ -2162,7 +2167,8 @@ gnu_create_inferior (struct target_ops *ops,
   thread_change_ptid (inferior_ptid,
 		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
+
   inf->pending_execs = 0;
   /* Get rid of the old shell threads.  */
   prune_threads ();
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index b19aaf9..af181f0 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -31,6 +31,8 @@
 #include "inf-ptrace.h"
 #include "inf-child.h"
 #include "gdbthread.h"
+#include "nat/fork-inferior.h"
+#include "utils.h"
 
 \f
 
@@ -93,7 +95,8 @@ inf_ptrace_create_inferior (struct target_ops *ops,
 			    const char *exec_file, const std::string &allargs,
 			    char **env, int from_tty)
 {
-  int pid;
+  pid_t pid;
+  ptid_t ptid;
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
@@ -110,13 +113,19 @@ inf_ptrace_create_inferior (struct target_ops *ops,
   pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
 		       NULL, NULL, NULL);
 
+  ptid = pid_to_ptid (pid);
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (ptid);
+
   discard_cleanups (back_to);
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
   /* On some targets, there must be some explicit actions taken after
      the inferior has been started up.  */
-  target_post_startup_inferior (pid_to_ptid (pid));
+  target_post_startup_inferior (ptid);
 }
 
 #ifdef PT_GET_PROCESS_STATE
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 7ee92ed..6376952 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -136,28 +136,10 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
-/* Report an error that happened when starting to trace the inferior
-   (i.e., when the "traceme_fun" callback is called on fork_inferior)
-   and bail out.  This function does not return.  */
-
-extern void trace_start_error (const char *fmt, ...)
-  ATTRIBUTE_NORETURN;
-
-/* Like "trace_start_error", but the error message is constructed by
-   combining STRING with the system error message for errno.  This
-   function does not return.  */
-
-extern void trace_start_error_with_name (const char *string)
-  ATTRIBUTE_NORETURN;
-
-extern int fork_inferior (const char *, const std::string &, char **,
-			  void (*)(void),
-			  void (*)(int), void (*)(void), char *,
-                          void (*)(const char *,
-                                   char * const *, char * const *));
-
-
-extern void startup_inferior (int);
+/* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
+   This function already calls set_executing.  Return the ptid_t from
+   STARTUP_INFERIOR.  */
+extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
 
 extern char *construct_inferior_arguments (int, char **);
 
@@ -282,12 +264,6 @@ enum stop_kind
 #define ON_STACK 1
 #define AT_ENTRY_POINT 4
 
-/* Number of traps that happen between exec'ing the shell to run an
-   inferior and when we finally get to the inferior code, not counting
-   the exec for the shell.  This is 1 on all supported
-   implementations.  */
-#define START_INFERIOR_TRAPS_EXPECTED	1
-
 struct private_inferior;
 
 /* Inferior process specific part of `struct infcall_control_state'.
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
new file mode 100644
index 0000000..0913409
--- /dev/null
+++ b/gdb/nat/fork-inferior.c
@@ -0,0 +1,595 @@
+/* Fork a Unix child process, and set up to debug it, for GDB and GDBserver.
+
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "common-defs.h"
+#include "fork-inferior.h"
+#include "target/waitstatus.h"
+#include "filestuff.h"
+#include "target/target.h"
+#include "common-inferior.h"
+#include "common-gdbthread.h"
+#include "signals-state-save-restore.h"
+#include <vector>
+
+extern char **environ;
+
+/* Default shell file to be used if 'startup-with-shell' is set but
+   $SHELL is not.  */
+#define SHELL_FILE "/bin/sh"
+
+/* Build the argument vector for execv(3).  */
+
+class execv_argv
+{
+public:
+  /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
+     arguments to the program.  If starting with a shell, SHELL_FILE
+     is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
+  execv_argv (const char *exec_file, const std::string &allargs,
+	      const char *shell_file);
+
+  /* Return a pointer to the built argv, in the type expected by
+     execv.  The result is (only) valid for as long as this execv_argv
+     object is live.  We return a "char **" because that's the type
+     that the execv functions expect.  Note that it is guaranteed that
+     the execv functions do not modify the argv[] array nor the
+     strings to which the array point.  */
+  char **argv ()
+  {
+    return const_cast<char **> (&m_argv[0]);
+  }
+
+private:
+  /* Disable copying.  */
+  execv_argv (const execv_argv &) = delete;
+  void operator= (const execv_argv &) = delete;
+
+  /* Helper methods for constructing the argument vector.  */
+
+  /* Used when building an argv for a straight execv call, without
+     going via the shell.  */
+  void init_for_no_shell (const char *exec_file,
+			  const std::string &allargs);
+
+  /* Used when building an argv for execing a shell that execs the
+     child program.  */
+  void init_for_shell (const char *exec_file,
+		       const std::string &allargs,
+		       const char *shell_file);
+
+  /* The argument vector built.  Holds non-owning pointers.  Elements
+     either point to the strings passed to the execv_argv ctor, or
+     inside M_STORAGE.  */
+  std::vector<const char *> m_argv;
+
+  /* Storage.  In the no-shell case, this contains a copy of the
+     arguments passed to the ctor, split by '\0'.  In the shell case,
+     this contains the quoted shell command.  I.e., SHELL_COMMAND in
+     {"$SHELL" "-c", SHELL_COMMAND, NULL}.  */
+  std::string m_storage;
+};
+
+/* Create argument vector for straight call to execvp.  Breaks up
+   ALLARGS into an argument vector suitable for passing to execvp and
+   stores it in M_ARGV.  E.g., on "run a b c d" this routine would get
+   as input the string "a b c d", and as output it would fill in
+   M_ARGV with the four arguments "a", "b", "c", "d".  Each argument
+   in M_ARGV points to a substring of a copy of ALLARGS stored in
+   M_STORAGE.  */
+
+void
+execv_argv::init_for_no_shell (const char *exec_file,
+			       const std::string &allargs)
+{
+
+  /* Save/work with a copy stored in our storage.  The pointers pushed
+     to M_ARGV point directly into M_STORAGE, which is modified in
+     place with the necessary NULL terminators.  This avoids N heap
+     allocations and string dups when 1 is sufficient.  */
+  std::string &args_copy = m_storage = allargs;
+
+  m_argv.push_back (exec_file);
+
+  for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
+    {
+      /* Skip whitespace-like chars.  */
+      std::size_t pos = args_copy.find_first_not_of (" \t\n", cur_pos);
+
+      if (pos != std::string::npos)
+	cur_pos = pos;
+
+      /* Find the position of the next separator.  */
+      std::size_t next_sep = args_copy.find_first_of (" \t\n", cur_pos);
+
+      if (next_sep == std::string::npos)
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = args_copy.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  args_copy[next_sep++] = '\0';
+	}
+
+      m_argv.push_back (&args_copy[cur_pos]);
+
+      cur_pos = next_sep;
+    }
+
+  /* NULL-terminate the vector.  */
+  m_argv.push_back (NULL);
+}
+
+/* When executing a command under the given shell, return true if the
+   '!' character should be escaped when embedded in a quoted
+   command-line argument.  */
+
+static bool
+escape_bang_in_quoted_argument (const char *shell_file)
+{
+  size_t shell_file_len = strlen (shell_file);
+
+  /* Bang should be escaped only in C Shells.  For now, simply check
+     that the shell name ends with 'csh', which covers at least csh
+     and tcsh.  This should be good enough for now.  */
+
+  if (shell_file_len < 3)
+    return false;
+
+  if (shell_file[shell_file_len - 3] == 'c'
+      && shell_file[shell_file_len - 2] == 's'
+      && shell_file[shell_file_len - 1] == 'h')
+    return true;
+
+  return false;
+}
+
+/* See declaration.  */
+
+execv_argv::execv_argv (const char *exec_file,
+			const std::string &allargs,
+			const char *shell_file)
+{
+  if (shell_file == NULL)
+    init_for_no_shell (exec_file, allargs);
+  else
+    init_for_shell (exec_file, allargs, shell_file);
+}
+
+/* See declaration.  */
+
+void
+execv_argv::init_for_shell (const char *exec_file,
+			    const std::string &allargs,
+			    const char *shell_file)
+{
+  const char *exec_wrapper = get_exec_wrapper ();
+
+  /* We're going to call a shell.  */
+  bool escape_bang = escape_bang_in_quoted_argument (shell_file);
+
+  /* We need to build a new shell command string, and make argv point
+     to it.  So build it in the storage.  */
+  std::string &shell_command = m_storage;
+
+  shell_command = "exec ";
+
+  /* Add any exec wrapper.  That may be a program name with arguments,
+     so the user must handle quoting.  */
+  if (exec_wrapper != NULL)
+    {
+      shell_command += exec_wrapper;
+      shell_command += ' ';
+    }
+
+  /* Now add exec_file, quoting as necessary.  */
+
+  /* Quoting in this style is said to work with all shells.  But csh
+     on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
+     to.  */
+  bool need_to_quote;
+  const char *p = exec_file;
+  while (1)
+    {
+      switch (*p)
+	{
+	case '\'':
+	case '!':
+	case '"':
+	case '(':
+	case ')':
+	case '$':
+	case '&':
+	case ';':
+	case '<':
+	case '>':
+	case ' ':
+	case '\n':
+	case '\t':
+	  need_to_quote = true;
+	  goto end_scan;
+
+	case '\0':
+	  need_to_quote = false;
+	  goto end_scan;
+
+	default:
+	  break;
+	}
+      ++p;
+    }
+ end_scan:
+  if (need_to_quote)
+    {
+      shell_command += '\'';
+      for (p = exec_file; *p != '\0'; ++p)
+	{
+	  if (*p == '\'')
+	    shell_command += "'\\''";
+	  else if (*p == '!' && escape_bang)
+	    shell_command += "\\!";
+	  else
+	    shell_command += *p;
+	}
+      shell_command += '\'';
+    }
+  else
+    shell_command += exec_file;
+
+  shell_command += ' ' + allargs;
+
+  /* If we decided above to start up with a shell, we exec the shell.
+     "-c" says to interpret the next arg as a shell command to
+     execute, and this command is "exec <target-program> <args>".  */
+  m_argv.reserve (4);
+  m_argv.push_back (shell_file);
+  m_argv.push_back ("-c");
+  m_argv.push_back (shell_command.c_str ());
+  m_argv.push_back (NULL);
+}
+
+/* Return the shell that must be used to startup the inferior.  The
+   first attempt is the environment variable SHELL; if it is not set,
+   then we default to SHELL_FILE.  */
+
+static const char *
+get_startup_shell ()
+{
+  static const char *ret;
+
+  ret = getenv ("SHELL");
+  if (ret == NULL)
+    ret = SHELL_FILE;
+
+  return ret;
+}
+
+/* See nat/fork-inferior.h.  */
+
+pid_t
+fork_inferior (const char *exec_file_arg, const std::string &allargs,
+	       char **env, void (*traceme_fun) (),
+	       void (*init_trace_fun) (int), void (*pre_trace_fun) (),
+	       const char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
+{
+  pid_t pid;
+  /* Set debug_fork then attach to the child while it sleeps, to debug.  */
+  int debug_fork = 0;
+  const char *shell_file;
+  const char *exec_file;
+  char **save_our_env;
+  int i;
+  int save_errno;
+
+  /* If no exec file handed to us, get it from the exec-file command
+     -- with a good, common error message if none is specified.  */
+  if (exec_file_arg == NULL)
+    exec_file = get_exec_file (1);
+  else
+    exec_file = exec_file_arg;
+
+  /* 'startup_with_shell' is declared in inferior.h and bound to the
+     "set startup-with-shell" option.  If 0, we'll just do a
+     fork/exec, no shell, so don't bother figuring out what shell.  */
+  if (startup_with_shell)
+    {
+      shell_file = shell_file_arg;
+
+      /* Figure out what shell to start up the user program under.  */
+      if (shell_file == NULL)
+	shell_file = get_startup_shell ();
+
+      gdb_assert (shell_file != NULL);
+    }
+  else
+    shell_file = NULL;
+
+  /* Build the argument vector.  */
+  execv_argv child_argv (exec_file, allargs, shell_file);
+
+  /* Retain a copy of our environment variables, since the child will
+     replace the value of environ and if we're vforked, we have to
+     restore it.  */
+  save_our_env = environ;
+
+  /* Perform any necessary actions regarding to TTY before the
+     fork/vfork call.  */
+  prefork_hook (allargs.c_str ());
+
+  /* It is generally good practice to flush any possible pending stdio
+     output prior to doing a fork, to avoid the possibility of both
+     the parent and child flushing the same data after the fork.  */
+  gdb_flush_out_err ();
+
+  /* If there's any initialization of the target layers that must
+     happen to prepare to handle the child we're about fork, do it
+     now...  */
+  if (pre_trace_fun != NULL)
+    (*pre_trace_fun) ();
+
+  /* Create the child process.  Since the child process is going to
+     exec(3) shortly afterwards, try to reduce the overhead by
+     calling vfork(2).  However, if PRE_TRACE_FUN is non-null, it's
+     likely that this optimization won't work since there's too much
+     work to do between the vfork(2) and the exec(3).  This is known
+     to be the case on ttrace(2)-based HP-UX, where some handshaking
+     between parent and child needs to happen between fork(2) and
+     exec(2).  However, since the parent is suspended in the vforked
+     state, this doesn't work.  Also note that the vfork(2) call might
+     actually be a call to fork(2) due to the fact that autoconf will
+     ``#define vfork fork'' on certain platforms.  */
+#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
+  if (pre_trace_fun || debug_fork)
+    pid = fork ();
+  else
+#endif
+    pid = vfork ();
+
+  if (pid < 0)
+    perror_with_name (("vfork"));
+
+  if (pid == 0)
+    {
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
+      close_most_fds ();
+
+      if (debug_fork)
+	sleep (debug_fork);
+
+      /* Execute any necessary post-fork actions before we exec.  */
+      postfork_child_hook ();
+
+      /* Changing the signal handlers for the inferior after
+         a vfork can also change them for the superior, so we don't mess
+         with signals here.  See comments in
+         initialize_signals for how we get the right signal handlers
+         for the inferior.  */
+
+      /* "Trace me, Dr. Memory!"  */
+      (*traceme_fun) ();
+
+      /* The call above set this process (the "child") as debuggable
+        by the original gdb process (the "parent").  Since processes
+        (unlike people) can have only one parent, if you are debugging
+        gdb itself (and your debugger is thus _already_ the
+        controller/parent for this child), code from here on out is
+        undebuggable.  Indeed, you probably got an error message
+        saying "not parent".  Sorry; you'll have to use print
+        statements!  */
+
+      restore_original_signals_state ();
+
+      /* There is no execlpe call, so we have to set the environment
+         for our child in the global variable.  If we've vforked, this
+         clobbers the parent, but environ is restored a few lines down
+         in the parent.  By the way, yes we do need to look down the
+         path to find $SHELL.  Rich Pixley says so, and I agree.  */
+      environ = env;
+
+      char **argv = child_argv.argv ();
+
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], &argv[0], env);
+      else
+        execvp (argv[0], &argv[0]);
+
+      /* If we get here, it's an error.  */
+      save_errno = errno;
+      warning ("Cannot exec %s", argv[0]);
+
+      for (i = 1; argv[i] != NULL; i++)
+	warning (" %s", argv[i]);
+
+      warning ("Error: %s\n", safe_strerror (save_errno));
+
+      _exit (0177);
+    }
+
+  /* Restore our environment in case a vforked child clob'd it.  */
+  environ = save_our_env;
+
+  postfork_hook (pid);
+
+  /* Now that we have a child process, make it our target, and
+     initialize anything target-vector-specific that needs
+     initializing.  */
+  if (init_trace_fun)
+    (*init_trace_fun) (pid);
+
+  /* We are now in the child process of interest, having exec'd the
+     correct program, and are poised at the first instruction of the
+     new program.  */
+  return pid;
+}
+
+/* See nat/fork-inferior.h.  */
+
+ptid_t
+startup_inferior (pid_t pid, int ntraps,
+		  struct target_waitstatus *last_waitstatus,
+		  ptid_t *last_ptid)
+{
+  int pending_execs = ntraps;
+  int terminal_initted = 0;
+  ptid_t resume_ptid;
+
+  if (startup_with_shell)
+    {
+      /* One trap extra for exec'ing the shell.  */
+      pending_execs++;
+    }
+
+  if (target_supports_multi_process ())
+    resume_ptid = pid_to_ptid (pid);
+  else
+    resume_ptid = minus_one_ptid;
+
+  /* The process was started by the fork that created it, but it will
+     have stopped one instruction after execing the shell.  Here we
+     must get it up to actual execution of the real program.  */
+  if (get_exec_wrapper () != NULL)
+    pending_execs++;
+
+  while (1)
+    {
+      enum gdb_signal resume_signal = GDB_SIGNAL_0;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (resume_ptid, &ws, 0);
+
+      if (last_waitstatus != NULL)
+	*last_waitstatus = ws;
+      if (last_ptid != NULL)
+	*last_ptid = event_ptid;
+
+      if (ws.kind == TARGET_WAITKIND_IGNORE)
+	/* The inferior didn't really stop, keep waiting.  */
+	continue;
+
+      switch (ws.kind)
+	{
+	  case TARGET_WAITKIND_SPURIOUS:
+	  case TARGET_WAITKIND_LOADED:
+	  case TARGET_WAITKIND_FORKED:
+	  case TARGET_WAITKIND_VFORKED:
+	  case TARGET_WAITKIND_SYSCALL_ENTRY:
+	  case TARGET_WAITKIND_SYSCALL_RETURN:
+	    /* Ignore gracefully during startup of the inferior.  */
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_SIGNALLED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    error (_("During startup program terminated with signal %s, %s."),
+		   gdb_signal_to_name (ws.value.sig),
+		   gdb_signal_to_string (ws.value.sig));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXITED:
+	    target_terminal_ours ();
+	    target_mourn_inferior (event_ptid);
+	    if (ws.value.integer)
+	      error (_("During startup program exited with code %d."),
+		     ws.value.integer);
+	    else
+	      error (_("During startup program exited normally."));
+	    return resume_ptid;
+
+	  case TARGET_WAITKIND_EXECD:
+	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
+	    xfree (ws.value.execd_pathname);
+	    resume_signal = GDB_SIGNAL_TRAP;
+	    switch_to_thread (event_ptid);
+	    break;
+
+	  case TARGET_WAITKIND_STOPPED:
+	    resume_signal = ws.value.sig;
+	    switch_to_thread (event_ptid);
+	    break;
+	}
+
+      if (resume_signal != GDB_SIGNAL_TRAP)
+	{
+	  /* Let shell child handle its own signals in its own way.  */
+	  target_continue (resume_ptid, resume_signal);
+	}
+      else
+	{
+	  /* We handle SIGTRAP, however; it means child did an exec.  */
+	  if (!terminal_initted)
+	    {
+	      /* Now that the child has exec'd we know it has already
+	         set its process group.  On POSIX systems, tcsetpgrp
+	         will fail with EPERM if we try it before the child's
+	         setpgid.  */
+
+	      /* Set up the "saved terminal modes" of the inferior
+	         based on what modes we are starting it with.  */
+	      target_terminal_init ();
+
+	      /* Install inferior's terminal modes.  */
+	      target_terminal_inferior ();
+
+	      terminal_initted = 1;
+	    }
+
+	  if (--pending_execs == 0)
+	    break;
+
+	  /* Just make it go on.  */
+	  target_continue_no_signal (resume_ptid);
+	}
+    }
+
+  return resume_ptid;
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  warning ("Could not trace the inferior process.\nError: ");
+  vwarning (fmt, ap);
+  va_end (ap);
+
+  gdb_flush_out_err ();
+  _exit (0177);
+}
+
+/* See nat/fork-inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
diff --git a/gdb/nat/fork-inferior.h b/gdb/nat/fork-inferior.h
new file mode 100644
index 0000000..10e3832
--- /dev/null
+++ b/gdb/nat/fork-inferior.h
@@ -0,0 +1,106 @@
+/* Functions and data responsible for forking the inferior process.
+
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef FORK_INFERIOR_H
+#define FORK_INFERIOR_H
+
+#include <string>
+
+/* Number of traps that happen between exec'ing the shell to run an
+   inferior and when we finally get to the inferior code, not counting
+   the exec for the shell.  This is 1 on all supported
+   implementations.  */
+#define START_INFERIOR_TRAPS_EXPECTED 1
+
+/* Start an inferior Unix child process and sets inferior_ptid to its
+   pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
+   the arguments to the program.  ENV is the environment vector to
+   pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
+   one.  */
+
+/* This function is NOT reentrant.  Some of the variables have been
+   made static to ensure that they survive the vfork call.  */
+extern pid_t fork_inferior (const char *exec_file_arg,
+			    const std::string &allargs,
+			    char **env, void (*traceme_fun) (),
+			    void (*init_trace_fun) (int),
+			    void (*pre_trace_fun) (),
+			    const char *shell_file_arg,
+			    void (*exec_fun) (const char *file,
+					      char * const *argv,
+					      char * const *env));
+
+/* Accept NTRAPS traps from the inferior.
+
+   Return the ptid of the inferior being started.  */
+extern ptid_t startup_inferior (pid_t pid, int ntraps,
+				struct target_waitstatus *mystatus,
+				ptid_t *myptid);
+
+/* Whether to start up the debuggee under a shell.
+
+   If startup-with-shell is set, GDB's "run" will attempt to start up
+   the debuggee under a shell.  This also happens when using GDBserver
+   under extended remote mode.
+
+   This is in order for argument-expansion to occur.  E.g.,
+
+   (gdb) run *
+
+   The "*" gets expanded by the shell into a list of files.
+
+   While this is a nice feature, it may be handy to bypass the shell
+   in some cases.  To disable this feature, do "set startup-with-shell
+   false".
+
+   The catch-exec traps expected during start-up will be one more if
+   the target is started up with a shell.  */
+extern int startup_with_shell;
+
+/* Perform any necessary tasks before a fork/vfork takes place.  ARGS
+   is a string containing all the arguments received by the inferior.
+   This function is mainly used by fork_inferior.  */
+extern void prefork_hook (const char *args);
+
+/* Perform any necessary tasks after a fork/vfork takes place.  This
+   function is mainly used by fork_inferior.  */
+extern void postfork_hook (pid_t pid);
+
+/* Perform any necessary tasks *on the child* after a fork/vfork takes
+   place.  This function is mainly used by fork_inferior.  */
+extern void postfork_child_hook ();
+
+/* Flush both stdout and stderr.  This function needs to be
+   implemented differently on GDB and GDBserver.  */
+extern void gdb_flush_out_err ();
+
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
+#endif /* ! FORK_INFERIOR_H */
diff --git a/gdb/procfs.c b/gdb/procfs.c
index adb2e84..b03809c 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4377,7 +4377,7 @@ procfs_init_inferior (struct target_ops *ops, int pid)
   thread_change_ptid (pid_to_ptid (pid),
 		      ptid_build (pid, lwpid, 0));
 
-  startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+  gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
 
 #ifdef SYS_syssgi
   /* On mips-irix, we need to stop the inferior early enough during
@@ -4604,6 +4604,11 @@ procfs_create_inferior (struct target_ops *ops, const char *exec_file,
   pid = fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
 		       NULL, NULL, shell_file, NULL);
 
+  /* We have something that executes now.  We'll be running through
+     the shell at this point (if startup-with-shell is true), but the
+     pid shouldn't change.  */
+  add_thread_silent (pid_to_ptid (pid));
+
   procfs_init_inferior (ops, pid);
 }
 
diff --git a/gdb/target.h b/gdb/target.h
index a971adf..083d2bc 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1538,16 +1538,8 @@ extern int target_terminal_is_inferior (void);
 
 extern int target_terminal_is_ours (void);
 
-/* Initialize the terminal settings we record for the inferior,
-   before we actually run the inferior.  */
-
-extern void target_terminal_init (void);
-
-/* Put the inferior's terminal settings into effect.  This is
-   preparation for starting or resuming the inferior.  This is a no-op
-   unless called with the main UI as current UI.  */
-
-extern void target_terminal_inferior (void);
+/* For target_terminal_init, target_terminal_inferior and
+   target_terminal_ours, see target/target.h.  */
 
 /* Put some of our terminal settings into effect, enough to get proper
    results from our output, but do not change into or out of RAW mode
@@ -1557,12 +1549,6 @@ extern void target_terminal_inferior (void);
 
 extern void target_terminal_ours_for_output (void);
 
-/* Put our terminal settings into effect.  First record the inferior's
-   terminal settings so they can be restored properly later.  This is
-   a no-op unless called with the main UI as current UI.  */
-
-extern void target_terminal_ours (void);
-
 /* Return true if the target stack has a non-default
   "to_terminal_ours" method.  */
 
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 582852c..0528766 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -95,4 +95,18 @@ extern void target_mourn_inferior (ptid_t ptid);
 
 extern int target_supports_multi_process (void);
 
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+extern void target_terminal_init ();
+
+/* Put the inferior's terminal settings into effect.  This is
+   preparation for starting or resuming the inferior.  This is a no-op
+   unless called with the main UI as current UI.  */
+extern void target_terminal_inferior ();
+
+/* Put our terminal settings into effect.  First record the inferior's
+   terminal settings so they can be restored properly later.  This is
+   a no-op unless called with the main UI as current UI.  */
+extern void target_terminal_ours ();
+
 #endif /* TARGET_COMMON_H */
diff --git a/gdb/testsuite/gdb.server/non-existing-program.exp b/gdb/testsuite/gdb.server/non-existing-program.exp
index d404564..68d4d53 100644
--- a/gdb/testsuite/gdb.server/non-existing-program.exp
+++ b/gdb/testsuite/gdb.server/non-existing-program.exp
@@ -39,8 +39,16 @@ set spawn_id [remote_spawn target "$gdbserver stdio non-existing-program"]
 set msg "gdbserver exits cleanly"
 set saw_exiting 0
 expect {
-    # This is what we get on ptrace-based targets.
-    -re "stdin/stdout redirected.*No program to debug\r\nExiting\r\n$" {
+    # This is what we get on ptrace-based targets with
+    # startup-with-shell disabled (e.g., when the SHELL variable is
+    # unset).
+    -re "stdin/stdout redirected.*gdbserver: Cannot exec non-existing-program\r\ngdbserver: Error: No such file or directory\r\n\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
+	set saw_exiting 1
+	exp_continue
+    }
+    # Likewise, but with startup-with-shell enabled, which is the
+    # default behaviour.
+    -re "stdin/stdout redirected.*exec: non-existing-program: not found\r\nDuring startup program exited with code 127\.\r\nExiting\r\n$" {
 	set saw_exiting 1
 	exp_continue
     }
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 22:15         ` Sergio Durigan Junior
@ 2017-06-07 22:29           ` Pedro Alves
  2017-06-08  0:00             ` Sergio Durigan Junior
  0 siblings, 1 reply; 157+ messages in thread
From: Pedro Alves @ 2017-06-07 22:29 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

In the commit log:

On 06/07/2017 11:15 PM, Sergio Durigan Junior wrote:
> This is the most important (and the biggest, sorry) patch of the
> series.  It moves fork_inferior from gdb/fork-child.c to
> common/common-fork-child.c and makes all the necessary adjustments to
> both GDB and gdbserver to make sure everything works OK.

common/common-fork-child.c -> nat/fork-inferior.c

Series is OK.  Please push.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-07 22:29           ` Pedro Alves
@ 2017-06-08  0:00             ` Sergio Durigan Junior
  2019-02-14 15:38               ` Thomas Schwinge
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-08  0:00 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Wednesday, June 07 2017, Pedro Alves wrote:

> In the commit log:
>
> On 06/07/2017 11:15 PM, Sergio Durigan Junior wrote:
>> This is the most important (and the biggest, sorry) patch of the
>> series.  It moves fork_inferior from gdb/fork-child.c to
>> common/common-fork-child.c and makes all the necessary adjustments to
>> both GDB and gdbserver to make sure everything works OK.
>
> common/common-fork-child.c -> nat/fork-inferior.c
>
> Series is OK.  Please push.

Thanks, pushed.

aefd8b33d97bded58e51d75271f99e1eaec9fb28
2090129c36c7e582943b7d300968d19b46160d84
043a49349c713dc329a2dfc413b082c3826ecdb8
156525114c1cbbace0dec223494b842ffc60d52e

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
  2017-06-07 12:29     ` Pedro Alves
@ 2017-06-08 16:40     ` Yao Qi
  2017-06-08 18:49       ` Sergio Durigan Junior
                         ` (2 more replies)
  2017-06-21 17:01     ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Simon Marchi
  2 siblings, 3 replies; 157+ messages in thread
From: Yao Qi @ 2017-06-08 16:40 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Pedro Alves

Sergio Durigan Junior <sergiodj@redhat.com> writes:

Hi Sergio,
This patch causes a lot of test fails on AArch64, shown by buildbot,
https://gdb-build.sergiodj.net/builders/Ubuntu-AArch64-native-gdbserver-m64/builds/2099
However, other builders with GDBserver look fine.  I haven't triage them yet.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-08 16:40     ` Yao Qi
@ 2017-06-08 18:49       ` Sergio Durigan Junior
  2017-06-08 21:02       ` [commit/obvious] Fix possible bug when no args have been provided to the executable Sergio Durigan Junior
  2017-06-09 22:19       ` [commit/obvious] Include <signal.h> on gdbserver/fork-child.c (and fix regressions) Sergio Durigan Junior
  2 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-08 18:49 UTC (permalink / raw)
  To: Yao Qi; +Cc: GDB Patches, Pedro Alves

On Thursday, June 08 2017, Yao Qi wrote:

> Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Hi Sergio,
> This patch causes a lot of test fails on AArch64, shown by buildbot,
> https://gdb-build.sergiodj.net/builders/Ubuntu-AArch64-native-gdbserver-m64/builds/2099
> However, other builders with GDBserver look fine.  I haven't triage them yet.

Hi Yao,

Thanks for the message.  I'll look at these right away.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [commit/obvious] Fix possible bug when no args have been provided to the executable
  2017-06-08 16:40     ` Yao Qi
  2017-06-08 18:49       ` Sergio Durigan Junior
@ 2017-06-08 21:02       ` Sergio Durigan Junior
  2017-06-09 22:19       ` [commit/obvious] Include <signal.h> on gdbserver/fork-child.c (and fix regressions) Sergio Durigan Junior
  2 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-08 21:02 UTC (permalink / raw)
  To: GDB Patches; +Cc: Yao Qi, Sergio Durigan Junior

Hi,

This bug is related to:

  <https://sourceware.org/ml/gdb-patches/2017-06/msg00216.html>

On stringify_argv, we have to check if args[0] is not NULL before
stringifying anything, otherwise we might do the wrong thing when
trimming the "ret" string in the end.  args[0] will be NULL when no
arguments are passed to the inferior that will be started.

Checked in as obvious.

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

	* common/common-utils.c (stringify_argv): Check for "arg[0] !=
	NULL".
---
 gdb/ChangeLog             | 5 +++++
 gdb/common/common-utils.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 993fabe..5ebc7f8 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-06-08  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	* common/common-utils.c (stringify_argv): Check for "arg[0] !=
+	NULL".
+
 2017-06-08 Alan Hayward  <alan.hayward@arm.com>
 
 	* mn10300-tdep.c (MN10300_MAX_REGISTER_SIZE): Add.
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 793ab3b..e75a1b9 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -337,7 +337,7 @@ stringify_argv (const std::vector<char *> &args)
 {
   std::string ret;
 
-  if (!args.empty ())
+  if (!args.empty () && args[0] != NULL)
     {
       for (auto s : args)
 	if (s != NULL)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [commit/obvious] Include <signal.h> on gdbserver/fork-child.c (and fix regressions)
  2017-06-08 16:40     ` Yao Qi
  2017-06-08 18:49       ` Sergio Durigan Junior
  2017-06-08 21:02       ` [commit/obvious] Fix possible bug when no args have been provided to the executable Sergio Durigan Junior
@ 2017-06-09 22:19       ` Sergio Durigan Junior
  2 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-09 22:19 UTC (permalink / raw)
  To: GDB Patches; +Cc: Yao Qi, Sergio Durigan Junior

Hi,

This is another obvious patch that fixes a thinko from my previous
startup-with-shell series.  We should conditionally include <signal.h>
on gdb/gdbserver/fork-child.c because gdbserver will be putting the
inferior's terminal on the correct mode after the call to
fork_inferior, and for that it needs to ignore SIGTTOU.

This patch fixes a bunch of regressions happening on AArch64 that were
reported by Yao.

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

	* fork-child.c: Conditionally include <signal.h>.
---
 gdb/gdbserver/ChangeLog    | 4 ++++
 gdb/gdbserver/fork-child.c | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index a5effe2..80240ff 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,7 @@
+2017-06-09  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	* fork-child.c: Conditionally include <signal.h>.
+
 2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* server.c (handle_general_set): Handle new packet
diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
index a1a8ff1..1002620 100644
--- a/gdb/gdbserver/fork-child.c
+++ b/gdb/gdbserver/fork-child.c
@@ -19,6 +19,9 @@
 #include "server.h"
 #include "job-control.h"
 #include "nat/fork-inferior.h"
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 
 #ifdef SIGTTOU
 /* A file descriptor for the controlling terminal.  */
-- 
2.9.3

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
  2017-06-07 12:29     ` Pedro Alves
  2017-06-08 16:40     ` Yao Qi
@ 2017-06-21 17:01     ` Simon Marchi
  2017-06-21 17:19       ` Sergio Durigan Junior
  2 siblings, 1 reply; 157+ messages in thread
From: Simon Marchi @ 2017-06-21 17:01 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, Pedro Alves, Tristan Gingold

On 2017-06-05 00:18, Sergio Durigan Junior wrote:
> This is the most important (and the biggest, sorry) patch of the
> series.  It moves fork_inferior from gdb/fork-child.c to
> common/common-fork-child.c and makes all the necessary adjustments to
> both GDB and gdbserver to make sure everything works OK.
> 
> There is no "most important change" with this patch; all changes are
> made in a progressive way, making sure that gdbserver had the
> necessary features while not breaking GDB at the same time.
> 
> I decided to go ahead and implement a partial support for starting the
> inferior with a shell on gdbserver, although the full feature comes in
> the next patch.  The user won't have the option to disable the
> startup-with-shell, and also won't be able to change which shell
> gdbserver will use (other than setting the $SHELL environment
> variable, that is).
> 
> Everything is working as expected, and no regressions were present
> during the tests.

I just started to play with GDB on macOS, and it seems currently broken, 
a bisect pointed me to this commit 
(2090129c36c7e582943b7d300968d19b46160d84).

When trying to run/start, I get this:

Temporary breakpoint 1 at 0x100000fb6: file /Users/simark/test.c, line 
2.
Starting program: /Users/simark/test
/Users/simark/src/binutils-gdb/gdb/darwin-nat.c:383: internal-error: 
void darwin_check_new_threads(struct inferior *): Assertion `tp' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)

I haven't investigated yet, but I thought I'd share the information in 
case somebody is interested .

I am CCing Tristan because he's the last person who made fixes to keep 
the macOS support somewhat working (thanks!).  If you could at least 
tell if you get the same error, it would be helpful.

Thanks,

Simon

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-21 17:01     ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Simon Marchi
@ 2017-06-21 17:19       ` Sergio Durigan Junior
  0 siblings, 0 replies; 157+ messages in thread
From: Sergio Durigan Junior @ 2017-06-21 17:19 UTC (permalink / raw)
  To: Simon Marchi; +Cc: GDB Patches, Pedro Alves, Tristan Gingold

On Wednesday, June 21 2017, Simon Marchi wrote:

> On 2017-06-05 00:18, Sergio Durigan Junior wrote:
>> This is the most important (and the biggest, sorry) patch of the
>> series.  It moves fork_inferior from gdb/fork-child.c to
>> common/common-fork-child.c and makes all the necessary adjustments to
>> both GDB and gdbserver to make sure everything works OK.
>>
>> There is no "most important change" with this patch; all changes are
>> made in a progressive way, making sure that gdbserver had the
>> necessary features while not breaking GDB at the same time.
>>
>> I decided to go ahead and implement a partial support for starting the
>> inferior with a shell on gdbserver, although the full feature comes in
>> the next patch.  The user won't have the option to disable the
>> startup-with-shell, and also won't be able to change which shell
>> gdbserver will use (other than setting the $SHELL environment
>> variable, that is).
>>
>> Everything is working as expected, and no regressions were present
>> during the tests.
>
> I just started to play with GDB on macOS, and it seems currently
> broken, a bisect pointed me to this commit
> (2090129c36c7e582943b7d300968d19b46160d84).
>
> When trying to run/start, I get this:
>
> Temporary breakpoint 1 at 0x100000fb6: file /Users/simark/test.c, line
> 2.
> Starting program: /Users/simark/test
> /Users/simark/src/binutils-gdb/gdb/darwin-nat.c:383: internal-error:
> void darwin_check_new_threads(struct inferior *): Assertion `tp'
> failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
> Quit this debugging session? (y or n)
>
> I haven't investigated yet, but I thought I'd share the information in
> case somebody is interested .
>
> I am CCing Tristan because he's the last person who made fixes to keep
> the macOS support somewhat working (thanks!).  If you could at least
> tell if you get the same error, it would be helpful.

I'll try to investigate as well, but for obvious reasons I don't have a
mac.  I'll keep you posted.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver")
  2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
  2017-01-03 23:32   ` Luis Machado
@ 2018-02-21  3:58   ` Joel Brobecker
  2018-02-21  6:15     ` [RFC] "gdbserver ... BASENAME_EXE" no longer works Sergio Durigan Junior
  1 sibling, 1 reply; 157+ messages in thread
From: Joel Brobecker @ 2018-02-21  3:58 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, palves

[-- Attachment #1: Type: text/plain, Size: 1652 bytes --]

Hello,

I just noticed that the following patch...

    commit 2090129c36c7e582943b7d300968d19b46160d84
    Date:   Thu Dec 22 21:11:11 2016 -0500
    Subject: Share fork_inferior et al with gdbserver

... caused a change of behavior in GDBserver, where the following
no longer works (unless '.' is in your PATH, but for me, that's
not a good idea):

    $ gdbserver  --once :4444 simple_main
    zsh:1: command not found: simple_main
    During startup program exited with code 127.
    Exiting

Prior to the change we we able to start simple_main without problems:

    $ gdbserver --once :4444 simple_main
    Process simple_main created; pid = 26579
    Listening on port 4444

Was that intentional? Reading the revision log, there is no mention
of this, and this was a fairly natural thing to be doing. This also
matches something we do with GDBserver as well, so it would make
the two tools consistent in that regard.

Attached is a preliminary hack meant to help me explore what would
be needed to bring this feature back. If we agree we want the feature
back, and that I'm doing it at the right location, I'll split it,
finish the C++-ification of the execv_argv class, and then resubmit
as an official RFA.

Comments on the code welcome, of course! (I feel like a C++ dummy,
sometimes).

Thanks!

On Thu, Dec 22, 2016 at 10:39:20PM -0500, Sergio Durigan Junior wrote:
> This is the most important (and the biggest, sorry) patch of the
> series.  It moves fork_inferior from gdb/fork-child.c to
> common/common-fork-child.c and makes all the necessary adjustments to
> both GDB and gdbserver to make sure everything works OK.
> [...]

-- 
Joel

[-- Attachment #2: 0001-WIP-GDBserver-no-longer-working-when-given-an-execut.patch --]
[-- Type: text/x-diff, Size: 11890 bytes --]

From 2f13f758b07ec2f65892f3708b5f44a922fceef8 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Tue, 20 Feb 2018 17:20:08 +0400
Subject: [PATCH] WIP: GDBserver no longer working when given an executable's
 basename

Recent versions of GDB are no longer able to start an executable
when the path to that executable is a basename. Eg:

    $ gdbserver  --once :4444 simple_main
    zsh:1: command not found: simple_main
    During startup program exited with code 127.
    Exiting

This is a regression which was introduced by the following commit:

    commit 2090129c36c7e582943b7d300968d19b46160d84
    Date:   Thu Dec 22 21:11:11 2016 -0500
    Subject: Share fork_inferior et al with gdbserver

Prior to this patch, each host that GDBserver was supporting
had its own create_inferior code, but the code in linux-low.c
prior to the change gives the idea of what one might be doing:

      execv (program, allargs);
      if (errno == ENOENT)
        execvp (program, allargs);

First we do an "execv", which doesn't search the path, but just
uses the program name as is. This is how our scenario used to work.
But if the executable couldn't be located with just the executable
name, then we'd try with execvp, which searches the PATH.

Today, this code has been factorized into a common implementation
of fork_inferior, which basically does:

      if (exec_fun != NULL)
        (*exec_fun) (argv[0], &argv[0], env);
      else
        execvp (argv[0], &argv[0]);

(The "exec_fun" case is only used in the case of Darwin, where
we have to provide the equivalent of the execvp function).

One could feel tempted to implement the same kind of approach
in fork_inferior, but it's not going to work, because we now
support running the inferior through the shell (so the execv
would apply to the shell, not the inferior).

Instead, what this patch does is explicitly handle the case where
the executable name is a basename, and that filename exists in
the current working directory - in that case, we implicitly
prepend that working directory and use that to execute it.

This is only a prototype, as you will see that there is a bit of
a C++-ification happening in execv_argv to make memory management
a little easier. If the principle of the patch is accepted, I will
likely split the patches in two, and also probably C++-ify the
code that quotes the arguments.

This patch has been validated on x86_64-linux, using both
the official testsuite as well as AdaCore's testsuite.
We ran the testsuite first in standalone native mode, and
then using the native-gdbserver board file.

Change-Id: I97268aacc724e07b3f8aff8d69b59c9f65615257
---
 gdb/common/filestuff.c  | 31 ++++++++++++++++++++
 gdb/common/filestuff.h  |  6 ++++
 gdb/nat/fork-inferior.c | 75 ++++++++++++++++++++++++++++++++++---------------
 gdb/source.c            | 33 ----------------------
 4 files changed, 90 insertions(+), 55 deletions(-)

diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c
index f5a754ffa66..e6e046dea12 100644
--- a/gdb/common/filestuff.c
+++ b/gdb/common/filestuff.c
@@ -145,6 +145,37 @@ fdwalk (int (*func) (void *, int), void *arg)
 
 #endif /* HAVE_FDWALK */
 
+/* See filestuff.h.  */
+
+int
+is_regular_file (const char *name, int *errno_ptr)
+{
+  struct stat st;
+  const int status = stat (name, &st);
+
+  /* Stat should never fail except when the file does not exist.
+     If stat fails, analyze the source of error and return True
+     unless the file does not exist, to avoid returning false results
+     on obscure systems where stat does not work as expected.  */
+
+  if (status != 0)
+    {
+      if (errno != ENOENT)
+        return 1;
+      *errno_ptr = ENOENT;
+      return 0;
+    }
+
+  if (S_ISREG (st.st_mode))
+    return 1;
+
+  if (S_ISDIR (st.st_mode))
+    *errno_ptr = EISDIR;
+  else
+    *errno_ptr = EINVAL;
+  return 0;
+}
+
 \f
 
 /* A vector holding all the fds open when notice_open_fds was called.  We
diff --git a/gdb/common/filestuff.h b/gdb/common/filestuff.h
index 92a2a5f4c70..64a0b963308 100644
--- a/gdb/common/filestuff.h
+++ b/gdb/common/filestuff.h
@@ -19,6 +19,12 @@
 #ifndef FILESTUFF_H
 #define FILESTUFF_H
 
+/* Return True if the file NAME exists and is a regular file.
+   If the result is false then *ERRNO_PTR is set to a useful value assuming
+   we're expecting a regular file.  */
+
+extern int is_regular_file (const char *name, int *errno_ptr);
+
 /* Note all the file descriptors which are open when this is called.
    These file descriptors will not be closed by close_most_fds.  */
 
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index 8b59387fa5a..4f089121fb9 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -27,6 +27,8 @@
 #include "signals-state-save-restore.h"
 #include "gdb_tilde_expand.h"
 #include <vector>
+#include "filenames.h"
+#include "host-defs.h"
 
 extern char **environ;
 
@@ -42,7 +44,7 @@ public:
   /* EXEC_FILE is the file to run.  ALLARGS is a string containing the
      arguments to the program.  If starting with a shell, SHELL_FILE
      is the shell to run.  Otherwise, SHELL_FILE is NULL.  */
-  execv_argv (const char *exec_file, const std::string &allargs,
+  execv_argv (const std::string &exec_file, const std::string &allargs,
 	      const char *shell_file);
 
   /* Return a pointer to the built argv, in the type expected by
@@ -63,12 +65,12 @@ private:
 
   /* Used when building an argv for a straight execv call, without
      going via the shell.  */
-  void init_for_no_shell (const char *exec_file,
+  void init_for_no_shell (const std::string &exec_file,
 			  const std::string &allargs);
 
   /* Used when building an argv for execing a shell that execs the
      child program.  */
-  void init_for_shell (const char *exec_file,
+  void init_for_shell (const std::string &exec_file,
 		       const std::string &allargs,
 		       const char *shell_file);
 
@@ -93,7 +95,7 @@ private:
    M_STORAGE.  */
 
 void
-execv_argv::init_for_no_shell (const char *exec_file,
+execv_argv::init_for_no_shell (const std::string &exec_file,
 			       const std::string &allargs)
 {
 
@@ -103,7 +105,7 @@ execv_argv::init_for_no_shell (const char *exec_file,
      allocations and string dups when 1 is sufficient.  */
   std::string &args_copy = m_storage = allargs;
 
-  m_argv.push_back (exec_file);
+  m_argv.push_back (exec_file.c_str ());
 
   for (size_t cur_pos = 0; cur_pos < args_copy.size ();)
     {
@@ -163,7 +165,7 @@ escape_bang_in_quoted_argument (const char *shell_file)
 
 /* See declaration.  */
 
-execv_argv::execv_argv (const char *exec_file,
+execv_argv::execv_argv (const std::string &exec_file,
 			const std::string &allargs,
 			const char *shell_file)
 {
@@ -176,7 +178,7 @@ execv_argv::execv_argv (const char *exec_file,
 /* See declaration.  */
 
 void
-execv_argv::init_for_shell (const char *exec_file,
+execv_argv::init_for_shell (const std::string &exec_file,
 			    const std::string &allargs,
 			    const char *shell_file)
 {
@@ -205,7 +207,7 @@ execv_argv::init_for_shell (const char *exec_file,
      on IRIX 4.0.1 can't deal with it.  So we only quote it if we need
      to.  */
   bool need_to_quote;
-  const char *p = exec_file;
+  const char *p = exec_file.c_str();
   while (1)
     {
       switch (*p)
@@ -239,7 +241,7 @@ execv_argv::init_for_shell (const char *exec_file,
   if (need_to_quote)
     {
       shell_command += '\'';
-      for (p = exec_file; *p != '\0'; ++p)
+      for (p = exec_file.c_str (); *p != '\0'; ++p)
 	{
 	  if (*p == '\'')
 	    shell_command += "'\\''";
@@ -295,7 +297,7 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   /* Set debug_fork then attach to the child while it sleeps, to debug.  */
   int debug_fork = 0;
   const char *shell_file;
-  const char *exec_file;
+  std::string exec_file;
   char **save_our_env;
   int i;
   int save_errno;
@@ -309,6 +311,47 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   else
     exec_file = exec_file_arg;
 
+  /* Check if the user wants to set a different working directory for
+     the inferior.  */
+  inferior_cwd = get_inferior_cwd ();
+
+  if (inferior_cwd != NULL)
+    {
+      /* Expand before forking because between fork and exec, the child
+	 process may only execute async-signal-safe operations.  */
+      expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
+      inferior_cwd = expanded_inferior_cwd.c_str ();
+    }
+
+  /* If EXEC_FILE is a basename, and that executable can be found in
+     the current working directory, then assume this is the executable
+     we want to run (that is, do not search the PATH).  This ensures
+     we preserve the traditional behavior where "gdb BASENAME_EXE" or
+     "gdbserver BASENAME_EXE", where BASENAME_EXE is the basename of
+     an executable, executes the BASENAME_EXE from the current working
+     directory, instead of either finding it on the PATH, or causing
+     an error because it could not be found in the PATH.  */
+  if (exec_file == lbasename (exec_file.c_str ()))
+    {
+      const char *base_dir = inferior_cwd;
+      if (base_dir == NULL)
+	base_dir = getcwd (NULL, 0);
+      if (base_dir != NULL)
+	{
+	  std::string exec_fullpath (base_dir);
+	  if (! IS_DIR_SEPARATOR (base_dir[strlen (base_dir) - 1]))
+	    exec_fullpath.append(SLASH_STRING);
+	  exec_fullpath.append(exec_file);
+
+	  int unused_errno;
+	  if (is_regular_file (exec_fullpath.c_str(), &unused_errno))
+	    exec_file = exec_fullpath;
+	}
+      else
+	warning (_("Error finding name of working directory: %s"),
+		 safe_strerror (errno));
+    }
+
   /* 'startup_with_shell' is declared in inferior.h and bound to the
      "set startup-with-shell" option.  If 0, we'll just do a
      fork/exec, no shell, so don't bother figuring out what shell.  */
@@ -342,18 +385,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
      the parent and child flushing the same data after the fork.  */
   gdb_flush_out_err ();
 
-  /* Check if the user wants to set a different working directory for
-     the inferior.  */
-  inferior_cwd = get_inferior_cwd ();
-
-  if (inferior_cwd != NULL)
-    {
-      /* Expand before forking because between fork and exec, the child
-	 process may only execute async-signal-safe operations.  */
-      expanded_inferior_cwd = gdb_tilde_expand (inferior_cwd);
-      inferior_cwd = expanded_inferior_cwd.c_str ();
-    }
-
   /* If there's any initialization of the target layers that must
      happen to prepare to handle the child we're about fork, do it
      now...  */
diff --git a/gdb/source.c b/gdb/source.c
index c6cb860fa64..e1281f978bb 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -669,39 +669,6 @@ info_source_command (const char *ignore, int from_tty)
 }
 \f
 
-/* Return True if the file NAME exists and is a regular file.
-   If the result is false then *ERRNO_PTR is set to a useful value assuming
-   we're expecting a regular file.  */
-
-static int
-is_regular_file (const char *name, int *errno_ptr)
-{
-  struct stat st;
-  const int status = stat (name, &st);
-
-  /* Stat should never fail except when the file does not exist.
-     If stat fails, analyze the source of error and return True
-     unless the file does not exist, to avoid returning false results
-     on obscure systems where stat does not work as expected.  */
-
-  if (status != 0)
-    {
-      if (errno != ENOENT)
-	return 1;
-      *errno_ptr = ENOENT;
-      return 0;
-    }
-
-  if (S_ISREG (st.st_mode))
-    return 1;
-
-  if (S_ISDIR (st.st_mode))
-    *errno_ptr = EISDIR;
-  else
-    *errno_ptr = EINVAL;
-  return 0;
-}
-
 /* Open a file named STRING, searching path PATH (dir names sep by some char)
    using mode MODE in the calls to open.  You cannot use this function to
    create files (O_CREAT).
-- 
2.11.0


^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [RFC] "gdbserver ... BASENAME_EXE" no longer works
  2018-02-21  3:58   ` [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver") Joel Brobecker
@ 2018-02-21  6:15     ` Sergio Durigan Junior
  2018-02-21  7:37       ` Joel Brobecker
  0 siblings, 1 reply; 157+ messages in thread
From: Sergio Durigan Junior @ 2018-02-21  6:15 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: GDB Patches, palves, Simon Marchi

On Tuesday, February 20 2018, Joel Brobecker wrote:

> Hello,
>
> I just noticed that the following patch...
>
>     commit 2090129c36c7e582943b7d300968d19b46160d84
>     Date:   Thu Dec 22 21:11:11 2016 -0500
>     Subject: Share fork_inferior et al with gdbserver
>
> ... caused a change of behavior in GDBserver, where the following
> no longer works (unless '.' is in your PATH, but for me, that's
> not a good idea):
>
>     $ gdbserver  --once :4444 simple_main
>     zsh:1: command not found: simple_main
>     During startup program exited with code 127.
>     Exiting
>
> Prior to the change we we able to start simple_main without problems:
>
>     $ gdbserver --once :4444 simple_main
>     Process simple_main created; pid = 26579
>     Listening on port 4444
>
> Was that intentional? Reading the revision log, there is no mention
> of this, and this was a fairly natural thing to be doing. This also
> matches something we do with GDBserver as well, so it would make
> the two tools consistent in that regard.
>
> Attached is a preliminary hack meant to help me explore what would
> be needed to bring this feature back. If we agree we want the feature
> back, and that I'm doing it at the right location, I'll split it,
> finish the C++-ification of the execv_argv class, and then resubmit
> as an official RFA.
>
> Comments on the code welcome, of course! (I feel like a C++ dummy,
> sometimes).

Hi, Joel,

Thanks for the patch.  Just a quick comment since it's past 1a.m. here.
I am trying to tackle this problem from a different angle here:

  https://sourceware.org/ml/gdb-patches/2018-02/msg00178.html

Simon's reply is here:

  https://sourceware.org/ml/gdb-patches/2018-02/msg00181.html

I still have to address it; I intend to do it tomorrow (sorry about the
delay).  I took a different approach than your patch, in that I'm doing
the path expansion before fork_inferior is even called.  The reason for
that is because we already take care of this on GDB by using openp, so I
thought it'd make more sense to modify only gdbserver in this case.

I confess I haven't looked deep into your code, but Simon has mentioned
that he'd like to avoid expanding filename-only paths that contain a
directory component on it.  For example a file name "dir/file" shouldn't
be expanded.

Anyway, I don't know right now if your approach makes more sense than
mine.  I'll give it more thought when I wake up (probably Pedro and/or
Simon will beat me to it).  I'm also planning on submitting v3 of my
current patch, unless the consensus is that your patch is better, of
course.

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [RFC] "gdbserver ... BASENAME_EXE" no longer works
  2018-02-21  6:15     ` [RFC] "gdbserver ... BASENAME_EXE" no longer works Sergio Durigan Junior
@ 2018-02-21  7:37       ` Joel Brobecker
  0 siblings, 0 replies; 157+ messages in thread
From: Joel Brobecker @ 2018-02-21  7:37 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches, palves, Simon Marchi

Hi Sergio,

Thanks for your preliminary answer and the pointers to your own
set of patches. I considered doing it for gdbserver only, but
thought it was less code doing it there than in in gdbserver
directly (you have to handle the case both when the executable
is passed via the command-line and the case when it's passed
via the remote protocol).

But I'm happy with your approach, as it avoids some unnecessary
work in the case of GDB (the overhead is a call to lbasename,
which is guaranteed to always return a different string than
the origin exec_file).

I'll send my comments for your patches...

-- 
Joel

^ permalink raw reply	[flat|nested] 157+ messages in thread

* Re: [PATCH v7 3/4] Share fork_inferior et al with gdbserver
  2017-06-08  0:00             ` Sergio Durigan Junior
@ 2019-02-14 15:38               ` Thomas Schwinge
  0 siblings, 0 replies; 157+ messages in thread
From: Thomas Schwinge @ 2019-02-14 15:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Sergio Durigan Junior, Pedro Alves

[-- Attachment #1: Type: text/plain, Size: 1004 bytes --]

Hi!

On Wed, 07 Jun 2017 20:00:00 -0400, Sergio Durigan Junior <sergiodj@redhat.com> wrote:
> On Wednesday, June 07 2017, Pedro Alves wrote:
> 
> > In the commit log:
> >
> > On 06/07/2017 11:15 PM, Sergio Durigan Junior wrote:
> >> This is the most important (and the biggest, sorry) patch of the
> >> series.  It moves fork_inferior from gdb/fork-child.c to
> >> common/common-fork-child.c and makes all the necessary adjustments to
> >> both GDB and gdbserver to make sure everything works OK.
> >
> > common/common-fork-child.c -> nat/fork-inferior.c
> >
> > Series is OK.  Please push.
> 
> Thanks, pushed.
> 
> aefd8b33d97bded58e51d75271f99e1eaec9fb28
> 2090129c36c7e582943b7d300968d19b46160d84
> 043a49349c713dc329a2dfc413b082c3826ecdb8
> 156525114c1cbbace0dec223494b842ffc60d52e

Pushed to master the attached commit
6c6ef69fb4e95d991fa5462d067d3f71a73fedce '[gdb, hurd] Repair build after
"Share fork_inferior et al with gdbserver" changes'.


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-gdb-hurd-Repair-build-after-Share-fork_inferior-et-a.patch --]
[-- Type: text/x-diff, Size: 3874 bytes --]

From 6c6ef69fb4e95d991fa5462d067d3f71a73fedce Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 4 Jul 2018 13:27:09 +0200
Subject: [PATCH] [gdb, hurd] Repair build after "Share fork_inferior et al
 with gdbserver" changes

..., that is commit 2090129c36c7e582943b7d300968d19b46160d84 causing:

    [...]/gdb/gnu-nat.c: In function 'void gnu_ptrace_me()':
    [...]/gdb/gnu-nat.c:2133:5: error: 'trace_start_error_with_name' was not declared in this scope
         trace_start_error_with_name ("ptrace");
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    [...]/gdb/gnu-nat.c:2133:5: note: suggested alternative: 'throw_perror_with_name'
         trace_start_error_with_name ("ptrace");
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
         throw_perror_with_name
    [...]/gdb/gnu-nat.c: In function 'void gnu_create_inferior(target_ops*, const char*, const string&, char**, int)':
    [...]/gdb/gnu-nat.c:2147:9: error: 'fork_inferior' was not declared in this scope
       pid = fork_inferior (exec_file, allargs, env, gnu_ptrace_me,
             ^~~~~~~~~~~~~
    [...]/gdb/gnu-nat.c:2147:9: note: suggested alternative: 'exit_inferior'
       pid = fork_inferior (exec_file, allargs, env, gnu_ptrace_me,
             ^~~~~~~~~~~~~
             exit_inferior
    [...]/gdb/gnu-nat.c:2174:30: error: 'START_INFERIOR_TRAPS_EXPECTED' was not declared in this scope
       gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED);
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /usr/bin/ld: gnu-nat.o: in function `gnu_ptrace_me()':
    [...]/gdb/gnu-nat.c:2134: undefined reference to `trace_start_error_with_name(char const*)'
    /usr/bin/ld: gnu-nat.o: in function `gnu_create_inferior(target_ops*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char**, int)':
    [...]/gdb/gnu-nat.c:2148: undefined reference to `fork_inferior(char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char**, void (*)(), void (*)(int), void (*)(), char const*, void (*)(char const*, char* const*, char* const*))'
    /usr/bin/ld: fork-child.o: in function `gdb_startup_inferior(int, int)':
    [...]/gdb/fork-child.c:136: undefined reference to `startup_inferior(int, int, target_waitstatus*, ptid_t*)'
    collect2: error: ld returned 1 exit status

	gdb/
	* configure.nat [gdb_host == i386gnu] (NATDEPFILES): Add
	'nat/fork-inferior.o'.
	* gnu-nat.c: #include "nat/fork-inferior.h".
---
 gdb/ChangeLog     | 4 ++++
 gdb/configure.nat | 1 +
 gdb/gnu-nat.c     | 1 +
 3 files changed, 6 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index fcaae6125e..2974d7275c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,9 @@
 2019-02-14  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* configure.nat [gdb_host == i386gnu] (NATDEPFILES): Add
+	'nat/fork-inferior.o'.
+	* gnu-nat.c: #include "nat/fork-inferior.h".
+
 	* gnu-nat.c (gnu_nat_target::detach): Instead of
 	'inf_child_maybe_unpush_target (ops)' call 'maybe_unpush_target'.
 	* gnu-nat.h: #include "inf-child.h".
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 3118263ac6..64ee101d83 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -215,6 +215,7 @@ case ${gdb_host} in
 		# Host: Intel 386 running the GNU Hurd
 		NATDEPFILES='i386-gnu-nat.o gnu-nat.o \
 		     x86-nat.o nat/x86-dregs.o fork-child.o \
+		     nat/fork-inferior.o \
 		     notify_S.o process_reply_S.o msg_reply_S.o \
 		     msg_U.o exc_request_U.o exc_request_S.o'
 		HAVE_NATIVE_GCORE_HOST=1
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 78966c805d..5a47cb7d63 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -69,6 +69,7 @@ extern "C"
 #include "gdbthread.h"
 #include "gdb_obstack.h"
 #include "tid-parse.h"
+#include "nat/fork-inferior.h"
 
 #include "inf-child.h"
 
-- 
2.19.2


^ permalink raw reply	[flat|nested] 157+ messages in thread

end of thread, other threads:[~2019-02-14 15:38 UTC | newest]

Thread overview: 157+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2017-01-03 21:16     ` Sergio Durigan Junior
2016-12-23  3:39 ` [PATCH 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2016-12-23  3:39 ` [PATCH 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
2016-12-26 21:35   ` Luis Machado
2017-01-03 21:14     ` Sergio Durigan Junior
2017-01-03 21:27       ` Luis Machado
2017-01-03 21:38         ` Sergio Durigan Junior
2016-12-23  3:45 ` [PATCH 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2016-12-26 21:35   ` Luis Machado
2017-01-03 21:31     ` Sergio Durigan Junior
2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-01-03 23:32   ` Luis Machado
2017-01-05 20:11     ` Sergio Durigan Junior
2018-02-21  3:58   ` [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver") Joel Brobecker
2018-02-21  6:15     ` [RFC] "gdbserver ... BASENAME_EXE" no longer works Sergio Durigan Junior
2018-02-21  7:37       ` Joel Brobecker
2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2016-12-23  8:07   ` Eli Zaretskii
2017-01-03 20:48     ` Sergio Durigan Junior
2017-01-04 16:08       ` Eli Zaretskii
2017-01-05 20:12         ` Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2017-01-03 21:35     ` Sergio Durigan Junior
2016-12-27  0:26   ` Tom Tromey
2017-01-03 21:32     ` Sergio Durigan Junior
2016-12-23  7:50 ` [PATCH 0/6] Implement the ability to start inferiors with a shell " Eli Zaretskii
2017-01-03 20:23   ` Sergio Durigan Junior
2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
2017-02-01 18:37     ` Luis Machado
2017-02-07 22:39       ` Sergio Durigan Junior
2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-01-18 16:43     ` Eli Zaretskii
2017-02-01 19:07     ` Luis Machado
2017-01-18 15:36   ` [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
2017-02-01 18:41     ` Luis Machado
2017-01-18 15:36   ` [PATCH v2 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
2017-02-01 20:35     ` Luis Machado
2017-01-18 15:42   ` [PATCH v2 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2017-02-01 18:54     ` Luis Machado
2017-02-07 22:42       ` Sergio Durigan Junior
2017-02-08  9:07         ` Luis Machado
2017-01-18 15:44   ` [PATCH v2 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-02-01 21:39     ` Luis Machado
2017-02-07 22:23       ` Sergio Durigan Junior
2017-01-26 22:47   ` [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2017-01-27  7:45     ` Eli Zaretskii
2017-01-27 17:59       ` Sergio Durigan Junior
2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
2017-02-15 15:54       ` Pedro Alves
2017-02-16 21:37         ` Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 3/6] Share parts of gdb/inflow.c " Sergio Durigan Junior
2017-02-15 16:02       ` Pedro Alves
2017-02-16 22:06         ` Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
2017-02-15 15:36       ` Pedro Alves
2017-03-07 20:50         ` Sergio Durigan Junior
2017-02-08  3:32     ` [PATCH v3 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-02-15 17:28       ` Pedro Alves
2017-02-16 12:23         ` Philipp Rudo
2017-02-16 12:26           ` Pedro Alves
2017-02-16 12:37             ` Philipp Rudo
2017-03-07 19:51         ` Sergio Durigan Junior
2017-03-13 15:34           ` Pedro Alves
2017-02-08  3:33     ` [PATCH v3 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2017-02-15 16:15       ` Pedro Alves
2017-02-21 21:27         ` Sergio Durigan Junior
2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-02-08 17:34       ` Eli Zaretskii
2017-02-09  0:02         ` Sergio Durigan Junior
2017-02-17 16:05       ` Pedro Alves
2017-02-17 16:27         ` Eli Zaretskii
2017-03-07 20:59         ` Sergio Durigan Junior
2017-03-13 15:12           ` Pedro Alves
2017-02-13 19:50     ` [PATCH v3 0/6] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 1/5] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-03-08 15:49         ` Eli Zaretskii
2017-03-13 17:26         ` Pedro Alves
2017-03-08  5:29       ` [PATCH v4 2/5] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 3/5] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 4/5] Share fork_inferior et al " Sergio Durigan Junior
2017-03-13 17:04         ` Pedro Alves
2017-03-17  1:02           ` Sergio Durigan Junior
2017-03-17 10:27             ` Pedro Alves
2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
2017-03-31 17:11     ` Pedro Alves
2017-03-31 17:31       ` Sergio Durigan Junior
2017-03-31 18:21         ` Pedro Alves
2017-03-31 21:20           ` Sergio Durigan Junior
2017-04-07 17:51             ` Pedro Alves
2017-04-12  0:25               ` Sergio Durigan Junior
2017-04-12  1:17                 ` [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h) Sergio Durigan Junior
2017-04-12 10:28                   ` Pedro Alves
2017-04-12 22:00                     ` Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior Sergio Durigan Junior
2017-04-07 18:30     ` Pedro Alves
2017-04-12  0:24       ` Sergio Durigan Junior
2017-04-12  5:04         ` Sergio Durigan Junior
2017-04-12  5:19           ` [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior) Sergio Durigan Junior
2017-04-12 10:14           ` [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior) Pedro Alves
2017-04-12 22:26             ` Sergio Durigan Junior
2017-04-13  3:42               ` Pedro Alves
2017-04-13  4:33                 ` Sergio Durigan Junior
2017-04-13 10:51                   ` Pedro Alves
2017-04-13 18:30                     ` Sergio Durigan Junior
2017-04-14  1:03           ` [obv/commit] Fix build breakage on Cygwin (PR gdb/21385) Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-03-31 17:15     ` Pedro Alves
2017-04-07  2:53       ` Sergio Durigan Junior
2017-04-07 17:33         ` Pedro Alves
2017-03-30  1:55   ` [PATCH v5 4/5] Share fork_inferior et al " Sergio Durigan Junior
2017-03-30  1:55   ` [PATCH v5 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-05-05 19:04     ` Pedro Alves
2017-05-06 14:15       ` Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 3/4] Share fork_inferior et al " Sergio Durigan Junior
2017-05-05 19:05     ` Pedro Alves
2017-05-31  3:43       ` Sergio Durigan Junior
2017-06-07 10:16         ` Pedro Alves
2017-06-07 12:23           ` Pedro Alves
2017-06-07 21:01             ` Sergio Durigan Junior
2017-06-07 21:06               ` Pedro Alves
2017-06-07 21:00           ` Sergio Durigan Junior
2017-05-04  5:38   ` [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-05-05 19:21     ` Pedro Alves
2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
2017-06-05  2:31     ` Eli Zaretskii
2017-06-04 22:18   ` [PATCH v7 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al " Sergio Durigan Junior
2017-06-07 12:29     ` Pedro Alves
2017-06-07 21:06       ` Sergio Durigan Junior
2017-06-07 21:41         ` Sergio Durigan Junior
2017-06-07 22:05           ` Pedro Alves
2017-06-07 22:08             ` Sergio Durigan Junior
2017-06-07 22:14               ` Pedro Alves
2017-06-07 22:15         ` Sergio Durigan Junior
2017-06-07 22:29           ` Pedro Alves
2017-06-08  0:00             ` Sergio Durigan Junior
2019-02-14 15:38               ` Thomas Schwinge
2017-06-08 16:40     ` Yao Qi
2017-06-08 18:49       ` Sergio Durigan Junior
2017-06-08 21:02       ` [commit/obvious] Fix possible bug when no args have been provided to the executable Sergio Durigan Junior
2017-06-09 22:19       ` [commit/obvious] Include <signal.h> on gdbserver/fork-child.c (and fix regressions) Sergio Durigan Junior
2017-06-21 17:01     ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Simon Marchi
2017-06-21 17:19       ` Sergio Durigan Junior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).