[PATCH 5/6] Share fork_inferior et al with gdbserver
Luis Machado
lgustavo@codesourcery.com
Tue Jan 3 23:32:00 GMT 2017
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
More information about the Gdb-patches
mailing list