daily update
[deliverable/binutils-gdb.git] / gdb / fork-child.c
index 41e42119e249104bb499b5e257446b470be26ed1..a1726bd543958b19b949bf10a4d319a0517594f4 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, 2007 Free Software Foundation, Inc.
+   2001, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    Contributed by Cygnus Support.
 
 #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
@@ -117,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)
@@ -162,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)
     {
@@ -187,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.  */
@@ -298,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
@@ -383,17 +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.  */
+  return pid;
 }
 
 /* Accept NTRAPS traps from the inferior.  */
@@ -408,24 +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 ();
-
-  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)
        {
-         /* 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);
+         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.  */
+         target_resume (resume_ptid, 0, resume_signal);
        }
       else
        {
@@ -450,8 +523,41 @@ 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;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_fork_child;
+
+void
+_initialize_fork_child (void)
+{
+  add_setshow_filename_cmd ("exec-wrapper", class_run, &exec_wrapper, _("\
+Set a wrapper for running programs.\n\
+The wrapper prepares the system and environment for the new program."),
+                           _("\
+Show the wrapper for running programs."), NULL,
+                           NULL, NULL,
+                           &setlist, &showlist);
+
+  add_cmd ("exec-wrapper", class_run, unset_exec_wrapper_command,
+           _("Disable use of an execution wrapper."),
+           &unsetlist);
 }
This page took 0.026958 seconds and 4 git commands to generate.