1 //===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===// 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 #include <sstream> 22 23 // clang-format off 24 #include <sys/types.h> 25 #include <sys/sysctl.h> 26 // clang-format on 27 28 using namespace lldb; 29 using namespace lldb_private; 30 using namespace lldb_private::process_netbsd; 31 32 NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, 33 lldb::tid_t tid) 34 : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), 35 m_stop_info(), m_reg_context_up( 36 NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) 37 ), m_stop_description() {} 38 39 void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, 40 const siginfo_t *info) { 41 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 42 LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); 43 44 SetStopped(); 45 46 m_stop_info.reason = StopReason::eStopReasonSignal; 47 m_stop_info.details.signal.signo = signo; 48 49 m_stop_description.clear(); 50 if (info) { 51 switch (signo) { 52 case SIGSEGV: 53 case SIGBUS: 54 case SIGFPE: 55 case SIGILL: 56 const auto reason = GetCrashReason(*info); 57 m_stop_description = GetCrashReasonString(reason, *info); 58 break; 59 } 60 } 61 } 62 63 void NativeThreadNetBSD::SetStoppedByBreakpoint() { 64 SetStopped(); 65 m_stop_info.reason = StopReason::eStopReasonBreakpoint; 66 m_stop_info.details.signal.signo = SIGTRAP; 67 } 68 69 void NativeThreadNetBSD::SetStoppedByTrace() { 70 SetStopped(); 71 m_stop_info.reason = StopReason::eStopReasonTrace; 72 m_stop_info.details.signal.signo = SIGTRAP; 73 } 74 75 void NativeThreadNetBSD::SetStoppedByExec() { 76 SetStopped(); 77 m_stop_info.reason = StopReason::eStopReasonExec; 78 m_stop_info.details.signal.signo = SIGTRAP; 79 } 80 81 void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { 82 SetStopped(); 83 84 lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); 85 86 std::ostringstream ostr; 87 ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; 88 ostr << wp_index; 89 90 ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); 91 92 m_stop_description = ostr.str(); 93 94 m_stop_info.reason = StopReason::eStopReasonWatchpoint; 95 m_stop_info.details.signal.signo = SIGTRAP; 96 } 97 98 void NativeThreadNetBSD::SetStopped() { 99 const StateType new_state = StateType::eStateStopped; 100 m_state = new_state; 101 m_stop_description.clear(); 102 } 103 104 void NativeThreadNetBSD::SetRunning() { 105 m_state = StateType::eStateRunning; 106 m_stop_info.reason = StopReason::eStopReasonNone; 107 } 108 109 void NativeThreadNetBSD::SetStepping() { 110 m_state = StateType::eStateStepping; 111 m_stop_info.reason = StopReason::eStopReasonNone; 112 } 113 114 std::string NativeThreadNetBSD::GetName() { 115 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 116 117 std::vector<struct kinfo_lwp> infos; 118 int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), 119 sizeof(struct kinfo_lwp), 0}; 120 size_t size; 121 122 if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { 123 LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", 124 llvm::sys::StrError()); 125 return ""; 126 } 127 128 mib[4] = size / sizeof(size_t); 129 infos.resize(size / sizeof(struct kinfo_lwp)); 130 131 if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { 132 LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); 133 return ""; 134 } 135 136 size_t nlwps = size / sizeof(struct kinfo_lwp); 137 for (size_t i = 0; i < nlwps; i++) { 138 if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { 139 return infos[i].l_name; 140 } 141 } 142 143 LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); 144 return ""; 145 } 146 147 lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } 148 149 bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, 150 std::string &description) { 151 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 152 153 description.clear(); 154 155 switch (m_state) { 156 case eStateStopped: 157 case eStateCrashed: 158 case eStateExited: 159 case eStateSuspended: 160 case eStateUnloaded: 161 stop_info = m_stop_info; 162 description = m_stop_description; 163 164 return true; 165 166 case eStateInvalid: 167 case eStateConnected: 168 case eStateAttaching: 169 case eStateLaunching: 170 case eStateRunning: 171 case eStateStepping: 172 case eStateDetached: 173 LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), 174 StateAsCString(m_state)); 175 return false; 176 } 177 llvm_unreachable("unhandled StateType!"); 178 } 179 180 NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() { 181 assert(m_reg_context_up); 182 return *m_reg_context_up; 183 } 184 185 Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, 186 uint32_t watch_flags, bool hardware) { 187 if (!hardware) 188 return Status("not implemented"); 189 if (m_state == eStateLaunching) 190 return Status(); 191 Status error = RemoveWatchpoint(addr); 192 if (error.Fail()) 193 return error; 194 uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); 195 if (wp_index == LLDB_INVALID_INDEX32) 196 return Status("Setting hardware watchpoint failed."); 197 m_watchpoint_index_map.insert({addr, wp_index}); 198 return Status(); 199 } 200 201 Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { 202 auto wp = m_watchpoint_index_map.find(addr); 203 if (wp == m_watchpoint_index_map.end()) 204 return Status(); 205 uint32_t wp_index = wp->second; 206 m_watchpoint_index_map.erase(wp); 207 if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) 208 return Status(); 209 return Status("Clearing hardware watchpoint failed."); 210 } 211 212 Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, 213 size_t size) { 214 if (m_state == eStateLaunching) 215 return Status(); 216 217 Status error = RemoveHardwareBreakpoint(addr); 218 if (error.Fail()) 219 return error; 220 221 uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); 222 223 if (bp_index == LLDB_INVALID_INDEX32) 224 return Status("Setting hardware breakpoint failed."); 225 226 m_hw_break_index_map.insert({addr, bp_index}); 227 return Status(); 228 } 229 230 Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { 231 auto bp = m_hw_break_index_map.find(addr); 232 if (bp == m_hw_break_index_map.end()) 233 return Status(); 234 235 uint32_t bp_index = bp->second; 236 if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { 237 m_hw_break_index_map.erase(bp); 238 return Status(); 239 } 240 241 return Status("Clearing hardware breakpoint failed."); 242 } 243