mgorny updated this revision to Diff 228567.
mgorny marked 2 inline comments as done.
mgorny added a comment.
Update wrt comments. Also remove non-working hardware breakpoint boilerplate as
noted.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D70022/new/
https://reviews.llvm.org/D70022
Files:
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,11 +48,16 @@
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();
void SetStoppedByExec();
void SetStoppedByWatchpoint(uint32_t wp_index);
+ void SetStoppedWithNoReason();
void SetStopped();
void SetRunning();
void SetStepping();
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));
@@ -89,6 +126,13 @@
m_stop_info.details.signal.signo = SIGTRAP;
}
+void NativeThreadNetBSD::SetStoppedWithNoReason() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.details.signal.signo = 0;
+}
+
void NativeThreadNetBSD::SetStopped() {
const StateType new_state = StateType::eStateStopped;
m_state = new_state;
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();
@@ -211,17 +221,32 @@
return;
}
+ NativeThreadNetBSD* thread = nullptr;
+ if (info.psi_lwpid > 0) {
+ for (const auto &t : m_threads) {
+ if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
+ thread = static_cast<NativeThreadNetBSD *>(t.get());
+ break;
+ }
+ static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
+ }
+ if (!thread)
+ LLDB_LOG(log,
+ "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+ info.psi_lwpid);
+ }
+
switch (info.psi_siginfo.si_code) {
case TRAP_BRKPT:
- for (const auto &thread : m_threads) {
- static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint();
- FixupBreakpointPCAsNeeded(static_cast<NativeThreadNetBSD &>(*thread));
+ if (thread) {
+ thread->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(*thread);
}
SetState(StateType::eStateStopped, true);
break;
case TRAP_TRACE:
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByTrace();
+ if (thread)
+ thread->SetStoppedByTrace();
SetState(StateType::eStateStopped, true);
break;
case TRAP_EXEC: {
@@ -238,54 +263,54 @@
static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
SetState(StateType::eStateStopped, true);
} break;
- case TRAP_DBREG: {
- // Find the thread.
- NativeThreadNetBSD* thread = nullptr;
- for (const auto &t : m_threads) {
- if (t->GetID() == info.psi_lwpid) {
- thread = static_cast<NativeThreadNetBSD *>(t.get());
+ case TRAP_LWP: {
+ ptrace_state_t pst;
+ Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ switch (pst.pe_report_event) {
+ case PTRACE_LWP_CREATE:
+ LLDB_LOG(log,
+ "monitoring new thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ AddThread(pst.pe_lwp);
+ break;
+ case PTRACE_LWP_EXIT:
+ LLDB_LOG(log,
+ "removing exited thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ RemoveThread(pst.pe_lwp);
break;
- }
}
- if (!thread) {
- LLDB_LOG(log,
- "thread not found in m_threads, pid = {0}, LWP = {1}",
- GetID(), info.psi_lwpid);
- break;
+
+ error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0);
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
}
+ } break;
+ case TRAP_DBREG: {
+ if (!thread)
+ break;
- // If a watchpoint was hit, report it
uint32_t wp_index = LLDB_INVALID_INDEX32;
Status error = thread->GetRegisterContext().GetWatchpointHitIndex(
wp_index, (uintptr_t)info.psi_siginfo.si_addr);
if (error.Fail())
LLDB_LOG(log,
"received error while checking for watchpoint hits, pid = "
- "{0}, LWP = {1}, error = {2}",
- GetID(), info.psi_lwpid, error);
+ "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error);
if (wp_index != LLDB_INVALID_INDEX32) {
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByWatchpoint(
- wp_index);
+ thread->SetStoppedByWatchpoint(wp_index);
SetState(StateType::eStateStopped, true);
break;
}
- // If a breakpoint was hit, report it
- uint32_t bp_index = LLDB_INVALID_INDEX32;
- error = thread->GetRegisterContext().GetHardwareBreakHitIndex(
- bp_index, (uintptr_t)info.psi_siginfo.si_addr);
- if (error.Fail())
- LLDB_LOG(log,
- "received error while checking for hardware "
- "breakpoint hits, pid = {0}, LWP = {1}, error = {2}",
- GetID(), info.psi_lwpid, error);
- if (bp_index != LLDB_INVALID_INDEX32) {
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint();
- SetState(StateType::eStateStopped, true);
- break;
- }
+ thread->SetStoppedByTrace();
+ SetState(StateType::eStateStopped, true);
} break;
}
}
@@ -295,9 +320,14 @@
const auto siginfo_err =
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
- for (const auto &thread : m_threads) {
- static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
- info.psi_siginfo.si_signo, &info.psi_siginfo);
+ for (const auto &abs_thread : m_threads) {
+ NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
+ assert(info.psi_lwpid >= 0);
+ if (info.psi_lwpid == 0 ||
+ static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
+ thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
+ else
+ thread.SetStoppedWithNoReason();
}
SetState(StateType::eStateStopped, true);
}
@@ -325,59 +355,133 @@
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 = 0;
+ int signal = LLDB_INVALID_SIGNAL_NUMBER;
+ lldb::tid_t 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;
- int signal =
- action->signal != LLDB_INVALID_SIGNAL_NUMBER ? action->signal : 0;
-
- switch (action->state) {
- case eStateRunning: {
- // Run the thread, possibly feeding it the signal.
- error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1,
- 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,
- signal);
- if (!error.Success())
- return error;
- for (const auto &thread : m_threads)
- static_cast<NativeThreadNetBSD &>(*thread).SetStepping();
- SetState(eStateStepping, true);
- break;
+ for (const auto &abs_thread : m_threads) {
+ assert(abs_thread && "thread list should not contain NULL threads");
+ NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
- case eStateSuspended:
- case eStateStopped:
- llvm_unreachable("Unexpected state");
+ 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};
- default:
- return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
- "for pid %" PRIu64 ", tid %" PRIu64,
- __FUNCTION__, StateAsCString(action->state), GetID(),
- thread->GetID());
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread.GetID());
+ action = &suspend_action;
+ }
+
+ LLDB_LOG(
+ log,
+ "processing resume action state {0} signal {1} for pid {2} tid {3}",
+ action->state, action->signal, 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() {
@@ -650,10 +754,10 @@
}
NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
-
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+ assert(thread_id > 0);
assert(!HasThreadNoLock(thread_id) &&
"attempted to add a thread by id that already exists");
@@ -665,6 +769,22 @@
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(thread_id > 0);
+ 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.
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits