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