aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r--gdb/linux-nat.c104
1 files changed, 69 insertions, 35 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index eb609c8..6ded38d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -3466,44 +3466,44 @@ linux_nat_wait (struct target_ops *ops,
return event_ptid;
}
-static int
-kill_callback (struct lwp_info *lp, void *data)
+/* Kill one LWP. */
+
+static void
+kill_one_lwp (pid_t pid)
{
/* PTRACE_KILL may resume the inferior. Send SIGKILL first. */
errno = 0;
- kill_lwp (ptid_get_lwp (lp->ptid), SIGKILL);
+ kill_lwp (pid, SIGKILL);
if (debug_linux_nat)
{
int save_errno = errno;
fprintf_unfiltered (gdb_stdlog,
- "KC: kill (SIGKILL) %s, 0, 0 (%s)\n",
- target_pid_to_str (lp->ptid),
+ "KC: kill (SIGKILL) %ld, 0, 0 (%s)\n", (long) pid,
save_errno ? safe_strerror (save_errno) : "OK");
}
/* Some kernels ignore even SIGKILL for processes under ptrace. */
errno = 0;
- ptrace (PTRACE_KILL, ptid_get_lwp (lp->ptid), 0, 0);
+ ptrace (PTRACE_KILL, pid, 0, 0);
if (debug_linux_nat)
{
int save_errno = errno;
fprintf_unfiltered (gdb_stdlog,
- "KC: PTRACE_KILL %s, 0, 0 (%s)\n",
- target_pid_to_str (lp->ptid),
+ "KC: PTRACE_KILL %ld, 0, 0 (%s)\n", (long) pid,
save_errno ? safe_strerror (save_errno) : "OK");
}
-
- return 0;
}
-static int
-kill_wait_callback (struct lwp_info *lp, void *data)
+/* Wait for an LWP to die. */
+
+static void
+kill_wait_one_lwp (pid_t pid)
{
- pid_t pid;
+ pid_t res;
/* We must make sure that there are no pending events (delayed
SIGSTOPs, pending SIGTRAPs, etc.) to make sure the current
@@ -3511,49 +3511,83 @@ kill_wait_callback (struct lwp_info *lp, void *data)
do
{
- pid = my_waitpid (ptid_get_lwp (lp->ptid), NULL, __WALL);
- if (pid != (pid_t) -1)
+ res = my_waitpid (pid, NULL, __WALL);
+ if (res != (pid_t) -1)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "KWC: wait %s received unknown.\n",
- target_pid_to_str (lp->ptid));
+ "KWC: wait %ld received unknown.\n",
+ (long) pid);
/* The Linux kernel sometimes fails to kill a thread
completely after PTRACE_KILL; that goes from the stop
point in do_fork out to the one in get_signal_to_deliver
and waits again. So kill it again. */
- kill_callback (lp, NULL);
+ kill_one_lwp (pid);
}
}
- while (pid == ptid_get_lwp (lp->ptid));
+ while (res == pid);
+
+ gdb_assert (res == -1 && errno == ECHILD);
+}
+
+/* Callback for iterate_over_lwps. */
- gdb_assert (pid == -1 && errno == ECHILD);
+static int
+kill_callback (struct lwp_info *lp, void *data)
+{
+ kill_one_lwp (ptid_get_lwp (lp->ptid));
return 0;
}
+/* Callback for iterate_over_lwps. */
+
+static int
+kill_wait_callback (struct lwp_info *lp, void *data)
+{
+ kill_wait_one_lwp (ptid_get_lwp (lp->ptid));
+ return 0;
+}
+
+/* Kill the fork children of any threads of inferior INF that are
+ stopped at a fork event. */
+
+static void
+kill_unfollowed_fork_children (struct inferior *inf)
+{
+ struct thread_info *thread;
+
+ ALL_NON_EXITED_THREADS (thread)
+ if (thread->inf == inf)
+ {
+ struct target_waitstatus *ws = &thread->pending_follow;
+
+ if (ws->kind == TARGET_WAITKIND_FORKED
+ || ws->kind == TARGET_WAITKIND_VFORKED)
+ {
+ ptid_t child_ptid = ws->value.related_pid;
+ int child_pid = ptid_get_pid (child_ptid);
+ int child_lwp = ptid_get_lwp (child_ptid);
+ int status;
+
+ kill_one_lwp (child_lwp);
+ kill_wait_one_lwp (child_lwp);
+
+ /* Let the arch-specific native code know this process is
+ gone. */
+ linux_nat_forget_process (child_pid);
+ }
+ }
+}
+
static void
linux_nat_kill (struct target_ops *ops)
{
struct target_waitstatus last;
- ptid_t last_ptid;
- int status;
/* 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)
- {
- ptrace (PT_KILL, ptid_get_pid (last.value.related_pid), 0, 0);
- wait (&status);
-
- /* Let the arch-specific native code know this process is
- gone. */
- linux_nat_forget_process (ptid_get_pid (last.value.related_pid));
- }
+ kill_unfollowed_fork_children (current_inferior ());
if (forks_exist_p ())
linux_fork_killall ();