/* GNU/Linux native-dependent code for debugging multiple forks.
- Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "gdbcmd.h"
#include "infcall.h"
+#include "objfiles.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "linux-fork.h"
#include "linux-nat.h"
#include <sys/ptrace.h>
-#include <sys/wait.h>
+#include "gdb_wait.h"
#include <sys/param.h>
-#include <dirent.h>
+#include "gdb_dirent.h"
#include <ctype.h>
struct fork_info *fork_list;
for (fp = fork_list; fp; fp = fpnext)
{
fpnext = fp->next;
+ delete_inferior (ptid_get_pid (fp->ptid));
free_fork (fp);
}
{
pid = PIDGET (fp->ptid);
do {
- ptrace (PT_KILL, pid, 0, 0);
+ /* Use SIGKILL instead of PTRACE_KILL because the former works even
+ if the thread is running, while the later doesn't. */
+ kill (pid, SIGKILL);
ret = waitpid (pid, &status, 0);
/* We might get a SIGCHLD instead of an exit status. This is
aggravated by the first kill above - a child has just
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
delete_fork (inferior_ptid);
}
+/* The current inferior_ptid is being detached, but there are other
+ viable forks to debug. Detach and delete it and context-switch to
+ the first available. */
+
+extern void
+linux_fork_detach (char *args, int from_tty)
+{
+ /* OK, inferior_ptid is the one we are detaching from. We need to
+ delete it from the fork_list, and switch to the next available
+ fork. */
+
+ if (ptrace (PTRACE_DETACH, PIDGET (inferior_ptid), 0, 0))
+ 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
+ inferior_ptid yet. */
+ gdb_assert (fork_list);
+
+ fork_load_infrun_state (fork_list);
+
+ if (from_tty)
+ printf_filtered (_("[Switching to %s]\n"),
+ target_pid_to_str (inferior_ptid));
+
+ /* If there's only one fork, switch back to non-fork mode. */
+ if (fork_list->next == NULL)
+ delete_fork (inferior_ptid);
+}
+
/* Fork list <-> user interface. */
static void
error (_("Please switch to another fork/checkpoint before deleting the current one"));
if (ptrace (PTRACE_KILL, PIDGET (ptid), 0, 0))
- error (_("Unable to kill pid %s"), target_tid_to_str (ptid));
+ error (_("Unable to kill pid %s"), target_pid_to_str (ptid));
if (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
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. */
if (fp->num == 0)
printf_filtered (_(" (main process)"));
printf_filtered (_(" at "));
- deprecated_print_address_numeric (pc, 1, gdb_stdout);
+ fputs_filtered (paddress (pc), gdb_stdout);
sal = find_pc_line (pc, 0);
if (sal.symtab)
static void
checkpoint_command (char *args, int from_tty)
{
+ struct objfile *fork_objf;
+ struct gdbarch *gdbarch;
struct target_waitstatus last_target_waitstatus;
ptid_t last_target_ptid;
struct value *fork_fn = NULL, *ret;
/* 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. */
if (lookup_minimal_symbol ("fork", NULL, NULL) != NULL)
- fork_fn = find_function_in_inferior ("fork");
+ fork_fn = find_function_in_inferior ("fork", &fork_objf);
if (!fork_fn)
if (lookup_minimal_symbol ("_fork", NULL, NULL) != NULL)
- fork_fn = find_function_in_inferior ("fork");
+ fork_fn = find_function_in_inferior ("fork", &fork_objf);
if (!fork_fn)
error (_("checkpoint: can't find fork function in inferior."));
- ret = value_from_longest (builtin_type_int, 0);
+ 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;
ret = call_function_by_hand (fork_fn, 0, &ret);
if (!fp)
error (_("Failed to find new fork"));
fork_save_infrun_state (fp, 1);
+ insert_breakpoints ();
}
static void
linux_fork_context (struct fork_info *newfp, int from_tty)
{
/* Now we attempt to switch processes. */
- struct fork_info *oldfp = find_fork_ptid (inferior_ptid);
+ struct fork_info *oldfp;
ptid_t ptid;
int id, i;
- if (!newfp)
- error (_("No such fork/process"));
+ gdb_assert (newfp != NULL);
- if (!oldfp)
- oldfp = add_fork (ptid_get_pid (inferior_ptid));
+ oldfp = find_fork_ptid (inferior_ptid);
+ gdb_assert (oldfp != NULL);
fork_save_infrun_state (oldfp, 1);
+ remove_breakpoints ();
fork_load_infrun_state (newfp);
+ insert_breakpoints ();
printf_filtered (_("Switching to %s\n"),
target_pid_to_str (inferior_ptid));