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 33 using namespace lldb; 34 using namespace lldb_private; 35 using namespace lldb_private::process_netbsd; 36 37 NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, 38 lldb::tid_t tid) 39 : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 40 m_stop_info(), m_reg_context_up( 41 NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) 42 ), m_stop_description() {} 43 44 Status 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 56 Status 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 68 Status 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 76 void 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 100 void NativeThreadNetBSD::SetStoppedByBreakpoint() { 101 SetStopped(); 102 m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103 m_stop_info.details.signal.signo = SIGTRAP; 104 } 105 106 void NativeThreadNetBSD::SetStoppedByTrace() { 107 SetStopped(); 108 m_stop_info.reason = StopReason::eStopReasonTrace; 109 m_stop_info.details.signal.signo = SIGTRAP; 110 } 111 112 void NativeThreadNetBSD::SetStoppedByExec() { 113 SetStopped(); 114 m_stop_info.reason = StopReason::eStopReasonExec; 115 m_stop_info.details.signal.signo = SIGTRAP; 116 } 117 118 void 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 135 void NativeThreadNetBSD::SetStoppedWithNoReason() { 136 SetStopped(); 137 138 m_stop_info.reason = StopReason::eStopReasonNone; 139 m_stop_info.details.signal.signo = 0; 140 } 141 142 void NativeThreadNetBSD::SetStopped() { 143 const StateType new_state = StateType::eStateStopped; 144 m_state = new_state; 145 m_stop_description.clear(); 146 } 147 148 void NativeThreadNetBSD::SetRunning() { 149 m_state = StateType::eStateRunning; 150 m_stop_info.reason = StopReason::eStopReasonNone; 151 } 152 153 void NativeThreadNetBSD::SetStepping() { 154 m_state = StateType::eStateStepping; 155 m_stop_info.reason = StopReason::eStopReasonNone; 156 } 157 158 std::string NativeThreadNetBSD::GetName() { 159 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 160 161 std::vector<struct kinfo_lwp> infos; 162 int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 163 sizeof(struct kinfo_lwp), 0}; 164 size_t size; 165 166 if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 167 LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 168 llvm::sys::StrError()); 169 return ""; 170 } 171 172 mib[4] = size / sizeof(size_t); 173 infos.resize(size / sizeof(struct kinfo_lwp)); 174 175 if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 176 LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 177 return ""; 178 } 179 180 size_t nlwps = size / sizeof(struct kinfo_lwp); 181 for (size_t i = 0; i < nlwps; i++) { 182 if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 183 return infos[i].l_name; 184 } 185 } 186 187 LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 188 return ""; 189 } 190 191 lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 192 193 bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 194 std::string &description) { 195 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 196 197 description.clear(); 198 199 switch (m_state) { 200 case eStateStopped: 201 case eStateCrashed: 202 case eStateExited: 203 case eStateSuspended: 204 case eStateUnloaded: 205 stop_info = m_stop_info; 206 description = m_stop_description; 207 208 return true; 209 210 case eStateInvalid: 211 case eStateConnected: 212 case eStateAttaching: 213 case eStateLaunching: 214 case eStateRunning: 215 case eStateStepping: 216 case eStateDetached: 217 LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 218 StateAsCString(m_state)); 219 return false; 220 } 221 llvm_unreachable("unhandled StateType!"); 222 } 223 224 NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 225 assert(m_reg_context_up); 226 return *m_reg_context_up; 227 } 228 229 Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 230 uint32_t watch_flags, bool hardware) { 231 if (!hardware) 232 return Status("not implemented"); 233 if (m_state == eStateLaunching) 234 return Status(); 235 Status error = RemoveWatchpoint(addr); 236 if (error.Fail()) 237 return error; 238 uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 239 if (wp_index == LLDB_INVALID_INDEX32) 240 return Status("Setting hardware watchpoint failed."); 241 m_watchpoint_index_map.insert({addr, wp_index}); 242 return Status(); 243 } 244 245 Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 246 auto wp = m_watchpoint_index_map.find(addr); 247 if (wp == m_watchpoint_index_map.end()) 248 return Status(); 249 uint32_t wp_index = wp->second; 250 m_watchpoint_index_map.erase(wp); 251 if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 252 return Status(); 253 return Status("Clearing hardware watchpoint failed."); 254 } 255 256 Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 257 size_t size) { 258 if (m_state == eStateLaunching) 259 return Status(); 260 261 Status error = RemoveHardwareBreakpoint(addr); 262 if (error.Fail()) 263 return error; 264 265 uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 266 267 if (bp_index == LLDB_INVALID_INDEX32) 268 return Status("Setting hardware breakpoint failed."); 269 270 m_hw_break_index_map.insert({addr, bp_index}); 271 return Status(); 272 } 273 274 Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 275 auto bp = m_hw_break_index_map.find(addr); 276 if (bp == m_hw_break_index_map.end()) 277 return Status(); 278 279 uint32_t bp_index = bp->second; 280 if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 281 m_hw_break_index_map.erase(bp); 282 return Status(); 283 } 284 285 return Status("Clearing hardware breakpoint failed."); 286 } 287 288 Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 289 Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( 290 source.GetRegisterContext()); 291 if (!s.Fail()) { 292 m_watchpoint_index_map = source.m_watchpoint_index_map; 293 m_hw_break_index_map = source.m_hw_break_index_map; 294 } 295 return s; 296 } 297