1cfca06d7SDimitry Andric //===-- NativeThreadNetBSD.cpp --------------------------------------------===//
274a628f7SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674a628f7SDimitry Andric //
774a628f7SDimitry Andric //===----------------------------------------------------------------------===//
874a628f7SDimitry Andric
974a628f7SDimitry Andric #include "NativeThreadNetBSD.h"
1074a628f7SDimitry Andric #include "NativeRegisterContextNetBSD.h"
1174a628f7SDimitry Andric
1274a628f7SDimitry Andric #include "NativeProcessNetBSD.h"
1374a628f7SDimitry Andric
1474a628f7SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h"
1574a628f7SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16d44a35e8SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
1794994d37SDimitry Andric #include "lldb/Utility/RegisterValue.h"
1894994d37SDimitry Andric #include "lldb/Utility/State.h"
19706b4fc4SDimitry Andric #include "llvm/Support/Errno.h"
20706b4fc4SDimitry Andric
21706b4fc4SDimitry Andric // clang-format off
22706b4fc4SDimitry Andric #include <sys/types.h>
23706b4fc4SDimitry Andric #include <sys/ptrace.h>
24706b4fc4SDimitry Andric // clang-format on
25d44a35e8SDimitry Andric
26d44a35e8SDimitry Andric #include <sstream>
2774a628f7SDimitry Andric
28706b4fc4SDimitry Andric // clang-format off
29706b4fc4SDimitry Andric #include <sys/types.h>
30706b4fc4SDimitry Andric #include <sys/sysctl.h>
31706b4fc4SDimitry Andric // clang-format on
32706b4fc4SDimitry Andric
3374a628f7SDimitry Andric using namespace lldb;
3474a628f7SDimitry Andric using namespace lldb_private;
3574a628f7SDimitry Andric using namespace lldb_private::process_netbsd;
3674a628f7SDimitry Andric
NativeThreadNetBSD(NativeProcessNetBSD & process,lldb::tid_t tid)37a884e649SDimitry Andric NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
3874a628f7SDimitry Andric lldb::tid_t tid)
3974a628f7SDimitry Andric : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
40ef5d0b5eSDimitry Andric m_stop_info(), m_reg_context_up(
41ef5d0b5eSDimitry Andric NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
42ef5d0b5eSDimitry Andric ), m_stop_description() {}
4374a628f7SDimitry Andric
Resume()44706b4fc4SDimitry Andric Status NativeThreadNetBSD::Resume() {
45706b4fc4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
46706b4fc4SDimitry Andric nullptr, GetID());
47706b4fc4SDimitry Andric if (!ret.Success())
48706b4fc4SDimitry Andric return ret;
49706b4fc4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
50706b4fc4SDimitry Andric nullptr, GetID());
51706b4fc4SDimitry Andric if (ret.Success())
52706b4fc4SDimitry Andric SetRunning();
53706b4fc4SDimitry Andric return ret;
54706b4fc4SDimitry Andric }
55706b4fc4SDimitry Andric
SingleStep()56706b4fc4SDimitry Andric Status NativeThreadNetBSD::SingleStep() {
57706b4fc4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
58706b4fc4SDimitry Andric nullptr, GetID());
59706b4fc4SDimitry Andric if (!ret.Success())
60706b4fc4SDimitry Andric return ret;
61706b4fc4SDimitry Andric ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
62706b4fc4SDimitry Andric nullptr, GetID());
63706b4fc4SDimitry Andric if (ret.Success())
64706b4fc4SDimitry Andric SetStepping();
65706b4fc4SDimitry Andric return ret;
66706b4fc4SDimitry Andric }
67706b4fc4SDimitry Andric
Suspend()68706b4fc4SDimitry Andric Status NativeThreadNetBSD::Suspend() {
69706b4fc4SDimitry Andric Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
70706b4fc4SDimitry Andric nullptr, GetID());
71706b4fc4SDimitry Andric if (ret.Success())
72706b4fc4SDimitry Andric SetStopped();
73706b4fc4SDimitry Andric return ret;
74706b4fc4SDimitry Andric }
75706b4fc4SDimitry Andric
SetStoppedBySignal(uint32_t signo,const siginfo_t * info)7674a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
7774a628f7SDimitry Andric const siginfo_t *info) {
786f8fc217SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
7974a628f7SDimitry Andric LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
8074a628f7SDimitry Andric
8174a628f7SDimitry Andric SetStopped();
8274a628f7SDimitry Andric
8374a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonSignal;
84145449b1SDimitry Andric m_stop_info.signo = signo;
8574a628f7SDimitry Andric
8674a628f7SDimitry Andric m_stop_description.clear();
8774a628f7SDimitry Andric if (info) {
8874a628f7SDimitry Andric switch (signo) {
8974a628f7SDimitry Andric case SIGSEGV:
9074a628f7SDimitry Andric case SIGBUS:
9174a628f7SDimitry Andric case SIGFPE:
9274a628f7SDimitry Andric case SIGILL:
937fa27ce4SDimitry Andric m_stop_description = GetCrashReasonString(*info);
9474a628f7SDimitry Andric break;
9574a628f7SDimitry Andric }
9674a628f7SDimitry Andric }
9774a628f7SDimitry Andric }
9874a628f7SDimitry Andric
SetStoppedByBreakpoint()9974a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByBreakpoint() {
10074a628f7SDimitry Andric SetStopped();
10174a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonBreakpoint;
102145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
10374a628f7SDimitry Andric }
10474a628f7SDimitry Andric
SetStoppedByTrace()10574a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByTrace() {
10674a628f7SDimitry Andric SetStopped();
10774a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonTrace;
108145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
10974a628f7SDimitry Andric }
11074a628f7SDimitry Andric
SetStoppedByExec()11174a628f7SDimitry Andric void NativeThreadNetBSD::SetStoppedByExec() {
11274a628f7SDimitry Andric SetStopped();
11374a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonExec;
114145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
11574a628f7SDimitry Andric }
11674a628f7SDimitry Andric
SetStoppedByWatchpoint(uint32_t wp_index)117d44a35e8SDimitry Andric void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
118d44a35e8SDimitry Andric lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
119d44a35e8SDimitry Andric
120d44a35e8SDimitry Andric std::ostringstream ostr;
121ef5d0b5eSDimitry Andric ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
122d44a35e8SDimitry Andric ostr << wp_index;
123d44a35e8SDimitry Andric
124ef5d0b5eSDimitry Andric ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
125d44a35e8SDimitry Andric
126b60736ecSDimitry Andric SetStopped();
127d44a35e8SDimitry Andric m_stop_description = ostr.str();
128d44a35e8SDimitry Andric m_stop_info.reason = StopReason::eStopReasonWatchpoint;
129145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
130d44a35e8SDimitry Andric }
131d44a35e8SDimitry Andric
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)132344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
133344a3780SDimitry Andric lldb::tid_t child_tid) {
134344a3780SDimitry Andric SetStopped();
135344a3780SDimitry Andric
136344a3780SDimitry Andric m_stop_info.reason = StopReason::eStopReasonFork;
137145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
138344a3780SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
139344a3780SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
140344a3780SDimitry Andric }
141344a3780SDimitry Andric
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143344a3780SDimitry Andric lldb::tid_t child_tid) {
144344a3780SDimitry Andric SetStopped();
145344a3780SDimitry Andric
146344a3780SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVFork;
147145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
148344a3780SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
149344a3780SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
150344a3780SDimitry Andric }
151344a3780SDimitry Andric
SetStoppedByVForkDone()152344a3780SDimitry Andric void NativeThreadNetBSD::SetStoppedByVForkDone() {
153344a3780SDimitry Andric SetStopped();
154344a3780SDimitry Andric
155344a3780SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVForkDone;
156145449b1SDimitry Andric m_stop_info.signo = SIGTRAP;
157344a3780SDimitry Andric }
158344a3780SDimitry Andric
SetStoppedWithNoReason()159706b4fc4SDimitry Andric void NativeThreadNetBSD::SetStoppedWithNoReason() {
160706b4fc4SDimitry Andric SetStopped();
161706b4fc4SDimitry Andric
162706b4fc4SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
163145449b1SDimitry Andric m_stop_info.signo = 0;
164706b4fc4SDimitry Andric }
165706b4fc4SDimitry Andric
SetStopped()16674a628f7SDimitry Andric void NativeThreadNetBSD::SetStopped() {
16774a628f7SDimitry Andric const StateType new_state = StateType::eStateStopped;
16874a628f7SDimitry Andric m_state = new_state;
16974a628f7SDimitry Andric m_stop_description.clear();
17074a628f7SDimitry Andric }
17174a628f7SDimitry Andric
SetRunning()17274a628f7SDimitry Andric void NativeThreadNetBSD::SetRunning() {
17374a628f7SDimitry Andric m_state = StateType::eStateRunning;
17474a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
17574a628f7SDimitry Andric }
17674a628f7SDimitry Andric
SetStepping()17774a628f7SDimitry Andric void NativeThreadNetBSD::SetStepping() {
17874a628f7SDimitry Andric m_state = StateType::eStateStepping;
17974a628f7SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
18074a628f7SDimitry Andric }
18174a628f7SDimitry Andric
GetName()182706b4fc4SDimitry Andric std::string NativeThreadNetBSD::GetName() {
183706b4fc4SDimitry Andric #ifdef PT_LWPSTATUS
184706b4fc4SDimitry Andric struct ptrace_lwpstatus info = {};
185706b4fc4SDimitry Andric info.pl_lwpid = m_tid;
186706b4fc4SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper(
187706b4fc4SDimitry Andric PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
188706b4fc4SDimitry Andric if (error.Fail()) {
189706b4fc4SDimitry Andric return "";
190706b4fc4SDimitry Andric }
191706b4fc4SDimitry Andric return info.pl_name;
192706b4fc4SDimitry Andric #else
193706b4fc4SDimitry Andric std::vector<struct kinfo_lwp> infos;
194ac9a064cSDimitry Andric Log *log = GetLog(POSIXLog::Thread);
195ac9a064cSDimitry Andric
196706b4fc4SDimitry Andric int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
197706b4fc4SDimitry Andric sizeof(struct kinfo_lwp), 0};
198706b4fc4SDimitry Andric size_t size;
199706b4fc4SDimitry Andric
200706b4fc4SDimitry Andric if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
201706b4fc4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
202706b4fc4SDimitry Andric llvm::sys::StrError());
203706b4fc4SDimitry Andric return "";
204706b4fc4SDimitry Andric }
205706b4fc4SDimitry Andric
206706b4fc4SDimitry Andric mib[4] = size / sizeof(size_t);
207706b4fc4SDimitry Andric infos.resize(size / sizeof(struct kinfo_lwp));
208706b4fc4SDimitry Andric
209706b4fc4SDimitry Andric if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
210706b4fc4SDimitry Andric LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
211706b4fc4SDimitry Andric return "";
212706b4fc4SDimitry Andric }
213706b4fc4SDimitry Andric
214706b4fc4SDimitry Andric size_t nlwps = size / sizeof(struct kinfo_lwp);
215706b4fc4SDimitry Andric for (size_t i = 0; i < nlwps; i++) {
216706b4fc4SDimitry Andric if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
217706b4fc4SDimitry Andric return infos[i].l_name;
218706b4fc4SDimitry Andric }
219706b4fc4SDimitry Andric }
220706b4fc4SDimitry Andric
221706b4fc4SDimitry Andric LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
222706b4fc4SDimitry Andric return "";
223706b4fc4SDimitry Andric #endif
224706b4fc4SDimitry Andric }
22574a628f7SDimitry Andric
GetState()22674a628f7SDimitry Andric lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
22774a628f7SDimitry Andric
GetStopReason(ThreadStopInfo & stop_info,std::string & description)22874a628f7SDimitry Andric bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
22974a628f7SDimitry Andric std::string &description) {
2306f8fc217SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
23174a628f7SDimitry Andric description.clear();
23274a628f7SDimitry Andric
23374a628f7SDimitry Andric switch (m_state) {
23474a628f7SDimitry Andric case eStateStopped:
23574a628f7SDimitry Andric case eStateCrashed:
23674a628f7SDimitry Andric case eStateExited:
23774a628f7SDimitry Andric case eStateSuspended:
23874a628f7SDimitry Andric case eStateUnloaded:
23974a628f7SDimitry Andric stop_info = m_stop_info;
24074a628f7SDimitry Andric description = m_stop_description;
24174a628f7SDimitry Andric
24274a628f7SDimitry Andric return true;
24374a628f7SDimitry Andric
24474a628f7SDimitry Andric case eStateInvalid:
24574a628f7SDimitry Andric case eStateConnected:
24674a628f7SDimitry Andric case eStateAttaching:
24774a628f7SDimitry Andric case eStateLaunching:
24874a628f7SDimitry Andric case eStateRunning:
24974a628f7SDimitry Andric case eStateStepping:
25074a628f7SDimitry Andric case eStateDetached:
25174a628f7SDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
25274a628f7SDimitry Andric StateAsCString(m_state));
25374a628f7SDimitry Andric return false;
25474a628f7SDimitry Andric }
25574a628f7SDimitry Andric llvm_unreachable("unhandled StateType!");
25674a628f7SDimitry Andric }
25774a628f7SDimitry Andric
GetRegisterContext()258706b4fc4SDimitry Andric NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
259ef5d0b5eSDimitry Andric assert(m_reg_context_up);
260ef5d0b5eSDimitry Andric return *m_reg_context_up;
26174a628f7SDimitry Andric }
26274a628f7SDimitry Andric
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)263b76161e4SDimitry Andric Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
26474a628f7SDimitry Andric uint32_t watch_flags, bool hardware) {
265b60736ecSDimitry Andric assert(m_state == eStateStopped);
266d44a35e8SDimitry Andric if (!hardware)
267b76161e4SDimitry Andric return Status("not implemented");
268b76161e4SDimitry Andric Status error = RemoveWatchpoint(addr);
269d44a35e8SDimitry Andric if (error.Fail())
270d44a35e8SDimitry Andric return error;
271b60736ecSDimitry Andric uint32_t wp_index =
272b60736ecSDimitry Andric GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
273d44a35e8SDimitry Andric if (wp_index == LLDB_INVALID_INDEX32)
274b76161e4SDimitry Andric return Status("Setting hardware watchpoint failed.");
275d44a35e8SDimitry Andric m_watchpoint_index_map.insert({addr, wp_index});
276b76161e4SDimitry Andric return Status();
27774a628f7SDimitry Andric }
27874a628f7SDimitry Andric
RemoveWatchpoint(lldb::addr_t addr)279b76161e4SDimitry Andric Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
280d44a35e8SDimitry Andric auto wp = m_watchpoint_index_map.find(addr);
281d44a35e8SDimitry Andric if (wp == m_watchpoint_index_map.end())
282b76161e4SDimitry Andric return Status();
283d44a35e8SDimitry Andric uint32_t wp_index = wp->second;
284d44a35e8SDimitry Andric m_watchpoint_index_map.erase(wp);
285ef5d0b5eSDimitry Andric if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
286b76161e4SDimitry Andric return Status();
287b76161e4SDimitry Andric return Status("Clearing hardware watchpoint failed.");
28874a628f7SDimitry Andric }
28974a628f7SDimitry Andric
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)290b76161e4SDimitry Andric Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
29174a628f7SDimitry Andric size_t size) {
292b60736ecSDimitry Andric assert(m_state == eStateStopped);
293b76161e4SDimitry Andric Status error = RemoveHardwareBreakpoint(addr);
294d44a35e8SDimitry Andric if (error.Fail())
295d44a35e8SDimitry Andric return error;
296d44a35e8SDimitry Andric
297ef5d0b5eSDimitry Andric uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
298d44a35e8SDimitry Andric
299d44a35e8SDimitry Andric if (bp_index == LLDB_INVALID_INDEX32)
300b76161e4SDimitry Andric return Status("Setting hardware breakpoint failed.");
301d44a35e8SDimitry Andric
302d44a35e8SDimitry Andric m_hw_break_index_map.insert({addr, bp_index});
303b76161e4SDimitry Andric return Status();
30474a628f7SDimitry Andric }
30574a628f7SDimitry Andric
RemoveHardwareBreakpoint(lldb::addr_t addr)306b76161e4SDimitry Andric Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
307d44a35e8SDimitry Andric auto bp = m_hw_break_index_map.find(addr);
308d44a35e8SDimitry Andric if (bp == m_hw_break_index_map.end())
309b76161e4SDimitry Andric return Status();
310d44a35e8SDimitry Andric
311d44a35e8SDimitry Andric uint32_t bp_index = bp->second;
312ef5d0b5eSDimitry Andric if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
313d44a35e8SDimitry Andric m_hw_break_index_map.erase(bp);
314b76161e4SDimitry Andric return Status();
315d44a35e8SDimitry Andric }
316d44a35e8SDimitry Andric
317b76161e4SDimitry Andric return Status("Clearing hardware breakpoint failed.");
31874a628f7SDimitry Andric }
319706b4fc4SDimitry Andric
320b60736ecSDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadNetBSD & source)321b60736ecSDimitry Andric NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
322b60736ecSDimitry Andric llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
323706b4fc4SDimitry Andric source.GetRegisterContext());
324b60736ecSDimitry Andric if (!s) {
325706b4fc4SDimitry Andric m_watchpoint_index_map = source.m_watchpoint_index_map;
326706b4fc4SDimitry Andric m_hw_break_index_map = source.m_hw_break_index_map;
327706b4fc4SDimitry Andric }
328706b4fc4SDimitry Andric return s;
329706b4fc4SDimitry Andric }
330