15ffd83dbSDimitry Andric //===-- NativeThreadNetBSD.cpp --------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "NativeThreadNetBSD.h"
100b57cec5SDimitry Andric #include "NativeRegisterContextNetBSD.h"
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "NativeProcessNetBSD.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h"
150b57cec5SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
160b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
170b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
180b57cec5SDimitry Andric #include "lldb/Utility/State.h"
19480093f4SDimitry Andric #include "llvm/Support/Errno.h"
20480093f4SDimitry Andric 
21480093f4SDimitry Andric // clang-format off
22480093f4SDimitry Andric #include <sys/types.h>
23480093f4SDimitry Andric #include <sys/ptrace.h>
24480093f4SDimitry Andric // clang-format on
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #include <sstream>
270b57cec5SDimitry Andric 
28480093f4SDimitry Andric // clang-format off
29480093f4SDimitry Andric #include <sys/types.h>
30480093f4SDimitry Andric #include <sys/sysctl.h>
31480093f4SDimitry Andric // clang-format on
32480093f4SDimitry Andric 
330b57cec5SDimitry Andric using namespace lldb;
340b57cec5SDimitry Andric using namespace lldb_private;
350b57cec5SDimitry Andric using namespace lldb_private::process_netbsd;
360b57cec5SDimitry Andric 
NativeThreadNetBSD(NativeProcessNetBSD & process,lldb::tid_t tid)370b57cec5SDimitry Andric NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
380b57cec5SDimitry Andric                                        lldb::tid_t tid)
390b57cec5SDimitry Andric     : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
400b57cec5SDimitry Andric       m_stop_info(), m_reg_context_up(
410b57cec5SDimitry Andric NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
420b57cec5SDimitry Andric ), m_stop_description() {}
430b57cec5SDimitry Andric 
Resume()44480093f4SDimitry Andric Status NativeThreadNetBSD::Resume() {
45480093f4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
46480093f4SDimitry Andric                                                   nullptr, GetID());
47480093f4SDimitry Andric   if (!ret.Success())
48480093f4SDimitry Andric     return ret;
49480093f4SDimitry Andric   ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
50480093f4SDimitry Andric                                            nullptr, GetID());
51480093f4SDimitry Andric   if (ret.Success())
52480093f4SDimitry Andric     SetRunning();
53480093f4SDimitry Andric   return ret;
54480093f4SDimitry Andric }
55480093f4SDimitry Andric 
SingleStep()56480093f4SDimitry Andric Status NativeThreadNetBSD::SingleStep() {
57480093f4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
58480093f4SDimitry Andric                                                   nullptr, GetID());
59480093f4SDimitry Andric   if (!ret.Success())
60480093f4SDimitry Andric     return ret;
61480093f4SDimitry Andric   ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
62480093f4SDimitry Andric                                            nullptr, GetID());
63480093f4SDimitry Andric   if (ret.Success())
64480093f4SDimitry Andric     SetStepping();
65480093f4SDimitry Andric   return ret;
66480093f4SDimitry Andric }
67480093f4SDimitry Andric 
Suspend()68480093f4SDimitry Andric Status NativeThreadNetBSD::Suspend() {
69480093f4SDimitry Andric   Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
70480093f4SDimitry Andric                                                   nullptr, GetID());
71480093f4SDimitry Andric   if (ret.Success())
72480093f4SDimitry Andric     SetStopped();
73480093f4SDimitry Andric   return ret;
74480093f4SDimitry Andric }
75480093f4SDimitry Andric 
SetStoppedBySignal(uint32_t signo,const siginfo_t * info)760b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
770b57cec5SDimitry Andric                                             const siginfo_t *info) {
7804eeddc0SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
790b57cec5SDimitry Andric   LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   SetStopped();
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonSignal;
8481ad6265SDimitry Andric   m_stop_info.signo = signo;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   m_stop_description.clear();
870b57cec5SDimitry Andric   if (info) {
880b57cec5SDimitry Andric     switch (signo) {
890b57cec5SDimitry Andric     case SIGSEGV:
900b57cec5SDimitry Andric     case SIGBUS:
910b57cec5SDimitry Andric     case SIGFPE:
920b57cec5SDimitry Andric     case SIGILL:
9306c3fb27SDimitry Andric       m_stop_description = GetCrashReasonString(*info);
940b57cec5SDimitry Andric       break;
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
SetStoppedByBreakpoint()990b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() {
1000b57cec5SDimitry Andric   SetStopped();
1010b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
10281ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
SetStoppedByTrace()1050b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() {
1060b57cec5SDimitry Andric   SetStopped();
1070b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonTrace;
10881ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
SetStoppedByExec()1110b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() {
1120b57cec5SDimitry Andric   SetStopped();
1130b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonExec;
11481ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
SetStoppedByWatchpoint(uint32_t wp_index)1170b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
1180b57cec5SDimitry Andric   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   std::ostringstream ostr;
1210b57cec5SDimitry Andric   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
1220b57cec5SDimitry Andric   ostr << wp_index;
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
1250b57cec5SDimitry Andric 
126e8d8bef9SDimitry Andric   SetStopped();
1270b57cec5SDimitry Andric   m_stop_description = ostr.str();
1280b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
12981ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)132fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
133fe6060f1SDimitry Andric                                            lldb::tid_t child_tid) {
134fe6060f1SDimitry Andric   SetStopped();
135fe6060f1SDimitry Andric 
136fe6060f1SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonFork;
13781ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
138fe6060f1SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
139fe6060f1SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
140fe6060f1SDimitry Andric }
141fe6060f1SDimitry Andric 
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143fe6060f1SDimitry Andric                                             lldb::tid_t child_tid) {
144fe6060f1SDimitry Andric   SetStopped();
145fe6060f1SDimitry Andric 
146fe6060f1SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVFork;
14781ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
148fe6060f1SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
149fe6060f1SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
150fe6060f1SDimitry Andric }
151fe6060f1SDimitry Andric 
SetStoppedByVForkDone()152fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByVForkDone() {
153fe6060f1SDimitry Andric   SetStopped();
154fe6060f1SDimitry Andric 
155fe6060f1SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVForkDone;
15681ad6265SDimitry Andric   m_stop_info.signo = SIGTRAP;
157fe6060f1SDimitry Andric }
158fe6060f1SDimitry Andric 
SetStoppedWithNoReason()159480093f4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() {
160480093f4SDimitry Andric   SetStopped();
161480093f4SDimitry Andric 
162480093f4SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
16381ad6265SDimitry Andric   m_stop_info.signo = 0;
164480093f4SDimitry Andric }
165480093f4SDimitry Andric 
SetStopped()1660b57cec5SDimitry Andric void NativeThreadNetBSD::SetStopped() {
1670b57cec5SDimitry Andric   const StateType new_state = StateType::eStateStopped;
1680b57cec5SDimitry Andric   m_state = new_state;
1690b57cec5SDimitry Andric   m_stop_description.clear();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
SetRunning()1720b57cec5SDimitry Andric void NativeThreadNetBSD::SetRunning() {
1730b57cec5SDimitry Andric   m_state = StateType::eStateRunning;
1740b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
SetStepping()1770b57cec5SDimitry Andric void NativeThreadNetBSD::SetStepping() {
1780b57cec5SDimitry Andric   m_state = StateType::eStateStepping;
1790b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
GetName()182480093f4SDimitry Andric std::string NativeThreadNetBSD::GetName() {
18304eeddc0SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
184480093f4SDimitry Andric 
185480093f4SDimitry Andric #ifdef PT_LWPSTATUS
186480093f4SDimitry Andric   struct ptrace_lwpstatus info = {};
187480093f4SDimitry Andric   info.pl_lwpid = m_tid;
188480093f4SDimitry Andric   Status error = NativeProcessNetBSD::PtraceWrapper(
189480093f4SDimitry Andric       PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
190480093f4SDimitry Andric   if (error.Fail()) {
191480093f4SDimitry Andric     return "";
192480093f4SDimitry Andric   }
193480093f4SDimitry Andric   return info.pl_name;
194480093f4SDimitry Andric #else
195480093f4SDimitry Andric   std::vector<struct kinfo_lwp> infos;
196480093f4SDimitry Andric   int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
197480093f4SDimitry Andric                 sizeof(struct kinfo_lwp), 0};
198480093f4SDimitry Andric   size_t size;
199480093f4SDimitry Andric 
200480093f4SDimitry Andric   if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
201480093f4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
202480093f4SDimitry Andric              llvm::sys::StrError());
203480093f4SDimitry Andric     return "";
204480093f4SDimitry Andric   }
205480093f4SDimitry Andric 
206480093f4SDimitry Andric   mib[4] = size / sizeof(size_t);
207480093f4SDimitry Andric   infos.resize(size / sizeof(struct kinfo_lwp));
208480093f4SDimitry Andric 
209480093f4SDimitry Andric   if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
210480093f4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
211480093f4SDimitry Andric     return "";
212480093f4SDimitry Andric   }
213480093f4SDimitry Andric 
214480093f4SDimitry Andric   size_t nlwps = size / sizeof(struct kinfo_lwp);
215480093f4SDimitry Andric   for (size_t i = 0; i < nlwps; i++) {
216480093f4SDimitry Andric     if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
217480093f4SDimitry Andric       return infos[i].l_name;
218480093f4SDimitry Andric     }
219480093f4SDimitry Andric   }
220480093f4SDimitry Andric 
221480093f4SDimitry Andric   LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
222480093f4SDimitry Andric   return "";
223480093f4SDimitry Andric #endif
224480093f4SDimitry Andric }
2250b57cec5SDimitry Andric 
GetState()2260b57cec5SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
2270b57cec5SDimitry Andric 
GetStopReason(ThreadStopInfo & stop_info,std::string & description)2280b57cec5SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
2290b57cec5SDimitry Andric                                        std::string &description) {
23004eeddc0SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
2310b57cec5SDimitry Andric   description.clear();
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   switch (m_state) {
2340b57cec5SDimitry Andric   case eStateStopped:
2350b57cec5SDimitry Andric   case eStateCrashed:
2360b57cec5SDimitry Andric   case eStateExited:
2370b57cec5SDimitry Andric   case eStateSuspended:
2380b57cec5SDimitry Andric   case eStateUnloaded:
2390b57cec5SDimitry Andric     stop_info = m_stop_info;
2400b57cec5SDimitry Andric     description = m_stop_description;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     return true;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   case eStateInvalid:
2450b57cec5SDimitry Andric   case eStateConnected:
2460b57cec5SDimitry Andric   case eStateAttaching:
2470b57cec5SDimitry Andric   case eStateLaunching:
2480b57cec5SDimitry Andric   case eStateRunning:
2490b57cec5SDimitry Andric   case eStateStepping:
2500b57cec5SDimitry Andric   case eStateDetached:
2510b57cec5SDimitry Andric     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
2520b57cec5SDimitry Andric              StateAsCString(m_state));
2530b57cec5SDimitry Andric     return false;
2540b57cec5SDimitry Andric   }
2550b57cec5SDimitry Andric   llvm_unreachable("unhandled StateType!");
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric 
GetRegisterContext()258480093f4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
2590b57cec5SDimitry Andric   assert(m_reg_context_up);
2600b57cec5SDimitry Andric   return *m_reg_context_up;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)2630b57cec5SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
2640b57cec5SDimitry Andric                                          uint32_t watch_flags, bool hardware) {
265e8d8bef9SDimitry Andric   assert(m_state == eStateStopped);
2660b57cec5SDimitry Andric   if (!hardware)
2670b57cec5SDimitry Andric     return Status("not implemented");
2680b57cec5SDimitry Andric   Status error = RemoveWatchpoint(addr);
2690b57cec5SDimitry Andric   if (error.Fail())
2700b57cec5SDimitry Andric     return error;
271e8d8bef9SDimitry Andric   uint32_t wp_index =
272e8d8bef9SDimitry Andric       GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
2730b57cec5SDimitry Andric   if (wp_index == LLDB_INVALID_INDEX32)
2740b57cec5SDimitry Andric     return Status("Setting hardware watchpoint failed.");
2750b57cec5SDimitry Andric   m_watchpoint_index_map.insert({addr, wp_index});
2760b57cec5SDimitry Andric   return Status();
2770b57cec5SDimitry Andric }
2780b57cec5SDimitry Andric 
RemoveWatchpoint(lldb::addr_t addr)2790b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
2800b57cec5SDimitry Andric   auto wp = m_watchpoint_index_map.find(addr);
2810b57cec5SDimitry Andric   if (wp == m_watchpoint_index_map.end())
2820b57cec5SDimitry Andric     return Status();
2830b57cec5SDimitry Andric   uint32_t wp_index = wp->second;
2840b57cec5SDimitry Andric   m_watchpoint_index_map.erase(wp);
2850b57cec5SDimitry Andric   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
2860b57cec5SDimitry Andric     return Status();
2870b57cec5SDimitry Andric   return Status("Clearing hardware watchpoint failed.");
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)2900b57cec5SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
2910b57cec5SDimitry Andric                                                  size_t size) {
292e8d8bef9SDimitry Andric   assert(m_state == eStateStopped);
2930b57cec5SDimitry Andric   Status error = RemoveHardwareBreakpoint(addr);
2940b57cec5SDimitry Andric   if (error.Fail())
2950b57cec5SDimitry Andric     return error;
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   if (bp_index == LLDB_INVALID_INDEX32)
3000b57cec5SDimitry Andric     return Status("Setting hardware breakpoint failed.");
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   m_hw_break_index_map.insert({addr, bp_index});
3030b57cec5SDimitry Andric   return Status();
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric 
RemoveHardwareBreakpoint(lldb::addr_t addr)3060b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
3070b57cec5SDimitry Andric   auto bp = m_hw_break_index_map.find(addr);
3080b57cec5SDimitry Andric   if (bp == m_hw_break_index_map.end())
3090b57cec5SDimitry Andric     return Status();
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric   uint32_t bp_index = bp->second;
3120b57cec5SDimitry Andric   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
3130b57cec5SDimitry Andric     m_hw_break_index_map.erase(bp);
3140b57cec5SDimitry Andric     return Status();
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   return Status("Clearing hardware breakpoint failed.");
3180b57cec5SDimitry Andric }
319480093f4SDimitry Andric 
320e8d8bef9SDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadNetBSD & source)321e8d8bef9SDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
322e8d8bef9SDimitry Andric   llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
323480093f4SDimitry Andric       source.GetRegisterContext());
324e8d8bef9SDimitry Andric   if (!s) {
325480093f4SDimitry Andric     m_watchpoint_index_map = source.m_watchpoint_index_map;
326480093f4SDimitry Andric     m_hw_break_index_map = source.m_hw_break_index_map;
327480093f4SDimitry Andric   }
328480093f4SDimitry Andric   return s;
329480093f4SDimitry Andric }
330