1 //===-- NativeThreadFreeBSD.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 "NativeThreadFreeBSD.h" 10 #include "NativeRegisterContextFreeBSD.h" 11 12 #include "NativeProcessFreeBSD.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 #include <sys/sysctl.h> 25 #include <sys/user.h> 26 // clang-format on 27 28 #include <sstream> 29 #include <vector> 30 31 using namespace lldb; 32 using namespace lldb_private; 33 using namespace lldb_private::process_freebsd; 34 35 NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process, 36 lldb::tid_t tid) 37 : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 38 m_stop_info(), 39 m_reg_context_up( 40 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( 41 process.GetArchitecture(), *this)), 42 m_stop_description() {} 43 44 Status NativeThreadFreeBSD::Resume() { 45 Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); 46 if (!ret.Success()) 47 return ret; 48 ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID()); 49 // we can get EINVAL if the architecture in question does not support 50 // hardware single-stepping -- that's fine, we have nothing to clear 51 // then 52 if (ret.GetError() == EINVAL) 53 ret.Clear(); 54 if (ret.Success()) 55 SetRunning(); 56 return ret; 57 } 58 59 Status NativeThreadFreeBSD::SingleStep() { 60 Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); 61 if (!ret.Success()) 62 return ret; 63 ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID()); 64 if (ret.Success()) 65 SetStepping(); 66 return ret; 67 } 68 69 Status NativeThreadFreeBSD::Suspend() { 70 Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID()); 71 if (ret.Success()) 72 SetStopped(); 73 return ret; 74 } 75 76 void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo, 77 const siginfo_t *info) { 78 Log *log = GetLog(POSIXLog::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.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 NativeThreadFreeBSD::SetStoppedByBreakpoint() { 101 SetStopped(); 102 m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103 m_stop_info.signo = SIGTRAP; 104 } 105 106 void NativeThreadFreeBSD::SetStoppedByTrace() { 107 SetStopped(); 108 m_stop_info.reason = StopReason::eStopReasonTrace; 109 m_stop_info.signo = SIGTRAP; 110 } 111 112 void NativeThreadFreeBSD::SetStoppedByExec() { 113 SetStopped(); 114 m_stop_info.reason = StopReason::eStopReasonExec; 115 m_stop_info.signo = SIGTRAP; 116 } 117 118 void NativeThreadFreeBSD::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.signo = SIGTRAP; 131 } 132 133 void NativeThreadFreeBSD::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.signo = SIGTRAP; 139 m_stop_info.details.fork.child_pid = child_pid; 140 m_stop_info.details.fork.child_tid = child_tid; 141 } 142 143 void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid, 144 lldb::tid_t child_tid) { 145 SetStopped(); 146 147 m_stop_info.reason = StopReason::eStopReasonVFork; 148 m_stop_info.signo = SIGTRAP; 149 m_stop_info.details.fork.child_pid = child_pid; 150 m_stop_info.details.fork.child_tid = child_tid; 151 } 152 153 void NativeThreadFreeBSD::SetStoppedByVForkDone() { 154 SetStopped(); 155 156 m_stop_info.reason = StopReason::eStopReasonVForkDone; 157 m_stop_info.signo = SIGTRAP; 158 } 159 160 void NativeThreadFreeBSD::SetStoppedWithNoReason() { 161 SetStopped(); 162 163 m_stop_info.reason = StopReason::eStopReasonNone; 164 m_stop_info.signo = 0; 165 } 166 167 void NativeThreadFreeBSD::SetStopped() { 168 const StateType new_state = StateType::eStateStopped; 169 m_state = new_state; 170 m_stop_description.clear(); 171 } 172 173 void NativeThreadFreeBSD::SetRunning() { 174 m_state = StateType::eStateRunning; 175 m_stop_info.reason = StopReason::eStopReasonNone; 176 } 177 178 void NativeThreadFreeBSD::SetStepping() { 179 m_state = StateType::eStateStepping; 180 m_stop_info.reason = StopReason::eStopReasonNone; 181 } 182 183 std::string NativeThreadFreeBSD::GetName() { 184 Log *log = GetLog(POSIXLog::Thread); 185 186 std::vector<struct kinfo_proc> kp; 187 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, 188 static_cast<int>(GetProcess().GetID())}; 189 190 while (1) { 191 size_t len = kp.size() * sizeof(struct kinfo_proc); 192 void *ptr = len == 0 ? nullptr : kp.data(); 193 int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); 194 if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { 195 kp.resize(len / sizeof(struct kinfo_proc)); 196 continue; 197 } 198 if (error != 0) { 199 len = 0; 200 LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", 201 GetID(), m_state, strerror(errno)); 202 } 203 kp.resize(len / sizeof(struct kinfo_proc)); 204 break; 205 } 206 207 for (auto &procinfo : kp) { 208 if (procinfo.ki_tid == static_cast<lwpid_t>(GetID())) 209 return procinfo.ki_tdname; 210 } 211 212 return ""; 213 } 214 215 lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } 216 217 bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, 218 std::string &description) { 219 Log *log = GetLog(POSIXLog::Thread); 220 description.clear(); 221 222 switch (m_state) { 223 case eStateStopped: 224 case eStateCrashed: 225 case eStateExited: 226 case eStateSuspended: 227 case eStateUnloaded: 228 stop_info = m_stop_info; 229 description = m_stop_description; 230 231 return true; 232 233 case eStateInvalid: 234 case eStateConnected: 235 case eStateAttaching: 236 case eStateLaunching: 237 case eStateRunning: 238 case eStateStepping: 239 case eStateDetached: 240 LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 241 StateAsCString(m_state)); 242 return false; 243 } 244 llvm_unreachable("unhandled StateType!"); 245 } 246 247 NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() { 248 assert(m_reg_context_up); 249 return *m_reg_context_up; 250 } 251 252 Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 253 uint32_t watch_flags, bool hardware) { 254 assert(m_state == eStateStopped); 255 if (!hardware) 256 return Status("not implemented"); 257 Status error = RemoveWatchpoint(addr); 258 if (error.Fail()) 259 return error; 260 uint32_t wp_index = 261 GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 262 if (wp_index == LLDB_INVALID_INDEX32) 263 return Status("Setting hardware watchpoint failed."); 264 m_watchpoint_index_map.insert({addr, wp_index}); 265 return Status(); 266 } 267 268 Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) { 269 auto wp = m_watchpoint_index_map.find(addr); 270 if (wp == m_watchpoint_index_map.end()) 271 return Status(); 272 uint32_t wp_index = wp->second; 273 m_watchpoint_index_map.erase(wp); 274 if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 275 return Status(); 276 return Status("Clearing hardware watchpoint failed."); 277 } 278 279 Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr, 280 size_t size) { 281 assert(m_state == eStateStopped); 282 Status error = RemoveHardwareBreakpoint(addr); 283 if (error.Fail()) 284 return error; 285 286 uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 287 288 if (bp_index == LLDB_INVALID_INDEX32) 289 return Status("Setting hardware breakpoint failed."); 290 291 m_hw_break_index_map.insert({addr, bp_index}); 292 return Status(); 293 } 294 295 Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 296 auto bp = m_hw_break_index_map.find(addr); 297 if (bp == m_hw_break_index_map.end()) 298 return Status(); 299 300 uint32_t bp_index = bp->second; 301 if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 302 m_hw_break_index_map.erase(bp); 303 return Status(); 304 } 305 306 return Status("Clearing hardware breakpoint failed."); 307 } 308 309 llvm::Error 310 NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { 311 llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( 312 source.GetRegisterContext()); 313 if (!s) { 314 m_watchpoint_index_map = source.m_watchpoint_index_map; 315 m_hw_break_index_map = source.m_hw_break_index_map; 316 } 317 return s; 318 } 319 320 llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> 321 NativeThreadFreeBSD::GetSiginfo() const { 322 Log *log = GetLog(POSIXLog::Process); 323 324 struct ptrace_lwpinfo info; 325 const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper( 326 PT_LWPINFO, GetID(), &info, sizeof(info)); 327 if (siginfo_err.Fail()) { 328 LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); 329 return siginfo_err.ToError(); 330 } 331 332 if (info.pl_event != PL_EVENT_SIGNAL) 333 return llvm::createStringError(llvm::inconvertibleErrorCode(), 334 "Thread not signaled"); 335 if (!(info.pl_flags & PL_FLAG_SI)) 336 return llvm::createStringError(llvm::inconvertibleErrorCode(), 337 "No siginfo for thread"); 338 339 return llvm::MemoryBuffer::getMemBufferCopy( 340 llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo), 341 sizeof(info.pl_siginfo))); 342 } 343