xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1*be691f3bSpatrick //===-- NativeThreadFreeBSD.cpp -------------------------------------------===//
2*be691f3bSpatrick //
3*be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information.
5*be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*be691f3bSpatrick //
7*be691f3bSpatrick //===----------------------------------------------------------------------===//
8*be691f3bSpatrick 
9*be691f3bSpatrick #include "NativeThreadFreeBSD.h"
10*be691f3bSpatrick #include "NativeRegisterContextFreeBSD.h"
11*be691f3bSpatrick 
12*be691f3bSpatrick #include "NativeProcessFreeBSD.h"
13*be691f3bSpatrick 
14*be691f3bSpatrick #include "Plugins/Process/POSIX/CrashReason.h"
15*be691f3bSpatrick #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16*be691f3bSpatrick #include "lldb/Utility/LLDBAssert.h"
17*be691f3bSpatrick #include "lldb/Utility/RegisterValue.h"
18*be691f3bSpatrick #include "lldb/Utility/State.h"
19*be691f3bSpatrick #include "llvm/Support/Errno.h"
20*be691f3bSpatrick 
21*be691f3bSpatrick // clang-format off
22*be691f3bSpatrick #include <sys/types.h>
23*be691f3bSpatrick #include <sys/ptrace.h>
24*be691f3bSpatrick #include <sys/sysctl.h>
25*be691f3bSpatrick #include <sys/user.h>
26*be691f3bSpatrick // clang-format on
27*be691f3bSpatrick 
28*be691f3bSpatrick #include <sstream>
29*be691f3bSpatrick #include <vector>
30*be691f3bSpatrick 
31*be691f3bSpatrick using namespace lldb;
32*be691f3bSpatrick using namespace lldb_private;
33*be691f3bSpatrick using namespace lldb_private::process_freebsd;
34*be691f3bSpatrick 
35*be691f3bSpatrick NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
36*be691f3bSpatrick                                          lldb::tid_t tid)
37*be691f3bSpatrick     : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
38*be691f3bSpatrick       m_stop_info(),
39*be691f3bSpatrick       m_reg_context_up(
40*be691f3bSpatrick           NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
41*be691f3bSpatrick               process.GetArchitecture(), *this)),
42*be691f3bSpatrick       m_stop_description() {}
43*be691f3bSpatrick 
44*be691f3bSpatrick Status NativeThreadFreeBSD::Resume() {
45*be691f3bSpatrick   Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
46*be691f3bSpatrick   if (!ret.Success())
47*be691f3bSpatrick     return ret;
48*be691f3bSpatrick   ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
49*be691f3bSpatrick   // we can get EINVAL if the architecture in question does not support
50*be691f3bSpatrick   // hardware single-stepping -- that's fine, we have nothing to clear
51*be691f3bSpatrick   // then
52*be691f3bSpatrick   if (ret.GetError() == EINVAL)
53*be691f3bSpatrick     ret.Clear();
54*be691f3bSpatrick   if (ret.Success())
55*be691f3bSpatrick     SetRunning();
56*be691f3bSpatrick   return ret;
57*be691f3bSpatrick }
58*be691f3bSpatrick 
59*be691f3bSpatrick Status NativeThreadFreeBSD::SingleStep() {
60*be691f3bSpatrick   Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
61*be691f3bSpatrick   if (!ret.Success())
62*be691f3bSpatrick     return ret;
63*be691f3bSpatrick   ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());
64*be691f3bSpatrick   if (ret.Success())
65*be691f3bSpatrick     SetStepping();
66*be691f3bSpatrick   return ret;
67*be691f3bSpatrick }
68*be691f3bSpatrick 
69*be691f3bSpatrick Status NativeThreadFreeBSD::Suspend() {
70*be691f3bSpatrick   Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());
71*be691f3bSpatrick   if (ret.Success())
72*be691f3bSpatrick     SetStopped();
73*be691f3bSpatrick   return ret;
74*be691f3bSpatrick }
75*be691f3bSpatrick 
76*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo,
77*be691f3bSpatrick                                              const siginfo_t *info) {
78*be691f3bSpatrick   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
79*be691f3bSpatrick   LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
80*be691f3bSpatrick 
81*be691f3bSpatrick   SetStopped();
82*be691f3bSpatrick 
83*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonSignal;
84*be691f3bSpatrick   m_stop_info.details.signal.signo = signo;
85*be691f3bSpatrick 
86*be691f3bSpatrick   m_stop_description.clear();
87*be691f3bSpatrick   if (info) {
88*be691f3bSpatrick     switch (signo) {
89*be691f3bSpatrick     case SIGSEGV:
90*be691f3bSpatrick     case SIGBUS:
91*be691f3bSpatrick     case SIGFPE:
92*be691f3bSpatrick     case SIGILL:
93*be691f3bSpatrick       const auto reason = GetCrashReason(*info);
94*be691f3bSpatrick       m_stop_description = GetCrashReasonString(reason, *info);
95*be691f3bSpatrick       break;
96*be691f3bSpatrick     }
97*be691f3bSpatrick   }
98*be691f3bSpatrick }
99*be691f3bSpatrick 
100*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByBreakpoint() {
101*be691f3bSpatrick   SetStopped();
102*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonBreakpoint;
103*be691f3bSpatrick   m_stop_info.details.signal.signo = SIGTRAP;
104*be691f3bSpatrick }
105*be691f3bSpatrick 
106*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByTrace() {
107*be691f3bSpatrick   SetStopped();
108*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonTrace;
109*be691f3bSpatrick   m_stop_info.details.signal.signo = SIGTRAP;
110*be691f3bSpatrick }
111*be691f3bSpatrick 
112*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByExec() {
113*be691f3bSpatrick   SetStopped();
114*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonExec;
115*be691f3bSpatrick   m_stop_info.details.signal.signo = SIGTRAP;
116*be691f3bSpatrick }
117*be691f3bSpatrick 
118*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
119*be691f3bSpatrick   lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
120*be691f3bSpatrick 
121*be691f3bSpatrick   std::ostringstream ostr;
122*be691f3bSpatrick   ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
123*be691f3bSpatrick   ostr << wp_index;
124*be691f3bSpatrick 
125*be691f3bSpatrick   ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
126*be691f3bSpatrick 
127*be691f3bSpatrick   SetStopped();
128*be691f3bSpatrick   m_stop_description = ostr.str();
129*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonWatchpoint;
130*be691f3bSpatrick   m_stop_info.details.signal.signo = SIGTRAP;
131*be691f3bSpatrick }
132*be691f3bSpatrick 
133*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid,
134*be691f3bSpatrick                                            lldb::tid_t child_tid) {
135*be691f3bSpatrick   SetStopped();
136*be691f3bSpatrick 
137*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonFork;
138*be691f3bSpatrick   m_stop_info.details.fork.child_pid = child_pid;
139*be691f3bSpatrick   m_stop_info.details.fork.child_tid = child_tid;
140*be691f3bSpatrick }
141*be691f3bSpatrick 
142*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143*be691f3bSpatrick                                             lldb::tid_t child_tid) {
144*be691f3bSpatrick   SetStopped();
145*be691f3bSpatrick 
146*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonVFork;
147*be691f3bSpatrick   m_stop_info.details.fork.child_pid = child_pid;
148*be691f3bSpatrick   m_stop_info.details.fork.child_tid = child_tid;
149*be691f3bSpatrick }
150*be691f3bSpatrick 
151*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedByVForkDone() {
152*be691f3bSpatrick   SetStopped();
153*be691f3bSpatrick 
154*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonVForkDone;
155*be691f3bSpatrick }
156*be691f3bSpatrick 
157*be691f3bSpatrick void NativeThreadFreeBSD::SetStoppedWithNoReason() {
158*be691f3bSpatrick   SetStopped();
159*be691f3bSpatrick 
160*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonNone;
161*be691f3bSpatrick   m_stop_info.details.signal.signo = 0;
162*be691f3bSpatrick }
163*be691f3bSpatrick 
164*be691f3bSpatrick void NativeThreadFreeBSD::SetStopped() {
165*be691f3bSpatrick   const StateType new_state = StateType::eStateStopped;
166*be691f3bSpatrick   m_state = new_state;
167*be691f3bSpatrick   m_stop_description.clear();
168*be691f3bSpatrick }
169*be691f3bSpatrick 
170*be691f3bSpatrick void NativeThreadFreeBSD::SetRunning() {
171*be691f3bSpatrick   m_state = StateType::eStateRunning;
172*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonNone;
173*be691f3bSpatrick }
174*be691f3bSpatrick 
175*be691f3bSpatrick void NativeThreadFreeBSD::SetStepping() {
176*be691f3bSpatrick   m_state = StateType::eStateStepping;
177*be691f3bSpatrick   m_stop_info.reason = StopReason::eStopReasonNone;
178*be691f3bSpatrick }
179*be691f3bSpatrick 
180*be691f3bSpatrick std::string NativeThreadFreeBSD::GetName() {
181*be691f3bSpatrick   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
182*be691f3bSpatrick 
183*be691f3bSpatrick   std::vector<struct kinfo_proc> kp;
184*be691f3bSpatrick   int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
185*be691f3bSpatrick                 static_cast<int>(GetProcess().GetID())};
186*be691f3bSpatrick 
187*be691f3bSpatrick   while (1) {
188*be691f3bSpatrick     size_t len = kp.size() * sizeof(struct kinfo_proc);
189*be691f3bSpatrick     void *ptr = len == 0 ? nullptr : kp.data();
190*be691f3bSpatrick     int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0);
191*be691f3bSpatrick     if (ptr == nullptr || (error != 0 && errno == ENOMEM)) {
192*be691f3bSpatrick       kp.resize(len / sizeof(struct kinfo_proc));
193*be691f3bSpatrick       continue;
194*be691f3bSpatrick     }
195*be691f3bSpatrick     if (error != 0) {
196*be691f3bSpatrick       len = 0;
197*be691f3bSpatrick       LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}",
198*be691f3bSpatrick                GetID(), m_state, strerror(errno));
199*be691f3bSpatrick     }
200*be691f3bSpatrick     kp.resize(len / sizeof(struct kinfo_proc));
201*be691f3bSpatrick     break;
202*be691f3bSpatrick   }
203*be691f3bSpatrick 
204*be691f3bSpatrick   for (auto &procinfo : kp) {
205*be691f3bSpatrick     if (procinfo.ki_tid == static_cast<lwpid_t>(GetID()))
206*be691f3bSpatrick       return procinfo.ki_tdname;
207*be691f3bSpatrick   }
208*be691f3bSpatrick 
209*be691f3bSpatrick   return "";
210*be691f3bSpatrick }
211*be691f3bSpatrick 
212*be691f3bSpatrick lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }
213*be691f3bSpatrick 
214*be691f3bSpatrick bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info,
215*be691f3bSpatrick                                         std::string &description) {
216*be691f3bSpatrick   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
217*be691f3bSpatrick   description.clear();
218*be691f3bSpatrick 
219*be691f3bSpatrick   switch (m_state) {
220*be691f3bSpatrick   case eStateStopped:
221*be691f3bSpatrick   case eStateCrashed:
222*be691f3bSpatrick   case eStateExited:
223*be691f3bSpatrick   case eStateSuspended:
224*be691f3bSpatrick   case eStateUnloaded:
225*be691f3bSpatrick     stop_info = m_stop_info;
226*be691f3bSpatrick     description = m_stop_description;
227*be691f3bSpatrick 
228*be691f3bSpatrick     return true;
229*be691f3bSpatrick 
230*be691f3bSpatrick   case eStateInvalid:
231*be691f3bSpatrick   case eStateConnected:
232*be691f3bSpatrick   case eStateAttaching:
233*be691f3bSpatrick   case eStateLaunching:
234*be691f3bSpatrick   case eStateRunning:
235*be691f3bSpatrick   case eStateStepping:
236*be691f3bSpatrick   case eStateDetached:
237*be691f3bSpatrick     LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
238*be691f3bSpatrick              StateAsCString(m_state));
239*be691f3bSpatrick     return false;
240*be691f3bSpatrick   }
241*be691f3bSpatrick   llvm_unreachable("unhandled StateType!");
242*be691f3bSpatrick }
243*be691f3bSpatrick 
244*be691f3bSpatrick NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {
245*be691f3bSpatrick   assert(m_reg_context_up);
246*be691f3bSpatrick   return *m_reg_context_up;
247*be691f3bSpatrick }
248*be691f3bSpatrick 
249*be691f3bSpatrick Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
250*be691f3bSpatrick                                           uint32_t watch_flags, bool hardware) {
251*be691f3bSpatrick   assert(m_state == eStateStopped);
252*be691f3bSpatrick   if (!hardware)
253*be691f3bSpatrick     return Status("not implemented");
254*be691f3bSpatrick   Status error = RemoveWatchpoint(addr);
255*be691f3bSpatrick   if (error.Fail())
256*be691f3bSpatrick     return error;
257*be691f3bSpatrick   uint32_t wp_index =
258*be691f3bSpatrick       GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
259*be691f3bSpatrick   if (wp_index == LLDB_INVALID_INDEX32)
260*be691f3bSpatrick     return Status("Setting hardware watchpoint failed.");
261*be691f3bSpatrick   m_watchpoint_index_map.insert({addr, wp_index});
262*be691f3bSpatrick   return Status();
263*be691f3bSpatrick }
264*be691f3bSpatrick 
265*be691f3bSpatrick Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {
266*be691f3bSpatrick   auto wp = m_watchpoint_index_map.find(addr);
267*be691f3bSpatrick   if (wp == m_watchpoint_index_map.end())
268*be691f3bSpatrick     return Status();
269*be691f3bSpatrick   uint32_t wp_index = wp->second;
270*be691f3bSpatrick   m_watchpoint_index_map.erase(wp);
271*be691f3bSpatrick   if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
272*be691f3bSpatrick     return Status();
273*be691f3bSpatrick   return Status("Clearing hardware watchpoint failed.");
274*be691f3bSpatrick }
275*be691f3bSpatrick 
276*be691f3bSpatrick Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,
277*be691f3bSpatrick                                                   size_t size) {
278*be691f3bSpatrick   assert(m_state == eStateStopped);
279*be691f3bSpatrick   Status error = RemoveHardwareBreakpoint(addr);
280*be691f3bSpatrick   if (error.Fail())
281*be691f3bSpatrick     return error;
282*be691f3bSpatrick 
283*be691f3bSpatrick   uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
284*be691f3bSpatrick 
285*be691f3bSpatrick   if (bp_index == LLDB_INVALID_INDEX32)
286*be691f3bSpatrick     return Status("Setting hardware breakpoint failed.");
287*be691f3bSpatrick 
288*be691f3bSpatrick   m_hw_break_index_map.insert({addr, bp_index});
289*be691f3bSpatrick   return Status();
290*be691f3bSpatrick }
291*be691f3bSpatrick 
292*be691f3bSpatrick Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
293*be691f3bSpatrick   auto bp = m_hw_break_index_map.find(addr);
294*be691f3bSpatrick   if (bp == m_hw_break_index_map.end())
295*be691f3bSpatrick     return Status();
296*be691f3bSpatrick 
297*be691f3bSpatrick   uint32_t bp_index = bp->second;
298*be691f3bSpatrick   if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
299*be691f3bSpatrick     m_hw_break_index_map.erase(bp);
300*be691f3bSpatrick     return Status();
301*be691f3bSpatrick   }
302*be691f3bSpatrick 
303*be691f3bSpatrick   return Status("Clearing hardware breakpoint failed.");
304*be691f3bSpatrick }
305*be691f3bSpatrick 
306*be691f3bSpatrick llvm::Error
307*be691f3bSpatrick NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
308*be691f3bSpatrick   llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
309*be691f3bSpatrick       source.GetRegisterContext());
310*be691f3bSpatrick   if (!s) {
311*be691f3bSpatrick     m_watchpoint_index_map = source.m_watchpoint_index_map;
312*be691f3bSpatrick     m_hw_break_index_map = source.m_hw_break_index_map;
313*be691f3bSpatrick   }
314*be691f3bSpatrick   return s;
315*be691f3bSpatrick }
316