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