From fdeef5e428c0d85003911262a7831babc66c60de Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 14 Aug 2023 13:38:42 -0700 Subject: [PATCH] fbsd-nat: Stop a process if it is running before killing it. In addition, detach from any child processes implicitly attached to by the kernel due to fork following that have not yet been processed by GDB's core. --- gdb/fbsd-nat.c | 93 +++++++++++++++++++++++++++++++++++++++++--------- gdb/fbsd-nat.h | 2 ++ 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 5f66a3053d5..41ca1f61561 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1140,6 +1140,31 @@ fbsd_is_child_pending (pid_t pid) return null_ptid; } +/* Wait for a child of a fork to report its stop. Returns the PTID of + the new child process. */ + +static ptid_t +fbsd_wait_for_fork_child (pid_t pid) +{ + ptid_t ptid = fbsd_is_child_pending (pid); + if (ptid != null_ptid) + return ptid; + + int status; + pid_t wpid = waitpid (pid, &status, 0); + if (wpid == -1) + perror_with_name (("waitpid")); + + gdb_assert (wpid == pid); + + struct ptrace_lwpinfo pl; + if (ptrace (PT_LWPINFO, wpid, (caddr_t) &pl, sizeof pl) == -1) + perror_with_name (("ptrace (PT_LWPINFO)")); + + gdb_assert (pl.pl_flags & PL_FLAG_CHILD); + return ptid_t (wpid, pl.pl_lwpid); +} + #ifndef PTRACE_VFORK /* Record a pending vfork done event. */ @@ -1447,23 +1472,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, #endif /* Make sure the other end of the fork is stopped too. */ - child_ptid = fbsd_is_child_pending (child); - if (child_ptid == null_ptid) - { - int status; - - pid = waitpid (child, &status, 0); - if (pid == -1) - perror_with_name (("waitpid")); - - gdb_assert (pid == child); - - if (ptrace (PT_LWPINFO, child, (caddr_t) &pl, sizeof pl) == -1) - perror_with_name (("ptrace (PT_LWPINFO)")); - - gdb_assert (pl.pl_flags & PL_FLAG_CHILD); - child_ptid = ptid_t (child, pl.pl_lwpid); - } + child_ptid = fbsd_wait_for_fork_child (child); /* Enable additional events on the child process. */ fbsd_enable_proc_events (child_ptid.pid ()); @@ -2105,6 +2114,56 @@ fbsd_nat_target::detach (inferior *inf, int from_tty) detach_success (inf); } +/* Implement the "kill" target method. */ + +void +fbsd_nat_target::kill () +{ + pid_t pid = inferior_ptid.pid (); + if (pid == 0) + return; + + inferior *inf = current_inferior (); + stop_process (inf); + + if (detach_fork_children (inf)) { + /* No need to kill now. */ + target_mourn_inferior (inferior_ptid); + + return; + } + +#ifdef TDP_RFPPWAIT + /* If there are any threads that have forked a new child but not yet + reported it because other threads reported events first, detach + from the children before killing the parent. */ + auto lambda = [] (const struct ptrace_lwpinfo &pl) + { + if (pl.pl_flags & PL_FLAG_FORKED) + { + pid_t child = pl.pl_child_pid; + + /* If the child hasn't reported its stop yet, wait for it to + stop. */ + fbsd_wait_for_fork_child (child); + + /* Detach from the child. */ + (void) ptrace (PT_DETACH, child, (caddr_t) 1, 0); + } + return false; + }; + iterate_other_ptrace_events (pid, gdb::make_function_view (lambda)); +#endif + + if (ptrace (PT_KILL, pid, NULL, 0) == -1) + perror_with_name (("ptrace (PT_KILL)")); + + int status; + waitpid (pid, &status, 0); + + target_mourn_inferior (inferior_ptid); +} + void fbsd_nat_target::mourn_inferior () { diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h index 3ae0a97a336..7016cc0242a 100644 --- a/gdb/fbsd-nat.h +++ b/gdb/fbsd-nat.h @@ -83,6 +83,8 @@ public: void detach (inferior *, int) override; + void kill () override; + void mourn_inferior () override; void resume (ptid_t, int, enum gdb_signal) override; -- 2.30.2