[9/9] fbsd-nat: Stop a process if it is running before killing it.

Message ID 20230228181845.99936-10-jhb@FreeBSD.org
State New
Headers
Series Fixes for multiprocess for FreeBSD's native target |

Commit Message

John Baldwin Feb. 28, 2023, 6:18 p.m. UTC
  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(-)
  

Patch

diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 32dd482ec3c..42c69875b0f 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -1158,6 +1158,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.  */
 
@@ -1467,23 +1492,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 ());
@@ -2115,6 +2124,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 (this, 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 3dc22ce1cca..8096c53bc03 100644
--- a/gdb/fbsd-nat.h
+++ b/gdb/fbsd-nat.h
@@ -80,6 +80,8 @@  class fbsd_nat_target : public inf_ptrace_target
 
   void detach (inferior *, int) override;
 
+  void kill () override;
+
   void mourn_inferior () override;
 
   void resume (ptid_t, int, enum gdb_signal) override;