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