11a3d19ddSKamil Rytarowski //===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===// 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) { 78f07a9995SKamil Rytarowski Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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 SetStopped(); 12036e23ecaSKamil Rytarowski 12136e23ecaSKamil Rytarowski lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 12236e23ecaSKamil Rytarowski 12336e23ecaSKamil Rytarowski std::ostringstream ostr; 124d37349f3SPavel Labath ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 12536e23ecaSKamil Rytarowski ostr << wp_index; 12636e23ecaSKamil Rytarowski 127d37349f3SPavel Labath ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 12836e23ecaSKamil Rytarowski 12936e23ecaSKamil Rytarowski m_stop_description = ostr.str(); 13036e23ecaSKamil Rytarowski 13136e23ecaSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonWatchpoint; 13236e23ecaSKamil Rytarowski m_stop_info.details.signal.signo = SIGTRAP; 13336e23ecaSKamil Rytarowski } 13436e23ecaSKamil Rytarowski 1358d9400b6SMichał Górny void NativeThreadNetBSD::SetStoppedWithNoReason() { 1368d9400b6SMichał Górny SetStopped(); 1378d9400b6SMichał Górny 1388d9400b6SMichał Górny m_stop_info.reason = StopReason::eStopReasonNone; 1398d9400b6SMichał Górny m_stop_info.details.signal.signo = 0; 1408d9400b6SMichał Górny } 1418d9400b6SMichał Górny 142f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetStopped() { 143f07a9995SKamil Rytarowski const StateType new_state = StateType::eStateStopped; 144f07a9995SKamil Rytarowski m_state = new_state; 145f07a9995SKamil Rytarowski m_stop_description.clear(); 146f07a9995SKamil Rytarowski } 147f07a9995SKamil Rytarowski 148f07a9995SKamil Rytarowski void NativeThreadNetBSD::SetRunning() { 149f07a9995SKamil Rytarowski m_state = StateType::eStateRunning; 150f07a9995SKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonNone; 151f07a9995SKamil Rytarowski } 152f07a9995SKamil Rytarowski 1533eef2b5eSKamil Rytarowski void NativeThreadNetBSD::SetStepping() { 1543eef2b5eSKamil Rytarowski m_state = StateType::eStateStepping; 1553eef2b5eSKamil Rytarowski m_stop_info.reason = StopReason::eStopReasonNone; 1563eef2b5eSKamil Rytarowski } 1573eef2b5eSKamil Rytarowski 15823a766dcSMichał Górny std::string NativeThreadNetBSD::GetName() { 15923a766dcSMichał Górny Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 16023a766dcSMichał Górny 16123a766dcSMichał Górny std::vector<struct kinfo_lwp> infos; 16223a766dcSMichał Górny int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 16323a766dcSMichał Górny sizeof(struct kinfo_lwp), 0}; 16423a766dcSMichał Górny size_t size; 16523a766dcSMichał Górny 16623a766dcSMichał Górny if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 16723a766dcSMichał Górny LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 16823a766dcSMichał Górny llvm::sys::StrError()); 16923a766dcSMichał Górny return ""; 17023a766dcSMichał Górny } 17123a766dcSMichał Górny 17223a766dcSMichał Górny mib[4] = size / sizeof(size_t); 17323a766dcSMichał Górny infos.resize(size / sizeof(struct kinfo_lwp)); 17423a766dcSMichał Górny 17523a766dcSMichał Górny if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 17623a766dcSMichał Górny LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 17723a766dcSMichał Górny return ""; 17823a766dcSMichał Górny } 17923a766dcSMichał Górny 18023a766dcSMichał Górny size_t nlwps = size / sizeof(struct kinfo_lwp); 18123a766dcSMichał Górny for (size_t i = 0; i < nlwps; i++) { 18223a766dcSMichał Górny if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 18323a766dcSMichał Górny return infos[i].l_name; 18423a766dcSMichał Górny } 18523a766dcSMichał Górny } 18623a766dcSMichał Górny 18723a766dcSMichał Górny LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 18823a766dcSMichał Górny return ""; 18923a766dcSMichał Górny } 190f07a9995SKamil Rytarowski 191f07a9995SKamil Rytarowski lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 192f07a9995SKamil Rytarowski 193f07a9995SKamil Rytarowski bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 194f07a9995SKamil Rytarowski std::string &description) { 195f07a9995SKamil Rytarowski Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 196f07a9995SKamil Rytarowski 197f07a9995SKamil Rytarowski description.clear(); 198f07a9995SKamil Rytarowski 199f07a9995SKamil Rytarowski switch (m_state) { 200f07a9995SKamil Rytarowski case eStateStopped: 201f07a9995SKamil Rytarowski case eStateCrashed: 202f07a9995SKamil Rytarowski case eStateExited: 203f07a9995SKamil Rytarowski case eStateSuspended: 204f07a9995SKamil Rytarowski case eStateUnloaded: 205f07a9995SKamil Rytarowski stop_info = m_stop_info; 206f07a9995SKamil Rytarowski description = m_stop_description; 207f07a9995SKamil Rytarowski 208f07a9995SKamil Rytarowski return true; 209f07a9995SKamil Rytarowski 210f07a9995SKamil Rytarowski case eStateInvalid: 211f07a9995SKamil Rytarowski case eStateConnected: 212f07a9995SKamil Rytarowski case eStateAttaching: 213f07a9995SKamil Rytarowski case eStateLaunching: 214f07a9995SKamil Rytarowski case eStateRunning: 215f07a9995SKamil Rytarowski case eStateStepping: 216f07a9995SKamil Rytarowski case eStateDetached: 217f07a9995SKamil Rytarowski LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 218f07a9995SKamil Rytarowski StateAsCString(m_state)); 219f07a9995SKamil Rytarowski return false; 220f07a9995SKamil Rytarowski } 221f07a9995SKamil Rytarowski llvm_unreachable("unhandled StateType!"); 222f07a9995SKamil Rytarowski } 223f07a9995SKamil Rytarowski 224*d970d4d4SMichał Górny NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 225d37349f3SPavel Labath assert(m_reg_context_up); 226d37349f3SPavel Labath return *m_reg_context_up; 227f07a9995SKamil Rytarowski } 228f07a9995SKamil Rytarowski 22997206d57SZachary Turner Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 230f07a9995SKamil Rytarowski uint32_t watch_flags, bool hardware) { 23136e23ecaSKamil Rytarowski if (!hardware) 23297206d57SZachary Turner return Status("not implemented"); 23336e23ecaSKamil Rytarowski if (m_state == eStateLaunching) 23497206d57SZachary Turner return Status(); 23597206d57SZachary Turner Status error = RemoveWatchpoint(addr); 23636e23ecaSKamil Rytarowski if (error.Fail()) 23736e23ecaSKamil Rytarowski return error; 238d37349f3SPavel Labath uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 23936e23ecaSKamil Rytarowski if (wp_index == LLDB_INVALID_INDEX32) 24097206d57SZachary Turner return Status("Setting hardware watchpoint failed."); 24136e23ecaSKamil Rytarowski m_watchpoint_index_map.insert({addr, wp_index}); 24297206d57SZachary Turner return Status(); 243f07a9995SKamil Rytarowski } 244f07a9995SKamil Rytarowski 24597206d57SZachary Turner Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 24636e23ecaSKamil Rytarowski auto wp = m_watchpoint_index_map.find(addr); 24736e23ecaSKamil Rytarowski if (wp == m_watchpoint_index_map.end()) 24897206d57SZachary Turner return Status(); 24936e23ecaSKamil Rytarowski uint32_t wp_index = wp->second; 25036e23ecaSKamil Rytarowski m_watchpoint_index_map.erase(wp); 251d37349f3SPavel Labath if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 25297206d57SZachary Turner return Status(); 25397206d57SZachary Turner return Status("Clearing hardware watchpoint failed."); 254f07a9995SKamil Rytarowski } 255f07a9995SKamil Rytarowski 25697206d57SZachary Turner Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 257f07a9995SKamil Rytarowski size_t size) { 25836e23ecaSKamil Rytarowski if (m_state == eStateLaunching) 25997206d57SZachary Turner return Status(); 26036e23ecaSKamil Rytarowski 26197206d57SZachary Turner Status error = RemoveHardwareBreakpoint(addr); 26236e23ecaSKamil Rytarowski if (error.Fail()) 26336e23ecaSKamil Rytarowski return error; 26436e23ecaSKamil Rytarowski 265d37349f3SPavel Labath uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 26636e23ecaSKamil Rytarowski 26736e23ecaSKamil Rytarowski if (bp_index == LLDB_INVALID_INDEX32) 26897206d57SZachary Turner return Status("Setting hardware breakpoint failed."); 26936e23ecaSKamil Rytarowski 27036e23ecaSKamil Rytarowski m_hw_break_index_map.insert({addr, bp_index}); 27197206d57SZachary Turner return Status(); 272f07a9995SKamil Rytarowski } 273f07a9995SKamil Rytarowski 27497206d57SZachary Turner Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 27536e23ecaSKamil Rytarowski auto bp = m_hw_break_index_map.find(addr); 27636e23ecaSKamil Rytarowski if (bp == m_hw_break_index_map.end()) 27797206d57SZachary Turner return Status(); 27836e23ecaSKamil Rytarowski 27936e23ecaSKamil Rytarowski uint32_t bp_index = bp->second; 280d37349f3SPavel Labath if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 28136e23ecaSKamil Rytarowski m_hw_break_index_map.erase(bp); 28297206d57SZachary Turner return Status(); 28336e23ecaSKamil Rytarowski } 28436e23ecaSKamil Rytarowski 28597206d57SZachary Turner return Status("Clearing hardware breakpoint failed."); 286f07a9995SKamil Rytarowski } 287*d970d4d4SMichał Górny 288*d970d4d4SMichał Górny Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 289*d970d4d4SMichał Górny Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( 290*d970d4d4SMichał Górny source.GetRegisterContext()); 291*d970d4d4SMichał Górny if (!s.Fail()) { 292*d970d4d4SMichał Górny m_watchpoint_index_map = source.m_watchpoint_index_map; 293*d970d4d4SMichał Górny m_hw_break_index_map = source.m_hw_break_index_map; 294*d970d4d4SMichał Górny } 295*d970d4d4SMichał Górny return s; 296*d970d4d4SMichał Górny } 297