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; 84*81ad6265SDimitry 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: 93d409305fSDimitry Andric const auto reason = GetCrashReason(*info); 94d409305fSDimitry Andric m_stop_description = GetCrashReasonString(reason, *info); 95d409305fSDimitry Andric break; 96d409305fSDimitry Andric } 97d409305fSDimitry Andric } 98d409305fSDimitry Andric } 99d409305fSDimitry Andric 100d409305fSDimitry Andric void NativeThreadFreeBSD::SetStoppedByBreakpoint() { 101d409305fSDimitry Andric SetStopped(); 102d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 104d409305fSDimitry Andric } 105d409305fSDimitry Andric 106d409305fSDimitry Andric void NativeThreadFreeBSD::SetStoppedByTrace() { 107d409305fSDimitry Andric SetStopped(); 108d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonTrace; 109*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 110d409305fSDimitry Andric } 111d409305fSDimitry Andric 112d409305fSDimitry Andric void NativeThreadFreeBSD::SetStoppedByExec() { 113d409305fSDimitry Andric SetStopped(); 114d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonExec; 115*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 116d409305fSDimitry Andric } 117d409305fSDimitry Andric 118d409305fSDimitry Andric void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 119d409305fSDimitry Andric lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 120d409305fSDimitry Andric 121d409305fSDimitry Andric std::ostringstream ostr; 122d409305fSDimitry Andric ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 123d409305fSDimitry Andric ostr << wp_index; 124d409305fSDimitry Andric 125d409305fSDimitry Andric ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 126d409305fSDimitry Andric 127d409305fSDimitry Andric SetStopped(); 128d409305fSDimitry Andric m_stop_description = ostr.str(); 129d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonWatchpoint; 130*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 131d409305fSDimitry Andric } 132d409305fSDimitry Andric 133fe6060f1SDimitry Andric void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid, 134fe6060f1SDimitry Andric lldb::tid_t child_tid) { 135fe6060f1SDimitry Andric SetStopped(); 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonFork; 138*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 139fe6060f1SDimitry Andric m_stop_info.details.fork.child_pid = child_pid; 140fe6060f1SDimitry Andric m_stop_info.details.fork.child_tid = child_tid; 141fe6060f1SDimitry Andric } 142fe6060f1SDimitry Andric 143fe6060f1SDimitry Andric void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid, 144fe6060f1SDimitry Andric lldb::tid_t child_tid) { 145fe6060f1SDimitry Andric SetStopped(); 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVFork; 148*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 149fe6060f1SDimitry Andric m_stop_info.details.fork.child_pid = child_pid; 150fe6060f1SDimitry Andric m_stop_info.details.fork.child_tid = child_tid; 151fe6060f1SDimitry Andric } 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric void NativeThreadFreeBSD::SetStoppedByVForkDone() { 154fe6060f1SDimitry Andric SetStopped(); 155fe6060f1SDimitry Andric 156fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVForkDone; 157*81ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 158fe6060f1SDimitry Andric } 159fe6060f1SDimitry Andric 160d409305fSDimitry Andric void NativeThreadFreeBSD::SetStoppedWithNoReason() { 161d409305fSDimitry Andric SetStopped(); 162d409305fSDimitry Andric 163d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 164*81ad6265SDimitry Andric m_stop_info.signo = 0; 165d409305fSDimitry Andric } 166d409305fSDimitry Andric 167d409305fSDimitry Andric void NativeThreadFreeBSD::SetStopped() { 168d409305fSDimitry Andric const StateType new_state = StateType::eStateStopped; 169d409305fSDimitry Andric m_state = new_state; 170d409305fSDimitry Andric m_stop_description.clear(); 171d409305fSDimitry Andric } 172d409305fSDimitry Andric 173d409305fSDimitry Andric void NativeThreadFreeBSD::SetRunning() { 174d409305fSDimitry Andric m_state = StateType::eStateRunning; 175d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 176d409305fSDimitry Andric } 177d409305fSDimitry Andric 178d409305fSDimitry Andric void NativeThreadFreeBSD::SetStepping() { 179d409305fSDimitry Andric m_state = StateType::eStateStepping; 180d409305fSDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 181d409305fSDimitry Andric } 182d409305fSDimitry Andric 183d409305fSDimitry Andric std::string NativeThreadFreeBSD::GetName() { 18404eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread); 185d409305fSDimitry Andric 186d409305fSDimitry Andric std::vector<struct kinfo_proc> kp; 187d409305fSDimitry Andric int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, 188d409305fSDimitry Andric static_cast<int>(GetProcess().GetID())}; 189d409305fSDimitry Andric 190d409305fSDimitry Andric while (1) { 191d409305fSDimitry Andric size_t len = kp.size() * sizeof(struct kinfo_proc); 192d409305fSDimitry Andric void *ptr = len == 0 ? nullptr : kp.data(); 193d409305fSDimitry Andric int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); 194d409305fSDimitry Andric if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { 195d409305fSDimitry Andric kp.resize(len / sizeof(struct kinfo_proc)); 196d409305fSDimitry Andric continue; 197d409305fSDimitry Andric } 198d409305fSDimitry Andric if (error != 0) { 199d409305fSDimitry Andric len = 0; 200d409305fSDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", 201d409305fSDimitry Andric GetID(), m_state, strerror(errno)); 202d409305fSDimitry Andric } 203d409305fSDimitry Andric kp.resize(len / sizeof(struct kinfo_proc)); 204d409305fSDimitry Andric break; 205d409305fSDimitry Andric } 206d409305fSDimitry Andric 207d409305fSDimitry Andric for (auto &procinfo : kp) { 208d409305fSDimitry Andric if (procinfo.ki_tid == static_cast<lwpid_t>(GetID())) 209d409305fSDimitry Andric return procinfo.ki_tdname; 210d409305fSDimitry Andric } 211d409305fSDimitry Andric 212d409305fSDimitry Andric return ""; 213d409305fSDimitry Andric } 214d409305fSDimitry Andric 215d409305fSDimitry Andric lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } 216d409305fSDimitry Andric 217d409305fSDimitry Andric bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, 218d409305fSDimitry Andric std::string &description) { 21904eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread); 220d409305fSDimitry Andric description.clear(); 221d409305fSDimitry Andric 222d409305fSDimitry Andric switch (m_state) { 223d409305fSDimitry Andric case eStateStopped: 224d409305fSDimitry Andric case eStateCrashed: 225d409305fSDimitry Andric case eStateExited: 226d409305fSDimitry Andric case eStateSuspended: 227d409305fSDimitry Andric case eStateUnloaded: 228d409305fSDimitry Andric stop_info = m_stop_info; 229d409305fSDimitry Andric description = m_stop_description; 230d409305fSDimitry Andric 231d409305fSDimitry Andric return true; 232d409305fSDimitry Andric 233d409305fSDimitry Andric case eStateInvalid: 234d409305fSDimitry Andric case eStateConnected: 235d409305fSDimitry Andric case eStateAttaching: 236d409305fSDimitry Andric case eStateLaunching: 237d409305fSDimitry Andric case eStateRunning: 238d409305fSDimitry Andric case eStateStepping: 239d409305fSDimitry Andric case eStateDetached: 240d409305fSDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 241d409305fSDimitry Andric StateAsCString(m_state)); 242d409305fSDimitry Andric return false; 243d409305fSDimitry Andric } 244d409305fSDimitry Andric llvm_unreachable("unhandled StateType!"); 245d409305fSDimitry Andric } 246d409305fSDimitry Andric 247d409305fSDimitry Andric NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() { 248d409305fSDimitry Andric assert(m_reg_context_up); 249d409305fSDimitry Andric return *m_reg_context_up; 250d409305fSDimitry Andric } 251d409305fSDimitry Andric 252d409305fSDimitry Andric Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 253d409305fSDimitry Andric uint32_t watch_flags, bool hardware) { 254d409305fSDimitry Andric assert(m_state == eStateStopped); 255d409305fSDimitry Andric if (!hardware) 256d409305fSDimitry Andric return Status("not implemented"); 257d409305fSDimitry Andric Status error = RemoveWatchpoint(addr); 258d409305fSDimitry Andric if (error.Fail()) 259d409305fSDimitry Andric return error; 260d409305fSDimitry Andric uint32_t wp_index = 261d409305fSDimitry Andric GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 262d409305fSDimitry Andric if (wp_index == LLDB_INVALID_INDEX32) 263d409305fSDimitry Andric return Status("Setting hardware watchpoint failed."); 264d409305fSDimitry Andric m_watchpoint_index_map.insert({addr, wp_index}); 265d409305fSDimitry Andric return Status(); 266d409305fSDimitry Andric } 267d409305fSDimitry Andric 268d409305fSDimitry Andric Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) { 269d409305fSDimitry Andric auto wp = m_watchpoint_index_map.find(addr); 270d409305fSDimitry Andric if (wp == m_watchpoint_index_map.end()) 271d409305fSDimitry Andric return Status(); 272d409305fSDimitry Andric uint32_t wp_index = wp->second; 273d409305fSDimitry Andric m_watchpoint_index_map.erase(wp); 274d409305fSDimitry Andric if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 275d409305fSDimitry Andric return Status(); 276d409305fSDimitry Andric return Status("Clearing hardware watchpoint failed."); 277d409305fSDimitry Andric } 278d409305fSDimitry Andric 279d409305fSDimitry Andric Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr, 280d409305fSDimitry Andric size_t size) { 281d409305fSDimitry Andric assert(m_state == eStateStopped); 282d409305fSDimitry Andric Status error = RemoveHardwareBreakpoint(addr); 283d409305fSDimitry Andric if (error.Fail()) 284d409305fSDimitry Andric return error; 285d409305fSDimitry Andric 286d409305fSDimitry Andric uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 287d409305fSDimitry Andric 288d409305fSDimitry Andric if (bp_index == LLDB_INVALID_INDEX32) 289d409305fSDimitry Andric return Status("Setting hardware breakpoint failed."); 290d409305fSDimitry Andric 291d409305fSDimitry Andric m_hw_break_index_map.insert({addr, bp_index}); 292d409305fSDimitry Andric return Status(); 293d409305fSDimitry Andric } 294d409305fSDimitry Andric 295d409305fSDimitry Andric Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 296d409305fSDimitry Andric auto bp = m_hw_break_index_map.find(addr); 297d409305fSDimitry Andric if (bp == m_hw_break_index_map.end()) 298d409305fSDimitry Andric return Status(); 299d409305fSDimitry Andric 300d409305fSDimitry Andric uint32_t bp_index = bp->second; 301d409305fSDimitry Andric if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 302d409305fSDimitry Andric m_hw_break_index_map.erase(bp); 303d409305fSDimitry Andric return Status(); 304d409305fSDimitry Andric } 305d409305fSDimitry Andric 306d409305fSDimitry Andric return Status("Clearing hardware breakpoint failed."); 307d409305fSDimitry Andric } 308d409305fSDimitry Andric 309d409305fSDimitry Andric llvm::Error 310d409305fSDimitry Andric NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { 311d409305fSDimitry Andric llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 312d409305fSDimitry Andric source.GetRegisterContext()); 313d409305fSDimitry Andric if (!s) { 314d409305fSDimitry Andric m_watchpoint_index_map = source.m_watchpoint_index_map; 315d409305fSDimitry Andric m_hw_break_index_map = source.m_hw_break_index_map; 316d409305fSDimitry Andric } 317d409305fSDimitry Andric return s; 318d409305fSDimitry Andric } 31904eeddc0SDimitry Andric 32004eeddc0SDimitry Andric llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> 32104eeddc0SDimitry Andric NativeThreadFreeBSD::GetSiginfo() const { 32204eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process); 32304eeddc0SDimitry Andric 32404eeddc0SDimitry Andric struct ptrace_lwpinfo info; 32504eeddc0SDimitry Andric const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper( 32604eeddc0SDimitry Andric PT_LWPINFO, GetID(), &info, sizeof(info)); 32704eeddc0SDimitry Andric if (siginfo_err.Fail()) { 32804eeddc0SDimitry Andric LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); 32904eeddc0SDimitry Andric return siginfo_err.ToError(); 33004eeddc0SDimitry Andric } 33104eeddc0SDimitry Andric 33204eeddc0SDimitry Andric if (info.pl_event != PL_EVENT_SIGNAL) 33304eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 33404eeddc0SDimitry Andric "Thread not signaled"); 33504eeddc0SDimitry Andric if (!(info.pl_flags & PL_FLAG_SI)) 33604eeddc0SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 33704eeddc0SDimitry Andric "No siginfo for thread"); 33804eeddc0SDimitry Andric 33904eeddc0SDimitry Andric return llvm::MemoryBuffer::getMemBufferCopy( 34004eeddc0SDimitry Andric llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo), 34104eeddc0SDimitry Andric sizeof(info.pl_siginfo))); 34204eeddc0SDimitry Andric } 343