Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
39642 views
//===-- NativeThreadFreeBSD.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "NativeThreadFreeBSD.h"9#include "NativeRegisterContextFreeBSD.h"1011#include "NativeProcessFreeBSD.h"1213#include "Plugins/Process/POSIX/CrashReason.h"14#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"15#include "lldb/Utility/LLDBAssert.h"16#include "lldb/Utility/RegisterValue.h"17#include "lldb/Utility/State.h"18#include "llvm/Support/Errno.h"1920// clang-format off21#include <sys/types.h>22#include <sys/ptrace.h>23#include <sys/sysctl.h>24#include <sys/user.h>25// clang-format on2627#include <sstream>28#include <vector>2930using namespace lldb;31using namespace lldb_private;32using namespace lldb_private::process_freebsd;3334NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,35lldb::tid_t tid)36: NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),37m_stop_info(),38m_reg_context_up(39NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(40process.GetArchitecture(), *this)),41m_stop_description() {}4243Status NativeThreadFreeBSD::Resume() {44Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());45if (!ret.Success())46return ret;47ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());48// we can get EINVAL if the architecture in question does not support49// hardware single-stepping -- that's fine, we have nothing to clear50// then51if (ret.GetError() == EINVAL)52ret.Clear();53if (ret.Success())54SetRunning();55return ret;56}5758Status NativeThreadFreeBSD::SingleStep() {59Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());60if (!ret.Success())61return ret;62ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());63if (ret.Success())64SetStepping();65return ret;66}6768Status NativeThreadFreeBSD::Suspend() {69Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());70if (ret.Success())71SetStopped();72return ret;73}7475void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo,76const siginfo_t *info) {77Log *log = GetLog(POSIXLog::Thread);78LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);7980SetStopped();8182m_stop_info.reason = StopReason::eStopReasonSignal;83m_stop_info.signo = signo;8485m_stop_description.clear();86if (info) {87switch (signo) {88case SIGSEGV:89case SIGBUS:90case SIGFPE:91case SIGILL:92m_stop_description = GetCrashReasonString(*info);93break;94}95}96}9798void NativeThreadFreeBSD::SetStoppedByBreakpoint() {99SetStopped();100m_stop_info.reason = StopReason::eStopReasonBreakpoint;101m_stop_info.signo = SIGTRAP;102}103104void NativeThreadFreeBSD::SetStoppedByTrace() {105SetStopped();106m_stop_info.reason = StopReason::eStopReasonTrace;107m_stop_info.signo = SIGTRAP;108}109110void NativeThreadFreeBSD::SetStoppedByExec() {111SetStopped();112m_stop_info.reason = StopReason::eStopReasonExec;113m_stop_info.signo = SIGTRAP;114}115116void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {117lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");118119std::ostringstream ostr;120ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";121ostr << wp_index;122123ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);124125SetStopped();126m_stop_description = ostr.str();127m_stop_info.reason = StopReason::eStopReasonWatchpoint;128m_stop_info.signo = SIGTRAP;129}130131void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid,132lldb::tid_t child_tid) {133SetStopped();134135m_stop_info.reason = StopReason::eStopReasonFork;136m_stop_info.signo = SIGTRAP;137m_stop_info.details.fork.child_pid = child_pid;138m_stop_info.details.fork.child_tid = child_tid;139}140141void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid,142lldb::tid_t child_tid) {143SetStopped();144145m_stop_info.reason = StopReason::eStopReasonVFork;146m_stop_info.signo = SIGTRAP;147m_stop_info.details.fork.child_pid = child_pid;148m_stop_info.details.fork.child_tid = child_tid;149}150151void NativeThreadFreeBSD::SetStoppedByVForkDone() {152SetStopped();153154m_stop_info.reason = StopReason::eStopReasonVForkDone;155m_stop_info.signo = SIGTRAP;156}157158void NativeThreadFreeBSD::SetStoppedWithNoReason() {159SetStopped();160161m_stop_info.reason = StopReason::eStopReasonNone;162m_stop_info.signo = 0;163}164165void NativeThreadFreeBSD::SetStopped() {166const StateType new_state = StateType::eStateStopped;167m_state = new_state;168m_stop_description.clear();169}170171void NativeThreadFreeBSD::SetRunning() {172m_state = StateType::eStateRunning;173m_stop_info.reason = StopReason::eStopReasonNone;174}175176void NativeThreadFreeBSD::SetStepping() {177m_state = StateType::eStateStepping;178m_stop_info.reason = StopReason::eStopReasonNone;179}180181std::string NativeThreadFreeBSD::GetName() {182Log *log = GetLog(POSIXLog::Thread);183184std::vector<struct kinfo_proc> kp;185int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,186static_cast<int>(GetProcess().GetID())};187188while (1) {189size_t len = kp.size() * sizeof(struct kinfo_proc);190void *ptr = len == 0 ? nullptr : kp.data();191int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0);192if (ptr == nullptr || (error != 0 && errno == ENOMEM)) {193kp.resize(len / sizeof(struct kinfo_proc));194continue;195}196if (error != 0) {197len = 0;198LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}",199GetID(), m_state, strerror(errno));200}201kp.resize(len / sizeof(struct kinfo_proc));202break;203}204205for (auto &procinfo : kp) {206if (procinfo.ki_tid == static_cast<lwpid_t>(GetID()))207return procinfo.ki_tdname;208}209210return "";211}212213lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }214215bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info,216std::string &description) {217Log *log = GetLog(POSIXLog::Thread);218description.clear();219220switch (m_state) {221case eStateStopped:222case eStateCrashed:223case eStateExited:224case eStateSuspended:225case eStateUnloaded:226stop_info = m_stop_info;227description = m_stop_description;228229return true;230231case eStateInvalid:232case eStateConnected:233case eStateAttaching:234case eStateLaunching:235case eStateRunning:236case eStateStepping:237case eStateDetached:238LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),239StateAsCString(m_state));240return false;241}242llvm_unreachable("unhandled StateType!");243}244245NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {246assert(m_reg_context_up);247return *m_reg_context_up;248}249250Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,251uint32_t watch_flags, bool hardware) {252assert(m_state == eStateStopped);253if (!hardware)254return Status("not implemented");255Status error = RemoveWatchpoint(addr);256if (error.Fail())257return error;258uint32_t wp_index =259GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);260if (wp_index == LLDB_INVALID_INDEX32)261return Status("Setting hardware watchpoint failed.");262m_watchpoint_index_map.insert({addr, wp_index});263return Status();264}265266Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {267auto wp = m_watchpoint_index_map.find(addr);268if (wp == m_watchpoint_index_map.end())269return Status();270uint32_t wp_index = wp->second;271m_watchpoint_index_map.erase(wp);272if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))273return Status();274return Status("Clearing hardware watchpoint failed.");275}276277Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,278size_t size) {279assert(m_state == eStateStopped);280Status error = RemoveHardwareBreakpoint(addr);281if (error.Fail())282return error;283284uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);285286if (bp_index == LLDB_INVALID_INDEX32)287return Status("Setting hardware breakpoint failed.");288289m_hw_break_index_map.insert({addr, bp_index});290return Status();291}292293Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {294auto bp = m_hw_break_index_map.find(addr);295if (bp == m_hw_break_index_map.end())296return Status();297298uint32_t bp_index = bp->second;299if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {300m_hw_break_index_map.erase(bp);301return Status();302}303304return Status("Clearing hardware breakpoint failed.");305}306307llvm::Error308NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {309llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(310source.GetRegisterContext());311if (!s) {312m_watchpoint_index_map = source.m_watchpoint_index_map;313m_hw_break_index_map = source.m_hw_break_index_map;314}315return s;316}317318NativeProcessFreeBSD &NativeThreadFreeBSD::GetProcess() {319return static_cast<NativeProcessFreeBSD &>(m_process);320}321322llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>323NativeThreadFreeBSD::GetSiginfo() const {324Log *log = GetLog(POSIXLog::Process);325326struct ptrace_lwpinfo info;327const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper(328PT_LWPINFO, GetID(), &info, sizeof(info));329if (siginfo_err.Fail()) {330LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);331return siginfo_err.ToError();332}333334if (info.pl_event != PL_EVENT_SIGNAL)335return llvm::createStringError(llvm::inconvertibleErrorCode(),336"Thread not signaled");337if (!(info.pl_flags & PL_FLAG_SI))338return llvm::createStringError(llvm::inconvertibleErrorCode(),339"No siginfo for thread");340341return llvm::MemoryBuffer::getMemBufferCopy(342llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo),343sizeof(info.pl_siginfo)));344}345346347