11a3d19ddSKamil Rytarowski //===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===//
21a3d19ddSKamil Rytarowski //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61a3d19ddSKamil Rytarowski //
71a3d19ddSKamil Rytarowski //===----------------------------------------------------------------------===//
81a3d19ddSKamil Rytarowski 
91a3d19ddSKamil Rytarowski #include "NativeThreadNetBSD.h"
101a3d19ddSKamil Rytarowski #include "NativeRegisterContextNetBSD.h"
111a3d19ddSKamil Rytarowski 
121a3d19ddSKamil Rytarowski #include "NativeProcessNetBSD.h"
131a3d19ddSKamil Rytarowski 
14f07a9995SKamil Rytarowski #include "Plugins/Process/POSIX/CrashReason.h"
15f07a9995SKamil Rytarowski #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
1636e23ecaSKamil Rytarowski #include "lldb/Utility/LLDBAssert.h"
17d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
18d821c997SPavel Labath #include "lldb/Utility/State.h"
19*23a766dcSMichał Górny #include "llvm/Support/Errno.h"
2036e23ecaSKamil Rytarowski 
2136e23ecaSKamil Rytarowski #include <sstream>
22f07a9995SKamil Rytarowski 
23*23a766dcSMichał Górny // clang-format off
24*23a766dcSMichał Górny #include <sys/types.h>
25*23a766dcSMichał Górny #include <sys/sysctl.h>
26*23a766dcSMichał Górny // clang-format on
27*23a766dcSMichał Górny 
281a3d19ddSKamil Rytarowski using namespace lldb;
291a3d19ddSKamil Rytarowski using namespace lldb_private;
301a3d19ddSKamil Rytarowski using namespace lldb_private::process_netbsd;
311a3d19ddSKamil Rytarowski 
3282abefa4SPavel Labath NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
331a3d19ddSKamil Rytarowski                                        lldb::tid_t tid)
34f07a9995SKamil Rytarowski     : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
35d37349f3SPavel Labath       m_stop_info(), m_reg_context_up(
36d37349f3SPavel Labath NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
37d37349f3SPavel Labath ), m_stop_description() {}
38f07a9995SKamil Rytarowski 
39f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
40f07a9995SKamil Rytarowski                                             const siginfo_t *info) {
41f07a9995SKamil Rytarowski   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
42f07a9995SKamil Rytarowski   LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
43f07a9995SKamil Rytarowski 
44f07a9995SKamil Rytarowski   SetStopped();
45f07a9995SKamil Rytarowski 
46f07a9995SKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonSignal;
47f07a9995SKamil Rytarowski   m_stop_info.details.signal.signo = signo;
48f07a9995SKamil Rytarowski 
49f07a9995SKamil Rytarowski   m_stop_description.clear();
50f07a9995SKamil Rytarowski   if (info) {
51f07a9995SKamil Rytarowski     switch (signo) {
52f07a9995SKamil Rytarowski     case SIGSEGV:
53f07a9995SKamil Rytarowski     case SIGBUS:
54f07a9995SKamil Rytarowski     case SIGFPE:
55f07a9995SKamil Rytarowski     case SIGILL:
56f07a9995SKamil Rytarowski       const auto reason = GetCrashReason(*info);
57f07a9995SKamil Rytarowski       m_stop_description = GetCrashReasonString(reason, *info);
58f07a9995SKamil Rytarowski       break;
59f07a9995SKamil Rytarowski     }
60f07a9995SKamil Rytarowski   }
61f07a9995SKamil Rytarowski }
62f07a9995SKamil Rytarowski 
63f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStoppedByBreakpoint() {
64f07a9995SKamil Rytarowski   SetStopped();
65f07a9995SKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
66f07a9995SKamil Rytarowski   m_stop_info.details.signal.signo = SIGTRAP;
67f07a9995SKamil Rytarowski }
68f07a9995SKamil Rytarowski 
693eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByTrace() {
703eef2b5eSKamil Rytarowski   SetStopped();
713eef2b5eSKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonTrace;
723eef2b5eSKamil Rytarowski   m_stop_info.details.signal.signo = SIGTRAP;
733eef2b5eSKamil Rytarowski }
743eef2b5eSKamil Rytarowski 
753eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByExec() {
763eef2b5eSKamil Rytarowski   SetStopped();
773eef2b5eSKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonExec;
783eef2b5eSKamil Rytarowski   m_stop_info.details.signal.signo = SIGTRAP;
793eef2b5eSKamil Rytarowski }
803eef2b5eSKamil Rytarowski 
8136e23ecaSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
8236e23ecaSKamil Rytarowski   SetStopped();
8336e23ecaSKamil Rytarowski 
8436e23ecaSKamil Rytarowski   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
8536e23ecaSKamil Rytarowski 
8636e23ecaSKamil Rytarowski   std::ostringstream ostr;
87d37349f3SPavel Labath   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
8836e23ecaSKamil Rytarowski   ostr << wp_index;
8936e23ecaSKamil Rytarowski 
90d37349f3SPavel Labath   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
9136e23ecaSKamil Rytarowski 
9236e23ecaSKamil Rytarowski   m_stop_description = ostr.str();
9336e23ecaSKamil Rytarowski 
9436e23ecaSKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
9536e23ecaSKamil Rytarowski   m_stop_info.details.signal.signo = SIGTRAP;
9636e23ecaSKamil Rytarowski }
9736e23ecaSKamil Rytarowski 
98f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStopped() {
99f07a9995SKamil Rytarowski   const StateType new_state = StateType::eStateStopped;
100f07a9995SKamil Rytarowski   m_state = new_state;
101f07a9995SKamil Rytarowski   m_stop_description.clear();
102f07a9995SKamil Rytarowski }
103f07a9995SKamil Rytarowski 
104f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetRunning() {
105f07a9995SKamil Rytarowski   m_state = StateType::eStateRunning;
106f07a9995SKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonNone;
107f07a9995SKamil Rytarowski }
108f07a9995SKamil Rytarowski 
1093eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStepping() {
1103eef2b5eSKamil Rytarowski   m_state = StateType::eStateStepping;
1113eef2b5eSKamil Rytarowski   m_stop_info.reason = StopReason::eStopReasonNone;
1123eef2b5eSKamil Rytarowski }
1133eef2b5eSKamil Rytarowski 
114*23a766dcSMichał Górny std::string NativeThreadNetBSD::GetName() {
115*23a766dcSMichał Górny   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
116*23a766dcSMichał Górny 
117*23a766dcSMichał Górny   std::vector<struct kinfo_lwp> infos;
118*23a766dcSMichał Górny   int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
119*23a766dcSMichał Górny                 sizeof(struct kinfo_lwp), 0};
120*23a766dcSMichał Górny   size_t size;
121*23a766dcSMichał Górny 
122*23a766dcSMichał Górny   if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
123*23a766dcSMichał Górny     LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
124*23a766dcSMichał Górny              llvm::sys::StrError());
125*23a766dcSMichał Górny     return "";
126*23a766dcSMichał Górny   }
127*23a766dcSMichał Górny 
128*23a766dcSMichał Górny   mib[4] = size / sizeof(size_t);
129*23a766dcSMichał Górny   infos.resize(size / sizeof(struct kinfo_lwp));
130*23a766dcSMichał Górny 
131*23a766dcSMichał Górny   if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
132*23a766dcSMichał Górny     LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
133*23a766dcSMichał Górny     return "";
134*23a766dcSMichał Górny   }
135*23a766dcSMichał Górny 
136*23a766dcSMichał Górny   size_t nlwps = size / sizeof(struct kinfo_lwp);
137*23a766dcSMichał Górny   for (size_t i = 0; i < nlwps; i++) {
138*23a766dcSMichał Górny     if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
139*23a766dcSMichał Górny       return infos[i].l_name;
140*23a766dcSMichał Górny     }
141*23a766dcSMichał Górny   }
142*23a766dcSMichał Górny 
143*23a766dcSMichał Górny   LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
144*23a766dcSMichał Górny   return "";
145*23a766dcSMichał Górny }
146f07a9995SKamil Rytarowski 
147f07a9995SKamil Rytarowski lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
148f07a9995SKamil Rytarowski 
149f07a9995SKamil Rytarowski bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
150f07a9995SKamil Rytarowski                                        std::string &description) {
151f07a9995SKamil Rytarowski   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
152f07a9995SKamil Rytarowski 
153f07a9995SKamil Rytarowski   description.clear();
154f07a9995SKamil Rytarowski 
155f07a9995SKamil Rytarowski   switch (m_state) {
156f07a9995SKamil Rytarowski   case eStateStopped:
157f07a9995SKamil Rytarowski   case eStateCrashed:
158f07a9995SKamil Rytarowski   case eStateExited:
159f07a9995SKamil Rytarowski   case eStateSuspended:
160f07a9995SKamil Rytarowski   case eStateUnloaded:
161f07a9995SKamil Rytarowski     stop_info = m_stop_info;
162f07a9995SKamil Rytarowski     description = m_stop_description;
163f07a9995SKamil Rytarowski 
164f07a9995SKamil Rytarowski     return true;
165f07a9995SKamil Rytarowski 
166f07a9995SKamil Rytarowski   case eStateInvalid:
167f07a9995SKamil Rytarowski   case eStateConnected:
168f07a9995SKamil Rytarowski   case eStateAttaching:
169f07a9995SKamil Rytarowski   case eStateLaunching:
170f07a9995SKamil Rytarowski   case eStateRunning:
171f07a9995SKamil Rytarowski   case eStateStepping:
172f07a9995SKamil Rytarowski   case eStateDetached:
173f07a9995SKamil Rytarowski     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
174f07a9995SKamil Rytarowski              StateAsCString(m_state));
175f07a9995SKamil Rytarowski     return false;
176f07a9995SKamil Rytarowski   }
177f07a9995SKamil Rytarowski   llvm_unreachable("unhandled StateType!");
178f07a9995SKamil Rytarowski }
179f07a9995SKamil Rytarowski 
180d37349f3SPavel Labath NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() {
181d37349f3SPavel Labath   assert(m_reg_context_up);
182d37349f3SPavel Labath return  *m_reg_context_up;
183f07a9995SKamil Rytarowski }
184f07a9995SKamil Rytarowski 
18597206d57SZachary Turner Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
186f07a9995SKamil Rytarowski                                          uint32_t watch_flags, bool hardware) {
18736e23ecaSKamil Rytarowski   if (!hardware)
18897206d57SZachary Turner     return Status("not implemented");
18936e23ecaSKamil Rytarowski   if (m_state == eStateLaunching)
19097206d57SZachary Turner     return Status();
19197206d57SZachary Turner   Status error = RemoveWatchpoint(addr);
19236e23ecaSKamil Rytarowski   if (error.Fail())
19336e23ecaSKamil Rytarowski     return error;
194d37349f3SPavel Labath   uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
19536e23ecaSKamil Rytarowski   if (wp_index == LLDB_INVALID_INDEX32)
19697206d57SZachary Turner     return Status("Setting hardware watchpoint failed.");
19736e23ecaSKamil Rytarowski   m_watchpoint_index_map.insert({addr, wp_index});
19897206d57SZachary Turner   return Status();
199f07a9995SKamil Rytarowski }
200f07a9995SKamil Rytarowski 
20197206d57SZachary Turner Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
20236e23ecaSKamil Rytarowski   auto wp = m_watchpoint_index_map.find(addr);
20336e23ecaSKamil Rytarowski   if (wp == m_watchpoint_index_map.end())
20497206d57SZachary Turner     return Status();
20536e23ecaSKamil Rytarowski   uint32_t wp_index = wp->second;
20636e23ecaSKamil Rytarowski   m_watchpoint_index_map.erase(wp);
207d37349f3SPavel Labath   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
20897206d57SZachary Turner     return Status();
20997206d57SZachary Turner   return Status("Clearing hardware watchpoint failed.");
210f07a9995SKamil Rytarowski }
211f07a9995SKamil Rytarowski 
21297206d57SZachary Turner Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
213f07a9995SKamil Rytarowski                                                  size_t size) {
21436e23ecaSKamil Rytarowski   if (m_state == eStateLaunching)
21597206d57SZachary Turner     return Status();
21636e23ecaSKamil Rytarowski 
21797206d57SZachary Turner   Status error = RemoveHardwareBreakpoint(addr);
21836e23ecaSKamil Rytarowski   if (error.Fail())
21936e23ecaSKamil Rytarowski     return error;
22036e23ecaSKamil Rytarowski 
221d37349f3SPavel Labath   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
22236e23ecaSKamil Rytarowski 
22336e23ecaSKamil Rytarowski   if (bp_index == LLDB_INVALID_INDEX32)
22497206d57SZachary Turner     return Status("Setting hardware breakpoint failed.");
22536e23ecaSKamil Rytarowski 
22636e23ecaSKamil Rytarowski   m_hw_break_index_map.insert({addr, bp_index});
22797206d57SZachary Turner   return Status();
228f07a9995SKamil Rytarowski }
229f07a9995SKamil Rytarowski 
23097206d57SZachary Turner Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
23136e23ecaSKamil Rytarowski   auto bp = m_hw_break_index_map.find(addr);
23236e23ecaSKamil Rytarowski   if (bp == m_hw_break_index_map.end())
23397206d57SZachary Turner     return Status();
23436e23ecaSKamil Rytarowski 
23536e23ecaSKamil Rytarowski   uint32_t bp_index = bp->second;
236d37349f3SPavel Labath   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
23736e23ecaSKamil Rytarowski     m_hw_break_index_map.erase(bp);
23897206d57SZachary Turner     return Status();
23936e23ecaSKamil Rytarowski   }
24036e23ecaSKamil Rytarowski 
24197206d57SZachary Turner   return Status("Clearing hardware breakpoint failed.");
242f07a9995SKamil Rytarowski }
243