From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 114309 invoked by alias); 3 Jan 2017 23:32:45 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 114278 invoked by uid 89); 3 Jan 2017 23:32:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.6 required=5.0 tests=AWL,BAYES_50,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=Quote, environ, 170,9, 1709 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 03 Jan 2017 23:32:30 +0000 Received: from svr-orw-mbx-03.mgc.mentorg.com ([147.34.90.203]) by relay1.mentorg.com with esmtp id 1cOYZA-0004sA-0P from Luis_Gustavo@mentor.com ; Tue, 03 Jan 2017 15:32:28 -0800 Received: from [172.30.9.137] (147.34.91.1) by svr-orw-mbx-03.mgc.mentorg.com (147.34.90.203) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Tue, 3 Jan 2017 15:32:23 -0800 Subject: Re: [PATCH 5/6] Share fork_inferior et al with gdbserver References: <1482464361-4068-1-git-send-email-sergiodj@redhat.com> <1482464361-4068-6-git-send-email-sergiodj@redhat.com> To: Sergio Durigan Junior , GDB Patches CC: From: Luis Machado Reply-To: Luis Machado Message-ID: <527b35bd-f2c2-094d-b10a-588df7ad7a3a@codesourcery.com> Date: Tue, 03 Jan 2017 23:32:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.5.1 MIME-Version: 1.0 In-Reply-To: <1482464361-4068-6-git-send-email-sergiodj@redhat.com> Content-Type: text/plain; charset="windows-1252"; format=flowed Content-Transfer-Encoding: 7bit X-ClientProxiedBy: svr-orw-mbx-03.mgc.mentorg.com (147.34.90.203) To svr-orw-mbx-03.mgc.mentorg.com (147.34.90.203) X-IsSubscribed: yes X-SW-Source: 2017-01/txt/msg00036.txt.bz2 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 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 > > * 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 > > * 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. > (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) : Update prototype > to accept one std::vector 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 > > * 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 . */ > > -#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 > - > -/* 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 . */ > + > +#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 . */ > > -#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 > > -/* 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 > - ". */ > - 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 > +#include "common-inferior.h" > +#include "environ.h" > #ifndef ELFMAG0 > /* Don't include 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 &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 &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 &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 program_argv; > +static std::vector 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::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 &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::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 &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 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 > > /* 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 &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 &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 &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 > > 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 &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 &v) > +{ > + for (std::vector::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 &argv) > +{ > + std::string ret (""); > + > + for (std::vector::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 > + > 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 &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 &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 &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