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