mirror of
https://github.com/intel/llvm.git
synced 2026-01-18 07:57:36 +08:00
Reland "[lldb] [Process] Watch for fork/vfork notifications" for FreeBSD
The original commit was reverted because of the problems it introduced on Linux. However, FreeBSD should not be affected, so restore that part and we will address Linux separately. While at it, remove the dbreg hack as the underlying issue has been fixed in the FreeBSD kernel and the problem is unlikely to happen in real life use anyway. Differential Revision: https://reviews.llvm.org/D98822
This commit is contained in:
@@ -247,6 +247,19 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.pl_flags & PL_FLAG_FORKED) {
|
||||
MonitorClone(info.pl_child_pid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.pl_flags & PL_FLAG_VFORK_DONE) {
|
||||
Status error =
|
||||
PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
|
||||
if (error.Fail())
|
||||
SetState(StateType::eStateInvalid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.pl_lwpid > 0) {
|
||||
for (const auto &t : m_threads) {
|
||||
if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid))
|
||||
@@ -705,17 +718,17 @@ NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
|
||||
|
||||
void NativeProcessFreeBSD::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, 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);
|
||||
@@ -885,7 +898,7 @@ Status NativeProcessFreeBSD::SetupTrace() {
|
||||
PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
|
||||
if (status.Fail())
|
||||
return status;
|
||||
events |= PTRACE_LWP;
|
||||
events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK;
|
||||
status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
|
||||
if (status.Fail())
|
||||
return status;
|
||||
@@ -919,3 +932,39 @@ Status NativeProcessFreeBSD::ReinitializeThreads() {
|
||||
bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
|
||||
return !m_arch.IsMIPS();
|
||||
}
|
||||
|
||||
void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid) {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
LLDB_LOG(log, "fork, 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;
|
||||
NativeProcessFreeBSD 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, pt_error.ToError(),
|
||||
"unable to resume parent process {1}: {0}", GetID());
|
||||
SetState(StateType::eStateInvalid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ private:
|
||||
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();
|
||||
|
||||
50
lldb/test/Shell/Subprocess/Inputs/fork.cpp
Normal file
50
lldb/test/Shell/Subprocess/Inputs/fork.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
#if defined(TEST_CLONE)
|
||||
#include <sched.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int g_val = 0;
|
||||
|
||||
void parent_func() {
|
||||
g_val = 1;
|
||||
printf("function run in parent\n");
|
||||
}
|
||||
|
||||
int child_func(void *unused) {
|
||||
// we need to avoid memory modifications for vfork(), yet we want
|
||||
// to be able to test watchpoints, so do the next best thing
|
||||
// and restore the original value
|
||||
g_val = 2;
|
||||
g_val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
alignas(uintmax_t) char stack[4096];
|
||||
|
||||
#if defined(TEST_CLONE)
|
||||
pid_t pid = clone(child_func, &stack[sizeof(stack)], 0, NULL);
|
||||
#elif defined(TEST_FORK)
|
||||
pid_t pid = TEST_FORK();
|
||||
if (pid == 0)
|
||||
_exit(child_func(NULL));
|
||||
#endif
|
||||
assert(pid != -1);
|
||||
|
||||
parent_func();
|
||||
int status, wait_flags = 0;
|
||||
#if defined(TEST_CLONE)
|
||||
wait_flags = __WALL;
|
||||
#endif
|
||||
pid_t waited = waitpid(pid, &status, wait_flags);
|
||||
assert(waited == pid);
|
||||
assert(WIFEXITED(status));
|
||||
printf("child exited: %d\n", WEXITSTATUS(status));
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
lldb/test/Shell/Subprocess/fork-follow-parent-wp.test
Normal file
13
lldb/test/Shell/Subprocess/fork-follow-parent-wp.test
Normal file
@@ -0,0 +1,13 @@
|
||||
# REQUIRES: native && dbregs-set
|
||||
# UNSUPPORTED: system-windows
|
||||
# RUN: %clangxx_host -g %p/Inputs/fork.cpp -DTEST_FORK=fork -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
|
||||
11
lldb/test/Shell/Subprocess/fork-follow-parent.test
Normal file
11
lldb/test/Shell/Subprocess/fork-follow-parent.test
Normal file
@@ -0,0 +1,11 @@
|
||||
# REQUIRES: native
|
||||
# UNSUPPORTED: system-windows
|
||||
# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_FORK=fork -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
|
||||
2
lldb/test/Shell/Subprocess/lit.local.cfg
Normal file
2
lldb/test/Shell/Subprocess/lit.local.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
if 'lldb-repro' in config.available_features:
|
||||
config.unsupported = True
|
||||
14
lldb/test/Shell/Subprocess/vfork-follow-parent-wp.test
Normal file
14
lldb/test/Shell/Subprocess/vfork-follow-parent-wp.test
Normal file
@@ -0,0 +1,14 @@
|
||||
# REQUIRES: native && dbregs-set
|
||||
# UNSUPPORTED: system-windows
|
||||
# UNSUPPORTED: system-darwin
|
||||
# RUN: %clangxx_host -g %p/Inputs/fork.cpp -DTEST_FORK=vfork -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
|
||||
11
lldb/test/Shell/Subprocess/vfork-follow-parent.test
Normal file
11
lldb/test/Shell/Subprocess/vfork-follow-parent.test
Normal file
@@ -0,0 +1,11 @@
|
||||
# REQUIRES: native
|
||||
# UNSUPPORTED: system-windows
|
||||
# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_FORK=vfork -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
|
||||
Reference in New Issue
Block a user