/* Fork a Unix child process, and set up to debug it, for GDB.
- Copyright 1990, 91, 92, 93, 94, 1996, 1999 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
#include "inferior.h"
#include "target.h"
#include "gdb_wait.h"
+#include "gdb_vfork.h"
#include "gdbcore.h"
#include "terminal.h"
#include "gdbthread.h"
}
-/* Start an inferior Unix child process and sets inferior_pid to its pid.
+/* 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. Errors reported with error(). */
+/* This function is NOT-REENTRANT. Some of the variables have been
+ made static to ensure that they survive the vfork() call. */
+
void
-fork_inferior (char *exec_file, char *allargs, char **env,
+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)
+ void (*pre_trace_fun) (void), char *shell_file_arg)
{
int pid;
char *shell_command;
/* 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;
- char **argv;
+ static char **argv;
/* 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);
* 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 (pre_trace_fun != NULL)
(*pre_trace_fun) ();
-#ifdef HAVE_VFORK
+ /* Create the child process. Note that the apparent call to vfork()
+ below *might* actually be a call to fork() due to the fact that
+ autoconf will ``#define vfork fork'' on certain platforms. */
if (debug_fork)
pid = fork ();
else
pid = vfork ();
-#else
- pid = fork ();
-#endif
if (pid < 0)
perror_with_name ("vfork");
init_thread_list ();
- inferior_pid = pid; /* Needed for wait_for_inferior stuff below */
+ inferior_ptid = pid_to_ptid (pid); /* Needed for wait_for_inferior stuff below */
/* Now that we have a child process, make it our target, and
initialize anything target-vector-specific that needs initializing. */
void
clone_and_follow_inferior (int child_pid, int *followed_child)
{
- extern int auto_solib_add;
-
int debugger_pid;
int status;
char pid_spelling[100]; /* Arbitrary but sufficient length. */
if (status < 0)
error ("error getting pipe for handoff semaphore");
- /* Clone the debugger. */
-#ifdef HAVE_VFORK
+ /* Clone the debugger. Note that the apparent call to vfork()
+ below *might* actually be a call to fork() due to the fact that
+ autoconf will ``#define vfork fork'' on certain platforms. */
if (debug_fork)
debugger_pid = fork ();
else
debugger_pid = vfork ();
-#else
- debugger_pid = fork ();
-#endif
if (debugger_pid < 0)
perror_with_name ("fork");
sleep (debug_fork);
/* The child (i.e., the cloned debugger) must now attach to
- CHILD_PID. inferior_pid is presently set to the parent process
+ CHILD_PID. inferior_ptid is presently set to the parent process
of the fork, while CHILD_PID should be the child process of the
fork.
*/
read (handoff_semaphore[SEM_LISTEN], &listen_value, sizeof (listen_value));
- /* Note that we DON'T want to actually detach from inferior_pid,
+ /* Note that we DON'T want to actually detach from inferior_ptid,
because that would allow it to run free. The original
debugger wants to retain control of the process. So, we
- just reset inferior_pid to CHILD_PID, and then ensure that all
+ just reset inferior_ptid to CHILD_PID, and then ensure that all
breakpoints are really set in CHILD_PID.
*/
target_mourn_inferior ();
#endif /* STARTUP_INFERIOR */
stop_soon_quietly = 0;
}
+
+/* Compute command-line string given argument vector. This does the
+ same shell processing as fork_inferior. */
+/* ARGSUSED */
+char *
+construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+{
+ char *result;
+
+ if (STARTUP_WITH_SHELL)
+ {
+ /* This holds all the characters considered special to the
+ typical Unix shells. We include `^' because the SunOS
+ /bin/sh treats it as a synonym for `|'. */
+ char *special = "\"!#$&*()\\|[]{}<>?'\"`~^; \t\n";
+ int i;
+ int length = 0;
+ char *out, *cp;
+
+ /* We over-compute the size. It shouldn't matter. */
+ for (i = 0; i < argc; ++i)
+ length += 2 * strlen (argv[i]) + 1;
+
+ result = (char *) xmalloc (length);
+ out = result;
+
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ *out++ = ' ';
+
+ for (cp = argv[i]; *cp; ++cp)
+ {
+ if (strchr (special, *cp) != NULL)
+ *out++ = '\\';
+ *out++ = *cp;
+ }
+ }
+ *out = '\0';
+ }
+ else
+ {
+ /* In this case we can't handle arguments that contain spaces,
+ tabs, or newlines -- see breakup_args(). */
+ int i;
+ int length = 0;
+
+ for (i = 0; i < argc; ++i)
+ {
+ char *cp = strchr (argv[i], ' ');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\t');
+ if (cp == NULL)
+ cp = strchr (argv[i], '\n');
+ if (cp != NULL)
+ error ("can't handle command-line argument containing whitespace");
+ length += strlen (argv[i]) + 1;
+ }
+
+ result = (char *) xmalloc (length);
+ result[0] = '\0';
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ strcat (result, " ");
+ strcat (result, argv[i]);
+ }
+ }
+
+ return result;
+}