1 //===-- NativeThreadNetBSD.cpp --------------------------------------------===// 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 lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 120 121 std::ostringstream ostr; 122 ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 123 ostr << wp_index; 124 125 ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 126 127 SetStopped(); 128 m_stop_description = ostr.str(); 129 m_stop_info.reason = StopReason::eStopReasonWatchpoint; 130 m_stop_info.details.signal.signo = SIGTRAP; 131 } 132 133 void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid, 134 lldb::tid_t child_tid) { 135 SetStopped(); 136 137 m_stop_info.reason = StopReason::eStopReasonFork; 138 m_stop_info.details.fork.child_pid = child_pid; 139 m_stop_info.details.fork.child_tid = child_tid; 140 } 141 142 void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid, 143 lldb::tid_t child_tid) { 144 SetStopped(); 145 146 m_stop_info.reason = StopReason::eStopReasonVFork; 147 m_stop_info.details.fork.child_pid = child_pid; 148 m_stop_info.details.fork.child_tid = child_tid; 149 } 150 151 void NativeThreadNetBSD::SetStoppedByVForkDone() { 152 SetStopped(); 153 154 m_stop_info.reason = StopReason::eStopReasonVForkDone; 155 } 156 157 void NativeThreadNetBSD::SetStoppedWithNoReason() { 158 SetStopped(); 159 160 m_stop_info.reason = StopReason::eStopReasonNone; 161 m_stop_info.details.signal.signo = 0; 162 } 163 164 void NativeThreadNetBSD::SetStopped() { 165 const StateType new_state = StateType::eStateStopped; 166 m_state = new_state; 167 m_stop_description.clear(); 168 } 169 170 void NativeThreadNetBSD::SetRunning() { 171 m_state = StateType::eStateRunning; 172 m_stop_info.reason = StopReason::eStopReasonNone; 173 } 174 175 void NativeThreadNetBSD::SetStepping() { 176 m_state = StateType::eStateStepping; 177 m_stop_info.reason = StopReason::eStopReasonNone; 178 } 179 180 std::string NativeThreadNetBSD::GetName() { 181 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 182 183 #ifdef PT_LWPSTATUS 184 struct ptrace_lwpstatus info = {}; 185 info.pl_lwpid = m_tid; 186 Status error = NativeProcessNetBSD::PtraceWrapper( 187 PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); 188 if (error.Fail()) { 189 return ""; 190 } 191 return info.pl_name; 192 #else 193 std::vector<struct kinfo_lwp> infos; 194 int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 195 sizeof(struct kinfo_lwp), 0}; 196 size_t size; 197 198 if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 199 LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 200 llvm::sys::StrError()); 201 return ""; 202 } 203 204 mib[4] = size / sizeof(size_t); 205 infos.resize(size / sizeof(struct kinfo_lwp)); 206 207 if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 208 LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 209 return ""; 210 } 211 212 size_t nlwps = size / sizeof(struct kinfo_lwp); 213 for (size_t i = 0; i < nlwps; i++) { 214 if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 215 return infos[i].l_name; 216 } 217 } 218 219 LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 220 return ""; 221 #endif 222 } 223 224 lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 225 226 bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 227 std::string &description) { 228 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 229 description.clear(); 230 231 switch (m_state) { 232 case eStateStopped: 233 case eStateCrashed: 234 case eStateExited: 235 case eStateSuspended: 236 case eStateUnloaded: 237 stop_info = m_stop_info; 238 description = m_stop_description; 239 240 return true; 241 242 case eStateInvalid: 243 case eStateConnected: 244 case eStateAttaching: 245 case eStateLaunching: 246 case eStateRunning: 247 case eStateStepping: 248 case eStateDetached: 249 LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 250 StateAsCString(m_state)); 251 return false; 252 } 253 llvm_unreachable("unhandled StateType!"); 254 } 255 256 NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 257 assert(m_reg_context_up); 258 return *m_reg_context_up; 259 } 260 261 Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 262 uint32_t watch_flags, bool hardware) { 263 assert(m_state == eStateStopped); 264 if (!hardware) 265 return Status("not implemented"); 266 Status error = RemoveWatchpoint(addr); 267 if (error.Fail()) 268 return error; 269 uint32_t wp_index = 270 GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 271 if (wp_index == LLDB_INVALID_INDEX32) 272 return Status("Setting hardware watchpoint failed."); 273 m_watchpoint_index_map.insert({addr, wp_index}); 274 return Status(); 275 } 276 277 Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 278 auto wp = m_watchpoint_index_map.find(addr); 279 if (wp == m_watchpoint_index_map.end()) 280 return Status(); 281 uint32_t wp_index = wp->second; 282 m_watchpoint_index_map.erase(wp); 283 if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 284 return Status(); 285 return Status("Clearing hardware watchpoint failed."); 286 } 287 288 Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 289 size_t size) { 290 assert(m_state == eStateStopped); 291 Status error = RemoveHardwareBreakpoint(addr); 292 if (error.Fail()) 293 return error; 294 295 uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 296 297 if (bp_index == LLDB_INVALID_INDEX32) 298 return Status("Setting hardware breakpoint failed."); 299 300 m_hw_break_index_map.insert({addr, bp_index}); 301 return Status(); 302 } 303 304 Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 305 auto bp = m_hw_break_index_map.find(addr); 306 if (bp == m_hw_break_index_map.end()) 307 return Status(); 308 309 uint32_t bp_index = bp->second; 310 if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 311 m_hw_break_index_map.erase(bp); 312 return Status(); 313 } 314 315 return Status("Clearing hardware breakpoint failed."); 316 } 317 318 llvm::Error 319 NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 320 llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 321 source.GetRegisterContext()); 322 if (!s) { 323 m_watchpoint_index_map = source.m_watchpoint_index_map; 324 m_hw_break_index_map = source.m_hw_break_index_map; 325 } 326 return s; 327 } 328