]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/linux-fork.c
2009-10-19 Pedro Alves <pedro@codesourcery.com>
[thirdparty/binutils-gdb.git] / gdb / linux-fork.c
index 861917d81bf491692cf685f35dcaa459b434f6c0..a69bc36bbab7a5ace6757aaf90158931e756415a 100644 (file)
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "inferior.h"
 #include "regcache.h"
 #include "gdbcmd.h"
@@ -40,35 +41,30 @@ static int highest_fork_num;
 /* Prevent warning from -Wmissing-prototypes.  */
 extern void _initialize_linux_fork (void);
 
-int detach_fork = 1;           /* Default behavior is to detach
-                                  newly forked processes (legacy).  */
-
 /* Fork list data structure:  */
 struct fork_info
 {
   struct fork_info *next;
   ptid_t ptid;
   int num;                     /* Convenient handle (GDB fork id) */
-  struct regcache *savedregs;  /* Convenient for info fork, saves 
+  struct regcache *savedregs;  /* Convenient for info fork, saves
                                   having to actually switch contexts.  */
   int clobber_regs;            /* True if we should restore saved regs.  */
-  ULONGEST pc;                 /* PC for info fork.  */
   off_t *filepos;              /* Set of open file descriptors' offsets.  */
   int maxfd;
 };
 
 /* Fork list methods:  */
 
-extern int
+int
 forks_exist_p (void)
 {
   return (fork_list != NULL);
 }
 
-/* Add a fork to internal fork list.
-   Called from linux child_follow_fork.  */
+/* Add a fork to the internal fork list.  */
 
