180814287SRaphael Isemann //===-- NativeThreadNetBSD.cpp --------------------------------------------===// 21a3d19ddSKamil Rytarowski // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61a3d19ddSKamil Rytarowski // 71a3d19ddSKamil Rytarowski //===----------------------------------------------------------------------===// 81a3d19ddSKamil Rytarowski 91a3d19ddSKamil Rytarowski #include "NativeThreadNetBSD.h" 101a3d19ddSKamil Rytarowski #include "NativeRegisterContextNetBSD.h" 111a3d19ddSKamil Rytarowski 121a3d19ddSKamil Rytarowski #include "NativeProcessNetBSD.h" 131a3d19ddSKamil Rytarowski 14f07a9995SKamil Rytarowski #include "Plugins/Process/POSIX/CrashReason.h" 15f07a9995SKamil Rytarowski #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 1636e23ecaSKamil Rytarowski #include "lldb/Utility/LLDBAssert.h" 17d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h" 18d821c997SPavel Labath #include "lldb/Utility/State.h" 1923a766dcSMichał Górny #include "llvm/Support/Errno.h" 2036e23ecaSKamil Rytarowski 218d9400b6SMichał Górny // clang-format off 228d9400b6SMichał Górny #include <sys/types.h> 238d9400b6SMichał Górny #include <sys/ptrace.h> 248d9400b6SMichał Górny // clang-format on 258d9400b6SMichał Górny 2636e23ecaSKamil Rytarowski #include <sstream> 27f07a9995SKamil Rytarowski 2823a766dcSMichał Górny // clang-format off 2923a766dcSMichał Górny #include <sys/types.h> 3023a766dcSMichał Górny #include <sys/sysctl.h> 3123a766dcSMichał Górny // clang-format on 3223a766dcSMichał Górny 331a3d19ddSKamil Rytarowski using namespace lldb; 341a3d19ddSKamil Rytarowski using namespace lldb_private; 351a3d19ddSKamil Rytarowski using namespace lldb_private::process_netbsd; 361a3d19ddSKamil Rytarowski 3782abefa4SPavel Labath NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, 381a3d19ddSKamil Rytarowski lldb::tid_t tid) 39f07a9995SKamil Rytarowski : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 40d37349f3SPavel Labath m_stop_info(), m_reg_context_up( 41d37349f3SPavel Labath NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) 42d37349f3SPavel Labath ), m_stop_description() {} 43f07a9995SKamil Rytarowski 448d9400b6SMichał Górny Status NativeThreadNetBSD::Resume() { 458d9400b6SMichał Górny Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 468d9400b6SMichał Górny nullptr, GetID()); 478d9400b6SMichał Górny if (!ret.Success()) 488d9400b6SMichał Górny return ret; 498d9400b6SMichał Górny ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(), 508d9400b6SMichał Górny nullptr, GetID()); 518d9400b6SMichał Górny if (ret.Success()) 528d9400b6SMichał Górny SetRunning(); 538d9400b6SMichał Górny return ret; 548d9400b6SMichał Górny } 558d9400b6SMichał Górny 568d9400b6SMichał Górny Status NativeThreadNetBSD::SingleStep() { 578d9400b6SMichał Górny Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 588d9400b6SMichał Górny nullptr, GetID()); 598d9400b6SMichał Górny if (!ret.Success()) 608d9400b6SMichał Górny return ret; 618d9400b6SMichał Górny ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(), 628d9400b6SMichał Górny nullptr, GetID()); 638d9400b6SMichał Górny if (ret.Success()) 648d9400b6SMichał Górny SetStepping(); 658d9400b6SMichał Górny return ret; 668d9400b6SMichał Górny } 678d9400b6SMichał Górny 688d9400b6SMichał Górny Status NativeThreadNetBSD::Suspend() { 698d9400b6SMichał Górny Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(), 708d9400b6SMichał Górny nullptr, GetID()); 718d9400b6SMichał Górny if (ret.Success()) 728d9400b6SMichał Górny SetStopped(); 738d9400b6SMichał Górny return ret; 748d9400b6SMichał Górny } 758d9400b6SMichał Górny 76f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, 77f07a9995SKamil Rytarowski const siginfo_t *info) { 78*4fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Thread); 79f07a9995SKamil Rytarowski LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); 80f07a9995SKamil Rytarowski 81f07a9995SKamil Rytarowski SetStopped(); 82f07a9995SKamil Rytarowski 83f07a9995SKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonSignal; 84f07a9995SKamil Rytarowski m_stop_info.details.signal.signo = signo; 85f07a9995SKamil Rytarowski 86f07a9995SKamil Rytarowski m_stop_description.clear(); 87f07a9995SKamil Rytarowski if (info) { 88f07a9995SKamil Rytarowski switch (signo) { 89f07a9995SKamil Rytarowski case SIGSEGV: 90f07a9995SKamil Rytarowski case SIGBUS: 91f07a9995SKamil Rytarowski case SIGFPE: 92f07a9995SKamil Rytarowski case SIGILL: 93f07a9995SKamil Rytarowski const auto reason = GetCrashReason(*info); 94f07a9995SKamil Rytarowski m_stop_description = GetCrashReasonString(reason, *info); 95f07a9995SKamil Rytarowski break; 96f07a9995SKamil Rytarowski } 97f07a9995SKamil Rytarowski } 98f07a9995SKamil Rytarowski } 99f07a9995SKamil Rytarowski 100f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStoppedByBreakpoint() { 101f07a9995SKamil Rytarowski SetStopped(); 102f07a9995SKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103f07a9995SKamil Rytarowski m_stop_info.details.signal.signo = SIGTRAP; 104f07a9995SKamil Rytarowski } 105f07a9995SKamil Rytarowski 1063eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByTrace() { 1073eef2b5eSKamil Rytarowski SetStopped(); 1083eef2b5eSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonTrace; 1093eef2b5eSKamil Rytarowski m_stop_info.details.signal.signo = SIGTRAP; 1103eef2b5eSKamil Rytarowski } 1113eef2b5eSKamil Rytarowski 1123eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByExec() { 1133eef2b5eSKamil Rytarowski SetStopped(); 1143eef2b5eSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonExec; 1153eef2b5eSKamil Rytarowski m_stop_info.details.signal.signo = SIGTRAP; 1163eef2b5eSKamil Rytarowski } 1173eef2b5eSKamil Rytarowski 11836e23ecaSKamil Rytarowski void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 11936e23ecaSKamil Rytarowski lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 12036e23ecaSKamil Rytarowski 12136e23ecaSKamil Rytarowski std::ostringstream ostr; 122d37349f3SPavel Labath ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 12336e23ecaSKamil Rytarowski ostr << wp_index; 12436e23ecaSKamil Rytarowski 125d37349f3SPavel Labath ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 12636e23ecaSKamil Rytarowski 127f21e704dSMichał Górny SetStopped(); 12836e23ecaSKamil Rytarowski m_stop_description = ostr.str(); 12936e23ecaSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonWatchpoint; 13036e23ecaSKamil Rytarowski m_stop_info.details.signal.signo = SIGTRAP; 13136e23ecaSKamil Rytarowski } 13236e23ecaSKamil Rytarowski 13306215023SMichał Górny void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid, 13406215023SMichał Górny lldb::tid_t child_tid) { 13506215023SMichał Górny SetStopped(); 13606215023SMichał Górny 13706215023SMichał Górny m_stop_info.reason = StopReason::eStopReasonFork; 13806215023SMichał Górny m_stop_info.details.fork.child_pid = child_pid; 13906215023SMichał Górny m_stop_info.details.fork.child_tid = child_tid; 14006215023SMichał Górny } 14106215023SMichał Górny 14206215023SMichał Górny void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid, 14306215023SMichał Górny lldb::tid_t child_tid) { 14406215023SMichał Górny SetStopped(); 14506215023SMichał Górny 14606215023SMichał Górny m_stop_info.reason = StopReason::eStopReasonVFork; 14706215023SMichał Górny m_stop_info.details.fork.child_pid = child_pid; 14806215023SMichał Górny m_stop_info.details.fork.child_tid = child_tid; 14906215023SMichał Górny } 15006215023SMichał Górny 15106215023SMichał Górny void NativeThreadNetBSD::SetStoppedByVForkDone() { 15206215023SMichał Górny SetStopped(); 15306215023SMichał Górny 15406215023SMichał Górny m_stop_info.reason = StopReason::eStopReasonVForkDone; 15506215023SMichał Górny } 15606215023SMichał Górny 1578d9400b6SMichał Górny void NativeThreadNetBSD::SetStoppedWithNoReason() { 1588d9400b6SMichał Górny SetStopped(); 1598d9400b6SMichał Górny 1608d9400b6SMichał Górny m_stop_info.reason = StopReason::eStopReasonNone; 1618d9400b6SMichał Górny m_stop_info.details.signal.signo = 0; 1628d9400b6SMichał Górny } 1638d9400b6SMichał Górny 164f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStopped() { 165f07a9995SKamil Rytarowski const StateType new_state = StateType::eStateStopped; 166f07a9995SKamil Rytarowski m_state = new_state; 167f07a9995SKamil Rytarowski m_stop_description.clear(); 168f07a9995SKamil Rytarowski } 169f07a9995SKamil Rytarowski 170f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetRunning() { 171f07a9995SKamil Rytarowski m_state = StateType::eStateRunning; 172f07a9995SKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonNone; 173f07a9995SKamil Rytarowski } 174f07a9995SKamil Rytarowski 1753eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStepping() { 1763eef2b5eSKamil Rytarowski m_state = StateType::eStateStepping; 1773eef2b5eSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonNone; 1783eef2b5eSKamil Rytarowski } 1793eef2b5eSKamil Rytarowski 18023a766dcSMichał Górny std::string NativeThreadNetBSD::GetName() { 181*4fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Thread); 18223a766dcSMichał Górny 183ab8a7a29SKamil Rytarowski #ifdef PT_LWPSTATUS 184ab8a7a29SKamil Rytarowski struct ptrace_lwpstatus info = {}; 185ab8a7a29SKamil Rytarowski info.pl_lwpid = m_tid; 186ab8a7a29SKamil Rytarowski Status error = NativeProcessNetBSD::PtraceWrapper( 187ab8a7a29SKamil Rytarowski PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); 188ab8a7a29SKamil Rytarowski if (error.Fail()) { 189ab8a7a29SKamil Rytarowski return ""; 190ab8a7a29SKamil Rytarowski } 191ab8a7a29SKamil Rytarowski return info.pl_name; 192ab8a7a29SKamil Rytarowski #else 19323a766dcSMichał Górny std::vector<struct kinfo_lwp> infos; 19423a766dcSMichał Górny int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 19523a766dcSMichał Górny sizeof(struct kinfo_lwp), 0}; 19623a766dcSMichał Górny size_t size; 19723a766dcSMichał Górny 19823a766dcSMichał Górny if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 19923a766dcSMichał Górny LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 20023a766dcSMichał Górny llvm::sys::StrError()); 20123a766dcSMichał Górny return ""; 20223a766dcSMichał Górny } 20323a766dcSMichał Górny 20423a766dcSMichał Górny mib[4] = size / sizeof(size_t); 20523a766dcSMichał Górny infos.resize(size / sizeof(struct kinfo_lwp)); 20623a766dcSMichał Górny 20723a766dcSMichał Górny if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 20823a766dcSMichał Górny LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 20923a766dcSMichał Górny return ""; 21023a766dcSMichał Górny } 21123a766dcSMichał Górny 21223a766dcSMichał Górny size_t nlwps = size / sizeof(struct kinfo_lwp); 21323a766dcSMichał Górny for (size_t i = 0; i < nlwps; i++) { 21423a766dcSMichał Górny if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 21523a766dcSMichał Górny return infos[i].l_name; 21623a766dcSMichał Górny } 21723a766dcSMichał Górny } 21823a766dcSMichał Górny 21923a766dcSMichał Górny LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 22023a766dcSMichał Górny return ""; 221ab8a7a29SKamil Rytarowski #endif 22223a766dcSMichał Górny } 223f07a9995SKamil Rytarowski 224f07a9995SKamil Rytarowski lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 225f07a9995SKamil Rytarowski 226f07a9995SKamil Rytarowski bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 227f07a9995SKamil Rytarowski std::string &description) { 228*4fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Thread); 229f07a9995SKamil Rytarowski description.clear(); 230f07a9995SKamil Rytarowski 231f07a9995SKamil Rytarowski switch (m_state) { 232f07a9995SKamil Rytarowski case eStateStopped: 233f07a9995SKamil Rytarowski case eStateCrashed: 234f07a9995SKamil Rytarowski case eStateExited: 235f07a9995SKamil Rytarowski case eStateSuspended: 236f07a9995SKamil Rytarowski case eStateUnloaded: 237f07a9995SKamil Rytarowski stop_info = m_stop_info; 238f07a9995SKamil Rytarowski description = m_stop_description; 239f07a9995SKamil Rytarowski 240f07a9995SKamil Rytarowski return true; 241f07a9995SKamil Rytarowski 242f07a9995SKamil Rytarowski case eStateInvalid: 243f07a9995SKamil Rytarowski case eStateConnected: 244f07a9995SKamil Rytarowski case eStateAttaching: 245f07a9995SKamil Rytarowski case eStateLaunching: 246f07a9995SKamil Rytarowski case eStateRunning: 247f07a9995SKamil Rytarowski case eStateStepping: 248f07a9995SKamil Rytarowski case eStateDetached: 249f07a9995SKamil Rytarowski LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 250f07a9995SKamil Rytarowski StateAsCString(m_state)); 251f07a9995SKamil Rytarowski return false; 252f07a9995SKamil Rytarowski } 253f07a9995SKamil Rytarowski llvm_unreachable("unhandled StateType!"); 254f07a9995SKamil Rytarowski } 255f07a9995SKamil Rytarowski 256d970d4d4SMichał Górny NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 257d37349f3SPavel Labath assert(m_reg_context_up); 258d37349f3SPavel Labath return *m_reg_context_up; 259f07a9995SKamil Rytarowski } 260f07a9995SKamil Rytarowski 26197206d57SZachary Turner Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 262f07a9995SKamil Rytarowski uint32_t watch_flags, bool hardware) { 263f21e704dSMichał Górny assert(m_state == eStateStopped); 26436e23ecaSKamil Rytarowski if (!hardware) 26597206d57SZachary Turner return Status("not implemented"); 26697206d57SZachary Turner Status error = RemoveWatchpoint(addr); 26736e23ecaSKamil Rytarowski if (error.Fail()) 26836e23ecaSKamil Rytarowski return error; 269f21e704dSMichał Górny uint32_t wp_index = 270f21e704dSMichał Górny GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 27136e23ecaSKamil Rytarowski if (wp_index == LLDB_INVALID_INDEX32) 27297206d57SZachary Turner return Status("Setting hardware watchpoint failed."); 27336e23ecaSKamil Rytarowski m_watchpoint_index_map.insert({addr, wp_index}); 27497206d57SZachary Turner return Status(); 275f07a9995SKamil Rytarowski } 276f07a9995SKamil Rytarowski 27797206d57SZachary Turner Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 27836e23ecaSKamil Rytarowski auto wp = m_watchpoint_index_map.find(addr); 27936e23ecaSKamil Rytarowski if (wp == m_watchpoint_index_map.end()) 28097206d57SZachary Turner return Status(); 28136e23ecaSKamil Rytarowski uint32_t wp_index = wp->second; 28236e23ecaSKamil Rytarowski m_watchpoint_index_map.erase(wp); 283d37349f3SPavel Labath if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 28497206d57SZachary Turner return Status(); 28597206d57SZachary Turner return Status("Clearing hardware watchpoint failed."); 286f07a9995SKamil Rytarowski } 287f07a9995SKamil Rytarowski 28897206d57SZachary Turner Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 289f07a9995SKamil Rytarowski size_t size) { 290f21e704dSMichał Górny assert(m_state == eStateStopped); 29197206d57SZachary Turner Status error = RemoveHardwareBreakpoint(addr); 29236e23ecaSKamil Rytarowski if (error.Fail()) 29336e23ecaSKamil Rytarowski return error; 29436e23ecaSKamil Rytarowski 295d37349f3SPavel Labath uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 29636e23ecaSKamil Rytarowski 29736e23ecaSKamil Rytarowski if (bp_index == LLDB_INVALID_INDEX32) 29897206d57SZachary Turner return Status("Setting hardware breakpoint failed."); 29936e23ecaSKamil Rytarowski 30036e23ecaSKamil Rytarowski m_hw_break_index_map.insert({addr, bp_index}); 30197206d57SZachary Turner return Status(); 302f07a9995SKamil Rytarowski } 303f07a9995SKamil Rytarowski 30497206d57SZachary Turner Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 30536e23ecaSKamil Rytarowski auto bp = m_hw_break_index_map.find(addr); 30636e23ecaSKamil Rytarowski if (bp == m_hw_break_index_map.end()) 30797206d57SZachary Turner return Status(); 30836e23ecaSKamil Rytarowski 30936e23ecaSKamil Rytarowski uint32_t bp_index = bp->second; 310d37349f3SPavel Labath if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 31136e23ecaSKamil Rytarowski m_hw_break_index_map.erase(bp); 31297206d57SZachary Turner return Status(); 31336e23ecaSKamil Rytarowski } 31436e23ecaSKamil Rytarowski 31597206d57SZachary Turner return Status("Clearing hardware breakpoint failed."); 316f07a9995SKamil Rytarowski } 317d970d4d4SMichał Górny 318f21e704dSMichał Górny llvm::Error 319f21e704dSMichał Górny NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 320f21e704dSMichał Górny llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 321d970d4d4SMichał Górny source.GetRegisterContext()); 322f21e704dSMichał Górny if (!s) { 323d970d4d4SMichał Górny m_watchpoint_index_map = source.m_watchpoint_index_map; 324d970d4d4SMichał Górny m_hw_break_index_map = source.m_hw_break_index_map; 325d970d4d4SMichał Górny } 326d970d4d4SMichał Górny return s; 327d970d4d4SMichał Górny } 328