1*bee4d6efSMichał Górny //===-- NativeThreadFreeBSD.cpp -------------------------------------------===// 2*bee4d6efSMichał Górny // 3*bee4d6efSMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*bee4d6efSMichał Górny // See https://llvm.org/LICENSE.txt for license information. 5*bee4d6efSMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*bee4d6efSMichał Górny // 7*bee4d6efSMichał Górny //===----------------------------------------------------------------------===// 8*bee4d6efSMichał Górny 9*bee4d6efSMichał Górny #include "NativeThreadFreeBSD.h" 10*bee4d6efSMichał Górny #include "NativeRegisterContextFreeBSD.h" 11*bee4d6efSMichał Górny 12*bee4d6efSMichał Górny #include "NativeProcessFreeBSD.h" 13*bee4d6efSMichał Górny 14*bee4d6efSMichał Górny #include "Plugins/Process/POSIX/CrashReason.h" 15*bee4d6efSMichał Górny #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 16*bee4d6efSMichał Górny #include "lldb/Utility/LLDBAssert.h" 17*bee4d6efSMichał Górny #include "lldb/Utility/RegisterValue.h" 18*bee4d6efSMichał Górny #include "lldb/Utility/State.h" 19*bee4d6efSMichał Górny #include "llvm/Support/Errno.h" 20*bee4d6efSMichał Górny 21*bee4d6efSMichał Górny // clang-format off 22*bee4d6efSMichał Górny #include <sys/types.h> 23*bee4d6efSMichał Górny #include <sys/ptrace.h> 24*bee4d6efSMichał Górny #include <sys/sysctl.h> 25*bee4d6efSMichał Górny #include <sys/user.h> 26*bee4d6efSMichał Górny // clang-format on 27*bee4d6efSMichał Górny 28*bee4d6efSMichał Górny #include <sstream> 29*bee4d6efSMichał Górny #include <vector> 30*bee4d6efSMichał Górny 31*bee4d6efSMichał Górny using namespace lldb; 32*bee4d6efSMichał Górny using namespace lldb_private; 33*bee4d6efSMichał Górny using namespace lldb_private::process_freebsd; 34*bee4d6efSMichał Górny 35*bee4d6efSMichał Górny NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process, 36*bee4d6efSMichał Górny lldb::tid_t tid) 37*bee4d6efSMichał Górny : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 38*bee4d6efSMichał Górny m_stop_info(), 39*bee4d6efSMichał Górny m_reg_context_up( 40*bee4d6efSMichał Górny NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( 41*bee4d6efSMichał Górny process.GetArchitecture(), *this)), 42*bee4d6efSMichał Górny m_stop_description() {} 43*bee4d6efSMichał Górny 44*bee4d6efSMichał Górny Status NativeThreadFreeBSD::Resume() { 45*bee4d6efSMichał Górny Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); 46*bee4d6efSMichał Górny if (!ret.Success()) 47*bee4d6efSMichał Górny return ret; 48*bee4d6efSMichał Górny ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID()); 49*bee4d6efSMichał Górny // we can get EINVAL if the architecture in question does not support 50*bee4d6efSMichał Górny // hardware single-stepping -- that's fine, we have nothing to clear 51*bee4d6efSMichał Górny // then 52*bee4d6efSMichał Górny if (ret.GetError() == EINVAL) 53*bee4d6efSMichał Górny ret.Clear(); 54*bee4d6efSMichał Górny if (ret.Success()) 55*bee4d6efSMichał Górny SetRunning(); 56*bee4d6efSMichał Górny return ret; 57*bee4d6efSMichał Górny } 58*bee4d6efSMichał Górny 59*bee4d6efSMichał Górny Status NativeThreadFreeBSD::SingleStep() { 60*bee4d6efSMichał Górny Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); 61*bee4d6efSMichał Górny if (!ret.Success()) 62*bee4d6efSMichał Górny return ret; 63*bee4d6efSMichał Górny ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID()); 64*bee4d6efSMichał Górny if (ret.Success()) 65*bee4d6efSMichał Górny SetStepping(); 66*bee4d6efSMichał Górny return ret; 67*bee4d6efSMichał Górny } 68*bee4d6efSMichał Górny 69*bee4d6efSMichał Górny Status NativeThreadFreeBSD::Suspend() { 70*bee4d6efSMichał Górny Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID()); 71*bee4d6efSMichał Górny if (ret.Success()) 72*bee4d6efSMichał Górny SetStopped(); 73*bee4d6efSMichał Górny return ret; 74*bee4d6efSMichał Górny } 75*bee4d6efSMichał Górny 76*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo, 77*bee4d6efSMichał Górny const siginfo_t *info) { 78*bee4d6efSMichał Górny Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 79*bee4d6efSMichał Górny LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); 80*bee4d6efSMichał Górny 81*bee4d6efSMichał Górny SetStopped(); 82*bee4d6efSMichał Górny 83*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonSignal; 84*bee4d6efSMichał Górny m_stop_info.details.signal.signo = signo; 85*bee4d6efSMichał Górny 86*bee4d6efSMichał Górny m_stop_description.clear(); 87*bee4d6efSMichał Górny if (info) { 88*bee4d6efSMichał Górny switch (signo) { 89*bee4d6efSMichał Górny case SIGSEGV: 90*bee4d6efSMichał Górny case SIGBUS: 91*bee4d6efSMichał Górny case SIGFPE: 92*bee4d6efSMichał Górny case SIGILL: 93*bee4d6efSMichał Górny const auto reason = GetCrashReason(*info); 94*bee4d6efSMichał Górny m_stop_description = GetCrashReasonString(reason, *info); 95*bee4d6efSMichał Górny break; 96*bee4d6efSMichał Górny } 97*bee4d6efSMichał Górny } 98*bee4d6efSMichał Górny } 99*bee4d6efSMichał Górny 100*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedByBreakpoint() { 101*bee4d6efSMichał Górny SetStopped(); 102*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103*bee4d6efSMichał Górny m_stop_info.details.signal.signo = SIGTRAP; 104*bee4d6efSMichał Górny } 105*bee4d6efSMichał Górny 106*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedByTrace() { 107*bee4d6efSMichał Górny SetStopped(); 108*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonTrace; 109*bee4d6efSMichał Górny m_stop_info.details.signal.signo = SIGTRAP; 110*bee4d6efSMichał Górny } 111*bee4d6efSMichał Górny 112*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedByExec() { 113*bee4d6efSMichał Górny SetStopped(); 114*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonExec; 115*bee4d6efSMichał Górny m_stop_info.details.signal.signo = SIGTRAP; 116*bee4d6efSMichał Górny } 117*bee4d6efSMichał Górny 118*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 119*bee4d6efSMichał Górny lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 120*bee4d6efSMichał Górny 121*bee4d6efSMichał Górny std::ostringstream ostr; 122*bee4d6efSMichał Górny ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 123*bee4d6efSMichał Górny ostr << wp_index; 124*bee4d6efSMichał Górny 125*bee4d6efSMichał Górny ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 126*bee4d6efSMichał Górny 127*bee4d6efSMichał Górny SetStopped(); 128*bee4d6efSMichał Górny m_stop_description = ostr.str(); 129*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonWatchpoint; 130*bee4d6efSMichał Górny m_stop_info.details.signal.signo = SIGTRAP; 131*bee4d6efSMichał Górny } 132*bee4d6efSMichał Górny 133*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStoppedWithNoReason() { 134*bee4d6efSMichał Górny SetStopped(); 135*bee4d6efSMichał Górny 136*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonNone; 137*bee4d6efSMichał Górny m_stop_info.details.signal.signo = 0; 138*bee4d6efSMichał Górny } 139*bee4d6efSMichał Górny 140*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStopped() { 141*bee4d6efSMichał Górny const StateType new_state = StateType::eStateStopped; 142*bee4d6efSMichał Górny m_state = new_state; 143*bee4d6efSMichał Górny m_stop_description.clear(); 144*bee4d6efSMichał Górny } 145*bee4d6efSMichał Górny 146*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetRunning() { 147*bee4d6efSMichał Górny m_state = StateType::eStateRunning; 148*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonNone; 149*bee4d6efSMichał Górny } 150*bee4d6efSMichał Górny 151*bee4d6efSMichał Górny void NativeThreadFreeBSD::SetStepping() { 152*bee4d6efSMichał Górny m_state = StateType::eStateStepping; 153*bee4d6efSMichał Górny m_stop_info.reason = StopReason::eStopReasonNone; 154*bee4d6efSMichał Górny } 155*bee4d6efSMichał Górny 156*bee4d6efSMichał Górny std::string NativeThreadFreeBSD::GetName() { 157*bee4d6efSMichał Górny Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 158*bee4d6efSMichał Górny 159*bee4d6efSMichał Górny std::vector<struct kinfo_proc> kp; 160*bee4d6efSMichał Górny int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, 161*bee4d6efSMichał Górny static_cast<int>(GetProcess().GetID())}; 162*bee4d6efSMichał Górny 163*bee4d6efSMichał Górny while (1) { 164*bee4d6efSMichał Górny size_t len = kp.size() * sizeof(struct kinfo_proc); 165*bee4d6efSMichał Górny void *ptr = len == 0 ? nullptr : kp.data(); 166*bee4d6efSMichał Górny int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); 167*bee4d6efSMichał Górny if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { 168*bee4d6efSMichał Górny kp.resize(len / sizeof(struct kinfo_proc)); 169*bee4d6efSMichał Górny continue; 170*bee4d6efSMichał Górny } 171*bee4d6efSMichał Górny if (error != 0) { 172*bee4d6efSMichał Górny len = 0; 173*bee4d6efSMichał Górny LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", 174*bee4d6efSMichał Górny GetID(), m_state, strerror(errno)); 175*bee4d6efSMichał Górny } 176*bee4d6efSMichał Górny kp.resize(len / sizeof(struct kinfo_proc)); 177*bee4d6efSMichał Górny break; 178*bee4d6efSMichał Górny } 179*bee4d6efSMichał Górny 180*bee4d6efSMichał Górny for (auto &procinfo : kp) { 181*bee4d6efSMichał Górny if (procinfo.ki_tid == static_cast<lwpid_t>(GetID())) 182*bee4d6efSMichał Górny return procinfo.ki_tdname; 183*bee4d6efSMichał Górny } 184*bee4d6efSMichał Górny 185*bee4d6efSMichał Górny return ""; 186*bee4d6efSMichał Górny } 187*bee4d6efSMichał Górny 188*bee4d6efSMichał Górny lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } 189*bee4d6efSMichał Górny 190*bee4d6efSMichał Górny bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, 191*bee4d6efSMichał Górny std::string &description) { 192*bee4d6efSMichał Górny Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 193*bee4d6efSMichał Górny description.clear(); 194*bee4d6efSMichał Górny 195*bee4d6efSMichał Górny switch (m_state) { 196*bee4d6efSMichał Górny case eStateStopped: 197*bee4d6efSMichał Górny case eStateCrashed: 198*bee4d6efSMichał Górny case eStateExited: 199*bee4d6efSMichał Górny case eStateSuspended: 200*bee4d6efSMichał Górny case eStateUnloaded: 201*bee4d6efSMichał Górny stop_info = m_stop_info; 202*bee4d6efSMichał Górny description = m_stop_description; 203*bee4d6efSMichał Górny 204*bee4d6efSMichał Górny return true; 205*bee4d6efSMichał Górny 206*bee4d6efSMichał Górny case eStateInvalid: 207*bee4d6efSMichał Górny case eStateConnected: 208*bee4d6efSMichał Górny case eStateAttaching: 209*bee4d6efSMichał Górny case eStateLaunching: 210*bee4d6efSMichał Górny case eStateRunning: 211*bee4d6efSMichał Górny case eStateStepping: 212*bee4d6efSMichał Górny case eStateDetached: 213*bee4d6efSMichał Górny LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 214*bee4d6efSMichał Górny StateAsCString(m_state)); 215*bee4d6efSMichał Górny return false; 216*bee4d6efSMichał Górny } 217*bee4d6efSMichał Górny llvm_unreachable("unhandled StateType!"); 218*bee4d6efSMichał Górny } 219*bee4d6efSMichał Górny 220*bee4d6efSMichał Górny NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() { 221*bee4d6efSMichał Górny assert(m_reg_context_up); 222*bee4d6efSMichał Górny return *m_reg_context_up; 223*bee4d6efSMichał Górny } 224*bee4d6efSMichał Górny 225*bee4d6efSMichał Górny Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 226*bee4d6efSMichał Górny uint32_t watch_flags, bool hardware) { 227*bee4d6efSMichał Górny assert(m_state == eStateStopped); 228*bee4d6efSMichał Górny if (!hardware) 229*bee4d6efSMichał Górny return Status("not implemented"); 230*bee4d6efSMichał Górny Status error = RemoveWatchpoint(addr); 231*bee4d6efSMichał Górny if (error.Fail()) 232*bee4d6efSMichał Górny return error; 233*bee4d6efSMichał Górny uint32_t wp_index = 234*bee4d6efSMichał Górny GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 235*bee4d6efSMichał Górny if (wp_index == LLDB_INVALID_INDEX32) 236*bee4d6efSMichał Górny return Status("Setting hardware watchpoint failed."); 237*bee4d6efSMichał Górny m_watchpoint_index_map.insert({addr, wp_index}); 238*bee4d6efSMichał Górny return Status(); 239*bee4d6efSMichał Górny } 240*bee4d6efSMichał Górny 241*bee4d6efSMichał Górny Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) { 242*bee4d6efSMichał Górny auto wp = m_watchpoint_index_map.find(addr); 243*bee4d6efSMichał Górny if (wp == m_watchpoint_index_map.end()) 244*bee4d6efSMichał Górny return Status(); 245*bee4d6efSMichał Górny uint32_t wp_index = wp->second; 246*bee4d6efSMichał Górny m_watchpoint_index_map.erase(wp); 247*bee4d6efSMichał Górny if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 248*bee4d6efSMichał Górny return Status(); 249*bee4d6efSMichał Górny return Status("Clearing hardware watchpoint failed."); 250*bee4d6efSMichał Górny } 251*bee4d6efSMichał Górny 252*bee4d6efSMichał Górny Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr, 253*bee4d6efSMichał Górny size_t size) { 254*bee4d6efSMichał Górny assert(m_state == eStateStopped); 255*bee4d6efSMichał Górny Status error = RemoveHardwareBreakpoint(addr); 256*bee4d6efSMichał Górny if (error.Fail()) 257*bee4d6efSMichał Górny return error; 258*bee4d6efSMichał Górny 259*bee4d6efSMichał Górny uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 260*bee4d6efSMichał Górny 261*bee4d6efSMichał Górny if (bp_index == LLDB_INVALID_INDEX32) 262*bee4d6efSMichał Górny return Status("Setting hardware breakpoint failed."); 263*bee4d6efSMichał Górny 264*bee4d6efSMichał Górny m_hw_break_index_map.insert({addr, bp_index}); 265*bee4d6efSMichał Górny return Status(); 266*bee4d6efSMichał Górny } 267*bee4d6efSMichał Górny 268*bee4d6efSMichał Górny Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 269*bee4d6efSMichał Górny auto bp = m_hw_break_index_map.find(addr); 270*bee4d6efSMichał Górny if (bp == m_hw_break_index_map.end()) 271*bee4d6efSMichał Górny return Status(); 272*bee4d6efSMichał Górny 273*bee4d6efSMichał Górny uint32_t bp_index = bp->second; 274*bee4d6efSMichał Górny if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 275*bee4d6efSMichał Górny m_hw_break_index_map.erase(bp); 276*bee4d6efSMichał Górny return Status(); 277*bee4d6efSMichał Górny } 278*bee4d6efSMichał Górny 279*bee4d6efSMichał Górny return Status("Clearing hardware breakpoint failed."); 280*bee4d6efSMichał Górny } 281*bee4d6efSMichał Górny 282*bee4d6efSMichał Górny llvm::Error 283*bee4d6efSMichał Górny NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { 284*bee4d6efSMichał Górny llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 285*bee4d6efSMichał Górny source.GetRegisterContext()); 286*bee4d6efSMichał Górny if (!s) { 287*bee4d6efSMichał Górny m_watchpoint_index_map = source.m_watchpoint_index_map; 288*bee4d6efSMichał Górny m_hw_break_index_map = source.m_hw_break_index_map; 289*bee4d6efSMichał Górny } 290*bee4d6efSMichał Górny return s; 291*bee4d6efSMichał Górny } 292