15ffd83dbSDimitry Andric //===-- NativeThreadNetBSD.cpp --------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "NativeThreadNetBSD.h" 100b57cec5SDimitry Andric #include "NativeRegisterContextNetBSD.h" 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "NativeProcessNetBSD.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h" 150b57cec5SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 160b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h" 170b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h" 180b57cec5SDimitry Andric #include "lldb/Utility/State.h" 19480093f4SDimitry Andric #include "llvm/Support/Errno.h" 20480093f4SDimitry Andric 21480093f4SDimitry Andric // clang-format off 22480093f4SDimitry Andric #include <sys/types.h> 23480093f4SDimitry Andric #include <sys/ptrace.h> 24480093f4SDimitry Andric // clang-format on 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #include <sstream> 270b57cec5SDimitry Andric 28480093f4SDimitry Andric // clang-format off 29480093f4SDimitry Andric #include <sys/types.h> 30480093f4SDimitry Andric #include <sys/sysctl.h> 31480093f4SDimitry Andric // clang-format on 32480093f4SDimitry Andric 330b57cec5SDimitry Andric using namespace lldb; 340b57cec5SDimitry Andric using namespace lldb_private; 350b57cec5SDimitry Andric using namespace lldb_private::process_netbsd; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, 380b57cec5SDimitry Andric lldb::tid_t tid) 390b57cec5SDimitry Andric : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 400b57cec5SDimitry Andric m_stop_info(), m_reg_context_up( 410b57cec5SDimitry Andric NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) 420b57cec5SDimitry Andric ), m_stop_description() {} 430b57cec5SDimitry Andric 44480093f4SDimitry Andric Status NativeThreadNetBSD::Resume() { 45480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 46480093f4SDimitry Andric nullptr, GetID()); 47480093f4SDimitry Andric if (!ret.Success()) 48480093f4SDimitry Andric return ret; 49480093f4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(), 50480093f4SDimitry Andric nullptr, GetID()); 51480093f4SDimitry Andric if (ret.Success()) 52480093f4SDimitry Andric SetRunning(); 53480093f4SDimitry Andric return ret; 54480093f4SDimitry Andric } 55480093f4SDimitry Andric 56480093f4SDimitry Andric Status NativeThreadNetBSD::SingleStep() { 57480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 58480093f4SDimitry Andric nullptr, GetID()); 59480093f4SDimitry Andric if (!ret.Success()) 60480093f4SDimitry Andric return ret; 61480093f4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(), 62480093f4SDimitry Andric nullptr, GetID()); 63480093f4SDimitry Andric if (ret.Success()) 64480093f4SDimitry Andric SetStepping(); 65480093f4SDimitry Andric return ret; 66480093f4SDimitry Andric } 67480093f4SDimitry Andric 68480093f4SDimitry Andric Status NativeThreadNetBSD::Suspend() { 69480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(), 70480093f4SDimitry Andric nullptr, GetID()); 71480093f4SDimitry Andric if (ret.Success()) 72480093f4SDimitry Andric SetStopped(); 73480093f4SDimitry Andric return ret; 74480093f4SDimitry Andric } 75480093f4SDimitry Andric 760b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, 770b57cec5SDimitry Andric const siginfo_t *info) { 7804eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread); 790b57cec5SDimitry Andric LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric SetStopped(); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonSignal; 8481ad6265SDimitry Andric m_stop_info.signo = signo; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric m_stop_description.clear(); 870b57cec5SDimitry Andric if (info) { 880b57cec5SDimitry Andric switch (signo) { 890b57cec5SDimitry Andric case SIGSEGV: 900b57cec5SDimitry Andric case SIGBUS: 910b57cec5SDimitry Andric case SIGFPE: 920b57cec5SDimitry Andric case SIGILL: 9306c3fb27SDimitry Andric m_stop_description = GetCrashReasonString(*info); 940b57cec5SDimitry Andric break; 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() { 1000b57cec5SDimitry Andric SetStopped(); 1010b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonBreakpoint; 10281ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() { 1060b57cec5SDimitry Andric SetStopped(); 1070b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonTrace; 10881ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() { 1120b57cec5SDimitry Andric SetStopped(); 1130b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonExec; 11481ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 1180b57cec5SDimitry Andric lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric std::ostringstream ostr; 1210b57cec5SDimitry Andric ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 1220b57cec5SDimitry Andric ostr << wp_index; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 1250b57cec5SDimitry Andric 126e8d8bef9SDimitry Andric SetStopped(); 1270b57cec5SDimitry Andric m_stop_description = ostr.str(); 1280b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonWatchpoint; 12981ad6265SDimitry Andric m_stop_info.signo = SIGTRAP; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 132fe6060f1SDimitry Andric void NativeThreadNetBSD::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 NativeThreadNetBSD::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 NativeThreadNetBSD::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 159480093f4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() { 160480093f4SDimitry Andric SetStopped(); 161480093f4SDimitry Andric 162480093f4SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 16381ad6265SDimitry Andric m_stop_info.signo = 0; 164480093f4SDimitry Andric } 165480093f4SDimitry Andric 1660b57cec5SDimitry Andric void NativeThreadNetBSD::SetStopped() { 1670b57cec5SDimitry Andric const StateType new_state = StateType::eStateStopped; 1680b57cec5SDimitry Andric m_state = new_state; 1690b57cec5SDimitry Andric m_stop_description.clear(); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric void NativeThreadNetBSD::SetRunning() { 1730b57cec5SDimitry Andric m_state = StateType::eStateRunning; 1740b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric void NativeThreadNetBSD::SetStepping() { 1780b57cec5SDimitry Andric m_state = StateType::eStateStepping; 1790b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 182480093f4SDimitry Andric std::string NativeThreadNetBSD::GetName() { 183480093f4SDimitry Andric #ifdef PT_LWPSTATUS 184480093f4SDimitry Andric struct ptrace_lwpstatus info = {}; 185480093f4SDimitry Andric info.pl_lwpid = m_tid; 186480093f4SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper( 187480093f4SDimitry Andric PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); 188480093f4SDimitry Andric if (error.Fail()) { 189480093f4SDimitry Andric return ""; 190480093f4SDimitry Andric } 191480093f4SDimitry Andric return info.pl_name; 192480093f4SDimitry Andric #else 193480093f4SDimitry Andric std::vector<struct kinfo_lwp> infos; 194*0fca6ea1SDimitry Andric Log *log = GetLog(POSIXLog::Thread); 195*0fca6ea1SDimitry Andric 196480093f4SDimitry Andric int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 197480093f4SDimitry Andric sizeof(struct kinfo_lwp), 0}; 198480093f4SDimitry Andric size_t size; 199480093f4SDimitry Andric 200480093f4SDimitry Andric if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 201480093f4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 202480093f4SDimitry Andric llvm::sys::StrError()); 203480093f4SDimitry Andric return ""; 204480093f4SDimitry Andric } 205480093f4SDimitry Andric 206480093f4SDimitry Andric mib[4] = size / sizeof(size_t); 207480093f4SDimitry Andric infos.resize(size / sizeof(struct kinfo_lwp)); 208480093f4SDimitry Andric 209480093f4SDimitry Andric if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 210480093f4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 211480093f4SDimitry Andric return ""; 212480093f4SDimitry Andric } 213480093f4SDimitry Andric 214480093f4SDimitry Andric size_t nlwps = size / sizeof(struct kinfo_lwp); 215480093f4SDimitry Andric for (size_t i = 0; i < nlwps; i++) { 216480093f4SDimitry Andric if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 217480093f4SDimitry Andric return infos[i].l_name; 218480093f4SDimitry Andric } 219480093f4SDimitry Andric } 220480093f4SDimitry Andric 221480093f4SDimitry Andric LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 222480093f4SDimitry Andric return ""; 223480093f4SDimitry Andric #endif 224480093f4SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 2290b57cec5SDimitry Andric std::string &description) { 23004eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread); 2310b57cec5SDimitry Andric description.clear(); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric switch (m_state) { 2340b57cec5SDimitry Andric case eStateStopped: 2350b57cec5SDimitry Andric case eStateCrashed: 2360b57cec5SDimitry Andric case eStateExited: 2370b57cec5SDimitry Andric case eStateSuspended: 2380b57cec5SDimitry Andric case eStateUnloaded: 2390b57cec5SDimitry Andric stop_info = m_stop_info; 2400b57cec5SDimitry Andric description = m_stop_description; 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric return true; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric case eStateInvalid: 2450b57cec5SDimitry Andric case eStateConnected: 2460b57cec5SDimitry Andric case eStateAttaching: 2470b57cec5SDimitry Andric case eStateLaunching: 2480b57cec5SDimitry Andric case eStateRunning: 2490b57cec5SDimitry Andric case eStateStepping: 2500b57cec5SDimitry Andric case eStateDetached: 2510b57cec5SDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 2520b57cec5SDimitry Andric StateAsCString(m_state)); 2530b57cec5SDimitry Andric return false; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric llvm_unreachable("unhandled StateType!"); 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 258480093f4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 2590b57cec5SDimitry Andric assert(m_reg_context_up); 2600b57cec5SDimitry Andric return *m_reg_context_up; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 2640b57cec5SDimitry Andric uint32_t watch_flags, bool hardware) { 265e8d8bef9SDimitry Andric assert(m_state == eStateStopped); 2660b57cec5SDimitry Andric if (!hardware) 2670b57cec5SDimitry Andric return Status("not implemented"); 2680b57cec5SDimitry Andric Status error = RemoveWatchpoint(addr); 2690b57cec5SDimitry Andric if (error.Fail()) 2700b57cec5SDimitry Andric return error; 271e8d8bef9SDimitry Andric uint32_t wp_index = 272e8d8bef9SDimitry Andric GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 2730b57cec5SDimitry Andric if (wp_index == LLDB_INVALID_INDEX32) 2740b57cec5SDimitry Andric return Status("Setting hardware watchpoint failed."); 2750b57cec5SDimitry Andric m_watchpoint_index_map.insert({addr, wp_index}); 2760b57cec5SDimitry Andric return Status(); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 2800b57cec5SDimitry Andric auto wp = m_watchpoint_index_map.find(addr); 2810b57cec5SDimitry Andric if (wp == m_watchpoint_index_map.end()) 2820b57cec5SDimitry Andric return Status(); 2830b57cec5SDimitry Andric uint32_t wp_index = wp->second; 2840b57cec5SDimitry Andric m_watchpoint_index_map.erase(wp); 2850b57cec5SDimitry Andric if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 2860b57cec5SDimitry Andric return Status(); 2870b57cec5SDimitry Andric return Status("Clearing hardware watchpoint failed."); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 2910b57cec5SDimitry Andric size_t size) { 292e8d8bef9SDimitry Andric assert(m_state == eStateStopped); 2930b57cec5SDimitry Andric Status error = RemoveHardwareBreakpoint(addr); 2940b57cec5SDimitry Andric if (error.Fail()) 2950b57cec5SDimitry Andric return error; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric if (bp_index == LLDB_INVALID_INDEX32) 3000b57cec5SDimitry Andric return Status("Setting hardware breakpoint failed."); 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric m_hw_break_index_map.insert({addr, bp_index}); 3030b57cec5SDimitry Andric return Status(); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 3070b57cec5SDimitry Andric auto bp = m_hw_break_index_map.find(addr); 3080b57cec5SDimitry Andric if (bp == m_hw_break_index_map.end()) 3090b57cec5SDimitry Andric return Status(); 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric uint32_t bp_index = bp->second; 3120b57cec5SDimitry Andric if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 3130b57cec5SDimitry Andric m_hw_break_index_map.erase(bp); 3140b57cec5SDimitry Andric return Status(); 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric return Status("Clearing hardware breakpoint failed."); 3180b57cec5SDimitry Andric } 319480093f4SDimitry Andric 320e8d8bef9SDimitry Andric llvm::Error 321e8d8bef9SDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 322e8d8bef9SDimitry Andric llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 323480093f4SDimitry Andric source.GetRegisterContext()); 324e8d8bef9SDimitry Andric if (!s) { 325480093f4SDimitry Andric m_watchpoint_index_map = source.m_watchpoint_index_map; 326480093f4SDimitry Andric m_hw_break_index_map = source.m_hw_break_index_map; 327480093f4SDimitry Andric } 328480093f4SDimitry Andric return s; 329480093f4SDimitry Andric } 330