summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
authorMichał Górny <mgorny@gentoo.org>2019-07-12 19:11:31 +0200
committerMichał Górny <mgorny@gentoo.org>2019-11-25 20:11:58 +0100
commit8d9400b65b972cb50fe2266360443192ea107ec9 (patch)
tree70d8457318ecfbdf1ffbf17898e5570075f845f5 /lldb/source/Plugins/Process
parentd018b556c7556b8fb599d44b17a936369b940297 (diff)
downloadbcm5719-llvm-8d9400b65b972cb50fe2266360443192ea107ec9.tar.gz
bcm5719-llvm-8d9400b65b972cb50fe2266360443192ea107ec9.zip
[lldb] [Process/NetBSD] Improve threading support
Implement major improvements to multithreaded program support. Notably, support tracking new and exited threads, associate signals and events with correct threads and support controlling individual threads when resuming. Firstly, use PT_SET_EVENT_MASK to enable reporting of created and exited threads via SIGTRAP. Handle TRAP_LWP events to keep track of the currently running threads. Secondly, update the signal (both generic and SIGTRAP) handling code to account for per-thread signals correctly. Signals delivered to the whole process are reported on all threads, while per-thread signals and events are reported only to the specific thread. The remaining threads are marked as 'stopped with no reason'. Note that NetBSD always stops all threads on debugger events. Thirdly, implement the ability to set every thread as running, stopped or single-stepping separately while continuing the process. This also provides the ability to send a signal to the whole process or to one of its thread while resuming. Differential Revision: https://reviews.llvm.org/D70022
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp292
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h1
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp44
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h5
4 files changed, 256 insertions, 86 deletions
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index a5f7c7db2cb..0b21c7862b0 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/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 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
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 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
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 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
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 @@ void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
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 @@ Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
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() {
@@ -649,10 +753,10 @@ bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
}
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");
@@ -664,6 +768,22 @@ NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
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.
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 2fe97628d41..6a06773f40a 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -100,6 +100,7 @@ private:
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);
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
index d732a72c932..c3251c88a42 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -18,6 +18,11 @@
#include "lldb/Utility/State.h"
#include "llvm/Support/Errno.h"
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
#include <sstream>
// clang-format off
@@ -36,6 +41,38 @@ NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
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));
@@ -95,6 +132,13 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
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;
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
index 015d8995db3..f944b50efe0 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -48,11 +48,16 @@ public:
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();
OpenPOWER on IntegriCloud