* corelow.c (core_close): Don't hardcode the core's pid.
[deliverable/binutils-gdb.git] / gdb / fork-child.c
index 894015120d686d04f662a8ab30cac952edf35a0e..8cd87e119927c1bf63d97b0ad5872e7d2f316512 100644 (file)
@@ -1,7 +1,7 @@
 /* Fork a Unix child process, and set up to debug it, for GDB.
 
-   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
-   2000, 2001, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2001, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    Contributed by Cygnus Support.
 
@@ -9,7 +9,7 @@
 
    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 2 of the License, or
+   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,
@@ -18,9 +18,7 @@
    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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdb_string.h"
 #include "terminal.h"
 #include "gdbthread.h"
 #include "command.h" /* for dont_repeat () */
+#include "gdbcmd.h"
 #include "solib.h"
 
 #include <signal.h>
 
 /* This just gets used as a default if we can't find SHELL.  */
-#ifndef SHELL_FILE
 #define SHELL_FILE "/bin/sh"
-#endif
 
 extern char **environ;
 
+static char *exec_wrapper;
+
 /* 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
@@ -119,7 +118,7 @@ escape_bang_in_quoted_argument (const char *shell_file)
 /* This function is NOT reentrant.  Some of the variables have been
    made static to ensure that they survive the vfork call.  */
 
-void
+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)
@@ -164,15 +163,11 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
      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 desired, concat something onto the front of ALLARGS.
-     SHELL_COMMAND is the result.  */
-#ifdef SHELL_COMMAND_CONCAT
-  shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len);
-  strcpy (shell_command, SHELL_COMMAND_CONCAT);
-#else
+  if (exec_wrapper)
+    len += strlen (exec_wrapper) + 1;
+
   shell_command = (char *) alloca (len);
   shell_command[0] = '\0';
-#endif
 
   if (!shell)
     {
@@ -189,14 +184,22 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
     {
       /* We're going to call a shell.  */
 
-      /* Now add exec_file, quoting as necessary.  */
-
       char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
       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.  */
@@ -277,7 +280,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
     (*pre_trace_fun) ();
 
   /* Create the child process.  Since the child process is going to
-     exec(3) shortlty afterwards, try to reduce the overhead by
+     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
@@ -300,10 +303,16 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       if (debug_fork)
        sleep (debug_fork);
 
-      /* Run inferior in a separate process group.  */
-      debug_setpgrp = gdb_setpgid ();
-      if (debug_setpgrp == -1)
-       perror ("setpgrp failed in child");
+      /* 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
@@ -336,11 +345,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       environ = env;
 
       /* If we decided above to start up with a shell, we exec the
-        shell, "-c" says to interpret the next arg as a shell command
-        to execute, and this command is "exec <target-program>
-        <args>".  "-f" means "fast startup" to the c-shell, which
-        means don't do .cshrc file. Doing .cshrc may cause fork/exec
-        events which will confuse debugger start-up code.  */
+        shell, "-c" says to interpret the next arg as a shell command
+        to execute, and this command is "exec <target-program>
+        <args>".  */
       if (shell)
        {
          execlp (shell_file, shell_file, "-c", shell_command, (char *) 0);
@@ -387,22 +394,27 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   init_thread_list ();
 
+  add_inferior (pid);
+
   /* Needed for wait_for_inferior stuff below.  */
   inferior_ptid = pid_to_ptid (pid);
 
+  /* 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.  */
-  (*init_trace_fun) (pid);
+  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.  */
-
-  /* Allow target dependent code to play with the new process.  This
-     might be used to have target-specific code initialize a variable
-     in the new process prior to executing the first instruction.  */
-  TARGET_CREATE_INFERIOR_HOOK (pid);
+  return pid;
 }
 
 /* Accept NTRAPS traps from the inferior.  */
@@ -417,28 +429,76 @@ startup_inferior (int ntraps)
      have stopped one instruction after execing the shell.  Here we
      must get it up to actual execution of the real program.  */
 
-  clear_proceed_status ();
-
-  init_wait_for_inferior ();
-
-  if (STARTUP_WITH_SHELL)
-    inferior_ignoring_startup_exec_events = ntraps;
-  else
-    inferior_ignoring_startup_exec_events = 0;
-  inferior_ignoring_leading_exec_events =
-    target_reported_exec_events_per_exec_call () - 1;
+  if (exec_wrapper)
+    pending_execs++;
 
   while (1)
     {
-      /* Make wait_for_inferior be quiet. */
-      stop_soon = STOP_QUIETLY;
-      wait_for_inferior ();
-      if (stop_signal != TARGET_SIGNAL_TRAP)
+      int resume_signal = TARGET_SIGNAL_0;
+      ptid_t resume_ptid;
+      ptid_t event_ptid;
+
+      struct target_waitstatus ws;
+      memset (&ws, 0, sizeof (ws));
+      event_ptid = target_wait (pid_to_ptid (-1), &ws);
+
+      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 ();
+           error (_("During startup program terminated with signal %s, %s."),
+                  target_signal_to_name (ws.value.sig),
+                  target_signal_to_string (ws.value.sig));
+           return;
+
+         case TARGET_WAITKIND_EXITED:
+           target_terminal_ours ();
+           target_mourn_inferior ();
+           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 = TARGET_SIGNAL_TRAP;
+           switch_to_thread (event_ptid);
+           break;
+
+         case TARGET_WAITKIND_STOPPED:
+           resume_signal = ws.value.sig;
+           switch_to_thread (event_ptid);
+           break;
+       }
+
+      /* In all-stop mode, resume all threads.  */
+      if (!non_stop)
+       resume_ptid = pid_to_ptid (-1);
+      else
+       resume_ptid = event_ptid;
+
+      if (resume_signal != TARGET_SIGNAL_TRAP)
        {
-         /* Let shell child handle its own signals in its own way.
-            FIXME: what if child has exited?  Must exit loop
-            somehow.  */
-         resume (0, stop_signal);
+         /* Let shell child handle its own signals in its own way.  */
+         target_resume (resume_ptid, 0, resume_signal);
        }
       else
        {
@@ -463,8 +523,38 @@ startup_inferior (int ntraps)
          if (--pending_execs == 0)
            break;
 
-         resume (0, TARGET_SIGNAL_0);  /* Just make it go on.  */
+         /* Just make it go on.  */
+         target_resume (resume_ptid, 0, TARGET_SIGNAL_0);
        }
     }
-  stop_soon = NO_STOP_QUIETLY;
+
+  /* Mark all threads non-executing.  */
+  set_executing (pid_to_ptid (-1), 0);
+
+  stop_pc = read_pc ();
+}
+
+/* Implement the "unset exec-wrapper" command.  */
+
+static void
+unset_exec_wrapper_command (char *args, int from_tty)
+{
+  xfree (exec_wrapper);
+  exec_wrapper = NULL;
+}
+
+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);
 }
This page took 0.02718 seconds and 4 git commands to generate.