diff options
author | Sergio Durigan Junior <sergiodj@redhat.com> | 2016-12-22 21:11:11 -0500 |
---|---|---|
committer | Sergio Durigan Junior <sergiodj@redhat.com> | 2017-06-07 19:56:09 -0400 |
commit | 2090129c36c7e582943b7d300968d19b46160d84 (patch) | |
tree | d7abde0c9c147cb404a6a0794adb49c26c29b015 /gdb/gdbserver | |
parent | 043a49349c713dc329a2dfc413b082c3826ecdb8 (diff) | |
download | gdb-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/ChangeLog | 69 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 1 | ||||
-rw-r--r-- | gdb/gdbserver/configure.srv | 6 | ||||
-rw-r--r-- | gdb/gdbserver/fork-child.c | 113 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 91 | ||||
-rw-r--r-- | gdb/gdbserver/lynx-low.c | 51 | ||||
-rw-r--r-- | gdb/gdbserver/nto-low.c | 10 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 240 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 14 | ||||
-rw-r--r-- | gdb/gdbserver/spu-low.c | 44 | ||||
-rw-r--r-- | gdb/gdbserver/target.c | 27 | ||||
-rw-r--r-- | gdb/gdbserver/target.h | 13 | ||||
-rw-r--r-- | gdb/gdbserver/win32-low.c | 23 |
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 |