mgorny updated this revision to Diff 220871.
mgorny marked 5 inline comments as done.
mgorny retitled this revision from "[lldb] [Process/NetBSD] Implement
per-thread execution control" to "<WIP> [lldb] [Process/NetBSD] Multithread
support".
mgorny edited the summary of this revision.
Herald added a reviewer: jfb.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D64647/new/
https://reviews.llvm.org/D64647
Files:
lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointOneDelayBreakpointThreads.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithBreak.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithSignal.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayedCrashWithBreakpointSignal.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointThreads.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
lldb/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
Index: lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+++ lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -48,6 +48,10 @@
private:
// Interface for friend classes
+ Status Resume();
+ Status SingleStep();
+ Status Suspend();
+
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
void SetStoppedByBreakpoint();
void SetStoppedByTrace();
Index: lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -17,6 +17,11 @@
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/State.h"
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
#include <sstream>
using namespace lldb;
@@ -30,6 +35,38 @@
NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
), m_stop_description() {}
+Status NativeThreadNetBSD::Resume() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+ nullptr, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetRunning();
+ return ret;
+}
+
+Status NativeThreadNetBSD::SingleStep() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+ nullptr, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetStepping();
+ return ret;
+}
+
+Status NativeThreadNetBSD::Suspend() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetStopped();
+ return ret;
+}
+
void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
const siginfo_t *info) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -98,6 +98,7 @@
bool HasThreadNoLock(lldb::tid_t thread_id);
NativeThreadNetBSD &AddThread(lldb::tid_t thread_id);
+ void RemoveThread(lldb::tid_t thread_id);
void MonitorCallback(lldb::pid_t pid, int signal);
void MonitorExited(lldb::pid_t pid, WaitStatus status);
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -9,7 +9,6 @@
#include "NativeProcessNetBSD.h"
-
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Host/common/NativeRegisterContext.h"
@@ -99,6 +98,17 @@
pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate,
Info.GetArchitecture(), mainloop));
+ // Enable event reporting
+ ptrace_event_t events;
+ status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events));
+ if (status.Fail())
+ return status.ToError();
+ // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
+ events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
+ status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events));
+ if (status.Fail())
+ return status.ToError();
+
status = process_up->ReinitializeThreads();
if (status.Fail())
return status.ToError();
@@ -238,6 +248,30 @@
static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
SetState(StateType::eStateStopped, true);
} break;
+ case TRAP_LWP: {
+ ptrace_state_t pst;
+ Status error = PtraceWrapper(PT_GET_PROCESS_STATE, GetID(), &pst,
+ sizeof(pst));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ switch (pst.pe_report_event) {
+ case PTRACE_LWP_CREATE:
+ AddThread(pst.pe_lwp);
+ break;
+ case PTRACE_LWP_EXIT:
+ RemoveThread(pst.pe_lwp);
+ break;
+ }
+
+ error = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void*>(1), 0);
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ } break;
case TRAP_DBREG: {
// Find the thread.
NativeThreadNetBSD* thread = nullptr;
@@ -325,57 +359,132 @@
return error;
}
+static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
+ const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
+ const ResumeActionList &resume_actions) {
+ // We need to account for three possible scenarios:
+ // 1. no signal being sent.
+ // 2. a signal being sent to one thread.
+ // 3. a signal being sent to the whole process.
+
+ // Count signaled threads. While at it, determine which signal is being sent
+ // and ensure there's only one.
+ size_t signaled_threads;
+ int signal = LLDB_INVALID_SIGNAL_NUMBER;
+ int signaled_lwp;
+ for (const auto &thread : threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread->GetID(), true);
+ if (action) {
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ signaled_threads++;
+ if (action->signal != signal) {
+ if (signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("NetBSD does not support passing multiple signals "
+ "simultaneously")
+ .ToError();
+ signal = action->signal;
+ signaled_lwp = thread->GetID();
+ }
+ }
+ }
+
+ if (signaled_threads == 0) {
+ ptrace_siginfo_t siginfo;
+ siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
+ return siginfo;
+ }
+
+ if (signaled_threads > 1 && signaled_threads < threads.size())
+ return Status("NetBSD does not support passing signal to 1<i<all threads")
+ .ToError();
+
+ ptrace_siginfo_t siginfo;
+ siginfo.psi_siginfo.si_signo = signal;
+ siginfo.psi_siginfo.si_code = SI_USER;
+ siginfo.psi_siginfo.si_pid = getpid();
+ siginfo.psi_siginfo.si_uid = getuid();
+ if (signaled_threads == 1)
+ siginfo.psi_lwpid = signaled_lwp;
+ else // signal for the whole process
+ siginfo.psi_lwpid = 0;
+ return siginfo;
+}
+
Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
LLDB_LOG(log, "pid {0}", GetID());
- const auto &thread = m_threads[0];
- const ResumeAction *const action =
- resume_actions.GetActionForThread(thread->GetID(), true);
+ Status ret;
- if (action == nullptr) {
- LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
- thread->GetID());
- return Status();
- }
+ Expected<ptrace_siginfo_t> siginfo =
+ ComputeSignalInfo(m_threads, resume_actions);
+ if (!siginfo)
+ return Status(siginfo.takeError());
- Status error;
+ for (const auto &abs_thread : m_threads) {
+ assert(abs_thread && "thread list should not contain NULL threads");
+ NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
- switch (action->state) {
- case eStateRunning: {
- // Run the thread, possibly feeding it the signal.
- error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1,
- action->signal);
- if (!error.Success())
- return error;
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetRunning();
- SetState(eStateRunning, true);
- break;
- }
- case eStateStepping:
- // Run the thread, possibly feeding it the signal.
- error = NativeProcessNetBSD::PtraceWrapper(PT_STEP, GetID(), (void *)1,
- action->signal);
- if (!error.Success())
- return error;
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetStepping();
- SetState(eStateStepping, true);
- break;
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread.GetID(), true);
+ // we need to explicit issue suspend requests, so it is simpler to map it
+ // into proper action
+ ResumeAction suspend_action{thread.GetID(), eStateSuspended,
+ LLDB_INVALID_SIGNAL_NUMBER};
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread.GetID());
+ action = &suspend_action;
+ }
- case eStateSuspended:
- case eStateStopped:
- llvm_unreachable("Unexpected state");
+ LLDB_LOG(
+ log,
+ "processing resume action state {0} signal {1} for pid {2} tid {3}",
+ action->state, action->signal, GetID(), thread.GetID());
- default:
- return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
- "for pid %" PRIu64 ", tid %" PRIu64,
- __FUNCTION__, StateAsCString(action->state), GetID(),
- thread->GetID());
+ switch (action->state) {
+ case eStateRunning:
+ ret = thread.Resume();
+ break;
+ case eStateStepping:
+ ret = thread.SingleStep();
+ break;
+ case eStateSuspended:
+ case eStateStopped:
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("Passing signal to suspended thread unsupported");
+
+ ret = thread.Suspend();
+ break;
+
+ default:
+ return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(),
+ thread.GetID());
+ }
+
+ if (!ret.Success())
+ return ret;
}
- return Status();
+ int signal = 0;
+ if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
+ ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
+ sizeof(*siginfo));
+ if (!ret.Success())
+ return ret;
+ signal = siginfo->psi_siginfo.si_signo;
+ }
+
+ ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1),
+ signal);
+ if (ret.Success())
+ SetState(eStateRunning, true);
+ return ret;
}
Status NativeProcessNetBSD::Halt() {
@@ -663,6 +772,21 @@
return static_cast<NativeThreadNetBSD &>(*m_threads.back());
}
+void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
+
+ assert(HasThreadNoLock(thread_id) &&
+ "attempted to remove a thread that does not exist");
+
+ for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
+ if ((*it)->GetID() == thread_id) {
+ m_threads.erase(it);
+ break;
+ }
+ }
+}
+
Status NativeProcessNetBSD::Attach() {
// Attach to the requested process.
// An attach will cause the thread to stop with a SIGSTOP.
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
@@ -25,7 +25,6 @@
bugnumber="llvm.org/pr18066 inferior does not exit")
@skipIfWindows # This test will hang on windows llvm.org/pr21753
@expectedFailureAll(oslist=["windows"])
- @expectedFailureNetBSD
def test_step_single_thread(self):
"""Test thread step out on one thread via command interpreter. """
self.build(dictionary=self.getBuildFlags())
@@ -42,7 +41,6 @@
@skipIfWindows # This test will hang on windows llvm.org/pr21753
@expectedFailureAll(oslist=["windows"])
@expectedFailureAll(oslist=["watchos"], archs=['armv7k'], bugnumber="rdar://problem/34674488") # stop reason is trace when it should be step-out
- @expectedFailureNetBSD
def test_step_all_threads(self):
"""Test thread step out on all threads via command interpreter. """
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
@@ -17,7 +17,6 @@
@skipIfFreeBSD # llvm.org/pr21411: test is hanging
@skipIfWindows # This is flakey on Windows: llvm.org/pr38373
- @expectedFailureNetBSD
def test(self):
"""Test thread exit during step handling."""
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointThreads.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointThreads.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointThreads.py
@@ -15,7 +15,6 @@
@skipIfFreeBSD # timing out on buildbot
# Atomic sequences are not supported yet for MIPS in LLDB.
@skipIf(triple='^mips')
- @expectedFailureNetBSD
def test(self):
"""Test two threads that trigger a breakpoint. """
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayedCrashWithBreakpointSignal.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayedCrashWithBreakpointSignal.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayedCrashWithBreakpointSignal.py
@@ -15,7 +15,6 @@
@skipIfFreeBSD # timing out on buildbot
# Atomic sequences are not supported yet for MIPS in LLDB.
@skipIf(triple='^mips')
- @expectedFailureNetBSD
def test(self):
""" Test a thread with a delayed crash while other threads generate a signal and hit a breakpoint. """
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithSignal.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithSignal.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithSignal.py
@@ -15,7 +15,6 @@
@skipIfFreeBSD # timing out on buildbot
# Atomic sequences are not supported yet for MIPS in LLDB.
@skipIf(triple='^mips')
- @expectedFailureNetBSD
def test(self):
""" Test a thread that crashes while another thread generates a signal."""
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithBreak.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithBreak.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentCrashWithBreak.py
@@ -15,7 +15,6 @@
@skipIfFreeBSD # timing out on buildbot
# Atomic sequences are not supported yet for MIPS in LLDB.
@skipIf(triple='^mips')
- @expectedFailureNetBSD
def test(self):
""" Test a thread that crashes while another thread hits a breakpoint."""
self.build(dictionary=self.getBuildFlags())
Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointOneDelayBreakpointThreads.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointOneDelayBreakpointThreads.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointOneDelayBreakpointThreads.py
@@ -15,7 +15,6 @@
@skipIfFreeBSD # timing out on buildbot
# Atomic sequences are not supported yet for MIPS in LLDB.
@skipIf(triple='^mips')
- @expectedFailureNetBSD
def test(self):
"""Test threads that trigger a breakpoint where one thread has a 1 second delay. """
self.build(dictionary=self.getBuildFlags())
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits