Reland "[lldb] [Process] Watch for fork/vfork notifications" for NetBSD

Differential Revision: https://reviews.llvm.org/D98822

GitOrigin-RevId: 7da3b44d67f81e4cff3ac4f72888e667bd9e6adb
diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index 57f0eb3..1f357e3 100644
--- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -256,6 +256,24 @@
     SetState(StateType::eStateStopped, true);
     return;
   }
+  case TRAP_CHLD: {
+    ptrace_state_t pst;
+    Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
+    if (error.Fail()) {
+      SetState(StateType::eStateInvalid);
+      return;
+    }
+
+    if (pst.pe_report_event == PTRACE_VFORK_DONE) {
+      Status error =
+          PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+      if (error.Fail())
+        SetState(StateType::eStateInvalid);
+      return;
+    } else
+      MonitorClone(pst.pe_other_pid);
+    return;
+  }
   case TRAP_LWP: {
     ptrace_state_t pst;
     Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
@@ -510,7 +528,7 @@
   if (GetID() == LLDB_INVALID_PROCESS_ID)
     return error;
 
-  return PtraceWrapper(PT_DETACH, GetID());
+  return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
 }
 
 Status NativeProcessNetBSD::Signal(int signo) {
@@ -738,17 +756,17 @@
 
 void NativeProcessNetBSD::SigchldHandler() {
   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
-  // Process all pending waitpid notifications.
   int status;
   ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
                                                  WALLSIG | WNOHANG);
 
   if (wait_pid == 0)
-    return; // We are done.
+    return;
 
   if (wait_pid == -1) {
     Status error(errno, eErrorTypePOSIX);
     LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+    return;
   }
 
   WaitStatus wait_status = WaitStatus::Decode(status);
@@ -936,8 +954,9 @@
       PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
   if (status.Fail())
     return status;
-  // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
-  events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
+  // TODO: PTRACE_POSIX_SPAWN?
+  events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
+                         PTRACE_VFORK | PTRACE_VFORK_DONE;
   status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
   if (status.Fail())
     return status;
@@ -974,3 +993,39 @@
 
   return error;
 }
+
+void NativeProcessNetBSD::MonitorClone(::pid_t child_pid) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  LLDB_LOG(log, "clone, child_pid={0}", child_pid);
+
+  int status;
+  ::pid_t wait_pid =
+      llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
+  if (wait_pid != child_pid) {
+    LLDB_LOG(log,
+             "waiting for pid {0} failed. Assuming the pid has "
+             "disappeared in the meantime",
+             child_pid);
+    return;
+  }
+  if (WIFEXITED(status)) {
+    LLDB_LOG(log,
+             "waiting for pid {0} returned an 'exited' event. Not "
+             "tracking it.",
+             child_pid);
+    return;
+  }
+
+  MainLoop unused_loop;
+  NativeProcessNetBSD child_process{static_cast<::pid_t>(child_pid),
+                                    m_terminal_fd, m_delegate, m_arch,
+                                    unused_loop};
+  child_process.Detach();
+  Status pt_error =
+      PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
+  if (pt_error.Fail()) {
+    LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),
+                   "unable to resume parent process {1}: {0}", GetID());
+    SetState(StateType::eStateInvalid);
+  }
+}
diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 3d59a4f..3384078 100644
--- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -106,6 +106,7 @@
   void MonitorSIGSTOP(lldb::pid_t pid);
   void MonitorSIGTRAP(lldb::pid_t pid);
   void MonitorSignal(lldb::pid_t pid, int signal);
+  void MonitorClone(::pid_t child_pid);
 
   Status PopulateMemoryRegionCache();
   void SigchldHandler();
diff --git a/test/Shell/Subprocess/clone-follow-parent-wp.test b/test/Shell/Subprocess/clone-follow-parent-wp.test
new file mode 100644
index 0000000..19fa7d6
--- /dev/null
+++ b/test/Shell/Subprocess/clone-follow-parent-wp.test
@@ -0,0 +1,14 @@
+# REQUIRES: native && system-netbsd && dbregs-set
+# clone() tests fails on arm64 Linux, PR #49899
+# UNSUPPORTED: system-linux && target-aarch64
+# RUN: %clangxx_host -g %p/Inputs/fork.cpp -DTEST_CLONE -o %t
+# RUN: %lldb -b -s %s %t | FileCheck %s
+process launch -s
+watchpoint set variable -w write g_val
+# CHECK: Watchpoint created:
+continue
+# CHECK-NOT: function run in parent
+# CHECK: stop reason = watchpoint
+continue
+# CHECK: function run in parent
+# CHECK: child exited: 0
diff --git a/test/Shell/Subprocess/clone-follow-parent.test b/test/Shell/Subprocess/clone-follow-parent.test
new file mode 100644
index 0000000..3d89279
--- /dev/null
+++ b/test/Shell/Subprocess/clone-follow-parent.test
@@ -0,0 +1,12 @@
+# REQUIRES: native && (system-linux || system-netbsd)
+# clone() tests fails on arm64 Linux, PR #49899
+# UNSUPPORTED: system-linux && target-aarch64
+# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_CLONE -o %t
+# RUN: %lldb -b -s %s %t | FileCheck %s
+b parent_func
+process launch
+# CHECK-NOT: function run in parent
+# CHECK: stop reason = breakpoint
+continue
+# CHECK: function run in parent
+# CHECK: child exited: 0