1317027Sdim//===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===// 2317027Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317027Sdim// 7317027Sdim//===----------------------------------------------------------------------===// 8317027Sdim 9317027Sdim#include "NativeThreadNetBSD.h" 10317027Sdim#include "NativeRegisterContextNetBSD.h" 11317027Sdim 12317027Sdim#include "NativeProcessNetBSD.h" 13317027Sdim 14317027Sdim#include "Plugins/Process/POSIX/CrashReason.h" 15317027Sdim#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 16317230Sdim#include "lldb/Utility/LLDBAssert.h" 17344779Sdim#include "lldb/Utility/RegisterValue.h" 18344779Sdim#include "lldb/Utility/State.h" 19360784Sdim#include "llvm/Support/Errno.h" 20317027Sdim 21360784Sdim// clang-format off 22360784Sdim#include <sys/types.h> 23360784Sdim#include <sys/ptrace.h> 24360784Sdim// clang-format on 25360784Sdim 26317230Sdim#include <sstream> 27317230Sdim 28360784Sdim// clang-format off 29360784Sdim#include <sys/types.h> 30360784Sdim#include <sys/sysctl.h> 31360784Sdim// clang-format on 32360784Sdim 33317027Sdimusing namespace lldb; 34317027Sdimusing namespace lldb_private; 35317027Sdimusing namespace lldb_private::process_netbsd; 36317027Sdim 37321238SdimNativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, 38317027Sdim lldb::tid_t tid) 39317027Sdim : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 40327952Sdim m_stop_info(), m_reg_context_up( 41327952SdimNativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) 42327952Sdim), m_stop_description() {} 43317027Sdim 44360784SdimStatus NativeThreadNetBSD::Resume() { 45360784Sdim Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 46360784Sdim nullptr, GetID()); 47360784Sdim if (!ret.Success()) 48360784Sdim return ret; 49360784Sdim ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(), 50360784Sdim nullptr, GetID()); 51360784Sdim if (ret.Success()) 52360784Sdim SetRunning(); 53360784Sdim return ret; 54360784Sdim} 55360784Sdim 56360784SdimStatus NativeThreadNetBSD::SingleStep() { 57360784Sdim Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), 58360784Sdim nullptr, GetID()); 59360784Sdim if (!ret.Success()) 60360784Sdim return ret; 61360784Sdim ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(), 62360784Sdim nullptr, GetID()); 63360784Sdim if (ret.Success()) 64360784Sdim SetStepping(); 65360784Sdim return ret; 66360784Sdim} 67360784Sdim 68360784SdimStatus NativeThreadNetBSD::Suspend() { 69360784Sdim Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(), 70360784Sdim nullptr, GetID()); 71360784Sdim if (ret.Success()) 72360784Sdim SetStopped(); 73360784Sdim return ret; 74360784Sdim} 75360784Sdim 76317027Sdimvoid NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, 77317027Sdim const siginfo_t *info) { 78317027Sdim Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 79317027Sdim LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); 80317027Sdim 81317027Sdim SetStopped(); 82317027Sdim 83317027Sdim m_stop_info.reason = StopReason::eStopReasonSignal; 84317027Sdim m_stop_info.details.signal.signo = signo; 85317027Sdim 86317027Sdim m_stop_description.clear(); 87317027Sdim if (info) { 88317027Sdim switch (signo) { 89317027Sdim case SIGSEGV: 90317027Sdim case SIGBUS: 91317027Sdim case SIGFPE: 92317027Sdim case SIGILL: 93317027Sdim const auto reason = GetCrashReason(*info); 94317027Sdim m_stop_description = GetCrashReasonString(reason, *info); 95317027Sdim break; 96317027Sdim } 97317027Sdim } 98317027Sdim} 99317027Sdim 100317027Sdimvoid NativeThreadNetBSD::SetStoppedByBreakpoint() { 101317027Sdim SetStopped(); 102317027Sdim m_stop_info.reason = StopReason::eStopReasonBreakpoint; 103317027Sdim m_stop_info.details.signal.signo = SIGTRAP; 104317027Sdim} 105317027Sdim 106317027Sdimvoid NativeThreadNetBSD::SetStoppedByTrace() { 107317027Sdim SetStopped(); 108317027Sdim m_stop_info.reason = StopReason::eStopReasonTrace; 109317027Sdim m_stop_info.details.signal.signo = SIGTRAP; 110317027Sdim} 111317027Sdim 112317027Sdimvoid NativeThreadNetBSD::SetStoppedByExec() { 113317027Sdim SetStopped(); 114317027Sdim m_stop_info.reason = StopReason::eStopReasonExec; 115317027Sdim m_stop_info.details.signal.signo = SIGTRAP; 116317027Sdim} 117317027Sdim 118317230Sdimvoid NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 119317230Sdim SetStopped(); 120317230Sdim 121317230Sdim lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 122317230Sdim 123317230Sdim std::ostringstream ostr; 124327952Sdim ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 125317230Sdim ostr << wp_index; 126317230Sdim 127327952Sdim ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 128317230Sdim 129317230Sdim m_stop_description = ostr.str(); 130317230Sdim 131317230Sdim m_stop_info.reason = StopReason::eStopReasonWatchpoint; 132317230Sdim m_stop_info.details.signal.signo = SIGTRAP; 133317230Sdim} 134317230Sdim 135360784Sdimvoid NativeThreadNetBSD::SetStoppedWithNoReason() { 136360784Sdim SetStopped(); 137360784Sdim 138360784Sdim m_stop_info.reason = StopReason::eStopReasonNone; 139360784Sdim m_stop_info.details.signal.signo = 0; 140360784Sdim} 141360784Sdim 142317027Sdimvoid NativeThreadNetBSD::SetStopped() { 143317027Sdim const StateType new_state = StateType::eStateStopped; 144317027Sdim m_state = new_state; 145317027Sdim m_stop_description.clear(); 146317027Sdim} 147317027Sdim 148317027Sdimvoid NativeThreadNetBSD::SetRunning() { 149317027Sdim m_state = StateType::eStateRunning; 150317027Sdim m_stop_info.reason = StopReason::eStopReasonNone; 151317027Sdim} 152317027Sdim 153317027Sdimvoid NativeThreadNetBSD::SetStepping() { 154317027Sdim m_state = StateType::eStateStepping; 155317027Sdim m_stop_info.reason = StopReason::eStopReasonNone; 156317027Sdim} 157317027Sdim 158360784Sdimstd::string NativeThreadNetBSD::GetName() { 159360784Sdim Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 160317027Sdim 161360784Sdim#ifdef PT_LWPSTATUS 162360784Sdim struct ptrace_lwpstatus info = {}; 163360784Sdim info.pl_lwpid = m_tid; 164360784Sdim Status error = NativeProcessNetBSD::PtraceWrapper( 165360784Sdim PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); 166360784Sdim if (error.Fail()) { 167360784Sdim return ""; 168360784Sdim } 169360784Sdim return info.pl_name; 170360784Sdim#else 171360784Sdim std::vector<struct kinfo_lwp> infos; 172360784Sdim int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 173360784Sdim sizeof(struct kinfo_lwp), 0}; 174360784Sdim size_t size; 175360784Sdim 176360784Sdim if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 177360784Sdim LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 178360784Sdim llvm::sys::StrError()); 179360784Sdim return ""; 180360784Sdim } 181360784Sdim 182360784Sdim mib[4] = size / sizeof(size_t); 183360784Sdim infos.resize(size / sizeof(struct kinfo_lwp)); 184360784Sdim 185360784Sdim if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 186360784Sdim LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 187360784Sdim return ""; 188360784Sdim } 189360784Sdim 190360784Sdim size_t nlwps = size / sizeof(struct kinfo_lwp); 191360784Sdim for (size_t i = 0; i < nlwps; i++) { 192360784Sdim if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 193360784Sdim return infos[i].l_name; 194360784Sdim } 195360784Sdim } 196360784Sdim 197360784Sdim LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 198360784Sdim return ""; 199360784Sdim#endif 200360784Sdim} 201360784Sdim 202317027Sdimlldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 203317027Sdim 204317027Sdimbool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 205317027Sdim std::string &description) { 206317027Sdim Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 207317027Sdim 208317027Sdim description.clear(); 209317027Sdim 210317027Sdim switch (m_state) { 211317027Sdim case eStateStopped: 212317027Sdim case eStateCrashed: 213317027Sdim case eStateExited: 214317027Sdim case eStateSuspended: 215317027Sdim case eStateUnloaded: 216317027Sdim stop_info = m_stop_info; 217317027Sdim description = m_stop_description; 218317027Sdim 219317027Sdim return true; 220317027Sdim 221317027Sdim case eStateInvalid: 222317027Sdim case eStateConnected: 223317027Sdim case eStateAttaching: 224317027Sdim case eStateLaunching: 225317027Sdim case eStateRunning: 226317027Sdim case eStateStepping: 227317027Sdim case eStateDetached: 228317027Sdim LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 229317027Sdim StateAsCString(m_state)); 230317027Sdim return false; 231317027Sdim } 232317027Sdim llvm_unreachable("unhandled StateType!"); 233317027Sdim} 234317027Sdim 235360784SdimNativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { 236327952Sdim assert(m_reg_context_up); 237360784Sdim return *m_reg_context_up; 238317027Sdim} 239317027Sdim 240318384SdimStatus NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 241318384Sdim uint32_t watch_flags, bool hardware) { 242317230Sdim if (!hardware) 243318384Sdim return Status("not implemented"); 244317230Sdim if (m_state == eStateLaunching) 245318384Sdim return Status(); 246318384Sdim Status error = RemoveWatchpoint(addr); 247317230Sdim if (error.Fail()) 248317230Sdim return error; 249327952Sdim uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 250317230Sdim if (wp_index == LLDB_INVALID_INDEX32) 251318384Sdim return Status("Setting hardware watchpoint failed."); 252317230Sdim m_watchpoint_index_map.insert({addr, wp_index}); 253318384Sdim return Status(); 254317027Sdim} 255317027Sdim 256318384SdimStatus NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 257317230Sdim auto wp = m_watchpoint_index_map.find(addr); 258317230Sdim if (wp == m_watchpoint_index_map.end()) 259318384Sdim return Status(); 260317230Sdim uint32_t wp_index = wp->second; 261317230Sdim m_watchpoint_index_map.erase(wp); 262327952Sdim if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 263318384Sdim return Status(); 264318384Sdim return Status("Clearing hardware watchpoint failed."); 265317027Sdim} 266317027Sdim 267318384SdimStatus NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 268318384Sdim size_t size) { 269317230Sdim if (m_state == eStateLaunching) 270318384Sdim return Status(); 271317230Sdim 272318384Sdim Status error = RemoveHardwareBreakpoint(addr); 273317230Sdim if (error.Fail()) 274317230Sdim return error; 275317230Sdim 276327952Sdim uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 277317230Sdim 278317230Sdim if (bp_index == LLDB_INVALID_INDEX32) 279318384Sdim return Status("Setting hardware breakpoint failed."); 280317230Sdim 281317230Sdim m_hw_break_index_map.insert({addr, bp_index}); 282318384Sdim return Status(); 283317027Sdim} 284317027Sdim 285318384SdimStatus NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 286317230Sdim auto bp = m_hw_break_index_map.find(addr); 287317230Sdim if (bp == m_hw_break_index_map.end()) 288318384Sdim return Status(); 289317230Sdim 290317230Sdim uint32_t bp_index = bp->second; 291327952Sdim if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 292317230Sdim m_hw_break_index_map.erase(bp); 293318384Sdim return Status(); 294317230Sdim } 295317230Sdim 296318384Sdim return Status("Clearing hardware breakpoint failed."); 297317027Sdim} 298360784Sdim 299360784SdimStatus NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { 300360784Sdim Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( 301360784Sdim source.GetRegisterContext()); 302360784Sdim if (!s.Fail()) { 303360784Sdim m_watchpoint_index_map = source.m_watchpoint_index_map; 304360784Sdim m_hw_break_index_map = source.m_hw_break_index_map; 305360784Sdim } 306360784Sdim return s; 307360784Sdim} 308