diff options
author | John Baldwin <jhb@FreeBSD.org> | 2023-08-14 13:38:42 -0700 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2023-08-14 13:38:42 -0700 |
commit | fdeef5e428c0d85003911262a7831babc66c60de (patch) | |
tree | dd56daf2ef6bf2c5f519bce8293baeefde92fc64 /gdb | |
parent | 57c28d45f9ad14130c8375b3b5ec6996b63574fd (diff) | |
download | gdb-fdeef5e428c0d85003911262a7831babc66c60de.zip gdb-fdeef5e428c0d85003911262a7831babc66c60de.tar.gz gdb-fdeef5e428c0d85003911262a7831babc66c60de.tar.bz2 |
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.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/fbsd-nat.c | 93 | ||||
-rw-r--r-- | 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 5f66a30..41ca1f6 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 3ae0a97..7016cc0 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; |