summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Snyder <msnyder@vmware.com>2005-11-26 22:52:10 +0000
committerMichael Snyder <msnyder@vmware.com>2005-11-26 22:52:10 +0000
commitb80f8a5de994430287506f85c58659584948628f (patch)
tree7ba0dfaffaba5552d67e345f2b1fddd5ee48e7c1
parent58f06d72a3440fd07b7c956d5f43bcf531fcafe8 (diff)
downloadbinutils-gdb-b80f8a5de994430287506f85c58659584948628f.tar.gz
2005-11-26 Michael Snyder <msnyder@redhat.com>
* linux-fork.h: New file. * linux-nat.c: Include linux-fork.h, remove forward declarations. (kill_inferior): Loop over forks and PTRACE_KILL them all. (add_fork): Special case -- insert original fork as special zeroeth element in list. (info_forks_command): Use current PC instead of savedregs pc for current fork. If no SAL, print a minsym. Identify the zeroeth fork as "main process".
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/linux-nat.c127
2 files changed, 93 insertions, 45 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b0e94034e50..df28ca7f187 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2005-11-26 Michael Snyder <msnyder@redhat.com>
+
+ * linux-fork.h: New file.
+ * linux-nat.c: Include linux-fork.h, remove forward declarations.
+ (kill_inferior): Loop over forks and PTRACE_KILL them all.
+ (add_fork): Special case -- insert original fork as special
+ zeroeth element in list.
+ (info_forks_command): Use current PC instead of savedregs pc
+ for current fork. If no SAL, print a minsym. Identify the
+ zeroeth fork as "main process".
+
2005-11-25 Michael Snyder <msnyder@redhat.com>
* linux-nat.c (restart_auto_finish): New set/show variable.
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 204cf16ca60..757b37e859d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -31,6 +31,7 @@
#endif
#include <sys/ptrace.h>
#include "linux-nat.h"
+#include "linux-fork.h"
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
@@ -339,11 +340,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
linux_enable_event_reporting (ptid);
}
-struct fork_info;
static int detach_fork = 1;
-static struct fork_info *add_fork (pid_t);
-static struct fork_info *find_fork_pid (pid_t);
-static void fork_save_infrun_state (struct fork_info *, int);
int
child_follow_fork (struct target_ops *ops, int follow_child)
@@ -617,30 +614,51 @@ kill_inferior (void)
if (pid == 0)
return;
- /* If we're stopped while forking and we haven't followed yet, kill the
- other task. We need to do this first because the parent will be
- sleeping if this is a vfork. */
-
- get_last_target_status (&last_ptid, &last);
-
- if (last.kind == TARGET_WAITKIND_FORKED
- || last.kind == TARGET_WAITKIND_VFORKED)
+ /* First cut -- let's crudely do everything inline. */
+ if (fork_list)
{
- ptrace (PT_KILL, last.value.related_pid, 0, 0);
- wait (&status);
+ /* Walk list and kill every pid. No need to treat the
+ current inferior_ptid as special (we do not return a
+ status for it) -- however any process may be a child
+ or a parent, so may get a SIGCHLD from a previously
+ killed child. Wait them all out. */
+
+ do {
+ pid = PIDGET (fork_list->ptid);
+ do {
+ ptrace (PT_KILL, pid, 0, 0);
+ ret = waitpid (pid, &status, 0);
+ } while (ret == pid && WIFSTOPPED (status));
+ delete_fork (fork_list->ptid);
+ } while (fork_list != NULL);
}
+ else
+ {
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the other task. We need to do this first because the
+ parent will be sleeping if this is a vfork. */
- /* Kill the current process. */
- ptrace (PT_KILL, pid, 0, 0);
- ret = wait (&status);
+ get_last_target_status (&last_ptid, &last);
- /* We might get a SIGCHLD instead of an exit status. This is
- aggravated by the first kill above - a child has just died. */
+ if (last.kind == TARGET_WAITKIND_FORKED
+ || last.kind == TARGET_WAITKIND_VFORKED)
+ {
+ ptrace (PT_KILL, last.value.related_pid, 0, 0);
+ wait (&status);
+ }
- while (ret == pid && WIFSTOPPED (status))
- {
+ /* Kill the current process. */
ptrace (PT_KILL, pid, 0, 0);
ret = wait (&status);
+
+ /* We might get a SIGCHLD instead of an exit status. This is
+ aggravated by the first kill above - a child has just died. */
+
+ while (ret == pid && WIFSTOPPED (status))
+ {
+ ptrace (PT_KILL, pid, 0, 0);
+ ret = wait (&status);
+ }
}
target_mourn_inferior ();
@@ -3356,17 +3374,6 @@ lin_thread_get_thread_signals (sigset_t *set)
/* Hack and slash, steal code from all over the place,
and just try stuff out. */
-struct fork_info
-{
- struct fork_info *next;
- ptid_t ptid; /* "Actual process id";
- In fact, this may be overloaded with
- kernel thread id, etc. */
- int num; /* Convenient handle (GDB fork id) */
- struct regcache *savedregs;
- int clobber_regs; /* True if we should restore saved regs. */
-};
-
/* Load infrun state for the fork PTID. */
static void
@@ -3382,7 +3389,7 @@ fork_load_infrun_state (struct fork_info *fp)
/* Save infrun state for the fork PTID. */
-static void
+extern void
fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
{
if (fp->savedregs)
@@ -3392,14 +3399,25 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
fp->clobber_regs = clobber_regs;
}
-static struct fork_info *fork_list = NULL;
+struct fork_info *fork_list = NULL;
static int highest_fork_num;
-static struct fork_info *
+extern struct fork_info *
add_fork (pid_t pid)
{
struct fork_info *fp;
+ if (fork_list == NULL &&
+ pid != PIDGET (inferior_ptid))
+ {
+ /* Special case -- if this is the first fork in the list
+ (the list is hitherto empty), and if this new fork is
+ NOT the current inferior_ptid, then add inferior_ptid
+ first, as a special zeroeth fork id. */
+ highest_fork_num = -1;
+ add_fork (PIDGET (inferior_ptid)); /* safe recursion */
+ }
+
fp = XZALLOC (struct fork_info);
fp->ptid = pid_to_ptid (pid);
fp->num = ++highest_fork_num;
@@ -3420,7 +3438,7 @@ free_fork (struct fork_info *fp)
}
}
-void
+extern void
delete_fork (ptid_t ptid)
{
struct fork_info *fp, *fpprev;
@@ -3486,7 +3504,7 @@ find_fork_ptid (ptid_t ptid)
}
/* Find a fork_info by matching pid. */
-static struct fork_info *
+extern struct fork_info *
find_fork_pid (pid_t pid)
{
struct fork_info *fp;
@@ -3619,11 +3637,18 @@ info_forks_command (char *arg, int from_tty)
for (fp = fork_list; fp; fp = fp->next)
{
if (ptid_equal (fp->ptid, inferior_ptid))
- printf_filtered ("* ");
+ {
+ printf_filtered ("* ");
+ pc = read_pc ();
+ }
else
- printf_filtered (" ");
+ {
+ printf_filtered (" ");
+ regcache_raw_read_unsigned (fp->savedregs, PC_REGNUM, &pc);
+ }
printf_filtered ("%d %s", fp->num, target_tid_to_str (fp->ptid));
- regcache_raw_read_unsigned (fp->savedregs, PC_REGNUM, &pc);
+ if (fp->num == 0)
+ printf_filtered (" (main process)");
printf_filtered (" at ");
deprecated_print_address_numeric (pc, 1, gdb_stdout);
@@ -3632,6 +3657,14 @@ info_forks_command (char *arg, int from_tty)
printf_filtered (", file %s", sal.symtab->filename);
if (sal.line)
printf_filtered (", line %d", sal.line);
+ if (!sal.symtab && !sal.line)
+ {
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym)
+ printf_filtered (", <%s>", SYMBOL_LINKAGE_NAME (msym));
+ }
putchar_filtered ('\n');
}
@@ -3729,6 +3762,7 @@ restart_command (char *args, int from_tty)
}
fork_save_infrun_state (oldfp, 1);
+ oldfp->been_restarted = 1;
inferior_ptid = newfp->ptid;
fork_load_infrun_state (newfp);
registers_changed ();
@@ -3738,14 +3772,17 @@ restart_command (char *args, int from_tty)
reinit_frame_cache ();
stop_pc = read_pc ();
select_frame (get_current_frame ());
+
+ if (!newfp->been_restarted)
+ for (i = 0; i < restart_auto_finish; i++)
+ {
+ execute_command ("finish", from_tty);
+ }
+
+ newfp->been_restarted = 1;
printf_filtered ("Switching to %s\n",
target_pid_or_tid_to_str (inferior_ptid));
- for (i = 0; i < restart_auto_finish; i++)
- {
- execute_command ("finish", from_tty);
- }
-
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}