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