xref: /llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp (revision 23a766dcad47993f632ab22ab3a8f3dc977bd838)
1 //===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "NativeThreadNetBSD.h"
10 #include "NativeRegisterContextNetBSD.h"
11 
12 #include "NativeProcessNetBSD.h"
13 
14 #include "Plugins/Process/POSIX/CrashReason.h"
15 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16 #include "lldb/Utility/LLDBAssert.h"
17 #include "lldb/Utility/RegisterValue.h"
18 #include "lldb/Utility/State.h"
19 #include "llvm/Support/Errno.h"
20 
21 #include <sstream>
22 
23 // clang-format off
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
26 // clang-format on
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::process_netbsd;
31 
32 NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
33                                        lldb::tid_t tid)
34     : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
35       m_stop_info(), m_reg_context_up(
36 NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
37 ), m_stop_description() {}
38 
39 void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
40                                             const siginfo_t *info) {
41   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
42   LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
43 
44   SetStopped();
45 
46   m_stop_info.reason = StopReason::eStopReasonSignal;
47   m_stop_info.details.signal.signo = signo;
48 
49   m_stop_description.clear();
50   if (info) {
51     switch (signo) {
52     case SIGSEGV:
53     case SIGBUS:
54     case SIGFPE:
55     case SIGILL:
56       const auto reason = GetCrashReason(*info);
57       m_stop_description = GetCrashReasonString(reason, *info);
58       break;
59     }
60   }
61 }
62 
63 void NativeThreadNetBSD::SetStoppedByBreakpoint() {
64   SetStopped();
65   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
66   m_stop_info.details.signal.signo = SIGTRAP;
67 }
68 
69 void NativeThreadNetBSD::SetStoppedByTrace() {
70   SetStopped();
71   m_stop_info.reason = StopReason::eStopReasonTrace;
72   m_stop_info.details.signal.signo = SIGTRAP;
73 }
74 
75 void NativeThreadNetBSD::SetStoppedByExec() {
76   SetStopped();
77   m_stop_info.reason = StopReason::eStopReasonExec;
78   m_stop_info.details.signal.signo = SIGTRAP;
79 }
80 
81 void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
82   SetStopped();
83 
84   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
85 
86   std::ostringstream ostr;
87   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
88   ostr << wp_index;
89 
90   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
91 
92   m_stop_description = ostr.str();
93 
94   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
95   m_stop_info.details.signal.signo = SIGTRAP;
96 }
97 
98 void NativeThreadNetBSD::SetStopped() {
99   const StateType new_state = StateType::eStateStopped;
100   m_state = new_state;
101   m_stop_description.clear();
102 }
103 
104 void NativeThreadNetBSD::SetRunning() {
105   m_state = StateType::eStateRunning;
106   m_stop_info.reason = StopReason::eStopReasonNone;
107 }
108 
109 void NativeThreadNetBSD::SetStepping() {
110   m_state = StateType::eStateStepping;
111   m_stop_info.reason = StopReason::eStopReasonNone;
112 }
113 
114 std::string NativeThreadNetBSD::GetName() {
115   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
116 
117   std::vector<struct kinfo_lwp> infos;
118   int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
119                 sizeof(struct kinfo_lwp), 0};
120   size_t size;
121 
122   if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
123     LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
124              llvm::sys::StrError());
125     return "";
126   }
127 
128   mib[4] = size / sizeof(size_t);
129   infos.resize(size / sizeof(struct kinfo_lwp));
130 
131   if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
132     LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
133     return "";
134   }
135 
136   size_t nlwps = size / sizeof(struct kinfo_lwp);
137   for (size_t i = 0; i < nlwps; i++) {
138     if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
139       return infos[i].l_name;
140     }
141   }
142 
143   LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
144   return "";
145 }
146 
147 lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
148 
149 bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
150                                        std::string &description) {
151   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
152 
153   description.clear();
154 
155   switch (m_state) {
156   case eStateStopped:
157   case eStateCrashed:
158   case eStateExited:
159   case eStateSuspended:
160   case eStateUnloaded:
161     stop_info = m_stop_info;
162     description = m_stop_description;
163 
164     return true;
165 
166   case eStateInvalid:
167   case eStateConnected:
168   case eStateAttaching:
169   case eStateLaunching:
170   case eStateRunning:
171   case eStateStepping:
172   case eStateDetached:
173     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
174              StateAsCString(m_state));
175     return false;
176   }
177   llvm_unreachable("unhandled StateType!");
178 }
179 
180 NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() {
181   assert(m_reg_context_up);
182 return  *m_reg_context_up;
183 }
184 
185 Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
186                                          uint32_t watch_flags, bool hardware) {
187   if (!hardware)
188     return Status("not implemented");
189   if (m_state == eStateLaunching)
190     return Status();
191   Status error = RemoveWatchpoint(addr);
192   if (error.Fail())
193     return error;
194   uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
195   if (wp_index == LLDB_INVALID_INDEX32)
196     return Status("Setting hardware watchpoint failed.");
197   m_watchpoint_index_map.insert({addr, wp_index});
198   return Status();
199 }
200 
201 Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
202   auto wp = m_watchpoint_index_map.find(addr);
203   if (wp == m_watchpoint_index_map.end())
204     return Status();
205   uint32_t wp_index = wp->second;
206   m_watchpoint_index_map.erase(wp);
207   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
208     return Status();
209   return Status("Clearing hardware watchpoint failed.");
210 }
211 
212 Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
213                                                  size_t size) {
214   if (m_state == eStateLaunching)
215     return Status();
216 
217   Status error = RemoveHardwareBreakpoint(addr);
218   if (error.Fail())
219     return error;
220 
221   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
222 
223   if (bp_index == LLDB_INVALID_INDEX32)
224     return Status("Setting hardware breakpoint failed.");
225 
226   m_hw_break_index_map.insert({addr, bp_index});
227   return Status();
228 }
229 
230 Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
231   auto bp = m_hw_break_index_map.find(addr);
232   if (bp == m_hw_break_index_map.end())
233     return Status();
234 
235   uint32_t bp_index = bp->second;
236   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
237     m_hw_break_index_map.erase(bp);
238     return Status();
239   }
240 
241   return Status("Clearing hardware breakpoint failed.");
242 }
243