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