15ffd83dbSDimitry Andric //===-- NativeThreadNetBSD.cpp --------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "NativeThreadNetBSD.h"
100b57cec5SDimitry Andric #include "NativeRegisterContextNetBSD.h"
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "NativeProcessNetBSD.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h"
150b57cec5SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
160b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
170b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
180b57cec5SDimitry Andric #include "lldb/Utility/State.h"
19480093f4SDimitry Andric #include "llvm/Support/Errno.h"
20480093f4SDimitry Andric
21480093f4SDimitry Andric // clang-format off
22480093f4SDimitry Andric #include <sys/types.h>
23480093f4SDimitry Andric #include <sys/ptrace.h>
24480093f4SDimitry Andric // clang-format on
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric #include <sstream>
270b57cec5SDimitry Andric
28480093f4SDimitry Andric // clang-format off
29480093f4SDimitry Andric #include <sys/types.h>
30480093f4SDimitry Andric #include <sys/sysctl.h>
31480093f4SDimitry Andric // clang-format on
32480093f4SDimitry Andric
330b57cec5SDimitry Andric using namespace lldb;
340b57cec5SDimitry Andric using namespace lldb_private;
350b57cec5SDimitry Andric using namespace lldb_private::process_netbsd;
360b57cec5SDimitry Andric
NativeThreadNetBSD(NativeProcessNetBSD & process,lldb::tid_t tid)370b57cec5SDimitry Andric NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
380b57cec5SDimitry Andric lldb::tid_t tid)
390b57cec5SDimitry Andric : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
400b57cec5SDimitry Andric m_stop_info(), m_reg_context_up(
410b57cec5SDimitry Andric NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
420b57cec5SDimitry Andric ), m_stop_description() {}
430b57cec5SDimitry Andric
Resume()44480093f4SDimitry Andric Status NativeThreadNetBSD::Resume() {
45480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
46480093f4SDimitry Andric nullptr, GetID());
47480093f4SDimitry Andric if (!ret.Success())
48480093f4SDimitry Andric return ret;
49480093f4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
50480093f4SDimitry Andric nullptr, GetID());
51480093f4SDimitry Andric if (ret.Success())
52480093f4SDimitry Andric SetRunning();
53480093f4SDimitry Andric return ret;
54480093f4SDimitry Andric }
55480093f4SDimitry Andric
SingleStep()56480093f4SDimitry Andric Status NativeThreadNetBSD::SingleStep() {
57480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
58480093f4SDimitry Andric nullptr, GetID());
59480093f4SDimitry Andric if (!ret.Success())
60480093f4SDimitry Andric return ret;
61480093f4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
62480093f4SDimitry Andric nullptr, GetID());
63480093f4SDimitry Andric if (ret.Success())
64480093f4SDimitry Andric SetStepping();
65480093f4SDimitry Andric return ret;
66480093f4SDimitry Andric }
67480093f4SDimitry Andric
Suspend()68480093f4SDimitry Andric Status NativeThreadNetBSD::Suspend() {
69480093f4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
70480093f4SDimitry Andric nullptr, GetID());
71480093f4SDimitry Andric if (ret.Success())
72480093f4SDimitry Andric SetStopped();
73480093f4SDimitry Andric return ret;
74480093f4SDimitry Andric }
75480093f4SDimitry Andric
SetStoppedBySignal(uint32_t signo,const siginfo_t * info)760b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
770b57cec5SDimitry Andric const siginfo_t *info) {
7804eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
790b57cec5SDimitry Andric LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric SetStopped();
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonSignal;
8481ad6265SDimitry Andric m_stop_info.signo = signo;
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric m_stop_description.clear();
870b57cec5SDimitry Andric if (info) {
880b57cec5SDimitry Andric switch (signo) {
890b57cec5SDimitry Andric case SIGSEGV:
900b57cec5SDimitry Andric case SIGBUS:
910b57cec5SDimitry Andric case SIGFPE:
920b57cec5SDimitry Andric case SIGILL:
9306c3fb27SDimitry Andric m_stop_description = GetCrashReasonString(*info);
940b57cec5SDimitry Andric break;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric
SetStoppedByBreakpoint()990b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() {
1000b57cec5SDimitry Andric SetStopped();
1010b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonBreakpoint;
10281ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
SetStoppedByTrace()1050b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() {
1060b57cec5SDimitry Andric SetStopped();
1070b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonTrace;
10881ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
SetStoppedByExec()1110b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() {
1120b57cec5SDimitry Andric SetStopped();
1130b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonExec;
11481ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
SetStoppedByWatchpoint(uint32_t wp_index)1170b57cec5SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
1180b57cec5SDimitry Andric lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric std::ostringstream ostr;
1210b57cec5SDimitry Andric ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
1220b57cec5SDimitry Andric ostr << wp_index;
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
1250b57cec5SDimitry Andric
126e8d8bef9SDimitry Andric SetStopped();
1270b57cec5SDimitry Andric m_stop_description = ostr.str();
1280b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonWatchpoint;
12981ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)132fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
133fe6060f1SDimitry Andric lldb::tid_t child_tid) {
134fe6060f1SDimitry Andric SetStopped();
135fe6060f1SDimitry Andric
136fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonFork;
13781ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
138fe6060f1SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
139fe6060f1SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
140fe6060f1SDimitry Andric }
141fe6060f1SDimitry Andric
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143fe6060f1SDimitry Andric lldb::tid_t child_tid) {
144fe6060f1SDimitry Andric SetStopped();
145fe6060f1SDimitry Andric
146fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVFork;
14781ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
148fe6060f1SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
149fe6060f1SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
150fe6060f1SDimitry Andric }
151fe6060f1SDimitry Andric
SetStoppedByVForkDone()152fe6060f1SDimitry Andric void NativeThreadNetBSD::SetStoppedByVForkDone() {
153fe6060f1SDimitry Andric SetStopped();
154fe6060f1SDimitry Andric
155fe6060f1SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVForkDone;
15681ad6265SDimitry Andric m_stop_info.signo = SIGTRAP;
157fe6060f1SDimitry Andric }
158fe6060f1SDimitry Andric
SetStoppedWithNoReason()159480093f4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() {
160480093f4SDimitry Andric SetStopped();
161480093f4SDimitry Andric
162480093f4SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
16381ad6265SDimitry Andric m_stop_info.signo = 0;
164480093f4SDimitry Andric }
165480093f4SDimitry Andric
SetStopped()1660b57cec5SDimitry Andric void NativeThreadNetBSD::SetStopped() {
1670b57cec5SDimitry Andric const StateType new_state = StateType::eStateStopped;
1680b57cec5SDimitry Andric m_state = new_state;
1690b57cec5SDimitry Andric m_stop_description.clear();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
SetRunning()1720b57cec5SDimitry Andric void NativeThreadNetBSD::SetRunning() {
1730b57cec5SDimitry Andric m_state = StateType::eStateRunning;
1740b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
SetStepping()1770b57cec5SDimitry Andric void NativeThreadNetBSD::SetStepping() {
1780b57cec5SDimitry Andric m_state = StateType::eStateStepping;
1790b57cec5SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
GetName()182480093f4SDimitry Andric std::string NativeThreadNetBSD::GetName() {
18304eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
184480093f4SDimitry Andric
185480093f4SDimitry Andric #ifdef PT_LWPSTATUS
186480093f4SDimitry Andric struct ptrace_lwpstatus info = {};
187480093f4SDimitry Andric info.pl_lwpid = m_tid;
188480093f4SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper(
189480093f4SDimitry Andric PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
190480093f4SDimitry Andric if (error.Fail()) {
191480093f4SDimitry Andric return "";
192480093f4SDimitry Andric }
193480093f4SDimitry Andric return info.pl_name;
194480093f4SDimitry Andric #else
195480093f4SDimitry Andric std::vector<struct kinfo_lwp> infos;
196480093f4SDimitry Andric int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
197480093f4SDimitry Andric sizeof(struct kinfo_lwp), 0};
198480093f4SDimitry Andric size_t size;
199480093f4SDimitry Andric
200480093f4SDimitry Andric if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
201480093f4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
202480093f4SDimitry Andric llvm::sys::StrError());
203480093f4SDimitry Andric return "";
204480093f4SDimitry Andric }
205480093f4SDimitry Andric
206480093f4SDimitry Andric mib[4] = size / sizeof(size_t);
207480093f4SDimitry Andric infos.resize(size / sizeof(struct kinfo_lwp));
208480093f4SDimitry Andric
209480093f4SDimitry Andric if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
210480093f4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
211480093f4SDimitry Andric return "";
212480093f4SDimitry Andric }
213480093f4SDimitry Andric
214480093f4SDimitry Andric size_t nlwps = size / sizeof(struct kinfo_lwp);
215480093f4SDimitry Andric for (size_t i = 0; i < nlwps; i++) {
216480093f4SDimitry Andric if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
217480093f4SDimitry Andric return infos[i].l_name;
218480093f4SDimitry Andric }
219480093f4SDimitry Andric }
220480093f4SDimitry Andric
221480093f4SDimitry Andric LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
222480093f4SDimitry Andric return "";
223480093f4SDimitry Andric #endif
224480093f4SDimitry Andric }
2250b57cec5SDimitry Andric
GetState()2260b57cec5SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
2270b57cec5SDimitry Andric
GetStopReason(ThreadStopInfo & stop_info,std::string & description)2280b57cec5SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
2290b57cec5SDimitry Andric std::string &description) {
23004eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
2310b57cec5SDimitry Andric description.clear();
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric switch (m_state) {
2340b57cec5SDimitry Andric case eStateStopped:
2350b57cec5SDimitry Andric case eStateCrashed:
2360b57cec5SDimitry Andric case eStateExited:
2370b57cec5SDimitry Andric case eStateSuspended:
2380b57cec5SDimitry Andric case eStateUnloaded:
2390b57cec5SDimitry Andric stop_info = m_stop_info;
2400b57cec5SDimitry Andric description = m_stop_description;
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric return true;
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric case eStateInvalid:
2450b57cec5SDimitry Andric case eStateConnected:
2460b57cec5SDimitry Andric case eStateAttaching:
2470b57cec5SDimitry Andric case eStateLaunching:
2480b57cec5SDimitry Andric case eStateRunning:
2490b57cec5SDimitry Andric case eStateStepping:
2500b57cec5SDimitry Andric case eStateDetached:
2510b57cec5SDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
2520b57cec5SDimitry Andric StateAsCString(m_state));
2530b57cec5SDimitry Andric return false;
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric llvm_unreachable("unhandled StateType!");
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric
GetRegisterContext()258480093f4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
2590b57cec5SDimitry Andric assert(m_reg_context_up);
2600b57cec5SDimitry Andric return *m_reg_context_up;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)2630b57cec5SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
2640b57cec5SDimitry Andric uint32_t watch_flags, bool hardware) {
265e8d8bef9SDimitry Andric assert(m_state == eStateStopped);
2660b57cec5SDimitry Andric if (!hardware)
2670b57cec5SDimitry Andric return Status("not implemented");
2680b57cec5SDimitry Andric Status error = RemoveWatchpoint(addr);
2690b57cec5SDimitry Andric if (error.Fail())
2700b57cec5SDimitry Andric return error;
271e8d8bef9SDimitry Andric uint32_t wp_index =
272e8d8bef9SDimitry Andric GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
2730b57cec5SDimitry Andric if (wp_index == LLDB_INVALID_INDEX32)
2740b57cec5SDimitry Andric return Status("Setting hardware watchpoint failed.");
2750b57cec5SDimitry Andric m_watchpoint_index_map.insert({addr, wp_index});
2760b57cec5SDimitry Andric return Status();
2770b57cec5SDimitry Andric }
2780b57cec5SDimitry Andric
RemoveWatchpoint(lldb::addr_t addr)2790b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
2800b57cec5SDimitry Andric auto wp = m_watchpoint_index_map.find(addr);
2810b57cec5SDimitry Andric if (wp == m_watchpoint_index_map.end())
2820b57cec5SDimitry Andric return Status();
2830b57cec5SDimitry Andric uint32_t wp_index = wp->second;
2840b57cec5SDimitry Andric m_watchpoint_index_map.erase(wp);
2850b57cec5SDimitry Andric if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
2860b57cec5SDimitry Andric return Status();
2870b57cec5SDimitry Andric return Status("Clearing hardware watchpoint failed.");
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)2900b57cec5SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
2910b57cec5SDimitry Andric size_t size) {
292e8d8bef9SDimitry Andric assert(m_state == eStateStopped);
2930b57cec5SDimitry Andric Status error = RemoveHardwareBreakpoint(addr);
2940b57cec5SDimitry Andric if (error.Fail())
2950b57cec5SDimitry Andric return error;
2960b57cec5SDimitry Andric
2970b57cec5SDimitry Andric uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
2980b57cec5SDimitry Andric
2990b57cec5SDimitry Andric if (bp_index == LLDB_INVALID_INDEX32)
3000b57cec5SDimitry Andric return Status("Setting hardware breakpoint failed.");
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric m_hw_break_index_map.insert({addr, bp_index});
3030b57cec5SDimitry Andric return Status();
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric
RemoveHardwareBreakpoint(lldb::addr_t addr)3060b57cec5SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
3070b57cec5SDimitry Andric auto bp = m_hw_break_index_map.find(addr);
3080b57cec5SDimitry Andric if (bp == m_hw_break_index_map.end())
3090b57cec5SDimitry Andric return Status();
3100b57cec5SDimitry Andric
3110b57cec5SDimitry Andric uint32_t bp_index = bp->second;
3120b57cec5SDimitry Andric if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
3130b57cec5SDimitry Andric m_hw_break_index_map.erase(bp);
3140b57cec5SDimitry Andric return Status();
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric
3170b57cec5SDimitry Andric return Status("Clearing hardware breakpoint failed.");
3180b57cec5SDimitry Andric }
319480093f4SDimitry Andric
320e8d8bef9SDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadNetBSD & source)321e8d8bef9SDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
322e8d8bef9SDimitry Andric llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
323480093f4SDimitry Andric source.GetRegisterContext());
324e8d8bef9SDimitry Andric if (!s) {
325480093f4SDimitry Andric m_watchpoint_index_map = source.m_watchpoint_index_map;
326480093f4SDimitry Andric m_hw_break_index_map = source.m_hw_break_index_map;
327480093f4SDimitry Andric }
328480093f4SDimitry Andric return s;
329480093f4SDimitry Andric }
330