-extern struct fork_info *
+struct fork_info *
 add_fork (pid_t pid)
 {
   struct fork_info *fp;
@@ -137,7 +133,7 @@ delete_fork (ptid_t ptid)
 
   free_fork (fp);
 
-  /* Special case: if there is now only one process in the list, 
+  /* Special case: if there is now only one process in the list,
      and if it is (hopefully!) the current inferior_ptid, then
      remove it, leaving the list empty -- we're now down to the
      default case of debugging a single process.  */
@@ -210,7 +206,6 @@ init_fork_list (void)
   for (fp = fork_list; fp; fp = fpnext)
     {
       fpnext = fp->next;
-      delete_inferior (ptid_get_pid (fp->ptid));
       free_fork (fp);
     }
 
@@ -219,7 +214,7 @@ init_fork_list (void)
 
 /* Fork list <-> gdb interface.  */
 
-/* Utility function for fork_load/fork_save.  
+/* Utility function for fork_load/fork_save.
    Calls lseek in the (current) inferior process.  */
 
 static off_t
@@ -240,9 +235,7 @@ fork_load_infrun_state (struct fork_info *fp)
   extern void nullify_last_target_wait_ptid ();
   int i;
 
-  inferior_ptid = fp->ptid;
-
-  linux_nat_switch_fork (inferior_ptid);
+  linux_nat_switch_fork (fp->ptid);
 
   if (fp->savedregs && fp->clobber_regs)
     regcache_cpy (get_current_regcache (), fp->savedregs);
@@ -250,7 +243,7 @@ fork_load_infrun_state (struct fork_info *fp)
   registers_changed ();
   reinit_frame_cache ();
 
-  stop_pc = read_pc ();
+  stop_pc = regcache_read_pc (get_current_regcache ());
   nullify_last_target_wait_ptid ();
 
   /* Now restore the file positions of open file descriptors.  */
@@ -268,7 +261,7 @@ fork_load_infrun_state (struct fork_info *fp)
 /* Save infrun state for the fork PTID.
    Exported for use by linux child_follow_fork.  */
 
-extern void
+static void
 fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
 {
   char path[MAXPATHLEN];
@@ -280,7 +273,6 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
 
   fp->savedregs = regcache_dup (get_current_regcache ());
   fp->clobber_regs = clobber_regs;
-  fp->pc = read_pc ();
 
   if (clobber_regs)
     {
@@ -301,7 +293,7 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
                fp->maxfd = tmp;
            }
          /* Allocate array of file positions.  */
-         fp->filepos = xrealloc (fp->filepos, 
+         fp->filepos = xrealloc (fp->filepos,
                                  (fp->maxfd + 1) * sizeof (*fp->filepos));
 
          /* Initialize to -1 (invalid).  */
@@ -323,7 +315,7 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
 
 /* Kill 'em all, let God sort 'em out...  */
 
-extern void
+void
 linux_fork_killall (void)
 {
   /* Walk list and kill every pid.  No need to treat the
@@ -355,7 +347,7 @@ linux_fork_killall (void)
    forks to debug.  Delete the exiting one and context-switch to the
    first available.  */
 
-extern void
+void
 linux_fork_mourn_inferior (void)
 {
   /* Wait just one more time to collect the inferior's exit status.
@@ -370,8 +362,6 @@ linux_fork_mourn_inferior (void)
      We need to delete that one from the fork_list, and switch
      to the next available fork.  */
   delete_fork (inferior_ptid);
-  /* Delete process from GDB's inferior list.  */
-  delete_inferior (ptid_get_pid (inferior_ptid));
 
   /* There should still be a fork - if there's only one left,
      delete_fork won't remove it, because we haven't updated
@@ -391,7 +381,7 @@ linux_fork_mourn_inferior (void)
    viable forks to debug.  Detach and delete it and context-switch to
    the first available.  */
 
-extern void
+void
 linux_fork_detach (char *args, int from_tty)
 {
   /* OK, inferior_ptid is the one we are detaching from.  We need to
@@ -402,8 +392,6 @@ linux_fork_detach (char *args, int from_tty)
     error (_("Unable to detach %s"), target_pid_to_str (inferior_ptid));
 
   delete_fork (inferior_ptid);
-  /* Delete process from GDB's inferior list.  */
-  delete_inferior (ptid_get_pid (inferior_ptid));
 
   /* There should still be a fork - if there's only one left,
      delete_fork won't remove it, because we haven't updated
@@ -424,19 +412,20 @@ linux_fork_detach (char *args, int from_tty)
 /* Fork list <-> user interface.  */
 
 static void
-delete_fork_command (char *args, int from_tty)
+delete_checkpoint_command (char *args, int from_tty)
 {
   ptid_t ptid;
 
   if (!args || !*args)
-    error (_("Requires argument (fork/checkpoint id to delete)"));
+    error (_("Requires argument (checkpoint id to delete)"));
 
   ptid = fork_id_to_ptid (parse_and_eval_long (args));
   if (ptid_equal (ptid, minus_one_ptid))
-    error (_("No such fork/checkpoint id, %s"), args);
+    error (_("No such checkpoint id, %s"), args);
 
   if (ptid_equal (ptid, inferior_ptid))
-    error (_("Please switch to another fork/checkpoint before deleting the current one"));
+    error (_("\
+Please switch to another checkpoint before deleting the current one"));
 
   if (ptrace (PTRACE_KILL, PIDGET (ptid), 0, 0))
     error (_("Unable to kill pid %s"), target_pid_to_str (ptid));
@@ -445,24 +434,23 @@ delete_fork_command (char *args, int from_tty)
     printf_filtered (_("Killed %s\n"), target_pid_to_str (ptid));
 
   delete_fork (ptid);
-  /* Delete process from GDB's inferior list.  */
-  delete_inferior (ptid_get_pid (ptid));
 }
 
 static void
-detach_fork_command (char *args, int from_tty)
+detach_checkpoint_command (char *args, int from_tty)
 {
   ptid_t ptid;
 
   if (!args || !*args)
-    error (_("Requires argument (fork id to detach)"));
+    error (_("Requires argument (checkpoint id to detach)"));
 
   ptid = fork_id_to_ptid (parse_and_eval_long (args));
   if (ptid_equal (ptid, minus_one_ptid))
-    error (_("No such fork id, %s"), args);
+    error (_("No such checkpoint id, %s"), args);
 
   if (ptid_equal (ptid, inferior_ptid))
-    error (_("Please switch to another fork before detaching the current one"));
+    error (_("\
+Please switch to another checkpoint before detaching the current one"));
 
   if (ptrace (PTRACE_DETACH, PIDGET (ptid), 0, 0))
     error (_("Unable to detach %s"), target_pid_to_str (ptid));
@@ -471,15 +459,14 @@ detach_fork_command (char *args, int from_tty)
     printf_filtered (_("Detached %s\n"), target_pid_to_str (ptid));
 
   delete_fork (ptid);
-  /* Delete process from GDB's process table.  */
-  detach_inferior (ptid_get_pid (ptid));
 }
 
-/* Print information about currently known forks.  */
+/* Print information about currently known checkpoints.  */
 
 static void
-info_forks_command (char *arg, int from_tty)
+info_checkpoints_command (char *arg, int from_tty)
 {
+  struct gdbarch *gdbarch = get_current_arch ();
   struct frame_info *cur_frame;
   struct symtab_and_line sal;
   struct symtab *cur_symtab;
@@ -501,18 +488,18 @@ info_forks_command (char *arg, int from_tty)
       if (ptid_equal (fp->ptid, inferior_ptid))
        {
          printf_filtered ("* ");
-         pc = read_pc ();
+         pc = regcache_read_pc (get_current_regcache ());
        }
       else
        {
          printf_filtered ("  ");
-         pc = fp->pc;
+         pc = regcache_read_pc (fp->savedregs);
        }
       printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
       if (fp->num == 0)
        printf_filtered (_(" (main process)"));
       printf_filtered (_(" at "));
-      fputs_filtered (paddress (pc), gdb_stdout);
+      fputs_filtered (paddress (gdbarch, pc), gdb_stdout);
 
       sal = find_pc_line (pc, 0);
       if (sal.symtab)
@@ -540,31 +527,19 @@ info_forks_command (char *arg, int from_tty)
   if (printed == NULL)
     {
       if (requested > 0)
-       printf_filtered (_("No fork number %d.\n"), requested);
+       printf_filtered (_("No checkpoint number %d.\n"), requested);
       else
-       printf_filtered (_("No forks.\n"));
+       printf_filtered (_("No checkpoints.\n"));
     }
 }
 
-/* Save/restore mode variable 'detach_fork':
-   We need to temporarily take over this mode variable, while
-   preserving the user-specified state, and make sure that it 
-   gets restored in case of error.
-
-   The int pointer that we use comes from the caller, so we can
-   be called more than once (even though currently we don't need to).  */
-
-static void 
-restore_detach_fork (void *arg)
-{
-  detach_fork = *(int *) arg;
-}
+/* The PID of the process we're checkpointing.  */
+static int checkpointing_pid = 0;
 
-static struct cleanup *
-save_detach_fork (int *saved_val)
+int
+linux_fork_checkpointing_p (int pid)
 {
-  *saved_val = detach_fork;
-  return make_cleanup (restore_detach_fork, (void *) saved_val);
+  return (checkpointing_pid == pid);
 }
 
 static void
@@ -579,12 +554,6 @@ checkpoint_command (char *args, int from_tty)
   pid_t retpid;
   struct cleanup *old_chain;
   long i;
-  /* Make this temp var static, 'cause it's used in the error context.  */
-  static int temp_detach_fork;
-
-  /* Remove breakpoints, so that they are not inserted
-     in the forked process.  */
-  remove_breakpoints ();
 
   /* Make the inferior fork, record its (and gdb's) state.  */
 
@@ -598,8 +567,11 @@ checkpoint_command (char *args, int from_tty)
 
   gdbarch = get_objfile_arch (fork_objf);
   ret = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
-  old_chain = save_detach_fork (&temp_detach_fork);
-  detach_fork = 0;
+
+  /* Tell linux-nat.c that we're checkpointing this inferior.  */
+  old_chain = make_cleanup_restore_integer (&checkpointing_pid);
+  checkpointing_pid = PIDGET (inferior_ptid);
+
   ret = call_function_by_hand (fork_fn, 0, &ret);
   do_cleanups (old_chain);
   if (!ret)    /* Probably can't happen.  */
@@ -611,14 +583,14 @@ checkpoint_command (char *args, int from_tty)
     {
       int parent_pid;
 
-      printf_filtered (_("checkpoint: fork returned pid %ld.\n"), 
+      printf_filtered (_("checkpoint: fork returned pid %ld.\n"),
                       (long) retpid);
       if (info_verbose)
        {
          parent_pid = ptid_get_lwp (last_target_ptid);
          if (parent_pid == 0)
            parent_pid = ptid_get_pid (last_target_ptid);
-         printf_filtered (_("   gdb says parent = %ld.\n"), 
+         printf_filtered (_("   gdb says parent = %ld.\n"),
                           (long) parent_pid);
        }
     }
@@ -627,7 +599,6 @@ checkpoint_command (char *args, int from_tty)
   if (!fp)
     error (_("Failed to find new fork"));
   fork_save_infrun_state (fp, 1);
-  insert_breakpoints ();
 }
 
 static void
@@ -648,43 +619,13 @@ linux_fork_context (struct fork_info *newfp, int from_tty)
   fork_load_infrun_state (newfp);
   insert_breakpoints ();
 
-  printf_filtered (_("Switching to %s\n"), 
+  printf_filtered (_("Switching to %s\n"),
                   target_pid_to_str (inferior_ptid));
 
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
 }
 
-/* Switch inferior process (fork) context, by process id.  */
-static void
-process_command (char *args, int from_tty)
-{
-  struct fork_info *fp;
-
-  if (!args || !*args)
-    error (_("Requires argument (process id to switch to)"));
-
-  if ((fp = find_fork_pid (parse_and_eval_long (args))) == NULL)
-    error (_("Not found: process id %s"), args);
-
-  linux_fork_context (fp, from_tty);
-}
-
-/* Switch inferior process (fork) context, by fork id.  */
-static void
-fork_command (char *args, int from_tty)
-{
-  struct fork_info *fp;
-
-  if (!args || !*args)
-    error (_("Requires argument (fork id to switch to)"));
-
-  if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
-    error (_("Not found: fork id %s"), args);
-
-  linux_fork_context (fp, from_tty);
-}
-
-/* Switch inferior process (fork) context, by checkpoint id.  */
+/* Switch inferior process (checkpoint) context, by checkpoint id.  */
 static void
 restart_command (char *args, int from_tty)
 {
@@ -704,69 +645,36 @@ _initialize_linux_fork (void)
 {
   init_fork_list ();
 
-  /* Set/show detach-on-fork: user-settable mode.  */
-
-  add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
-Set whether gdb will detach the child of a fork."), _("\
-Show whether gdb will detach the child of a fork."), _("\
-Tells gdb whether to detach the child of a fork."), 
-                          NULL, NULL, &setlist, &showlist);
-
-  /* Set/show restart-auto-finish: user-settable count.  Causes the
-     first "restart" of a fork to do some number of "finish" commands
-     before returning to user.
-
-     Useful because otherwise the virgin fork process will be stopped
-     somewhere in the un-interesting fork system call.  */
-
   /* Checkpoint command: create a fork of the inferior process
      and set it aside for later debugging.  */
 
   add_com ("checkpoint", class_obscure, checkpoint_command, _("\
 Fork a duplicate process (experimental)."));
 
-  /* Restart command: restore the context of a specified fork
-     process.  May be used for "program forks" as well as for
-     "debugger forks" (checkpoints).  */
+  /* Restart command: restore the context of a specified checkpoint
+     process.  */
 
   add_com ("restart", class_obscure, restart_command, _("\
 restart <n>: restore program context from a checkpoint.\n\
 Argument 'n' is checkpoint ID, as displayed by 'info checkpoints'."));
 
   /* Delete checkpoint command: kill the process and remove it from
-     fork list.  */
+     the fork list.  */
 
-  add_cmd ("checkpoint", class_obscure, delete_fork_command, _("\
-Delete a fork/checkpoint (experimental)."),
+  add_cmd ("checkpoint", class_obscure, delete_checkpoint_command, _("\
+Delete a checkpoint (experimental)."),
           &deletelist);
 
-  /* Detach checkpoint command: release the process to run independently, 
+  /* Detach checkpoint command: release the process to run independently,
      and remove it from the fork list.  */
 
-  add_cmd ("checkpoint", class_obscure, detach_fork_command, _("\
-Detach from a fork/checkpoint (experimental)."),
+  add_cmd ("checkpoint", class_obscure, detach_checkpoint_command, _("\
+Detach from a checkpoint (experimental)."),
           &detachlist);
 
-  /* Info checkpoints command: list all forks/checkpoints 
+  /* Info checkpoints command: list all forks/checkpoints
      currently under gdb's control.  */
 
-  add_info ("checkpoints", info_forks_command,
-           _("IDs of currently known forks/checkpoints."));
-
-  /* Command aliases (let "fork" and "checkpoint" be used 
-     interchangeably).  */
-
-  add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &deletelist);
-  add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &detachlist);
-  add_info_alias ("forks", "checkpoints", 0);
-
-  /* "fork <n>" (by analogy to "thread <n>").  */
-  add_com ("fork", class_obscure, fork_command, _("\
-fork <n>: Switch between forked processes.\n\
-Argument 'n' is fork ID, as displayed by 'info forks'."));
-
-  /* "process <proc id>" as opposed to "fork <fork id>".  */
-  add_com ("process", class_obscure, process_command, _("\
-process <pid>: Switch between forked processes.\n\
-Argument 'pid' is process ID, as displayed by 'info forks' or 'shell ps'."));
+  add_info ("checkpoints", info_checkpoints_command,
+           _("IDs of currently known checkpoints."));
 }