xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- NativeThreadNetBSD.cpp --------------------------------------------===//
274a628f7SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674a628f7SDimitry Andric //
774a628f7SDimitry Andric //===----------------------------------------------------------------------===//
874a628f7SDimitry Andric 
974a628f7SDimitry Andric #include "NativeThreadNetBSD.h"
1074a628f7SDimitry Andric #include "NativeRegisterContextNetBSD.h"
1174a628f7SDimitry Andric 
1274a628f7SDimitry Andric #include "NativeProcessNetBSD.h"
1374a628f7SDimitry Andric 
1474a628f7SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h"
1574a628f7SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16d44a35e8SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
1794994d37SDimitry Andric #include "lldb/Utility/RegisterValue.h"
1894994d37SDimitry Andric #include "lldb/Utility/State.h"
19706b4fc4SDimitry Andric #include "llvm/Support/Errno.h"
20706b4fc4SDimitry Andric 
21706b4fc4SDimitry Andric // clang-format off
22706b4fc4SDimitry Andric #include <sys/types.h>
23706b4fc4SDimitry Andric #include <sys/ptrace.h>
24706b4fc4SDimitry Andric // clang-format on
25d44a35e8SDimitry Andric 
26d44a35e8SDimitry Andric #include <sstream>
2774a628f7SDimitry Andric 
28706b4fc4SDimitry Andric // clang-format off
29706b4fc4SDimitry Andric #include <sys/types.h>
30706b4fc4SDimitry Andric #include <sys/sysctl.h>
31706b4fc4SDimitry Andric // clang-format on
32706b4fc4SDimitry Andric 
3374a628f7SDimitry Andric using namespace lldb;
3474a628f7SDimitry Andric using namespace lldb_private;
3574a628f7SDimitry Andric using namespace lldb_private::process_netbsd;
3674a628f7SDimitry Andric 
NativeThreadNetBSD(NativeProcessNetBSD & process,lldb::tid_t tid)37a884e649SDimitry Andric NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
3874a628f7SDimitry Andric                                        lldb::tid_t tid)
3974a628f7SDimitry Andric     : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
40ef5d0b5eSDimitry Andric       m_stop_info(), m_reg_context_up(
41ef5d0b5eSDimitry Andric NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
42ef5d0b5eSDimitry Andric ), m_stop_description() {}
4374a628f7SDimitry Andric 
Resume()44706b4fc4SDimitry Andric Status NativeThreadNetBSD::Resume() {
45706b4fc4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
46706b4fc4SDimitry Andric                                                   nullptr, GetID());
47706b4fc4SDimitry Andric   if (!ret.Success())
48706b4fc4SDimitry Andric     return ret;
49706b4fc4SDimitry Andric   ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
50706b4fc4SDimitry Andric                                            nullptr, GetID());
51706b4fc4SDimitry Andric   if (ret.Success())
52706b4fc4SDimitry Andric     SetRunning();
53706b4fc4SDimitry Andric   return ret;
54706b4fc4SDimitry Andric }
55706b4fc4SDimitry Andric 
SingleStep()56706b4fc4SDimitry Andric Status NativeThreadNetBSD::SingleStep() {
57706b4fc4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
58706b4fc4SDimitry Andric                                                   nullptr, GetID());
59706b4fc4SDimitry Andric   if (!ret.Success())
60706b4fc4SDimitry Andric     return ret;
61706b4fc4SDimitry Andric   ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
62706b4fc4SDimitry Andric                                            nullptr, GetID());
63706b4fc4SDimitry Andric   if (ret.Success())
64706b4fc4SDimitry Andric     SetStepping();
65706b4fc4SDimitry Andric   return ret;
66706b4fc4SDimitry Andric }
67706b4fc4SDimitry Andric 
Suspend()68706b4fc4SDimitry Andric Status NativeThreadNetBSD::Suspend() {
69706b4fc4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
70706b4fc4SDimitry Andric                                                   nullptr, GetID());
71706b4fc4SDimitry Andric   if (ret.Success())
72706b4fc4SDimitry Andric     SetStopped();
73706b4fc4SDimitry Andric   return ret;
74706b4fc4SDimitry Andric }
75706b4fc4SDimitry Andric 
SetStoppedBySignal(uint32_t signo,const siginfo_t * info)7674a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
7774a628f7SDimitry Andric                                             const siginfo_t *info) {
786f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
7974a628f7SDimitry Andric   LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
8074a628f7SDimitry Andric 
8174a628f7SDimitry Andric   SetStopped();
8274a628f7SDimitry Andric 
8374a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonSignal;
84145449b1SDimitry Andric   m_stop_info.signo = signo;
8574a628f7SDimitry Andric 
8674a628f7SDimitry Andric   m_stop_description.clear();
8774a628f7SDimitry Andric   if (info) {
8874a628f7SDimitry Andric     switch (signo) {
8974a628f7SDimitry Andric     case SIGSEGV:
9074a628f7SDimitry Andric     case SIGBUS:
9174a628f7SDimitry Andric     case SIGFPE:
9274a628f7SDimitry Andric     case SIGILL:
937fa27ce4SDimitry Andric       m_stop_description = GetCrashReasonString(*info);
9474a628f7SDimitry Andric       break;
9574a628f7SDimitry Andric     }
9674a628f7SDimitry Andric   }
9774a628f7SDimitry Andric }
9874a628f7SDimitry Andric 
SetStoppedByBreakpoint()9974a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() {
10074a628f7SDimitry Andric   SetStopped();
10174a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
102145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
10374a628f7SDimitry Andric }
10474a628f7SDimitry Andric 
SetStoppedByTrace()10574a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() {
10674a628f7SDimitry Andric   SetStopped();
10774a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonTrace;
108145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
10974a628f7SDimitry Andric }
11074a628f7SDimitry Andric 
SetStoppedByExec()11174a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() {
11274a628f7SDimitry Andric   SetStopped();
11374a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonExec;
114145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
11574a628f7SDimitry Andric }
11674a628f7SDimitry Andric 
SetStoppedByWatchpoint(uint32_t wp_index)117d44a35e8SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
118d44a35e8SDimitry Andric   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
119d44a35e8SDimitry Andric 
120d44a35e8SDimitry Andric   std::ostringstream ostr;
121ef5d0b5eSDimitry Andric   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
122d44a35e8SDimitry Andric   ostr << wp_index;
123d44a35e8SDimitry Andric 
124ef5d0b5eSDimitry Andric   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
125d44a35e8SDimitry Andric 
126b60736ecSDimitry Andric   SetStopped();
127d44a35e8SDimitry Andric   m_stop_description = ostr.str();
128d44a35e8SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
129145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
130d44a35e8SDimitry Andric }
131d44a35e8SDimitry Andric 
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)132344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
133344a3780SDimitry Andric                                            lldb::tid_t child_tid) {
134344a3780SDimitry Andric   SetStopped();
135344a3780SDimitry Andric 
136344a3780SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonFork;
137145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
138344a3780SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
139344a3780SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
140344a3780SDimitry Andric }
141344a3780SDimitry Andric 
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143344a3780SDimitry Andric                                             lldb::tid_t child_tid) {
144344a3780SDimitry Andric   SetStopped();
145344a3780SDimitry Andric 
146344a3780SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVFork;
147145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
148344a3780SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
149344a3780SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
150344a3780SDimitry Andric }
151344a3780SDimitry Andric 
SetStoppedByVForkDone()152344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByVForkDone() {
153344a3780SDimitry Andric   SetStopped();
154344a3780SDimitry Andric 
155344a3780SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVForkDone;
156145449b1SDimitry Andric   m_stop_info.signo = SIGTRAP;
157344a3780SDimitry Andric }
158344a3780SDimitry Andric 
SetStoppedWithNoReason()159706b4fc4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() {
160706b4fc4SDimitry Andric   SetStopped();
161706b4fc4SDimitry Andric 
162706b4fc4SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
163145449b1SDimitry Andric   m_stop_info.signo = 0;
164706b4fc4SDimitry Andric }
165706b4fc4SDimitry Andric 
SetStopped()16674a628f7SDimitry Andric void NativeThreadNetBSD::SetStopped() {
16774a628f7SDimitry Andric   const StateType new_state = StateType::eStateStopped;
16874a628f7SDimitry Andric   m_state = new_state;
16974a628f7SDimitry Andric   m_stop_description.clear();
17074a628f7SDimitry Andric }
17174a628f7SDimitry Andric 
SetRunning()17274a628f7SDimitry Andric void NativeThreadNetBSD::SetRunning() {
17374a628f7SDimitry Andric   m_state = StateType::eStateRunning;
17474a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
17574a628f7SDimitry Andric }
17674a628f7SDimitry Andric 
SetStepping()17774a628f7SDimitry Andric void NativeThreadNetBSD::SetStepping() {
17874a628f7SDimitry Andric   m_state = StateType::eStateStepping;
17974a628f7SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
18074a628f7SDimitry Andric }
18174a628f7SDimitry Andric 
GetName()182706b4fc4SDimitry Andric std::string NativeThreadNetBSD::GetName() {
183706b4fc4SDimitry Andric #ifdef PT_LWPSTATUS
184706b4fc4SDimitry Andric   struct ptrace_lwpstatus info = {};
185706b4fc4SDimitry Andric   info.pl_lwpid = m_tid;
186706b4fc4SDimitry Andric   Status error = NativeProcessNetBSD::PtraceWrapper(
187706b4fc4SDimitry Andric       PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
188706b4fc4SDimitry Andric   if (error.Fail()) {
189706b4fc4SDimitry Andric     return "";
190706b4fc4SDimitry Andric   }
191706b4fc4SDimitry Andric   return info.pl_name;
192706b4fc4SDimitry Andric #else
193706b4fc4SDimitry Andric   std::vector<struct kinfo_lwp> infos;
194ac9a064cSDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
195ac9a064cSDimitry Andric 
196706b4fc4SDimitry Andric   int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
197706b4fc4SDimitry Andric                 sizeof(struct kinfo_lwp), 0};
198706b4fc4SDimitry Andric   size_t size;
199706b4fc4SDimitry Andric 
200706b4fc4SDimitry Andric   if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
201706b4fc4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
202706b4fc4SDimitry Andric              llvm::sys::StrError());
203706b4fc4SDimitry Andric     return "";
204706b4fc4SDimitry Andric   }
205706b4fc4SDimitry Andric 
206706b4fc4SDimitry Andric   mib[4] = size / sizeof(size_t);
207706b4fc4SDimitry Andric   infos.resize(size / sizeof(struct kinfo_lwp));
208706b4fc4SDimitry Andric 
209706b4fc4SDimitry Andric   if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
210706b4fc4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
211706b4fc4SDimitry Andric     return "";
212706b4fc4SDimitry Andric   }
213706b4fc4SDimitry Andric 
214706b4fc4SDimitry Andric   size_t nlwps = size / sizeof(struct kinfo_lwp);
215706b4fc4SDimitry Andric   for (size_t i = 0; i < nlwps; i++) {
216706b4fc4SDimitry Andric     if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
217706b4fc4SDimitry Andric       return infos[i].l_name;
218706b4fc4SDimitry Andric     }
219706b4fc4SDimitry Andric   }
220706b4fc4SDimitry Andric 
221706b4fc4SDimitry Andric   LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
222706b4fc4SDimitry Andric   return "";
223706b4fc4SDimitry Andric #endif
224706b4fc4SDimitry Andric }
22574a628f7SDimitry Andric 
GetState()22674a628f7SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
22774a628f7SDimitry Andric 
GetStopReason(ThreadStopInfo & stop_info,std::string & description)22874a628f7SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
22974a628f7SDimitry Andric                                        std::string &description) {
2306f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
23174a628f7SDimitry Andric   description.clear();
23274a628f7SDimitry Andric 
23374a628f7SDimitry Andric   switch (m_state) {
23474a628f7SDimitry Andric   case eStateStopped:
23574a628f7SDimitry Andric   case eStateCrashed:
23674a628f7SDimitry Andric   case eStateExited:
23774a628f7SDimitry Andric   case eStateSuspended:
23874a628f7SDimitry Andric   case eStateUnloaded:
23974a628f7SDimitry Andric     stop_info = m_stop_info;
24074a628f7SDimitry Andric     description = m_stop_description;
24174a628f7SDimitry Andric 
24274a628f7SDimitry Andric     return true;
24374a628f7SDimitry Andric 
24474a628f7SDimitry Andric   case eStateInvalid:
24574a628f7SDimitry Andric   case eStateConnected:
24674a628f7SDimitry Andric   case eStateAttaching:
24774a628f7SDimitry Andric   case eStateLaunching:
24874a628f7SDimitry Andric   case eStateRunning:
24974a628f7SDimitry Andric   case eStateStepping:
25074a628f7SDimitry Andric   case eStateDetached:
25174a628f7SDimitry Andric     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
25274a628f7SDimitry Andric              StateAsCString(m_state));
25374a628f7SDimitry Andric     return false;
25474a628f7SDimitry Andric   }
25574a628f7SDimitry Andric   llvm_unreachable("unhandled StateType!");
25674a628f7SDimitry Andric }
25774a628f7SDimitry Andric 
GetRegisterContext()258706b4fc4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
259ef5d0b5eSDimitry Andric   assert(m_reg_context_up);
260ef5d0b5eSDimitry Andric   return *m_reg_context_up;
26174a628f7SDimitry Andric }
26274a628f7SDimitry Andric 
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)263b76161e4SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
26474a628f7SDimitry Andric                                          uint32_t watch_flags, bool hardware) {
265b60736ecSDimitry Andric   assert(m_state == eStateStopped);
266d44a35e8SDimitry Andric   if (!hardware)
267b76161e4SDimitry Andric     return Status("not implemented");
268b76161e4SDimitry Andric   Status error = RemoveWatchpoint(addr);
269d44a35e8SDimitry Andric   if (error.Fail())
270d44a35e8SDimitry Andric     return error;
271b60736ecSDimitry Andric   uint32_t wp_index =
272b60736ecSDimitry Andric       GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
273d44a35e8SDimitry Andric   if (wp_index == LLDB_INVALID_INDEX32)
274b76161e4SDimitry Andric     return Status("Setting hardware watchpoint failed.");
275d44a35e8SDimitry Andric   m_watchpoint_index_map.insert({addr, wp_index});
276b76161e4SDimitry Andric   return Status();
27774a628f7SDimitry Andric }
27874a628f7SDimitry Andric 
RemoveWatchpoint(lldb::addr_t addr)279b76161e4SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
280d44a35e8SDimitry Andric   auto wp = m_watchpoint_index_map.find(addr);
281d44a35e8SDimitry Andric   if (wp == m_watchpoint_index_map.end())
282b76161e4SDimitry Andric     return Status();
283d44a35e8SDimitry Andric   uint32_t wp_index = wp->second;
284d44a35e8SDimitry Andric   m_watchpoint_index_map.erase(wp);
285ef5d0b5eSDimitry Andric   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
286b76161e4SDimitry Andric     return Status();
287b76161e4SDimitry Andric   return Status("Clearing hardware watchpoint failed.");
28874a628f7SDimitry Andric }
28974a628f7SDimitry Andric 
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)290b76161e4SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
29174a628f7SDimitry Andric                                                  size_t size) {
292b60736ecSDimitry Andric   assert(m_state == eStateStopped);
293b76161e4SDimitry Andric   Status error = RemoveHardwareBreakpoint(addr);
294d44a35e8SDimitry Andric   if (error.Fail())
295d44a35e8SDimitry Andric     return error;
296d44a35e8SDimitry Andric 
297ef5d0b5eSDimitry Andric   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
298d44a35e8SDimitry Andric 
299d44a35e8SDimitry Andric   if (bp_index == LLDB_INVALID_INDEX32)
300b76161e4SDimitry Andric     return Status("Setting hardware breakpoint failed.");
301d44a35e8SDimitry Andric 
302d44a35e8SDimitry Andric   m_hw_break_index_map.insert({addr, bp_index});
303b76161e4SDimitry Andric   return Status();
30474a628f7SDimitry Andric }
30574a628f7SDimitry Andric 
RemoveHardwareBreakpoint(lldb::addr_t addr)306b76161e4SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
307d44a35e8SDimitry Andric   auto bp = m_hw_break_index_map.find(addr);
308d44a35e8SDimitry Andric   if (bp == m_hw_break_index_map.end())
309b76161e4SDimitry Andric     return Status();
310d44a35e8SDimitry Andric 
311d44a35e8SDimitry Andric   uint32_t bp_index = bp->second;
312ef5d0b5eSDimitry Andric   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
313d44a35e8SDimitry Andric     m_hw_break_index_map.erase(bp);
314b76161e4SDimitry Andric     return Status();
315d44a35e8SDimitry Andric   }
316d44a35e8SDimitry Andric 
317b76161e4SDimitry Andric   return Status("Clearing hardware breakpoint failed.");
31874a628f7SDimitry Andric }
319706b4fc4SDimitry Andric 
320b60736ecSDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadNetBSD & source)321b60736ecSDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
322b60736ecSDimitry Andric   llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
323706b4fc4SDimitry Andric       source.GetRegisterContext());
324b60736ecSDimitry Andric   if (!s) {
325706b4fc4SDimitry Andric     m_watchpoint_index_map = source.m_watchpoint_index_map;
326706b4fc4SDimitry Andric     m_hw_break_index_map = source.m_hw_break_index_map;
327706b4fc4SDimitry Andric   }
328706b4fc4SDimitry Andric   return s;
329706b4fc4SDimitry Andric }
330