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