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) {
780b57cec5SDimitry Andric   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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;
840b57cec5SDimitry Andric   m_stop_info.details.signal.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:
930b57cec5SDimitry Andric       const auto reason = GetCrashReason(*info);
940b57cec5SDimitry Andric       m_stop_description = GetCrashReasonString(reason, *info);
950b57cec5SDimitry Andric       break;
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
SetStoppedByBreakpoint()1000b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() {
1010b57cec5SDimitry Andric   SetStopped();
1020b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
1030b57cec5SDimitry Andric   m_stop_info.details.signal.signo = SIGTRAP;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
SetStoppedByTrace()1060b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() {
1070b57cec5SDimitry Andric   SetStopped();
1080b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonTrace;
1090b57cec5SDimitry Andric   m_stop_info.details.signal.signo = SIGTRAP;
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
SetStoppedByExec()1120b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() {
1130b57cec5SDimitry Andric   SetStopped();
1140b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonExec;
1150b57cec5SDimitry Andric   m_stop_info.details.signal.signo = SIGTRAP;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
SetStoppedByWatchpoint(uint32_t wp_index)1180b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
1190b57cec5SDimitry Andric   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   std::ostringstream ostr;
1220b57cec5SDimitry Andric   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
1230b57cec5SDimitry Andric   ostr << wp_index;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
1260b57cec5SDimitry Andric 
127af732203SDimitry Andric   SetStopped();
1280b57cec5SDimitry Andric   m_stop_description = ostr.str();
1290b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
1300b57cec5SDimitry Andric   m_stop_info.details.signal.signo = SIGTRAP;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)133*5f7ddb14SDimitry Andric void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
134*5f7ddb14SDimitry Andric                                            lldb::tid_t child_tid) {
135*5f7ddb14SDimitry Andric   SetStopped();
136*5f7ddb14SDimitry Andric 
137*5f7ddb14SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonFork;
138*5f7ddb14SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
139*5f7ddb14SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
140*5f7ddb14SDimitry Andric }
141*5f7ddb14SDimitry Andric 
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142*5f7ddb14SDimitry Andric void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143*5f7ddb14SDimitry Andric                                             lldb::tid_t child_tid) {
144*5f7ddb14SDimitry Andric   SetStopped();
145*5f7ddb14SDimitry Andric 
146*5f7ddb14SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVFork;
147*5f7ddb14SDimitry Andric   m_stop_info.details.fork.child_pid = child_pid;
148*5f7ddb14SDimitry Andric   m_stop_info.details.fork.child_tid = child_tid;
149*5f7ddb14SDimitry Andric }
150*5f7ddb14SDimitry Andric 
SetStoppedByVForkDone()151*5f7ddb14SDimitry Andric void NativeThreadNetBSD::SetStoppedByVForkDone() {
152*5f7ddb14SDimitry Andric   SetStopped();
153*5f7ddb14SDimitry Andric 
154*5f7ddb14SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonVForkDone;
155*5f7ddb14SDimitry Andric }
156*5f7ddb14SDimitry Andric 
SetStoppedWithNoReason()157480093f4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() {
158480093f4SDimitry Andric   SetStopped();
159480093f4SDimitry Andric 
160480093f4SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
161480093f4SDimitry Andric   m_stop_info.details.signal.signo = 0;
162480093f4SDimitry Andric }
163480093f4SDimitry Andric 
SetStopped()1640b57cec5SDimitry Andric void NativeThreadNetBSD::SetStopped() {
1650b57cec5SDimitry Andric   const StateType new_state = StateType::eStateStopped;
1660b57cec5SDimitry Andric   m_state = new_state;
1670b57cec5SDimitry Andric   m_stop_description.clear();
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
SetRunning()1700b57cec5SDimitry Andric void NativeThreadNetBSD::SetRunning() {
1710b57cec5SDimitry Andric   m_state = StateType::eStateRunning;
1720b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
SetStepping()1750b57cec5SDimitry Andric void NativeThreadNetBSD::SetStepping() {
1760b57cec5SDimitry Andric   m_state = StateType::eStateStepping;
1770b57cec5SDimitry Andric   m_stop_info.reason = StopReason::eStopReasonNone;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
GetName()180480093f4SDimitry Andric std::string NativeThreadNetBSD::GetName() {
181480093f4SDimitry Andric   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
182480093f4SDimitry Andric 
183480093f4SDimitry Andric #ifdef PT_LWPSTATUS
184480093f4SDimitry Andric   struct ptrace_lwpstatus info = {};
185480093f4SDimitry Andric   info.pl_lwpid = m_tid;
186480093f4SDimitry Andric   Status error = NativeProcessNetBSD::PtraceWrapper(
187480093f4SDimitry Andric       PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
188480093f4SDimitry Andric   if (error.Fail()) {
189480093f4SDimitry Andric     return "";
190480093f4SDimitry Andric   }
191480093f4SDimitry Andric   return info.pl_name;
192480093f4SDimitry Andric #else
193480093f4SDimitry Andric   std::vector<struct kinfo_lwp> infos;
194480093f4SDimitry Andric   int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
195480093f4SDimitry Andric                 sizeof(struct kinfo_lwp), 0};
196480093f4SDimitry Andric   size_t size;
197480093f4SDimitry Andric 
198480093f4SDimitry Andric   if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
199480093f4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
200480093f4SDimitry Andric              llvm::sys::StrError());
201480093f4SDimitry Andric     return "";
202480093f4SDimitry Andric   }
203480093f4SDimitry Andric 
204480093f4SDimitry Andric   mib[4] = size / sizeof(size_t);
205480093f4SDimitry Andric   infos.resize(size / sizeof(struct kinfo_lwp));
206480093f4SDimitry Andric 
207480093f4SDimitry Andric   if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
208480093f4SDimitry Andric     LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
209480093f4SDimitry Andric     return "";
210480093f4SDimitry Andric   }
211480093f4SDimitry Andric 
212480093f4SDimitry Andric   size_t nlwps = size / sizeof(struct kinfo_lwp);
213480093f4SDimitry Andric   for (size_t i = 0; i < nlwps; i++) {
214480093f4SDimitry Andric     if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
215480093f4SDimitry Andric       return infos[i].l_name;
216480093f4SDimitry Andric     }
217480093f4SDimitry Andric   }
218480093f4SDimitry Andric 
219480093f4SDimitry Andric   LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
220480093f4SDimitry Andric   return "";
221480093f4SDimitry Andric #endif
222480093f4SDimitry Andric }
2230b57cec5SDimitry Andric 
GetState()2240b57cec5SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
2250b57cec5SDimitry Andric 
GetStopReason(ThreadStopInfo & stop_info,std::string & description)2260b57cec5SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
2270b57cec5SDimitry Andric                                        std::string &description) {
2280b57cec5SDimitry Andric   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
2290b57cec5SDimitry Andric   description.clear();
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   switch (m_state) {
2320b57cec5SDimitry Andric   case eStateStopped:
2330b57cec5SDimitry Andric   case eStateCrashed:
2340b57cec5SDimitry Andric   case eStateExited:
2350b57cec5SDimitry Andric   case eStateSuspended:
2360b57cec5SDimitry Andric   case eStateUnloaded:
2370b57cec5SDimitry Andric     stop_info = m_stop_info;
2380b57cec5SDimitry Andric     description = m_stop_description;
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric     return true;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   case eStateInvalid:
2430b57cec5SDimitry Andric   case eStateConnected:
2440b57cec5SDimitry Andric   case eStateAttaching:
2450b57cec5SDimitry Andric   case eStateLaunching:
2460b57cec5SDimitry Andric   case eStateRunning:
2470b57cec5SDimitry Andric   case eStateStepping:
2480b57cec5SDimitry Andric   case eStateDetached:
2490b57cec5SDimitry Andric     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
2500b57cec5SDimitry Andric              StateAsCString(m_state));
2510b57cec5SDimitry Andric     return false;
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric   llvm_unreachable("unhandled StateType!");
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric 
GetRegisterContext()256480093f4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
2570b57cec5SDimitry Andric   assert(m_reg_context_up);
2580b57cec5SDimitry Andric   return *m_reg_context_up;
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric 
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)2610b57cec5SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
2620b57cec5SDimitry Andric                                          uint32_t watch_flags, bool hardware) {
263af732203SDimitry Andric   assert(m_state == eStateStopped);
2640b57cec5SDimitry Andric   if (!hardware)
2650b57cec5SDimitry Andric     return Status("not implemented");
2660b57cec5SDimitry Andric   Status error = RemoveWatchpoint(addr);
2670b57cec5SDimitry Andric   if (error.Fail())
2680b57cec5SDimitry Andric     return error;
269af732203SDimitry Andric   uint32_t wp_index =
270af732203SDimitry Andric       GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
2710b57cec5SDimitry Andric   if (wp_index == LLDB_INVALID_INDEX32)
2720b57cec5SDimitry Andric     return Status("Setting hardware watchpoint failed.");
2730b57cec5SDimitry Andric   m_watchpoint_index_map.insert({addr, wp_index});
2740b57cec5SDimitry Andric   return Status();
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric 
RemoveWatchpoint(lldb::addr_t addr)2770b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
2780b57cec5SDimitry Andric   auto wp = m_watchpoint_index_map.find(addr);
2790b57cec5SDimitry Andric   if (wp == m_watchpoint_index_map.end())
2800b57cec5SDimitry Andric     return Status();
2810b57cec5SDimitry Andric   uint32_t wp_index = wp->second;
2820b57cec5SDimitry Andric   m_watchpoint_index_map.erase(wp);
2830b57cec5SDimitry Andric   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
2840b57cec5SDimitry Andric     return Status();
2850b57cec5SDimitry Andric   return Status("Clearing hardware watchpoint failed.");
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)2880b57cec5SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
2890b57cec5SDimitry Andric                                                  size_t size) {
290af732203SDimitry Andric   assert(m_state == eStateStopped);
2910b57cec5SDimitry Andric   Status error = RemoveHardwareBreakpoint(addr);
2920b57cec5SDimitry Andric   if (error.Fail())
2930b57cec5SDimitry Andric     return error;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   if (bp_index == LLDB_INVALID_INDEX32)
2980b57cec5SDimitry Andric     return Status("Setting hardware breakpoint failed.");
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   m_hw_break_index_map.insert({addr, bp_index});
3010b57cec5SDimitry Andric   return Status();
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric 
RemoveHardwareBreakpoint(lldb::addr_t addr)3040b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
3050b57cec5SDimitry Andric   auto bp = m_hw_break_index_map.find(addr);
3060b57cec5SDimitry Andric   if (bp == m_hw_break_index_map.end())
3070b57cec5SDimitry Andric     return Status();
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   uint32_t bp_index = bp->second;
3100b57cec5SDimitry Andric   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
3110b57cec5SDimitry Andric     m_hw_break_index_map.erase(bp);
3120b57cec5SDimitry Andric     return Status();
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   return Status("Clearing hardware breakpoint failed.");
3160b57cec5SDimitry Andric }
317480093f4SDimitry Andric 
318af732203SDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadNetBSD & source)319af732203SDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
320af732203SDimitry Andric   llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
321480093f4SDimitry Andric       source.GetRegisterContext());
322af732203SDimitry Andric   if (!s) {
323480093f4SDimitry Andric     m_watchpoint_index_map = source.m_watchpoint_index_map;
324480093f4SDimitry Andric     m_hw_break_index_map = source.m_hw_break_index_map;
325480093f4SDimitry Andric   }
326480093f4SDimitry Andric   return s;
327480093f4SDimitry Andric }
328