aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorSergio Durigan Junior <sergiodj@redhat.com>2016-12-22 21:11:11 -0500
committerSergio Durigan Junior <sergiodj@redhat.com>2017-06-07 19:56:09 -0400
commit2090129c36c7e582943b7d300968d19b46160d84 (patch)
treed7abde0c9c147cb404a6a0794adb49c26c29b015 /gdb/gdbserver
parent043a49349c713dc329a2dfc413b082c3826ecdb8 (diff)
downloadgdb-2090129c36c7e582943b7d300968d19b46160d84.zip
gdb-2090129c36c7e582943b7d300968d19b46160d84.tar.gz
gdb-2090129c36c7e582943b7d300968d19b46160d84.tar.bz2
Share fork_inferior et al with gdbserver
This is the most important (and the biggest, sorry) patch of the series. It moves fork_inferior from gdb/fork-child.c to nat/fork-inferior.c and makes all the necessary adjustments to both GDB and gdbserver to make sure everything works OK. There is no "most important change" with this patch; all changes are made in a progressive way, making sure that gdbserver had the necessary features while not breaking GDB at the same time. I decided to go ahead and implement a partial support for starting the inferior with a shell on gdbserver, although the full feature comes in the next patch. The user won't have the option to disable the startup-with-shell, and also won't be able to change which shell gdbserver will use (other than setting the $SHELL environment variable, that is). Everything is working as expected, and no regressions were present during the tests. gdb/ChangeLog: 2017-06-07 Sergio Durigan Junior <sergiodj@redhat.com> Pedro Alves <palves@redhat.com> * Makefile.in (HFILES_NO_SRCDIR): Add "common/common-inferior.h" and "nat/fork-inferior.h". * common/common-inferior.h: New file, with contents from "gdb/inferior.h". * commom/common-utils.c: Include "common-utils.h". (stringify_argv): New function. * common/common-utils.h (stringify_argv): New prototype. * configure.nat: Add "fork-inferior.o" as a dependency for "*linux*", "fbsd*" and "nbsd*" hosts. * corefile.c (get_exec_file): Update comment. * darwin-nat.c (darwin_ptrace_him): Call "gdb_startup_inferior" instead of "startup_inferior". (darwin_create_inferior): Call "add_thread_silent" after "fork_inferior". * fork-child.c: Cleanup unnecessary includes. (SHELL_FILE): Move to "common/common-fork-child.c". (environ): Likewise. (exec_wrapper): Initialize. (get_exec_wrapper): New function. (breakup_args): Move to "common/common-fork-child.c"; rename to "breakup_args_for_exec". (escape_bang_in_quoted_argument): Move to "common/common-fork-child.c". (saved_ui): New variable. (prefork_hook): New function. (postfork_hook): Likewise. (postfork_child_hook): Likewise. (gdb_startup_inferior): Likewise. (fork_inferior): Move to "common/common-fork-child.c". Update function to support gdbserver. (startup_inferior): Likewise. * gdbcore.h (get_exec_file): Remove declaration. * gnu-nat.c (gnu_create_inferior): Call "gdb_startup_inferior" instead of "startup_inferior". Call "add_thread_silent" after "fork_inferior". * inf-ptrace.c: Include "nat/fork-inferior.h" and "utils.h". (inf_ptrace_create_inferior): Call "gdb_startup_inferior" instead of "startup_inferior". Call "add_thread_silent" after "fork_inferior". * inferior.h: Include "common-inferior.h". (trace_start_error): Move to "common/common-utils.h". (trace_start_error_with_name): Likewise. (fork_inferior): Move prototype to "nat/fork-inferior.h". (startup_inferior): Likewise. (gdb_startup_inferior): New prototype. * nat/fork-inferior.c: New file, with contents from "fork-child.c". * nat/fork-inferior.h: New file. * procfs.c (procfs_init_inferior): Call "gdb_startup_inferior" instead of "startup_inferior". Call "add_thread_silent" after "fork_inferior". * target.h (target_terminal_init): Move prototype to "target/target.h". (target_terminal_inferior): Likewise. (target_terminal_ours): Likewise. * target/target.h (target_terminal_init): New prototype, moved from "target.h". (target_terminal_inferior): Likewise. (target_terminal_ours): Likewise. * utils.c (gdb_flush_out_err): New function. gdb/gdbserver/ChangeLog: 2017-06-07 Sergio Durigan Junior <sergiodj@redhat.com> Pedro Alves <palves@redhat.com> * Makefile.in (SFILES): Add "nat/fork-inferior.o". * configure: Regenerate. * configure.srv (srv_linux_obj): Add "fork-child.o" and "fork-inferior.o". (i[34567]86-*-lynxos*): Likewise. (spu*-*-*): Likewise. * fork-child.c: New file. * linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h" and "environ.h". (linux_ptrace_fun): New function. (linux_create_inferior): Adjust function prototype to reflect change on "target.h". Adjust function code to use "fork_inferior". (linux_request_interrupt): Delete "signal_pid". * lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". (lynx_ptrace_fun): New function. (lynx_create_inferior): Adjust function prototype to reflect change on "target.h". Adjust function code to use "fork_inferior". * nto-low.c (nto_create_inferior): Adjust function prototype and code to reflect change on "target.h". Update comments. * server.c: Include "common-inferior.h", "nat/fork-inferior.h", "common-terminal.h" and "environ.h". (terminal_fd): Moved to fork-child.c. (old_foreground_pgrp): Likewise. (restore_old_foreground_pgrp): Likewise. (last_status): Make it global. (last_ptid): Likewise. (our_environ): New variable. (startup_with_shell): Likewise. (program_name): Likewise. (program_argv): Rename to... (program_args): ...this. (wrapper_argv): New variable. (start_inferior): Delete function. (get_exec_wrapper): New function. (get_exec_file): Likewise. (get_environ): Likewise. (prefork_hook): Likewise. (post_fork_inferior): Likewise. (postfork_hook): Likewise. (postfork_child_hook): Likewise. (handle_v_run): Update code to deal with arguments coming from the remote host. Update calls from "start_inferior" to "create_inferior". (captured_main): Likewise. Initialize environment variable. Call "have_job_control". * server.h (post_fork_inferior): New prototype. (get_environ): Likewise. (last_status): Declare. (last_ptid): Likewise. (signal_pid): Likewise. * spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". (spu_ptrace_fun): New function. (spu_create_inferior): Adjust function prototype to reflect change on "target.h". Adjust function code to use "fork_inferior". * target.c (target_terminal_init): New function. (target_terminal_inferior): Likewise. (target_terminal_ours): Likewise. * target.h: Include <vector>. (struct target_ops) <create_inferior>: Update prototype. (create_inferior): Update macro. * utils.c (gdb_flush_out_err): New function. * win32-low.c (win32_create_inferior): Adjust function prototype and code to reflect change on "target.h". gdb/testsuite/ChangeLog: 2017-06-07 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.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog69
-rw-r--r--gdb/gdbserver/Makefile.in1
-rw-r--r--gdb/gdbserver/configure.srv6
-rw-r--r--gdb/gdbserver/fork-child.c113
-rw-r--r--gdb/gdbserver/linux-low.c91
-rw-r--r--gdb/gdbserver/lynx-low.c51
-rw-r--r--gdb/gdbserver/nto-low.c10
-rw-r--r--gdb/gdbserver/server.c240
-rw-r--r--gdb/gdbserver/server.h14
-rw-r--r--gdb/gdbserver/spu-low.c44
-rw-r--r--gdb/gdbserver/target.c27
-rw-r--r--gdb/gdbserver/target.h13
-rw-r--r--gdb/gdbserver/win32-low.c23
13 files changed, 467 insertions, 235 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 840cf79..275f65c 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,4 +1,73 @@
2017-06-07 Sergio Durigan Junior <sergiodj@redhat.com>
+ Pedro Alves <palves@redhat.com>
+
+ * Makefile.in (SFILES): Add "nat/fork-inferior.o".
+ * configure: Regenerate.
+ * configure.srv (srv_linux_obj): Add "fork-child.o" and
+ "fork-inferior.o".
+ (i[34567]86-*-lynxos*): Likewise.
+ (spu*-*-*): Likewise.
+ * fork-child.c: New file.
+ * linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h"
+ and "environ.h".
+ (linux_ptrace_fun): New function.
+ (linux_create_inferior): Adjust function prototype to reflect
+ change on "target.h". Adjust function code to use
+ "fork_inferior".
+ (linux_request_interrupt): Delete "signal_pid".
+ * lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
+ (lynx_ptrace_fun): New function.
+ (lynx_create_inferior): Adjust function prototype to reflect
+ change on "target.h". Adjust function code to use
+ "fork_inferior".
+ * nto-low.c (nto_create_inferior): Adjust function prototype and
+ code to reflect change on "target.h". Update comments.
+ * server.c: Include "common-inferior.h", "nat/fork-inferior.h",
+ "common-terminal.h" and "environ.h".
+ (terminal_fd): Moved to fork-child.c.
+ (old_foreground_pgrp): Likewise.
+ (restore_old_foreground_pgrp): Likewise.
+ (last_status): Make it global.
+ (last_ptid): Likewise.
+ (our_environ): New variable.
+ (startup_with_shell): Likewise.
+ (program_name): Likewise.
+ (program_argv): Rename to...
+ (program_args): ...this.
+ (wrapper_argv): New variable.
+ (start_inferior): Delete function.
+ (get_exec_wrapper): New function.
+ (get_exec_file): Likewise.
+ (get_environ): Likewise.
+ (prefork_hook): Likewise.
+ (post_fork_inferior): Likewise.
+ (postfork_hook): Likewise.
+ (postfork_child_hook): Likewise.
+ (handle_v_run): Update code to deal with arguments coming from the
+ remote host. Update calls from "start_inferior" to
+ "create_inferior".
+ (captured_main): Likewise. Initialize environment variable. Call
+ "have_job_control".
+ * server.h (post_fork_inferior): New prototype.
+ (get_environ): Likewise.
+ (last_status): Declare.
+ (last_ptid): Likewise.
+ (signal_pid): Likewise.
+ * spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h".
+ (spu_ptrace_fun): New function.
+ (spu_create_inferior): Adjust function prototype to reflect change
+ on "target.h". Adjust function code to use "fork_inferior".
+ * target.c (target_terminal_init): New function.
+ (target_terminal_inferior): Likewise.
+ (target_terminal_ours): Likewise.
+ * target.h: Include <vector>.
+ (struct target_ops) <create_inferior>: Update prototype.
+ (create_inferior): Update macro.
+ * utils.c (gdb_flush_out_err): New function.
+ * win32-low.c (win32_create_inferior): Adjust function prototype
+ and code to reflect change on "target.h".
+
+2017-06-07 Sergio Durigan Junior <sergiodj@redhat.com>
* inferiors.c (switch_to_thread): New function.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d9f55de..834425d 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -218,6 +218,7 @@ SFILES = \
$(srcdir)/nat/linux-personality.c \
$(srcdir)/nat/mips-linux-watch.c \
$(srcdir)/nat/ppc-linux.c \
+ $(srcdir)/nat/fork-inferior.c \
$(srcdir)/target/waitstatus.c
DEPFILES = @GDBSERVER_DEPFILES@
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index d00d9e2..43f90c9 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -43,7 +43,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
# Linux object files. This is so we don't have to repeat
# these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o fork-child.o fork-inferior.o"
# Input is taken from the "${target}" variable.
@@ -131,7 +131,7 @@ case "${target}" in
ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
;;
i[34567]86-*-lynxos*) srv_regobj="i386.o"
- srv_tgtobj="lynx-low.o lynx-i386-low.o"
+ srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o fork-inferior.o"
srv_xmlfiles="i386/i386.xml"
srv_xmlfiles="${srv_xmlfiles} i386/32bit-core.xml"
srv_xmlfiles="${srv_xmlfiles} i386/32bit-sse.xml"
@@ -338,7 +338,7 @@ case "${target}" in
srv_linux_thread_db=yes
;;
spu*-*-*) srv_regobj=reg-spu.o
- srv_tgtobj="spu-low.o"
+ srv_tgtobj="spu-low.o fork-child.o fork-inferior.o"
;;
tic6x-*-uclinux) srv_regobj="tic6x-c64xp-linux.o"
srv_regobj="${srv_regobj} tic6x-c64x-linux.o"
diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
new file mode 100644
index 0000000..a1a8ff1
--- /dev/null
+++ b/gdb/gdbserver/fork-child.c
@@ -0,0 +1,113 @@
+/* Fork a Unix child process, and set up to debug it, for GDBserver.
+ Copyright (C) 1989-2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "server.h"
+#include "job-control.h"
+#include "nat/fork-inferior.h"
+
+#ifdef SIGTTOU
+/* A file descriptor for the controlling terminal. */
+static int terminal_fd;
+
+/* TERMINAL_FD's original foreground group. */
+static pid_t old_foreground_pgrp;
+
+/* Hand back terminal ownership to the original foreground group. */
+
+static void
+restore_old_foreground_pgrp (void)
+{
+ tcsetpgrp (terminal_fd, old_foreground_pgrp);
+}
+#endif
+
+/* See nat/fork-inferior.h. */
+
+void
+prefork_hook (const char *args)
+{
+ if (debug_threads)
+ {
+ debug_printf ("args: %s\n", args);
+ debug_flush ();
+ }
+
+#ifdef SIGTTOU
+ signal (SIGTTOU, SIG_DFL);
+ signal (SIGTTIN, SIG_DFL);
+#endif
+
+ /* Clear this so the backend doesn't get confused, thinking
+ CONT_THREAD died, and it needs to resume all threads. */
+ cont_thread = null_ptid;
+}
+
+/* See nat/fork-inferior.h. */
+
+void
+postfork_hook (pid_t pid)
+{
+}
+
+/* See nat/fork-inferior.h. */
+
+void
+postfork_child_hook ()
+{
+ /* This is set to the result of setpgrp, which if vforked, will be
+ visible to you in the parent process. It's only used by humans
+ for debugging. */
+ static int debug_setpgrp = 657473;
+
+ debug_setpgrp = gdb_setpgid ();
+ if (debug_setpgrp == -1)
+ perror (_("setpgrp failed in child"));
+}
+
+/* See nat/fork-inferior.h. */
+
+void
+gdb_flush_out_err ()
+{
+ fflush (stdout);
+ fflush (stderr);
+}
+
+/* See server.h. */
+
+void
+post_fork_inferior (int pid, const char *program)
+{
+#ifdef SIGTTOU
+ signal (SIGTTOU, SIG_IGN);
+ signal (SIGTTIN, SIG_IGN);
+ terminal_fd = fileno (stderr);
+ old_foreground_pgrp = tcgetpgrp (terminal_fd);
+ tcsetpgrp (terminal_fd, pid);
+ atexit (restore_old_foreground_pgrp);
+#endif
+
+ startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
+ &last_status, &last_ptid);
+ current_thread->last_resume_kind = resume_stop;
+ current_thread->last_status = last_status;
+ signal_pid = pid;
+ target_post_create_inferior ();
+ fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
+ fflush (stderr);
+}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ea3c81b..7fbf744 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,9 @@
#include "tracepoint.h"
#include "hostio.h"
#include <inttypes.h>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "environ.h"
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -946,59 +949,57 @@ add_lwp (ptid_t ptid)
return lwp;
}
+/* Callback to be used when calling fork_inferior, responsible for
+ actually initiating the tracing of the inferior. */
+
+static void
+linux_ptrace_fun ()
+{
+ if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+ (PTRACE_TYPE_ARG4) 0) < 0)
+ trace_start_error_with_name ("ptrace");
+
+ if (setpgid (0, 0) < 0)
+ trace_start_error_with_name ("setpgid");
+
+ /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+ stdout to stderr so that inferior i/o doesn't corrupt the connection.
+ Also, redirect stdin to /dev/null. */
+ if (remote_connection_is_stdio ())
+ {
+ if (close (0) < 0)
+ trace_start_error_with_name ("close");
+ if (open ("/dev/null", O_RDONLY) < 0)
+ trace_start_error_with_name ("open");
+ if (dup2 (2, 1) < 0)
+ trace_start_error_with_name ("dup2");
+ if (write (2, "stdin/stdout redirected\n",
+ sizeof ("stdin/stdout redirected\n") - 1) < 0)
+ {
+ /* Errors ignored. */;
+ }
+ }
+}
+
/* Start an inferior process and returns its pid.
- ALLARGS is a vector of program-name and args. */
+ PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+ are its arguments. */
static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
struct lwp_info *new_lwp;
int pid;
ptid_t ptid;
struct cleanup *restore_personality
= maybe_disable_address_space_randomization (disable_randomization);
+ std::string str_program_args = stringify_argv (program_args);
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
- pid = vfork ();
-#else
- pid = fork ();
-#endif
- if (pid < 0)
- perror_with_name ("fork");
-
- if (pid == 0)
- {
- close_most_fds ();
- ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
- setpgid (0, 0);
-
- /* If gdbserver is connected to gdb via stdio, redirect the inferior's
- stdout to stderr so that inferior i/o doesn't corrupt the connection.
- Also, redirect stdin to /dev/null. */
- if (remote_connection_is_stdio ())
- {
- close (0);
- open ("/dev/null", O_RDONLY);
- dup2 (2, 1);
- if (write (2, "stdin/stdout redirected\n",
- sizeof ("stdin/stdout redirected\n") - 1) < 0)
- {
- /* Errors ignored. */;
- }
- }
-
- restore_original_signals_state ();
-
- execv (program, allargs);
- if (errno == ENOENT)
- execvp (program, allargs);
-
- fprintf (stderr, "Cannot exec %s: %s.\n", program,
- strerror (errno));
- fflush (stderr);
- _exit (0177);
- }
+ pid = fork_inferior (program,
+ str_program_args.c_str (),
+ environ_vector (get_environ ()), linux_ptrace_fun,
+ NULL, NULL, NULL, NULL);
do_cleanups (restore_personality);
@@ -1008,6 +1009,8 @@ linux_create_inferior (char *program, char **allargs)
new_lwp = add_lwp (ptid);
new_lwp->must_set_ptrace_flags = 1;
+ post_fork_inferior (pid, program);
+
return pid;
}
@@ -6055,8 +6058,6 @@ linux_look_up_symbols (void)
static void
linux_request_interrupt (void)
{
- extern unsigned long signal_pid;
-
/* Send a SIGINT to the process group. This acts just like the user
typed a ^C on the controlling terminal. */
kill (-signal_pid, SIGINT);
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index d300aae..35160d6 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -28,6 +28,8 @@
#include "gdb_wait.h"
#include <signal.h>
#include "filestuff.h"
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
int using_threads = 1;
@@ -224,36 +226,43 @@ lynx_add_process (int pid, int attached)
return proc;
}
+/* Callback used by fork_inferior to start tracing the inferior. */
+
+static void
+lynx_ptrace_fun ()
+{
+ int pgrp;
+
+ /* Switch child to its own process group so that signals won't
+ directly affect GDBserver. */
+ pgrp = getpid();
+ if (pgrp < 0)
+ trace_start_error_with_name ("pgrp");
+ if (setpgid (0, pgrp) < 0)
+ trace_start_error_with_name ("setpgid");
+ if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
+ trace_start_error_with_name ("ioctl");
+ if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
+ trace_start_error_with_name ("lynx_ptrace");
+}
+
/* Implement the create_inferior method of the target_ops vector. */
static int
-lynx_create_inferior (char *program, char **allargs)
+lynx_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
int pid;
+ std::string str_program_args = stringify_argv (program_args);
lynx_debug ("lynx_create_inferior ()");
- pid = fork ();
- if (pid < 0)
- perror_with_name ("fork");
+ pid = fork_inferior (program,
+ str_program_args.c_str (),
+ environ_vector (get_environ ()), lynx_ptrace_fun,
+ NULL, NULL, NULL, NULL);
- if (pid == 0)
- {
- int pgrp;
-
- close_most_fds ();
-
- /* Switch child to its own process group so that signals won't
- directly affect gdbserver. */
- pgrp = getpid();
- setpgid (0, pgrp);
- ioctl (0, TIOCSPGRP, &pgrp);
- lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
- execv (program, allargs);
- fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
- fflush (stderr);
- _exit (0177);
- }
+ post_fork_inferior (pid, program);
lynx_add_process (pid, 0);
/* Do not add the process thread just yet, as we do not know its tid.
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 6229b4c..a5f1543 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -347,14 +347,17 @@ nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
return len_read;
}
-/* Start inferior specified by PROGRAM passing arguments ALLARGS. */
+/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
+ arguments. */
static int
-nto_create_inferior (char *program, char **allargs)
+nto_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
struct inheritance inherit;
pid_t pid;
sigset_t set;
+ std::string str_program_args = stringify_argv (program_args);
TRACE ("%s %s\n", __func__, program);
/* Clear any pending SIGUSR1's but keep the behavior the same. */
@@ -367,7 +370,8 @@ nto_create_inferior (char *program, char **allargs)
memset (&inherit, 0, sizeof (inherit));
inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
inherit.pgroup = SPAWN_NEWPGROUP;
- pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+ pid = spawnp (program, 0, NULL, &inherit,
+ (char *) str_program_args.c_str (), 0);
sigprocmask (SIG_BLOCK, &set, NULL);
if (pid == -1)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 69fcab1..3ab042d 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -36,6 +36,19 @@
#include "dll.h"
#include "hostio.h"
#include <vector>
+#include "common-inferior.h"
+#include "job-control.h"
+#include "environ.h"
+
+/* The environment to pass to the inferior when creating it. */
+
+struct gdb_environ *our_environ = NULL;
+
+/* Start the inferior using a shell. */
+
+/* We always try to start the inferior using a shell. */
+
+int startup_with_shell = 1;
/* The thread set with an `Hc' packet. `Hc' is deprecated in favor of
`vCont'. Note the multi-process extensions made `vCont' a
@@ -79,8 +92,9 @@ static int vCont_supported;
space randomization feature before starting an inferior. */
int disable_randomization = 1;
-static std::vector<char *> program_argv;
-static std::vector<char *> wrapper_argv;
+static char *program_name = NULL;
+static std::vector<char *> program_args;
+static std::string wrapper_argv;
int pass_signals[GDB_SIGNAL_LAST];
int program_signals[GDB_SIGNAL_LAST];
@@ -93,22 +107,6 @@ int program_signals_p;
unsigned long signal_pid;
-#ifdef SIGTTOU
-/* A file descriptor for the controlling terminal. */
-int terminal_fd;
-
-/* TERMINAL_FD's original foreground group. */
-pid_t old_foreground_pgrp;
-
-/* Hand back terminal ownership to the original foreground group. */
-
-static void
-restore_old_foreground_pgrp (void)
-{
- tcsetpgrp (terminal_fd, old_foreground_pgrp);
-}
-#endif
-
/* Set if you want to disable optional thread related packets support
in gdbserver, for the sake of testing GDB against stubs that don't
support them. */
@@ -118,8 +116,8 @@ int disable_packet_qC;
int disable_packet_qfThreadInfo;
/* Last status reported to GDB. */
-static struct target_waitstatus last_status;
-static ptid_t last_ptid;
+struct target_waitstatus last_status;
+ptid_t last_ptid;
char *own_buf;
static unsigned char *mem_buf;
@@ -238,94 +236,31 @@ target_running (void)
return get_first_thread () != NULL;
}
-static int
-start_inferior (char **argv)
-{
- std::vector<char *> new_argv;
-
- if (!wrapper_argv.empty ())
- new_argv.insert (new_argv.begin (),
- wrapper_argv.begin (),
- wrapper_argv.end ());
-
- for (int i = 0; argv[i] != NULL; ++i)
- new_argv.push_back (argv[i]);
-
- new_argv.push_back (NULL);
+/* See common/common-inferior.h. */
- if (debug_threads)
- {
- for (int i = 0; i < new_argv.size (); ++i)
- debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
- debug_flush ();
- }
-
-#ifdef SIGTTOU
- signal (SIGTTOU, SIG_DFL);
- signal (SIGTTIN, SIG_DFL);
-#endif
-
- signal_pid = create_inferior (new_argv[0], &new_argv[0]);
-
- /* FIXME: we don't actually know at this point that the create
- actually succeeded. We won't know that until we wait. */
- fprintf (stderr, "Process %s created; pid = %ld\n", argv[0],
- signal_pid);
- fflush (stderr);
-
-#ifdef SIGTTOU
- signal (SIGTTOU, SIG_IGN);
- signal (SIGTTIN, SIG_IGN);
- terminal_fd = fileno (stderr);
- old_foreground_pgrp = tcgetpgrp (terminal_fd);
- tcsetpgrp (terminal_fd, signal_pid);
- atexit (restore_old_foreground_pgrp);
-#endif
-
- if (!wrapper_argv.empty ())
- {
- ptid_t ptid = pid_to_ptid (signal_pid);
-
- last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
-
- if (last_status.kind == TARGET_WAITKIND_STOPPED)
- {
- do
- {
- target_continue_no_signal (ptid);
+const char *
+get_exec_wrapper ()
+{
+ return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL;
+}
- last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
- if (last_status.kind != TARGET_WAITKIND_STOPPED)
- break;
+/* See common/common-inferior.h. */
- current_thread->last_resume_kind = resume_stop;
- current_thread->last_status = last_status;
- }
- while (last_status.value.sig != GDB_SIGNAL_TRAP);
- }
- target_post_create_inferior ();
- return signal_pid;
- }
+char *
+get_exec_file (int err)
+{
+ if (err && program_name == NULL)
+ error (_("No executable file specified."));
- /* Wait till we are at 1st instruction in program, return new pid
- (assuming success). */
- last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+ return program_name;
+}
- /* At this point, the target process, if it exits, is stopped. Do not call
- the function target_post_create_inferior if the process has already
- exited, as the target implementation of the routine may rely on the
- process being live. */
- if (last_status.kind != TARGET_WAITKIND_EXITED
- && last_status.kind != TARGET_WAITKIND_SIGNALLED)
- {
- target_post_create_inferior ();
- current_thread->last_resume_kind = resume_stop;
- current_thread->last_status = last_status;
- }
- else
- target_mourn_inferior (last_ptid);
+/* See server.h. */
- return signal_pid;
+struct gdb_environ *
+get_environ ()
+{
+ return our_environ;
}
static int
@@ -2848,6 +2783,7 @@ handle_v_run (char *own_buf)
{
char *p, *next_p;
std::vector<char *> new_argv;
+ char *new_program_name = NULL;
int i, new_argc;
new_argc = 0;
@@ -2866,42 +2802,94 @@ handle_v_run (char *own_buf)
if (i == 0 && p == next_p)
{
/* No program specified. */
- new_argv.push_back (NULL);
+ new_program_name = NULL;
+ }
+ else if (p == next_p)
+ {
+ /* Empty argument. */
+ new_argv.push_back (xstrdup ("''"));
}
else
{
size_t len = (next_p - p) / 2;
+ /* ARG is the unquoted argument received via the RSP. */
char *arg = (char *) xmalloc (len + 1);
+ /* FULL_ARGS will contain the quoted version of ARG. */
+ char *full_arg = (char *) xmalloc ((len + 1) * 2);
+ /* These are pointers used to navigate the strings above. */
+ char *tmp_arg = arg;
+ char *tmp_full_arg = full_arg;
+ int need_quote = 0;
hex2bin (p, (gdb_byte *) arg, len);
arg[len] = '\0';
- new_argv.push_back (arg);
- }
+ while (*tmp_arg != '\0')
+ {
+ switch (*tmp_arg)
+ {
+ case '\n':
+ /* Quote \n. */
+ *tmp_full_arg = '\'';
+ ++tmp_full_arg;
+ need_quote = 1;
+ break;
+
+ case '\'':
+ /* Quote single quote. */
+ *tmp_full_arg = '\\';
+ ++tmp_full_arg;
+ break;
+
+ default:
+ break;
+ }
+
+ *tmp_full_arg = *tmp_arg;
+ ++tmp_full_arg;
+ ++tmp_arg;
+ }
+
+ if (need_quote)
+ *tmp_full_arg++ = '\'';
+
+ /* Finish FULL_ARG and push it into the vector containing
+ the argv. */
+ *tmp_full_arg = '\0';
+ if (i == 0)
+ new_program_name = full_arg;
+ else
+ new_argv.push_back (full_arg);
+ xfree (arg);
+ }
if (*next_p)
next_p++;
}
new_argv.push_back (NULL);
- if (new_argv[0] == NULL)
+ if (new_program_name == NULL)
{
/* GDB didn't specify a program to run. Use the program from the
last run with the new argument list. */
- if (program_argv.empty ())
+ if (program_name == NULL)
{
write_enn (own_buf);
free_vector_argv (new_argv);
return 0;
}
-
- new_argv.push_back (xstrdup (program_argv[0]));
+ }
+ else
+ {
+ xfree (program_name);
+ program_name = new_program_name;
}
/* Free the old argv and install the new one. */
- free_vector_argv (program_argv);
- program_argv = new_argv;
+ free_vector_argv (program_args);
+ program_args = new_argv;
+
+ create_inferior (program_name, program_args);
- start_inferior (&program_argv[0]);
if (last_status.kind == TARGET_WAITKIND_STOPPED)
{
prepare_resume_reply (own_buf, last_ptid, &last_status);
@@ -3527,10 +3515,17 @@ captured_main (int argc, char *argv[])
tmp = next_arg;
while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
{
- wrapper_argv.push_back (*next_arg);
+ wrapper_argv += *next_arg;
+ wrapper_argv += ' ';
next_arg++;
}
+ if (!wrapper_argv.empty ())
+ {
+ /* Erase the last whitespace. */
+ wrapper_argv.erase (wrapper_argv.end () - 1);
+ }
+
if (next_arg == tmp || *next_arg == NULL)
{
gdbserver_usage (stderr);
@@ -3666,8 +3661,13 @@ captured_main (int argc, char *argv[])
exit (1);
}
+ /* Gather information about the environment. */
+ our_environ = make_environ ();
+ init_environ (our_environ);
+
initialize_async_io ();
initialize_low ();
+ have_job_control ();
initialize_event_loop ();
if (target_supports_tracepoints ())
initialize_tracepoint ();
@@ -3681,12 +3681,13 @@ captured_main (int argc, char *argv[])
int i, n;
n = argc - (next_arg - argv);
- for (i = 0; i < n; i++)
- program_argv.push_back (xstrdup (next_arg[i]));
- program_argv.push_back (NULL);
+ program_name = xstrdup (next_arg[0]);
+ for (i = 1; i < n; i++)
+ program_args.push_back (xstrdup (next_arg[i]));
+ program_args.push_back (NULL);
/* Wait till we are at first instruction in program. */
- start_inferior (&program_argv[0]);
+ create_inferior (program_name, program_args);
/* We are now (hopefully) stopped at the first instruction of
the target process. This assumes that the target process was
@@ -4301,9 +4302,10 @@ process_serial_event (void)
fprintf (stderr, "GDBserver restarting\n");
/* Wait till we are at 1st instruction in prog. */
- if (!program_argv.empty ())
+ if (program_name != NULL)
{
- start_inferior (&program_argv[0]);
+ create_inferior (program_name, program_args);
+
if (last_status.kind == TARGET_WAITKIND_STOPPED)
{
/* Stopped at the first instruction of the target
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index d5fee38..4de4244 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -148,4 +148,18 @@ extern int in_queued_stop_replies (ptid_t ptid);
/* Definition for any syscall, used for unfiltered syscall reporting. */
#define ANY_SYSCALL (-2)
+/* After fork_inferior has been called, we need to adjust a few
+ signals and call startup_inferior to start the inferior and consume
+ its first events. This is done here. PID is the pid of the new
+ inferior and PROGRAM is its name. */
+extern void post_fork_inferior (int pid, const char *program);
+
+/* Get the 'struct gdb_environ *' being used in the current
+ session. */
+extern struct gdb_environ *get_environ ();
+
+extern target_waitstatus last_status;
+extern ptid_t last_ptid;
+extern unsigned long signal_pid;
+
#endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 117b871..0f770a0 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -27,6 +27,7 @@
#include <sys/syscall.h>
#include "filestuff.h"
#include "hostio.h"
+#include "nat/fork-inferior.h"
/* Some older glibc versions do not define this. */
#ifndef __WNOTHREAD
@@ -261,36 +262,37 @@ spu_proc_xfer_spu (const char *annex, unsigned char *readbuf,
return ret;
}
+/* Callback to be used when calling fork_inferior, responsible for
+ actually initiating the tracing of the inferior. */
+
+static void
+spu_ptrace_fun ()
+{
+ if (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0)
+ trace_start_error_with_name ("ptrace");
+ if (setpgid (0, 0) < 0)
+ trace_start_error_with_name ("setpgid");
+}
/* Start an inferior process and returns its pid.
- ALLARGS is a vector of program-name and args. */
+ PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+ are its arguments. */
+
static int
-spu_create_inferior (char *program, char **allargs)
+spu_create_inferior (const char *program,
+ const std::vector<char *> &program_argv)
{
int pid;
ptid_t ptid;
struct process_info *proc;
+ std::string str_program_args = stringify_argv (program_args);
- pid = fork ();
- if (pid < 0)
- perror_with_name ("fork");
-
- if (pid == 0)
- {
- close_most_fds ();
- ptrace (PTRACE_TRACEME, 0, 0, 0);
-
- setpgid (0, 0);
-
- execv (program, allargs);
- if (errno == ENOENT)
- execvp (program, allargs);
+ pid = fork_inferior (program,
+ str_program_args.c_str (),
+ environ_vector (get_environ ()), spu_ptrace_fun,
+ NULL, NULL, NULL, NULL);
- fprintf (stderr, "Cannot exec %s: %s.\n", program,
- strerror (errno));
- fflush (stderr);
- _exit (0177);
- }
+ post_fork_inferior (pid, program);
proc = add_process (pid, 0);
proc->tdesc = tdesc_spu;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fda72e8..7526463 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -387,3 +387,30 @@ default_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
(*the_target->sw_breakpoint_from_kind) (0, &size);
return size;
}
+
+/* See target/target.h. */
+
+void
+target_terminal_init ()
+{
+ /* Placeholder needed because of fork_inferior. Not necessary on
+ GDBserver. */
+}
+
+/* See target/target.h. */
+
+void
+target_terminal_inferior ()
+{
+ /* Placeholder needed because of fork_inferior. Not necessary on
+ GDBserver. */
+}
+
+/* See target/target.h. */
+
+void
+target_terminal_ours ()
+{
+ /* Placeholder needed because of fork_inferior. Not necessary on
+ GDBserver. */
+}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 3cc2bc4..be89258 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -28,6 +28,7 @@
#include "target/waitstatus.h"
#include "mem-break.h"
#include "btrace-common.h"
+#include <vector>
struct emit_ops;
struct buffer;
@@ -67,13 +68,13 @@ struct target_ops
/* Start a new process.
PROGRAM is a path to the program to execute.
- ARGS is a standard NULL-terminated array of arguments,
- to be passed to the inferior as ``argv''.
+ PROGRAM_ARGS is a standard NULL-terminated array of arguments,
+ to be passed to the inferior as ``argv'' (along with PROGRAM).
Returns the new PID on success, -1 on failure. Registers the new
process with the process list. */
-
- int (*create_inferior) (char *program, char **args);
+ int (*create_inferior) (const char *program,
+ const std::vector<char *> &program_args);
/* Do additional setup after a new process is created, including
exec-wrapper completion. */
@@ -480,8 +481,8 @@ extern struct target_ops *the_target;
void set_target_ops (struct target_ops *);
-#define create_inferior(program, args) \
- (*the_target->create_inferior) (program, args)
+#define create_inferior(program, program_args) \
+ (*the_target->create_inferior) (program, program_args)
#define target_post_create_inferior() \
do \
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7b09f4b..88f6911 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -608,13 +608,13 @@ create_process (const char *program, char *args,
}
/* Start a new process.
- PROGRAM is a path to the program to execute.
- ARGS is a standard NULL-terminated array of arguments,
- to be passed to the inferior as ``argv''.
+ PROGRAM is the program name.
+ PROGRAM_ARGS is the vector containing the inferior's args.
Returns the new PID on success, -1 on failure. Registers the new
process with the process list. */
static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
#ifndef USE_WIN32API
char real_path[PATH_MAX];
@@ -622,11 +622,12 @@ win32_create_inferior (char *program, char **program_args)
#endif
BOOL ret;
DWORD flags;
- char *args;
int argslen;
int argc;
PROCESS_INFORMATION pi;
DWORD err;
+ std::string str_program_args = stringify_argv (program_args);
+ char *args = (char *) str_program_args.c_str ();
/* win32_wait needs to know we're not attaching. */
attaching = 0;
@@ -652,18 +653,6 @@ win32_create_inferior (char *program, char **program_args)
program = real_path;
#endif
- argslen = 1;
- for (argc = 1; program_args[argc]; argc++)
- argslen += strlen (program_args[argc]) + 1;
- args = (char *) alloca (argslen);
- args[0] = '\0';
- for (argc = 1; program_args[argc]; argc++)
- {
- /* FIXME: Can we do better about quoting? How does Cygwin
- handle this? */
- strcat (args, " ");
- strcat (args, program_args[argc]);
- }
OUTMSG2 (("Command line is \"%s\"\n", args));
#ifdef CREATE_NEW_PROCESS_GROUP