1af732203SDimitry Andric //===-- NativeThreadFreeBSD.cpp -------------------------------------------===//
2af732203SDimitry Andric //
3af732203SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af732203SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5af732203SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af732203SDimitry Andric //
7af732203SDimitry Andric //===----------------------------------------------------------------------===//
8af732203SDimitry Andric
9af732203SDimitry Andric #include "NativeThreadFreeBSD.h"
10af732203SDimitry Andric #include "NativeRegisterContextFreeBSD.h"
11af732203SDimitry Andric
12af732203SDimitry Andric #include "NativeProcessFreeBSD.h"
13af732203SDimitry Andric
14af732203SDimitry Andric #include "Plugins/Process/POSIX/CrashReason.h"
15af732203SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16af732203SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
17af732203SDimitry Andric #include "lldb/Utility/RegisterValue.h"
18af732203SDimitry Andric #include "lldb/Utility/State.h"
19af732203SDimitry Andric #include "llvm/Support/Errno.h"
20af732203SDimitry Andric
21af732203SDimitry Andric // clang-format off
22af732203SDimitry Andric #include <sys/types.h>
23af732203SDimitry Andric #include <sys/ptrace.h>
24af732203SDimitry Andric #include <sys/sysctl.h>
25af732203SDimitry Andric #include <sys/user.h>
26af732203SDimitry Andric // clang-format on
27af732203SDimitry Andric
28af732203SDimitry Andric #include <sstream>
29af732203SDimitry Andric #include <vector>
30af732203SDimitry Andric
31af732203SDimitry Andric using namespace lldb;
32af732203SDimitry Andric using namespace lldb_private;
33af732203SDimitry Andric using namespace lldb_private::process_freebsd;
34af732203SDimitry Andric
NativeThreadFreeBSD(NativeProcessFreeBSD & process,lldb::tid_t tid)35af732203SDimitry Andric NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
36af732203SDimitry Andric lldb::tid_t tid)
37af732203SDimitry Andric : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
38af732203SDimitry Andric m_stop_info(),
39af732203SDimitry Andric m_reg_context_up(
40af732203SDimitry Andric NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
41af732203SDimitry Andric process.GetArchitecture(), *this)),
42af732203SDimitry Andric m_stop_description() {}
43af732203SDimitry Andric
Resume()44af732203SDimitry Andric Status NativeThreadFreeBSD::Resume() {
45af732203SDimitry Andric Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
46af732203SDimitry Andric if (!ret.Success())
47af732203SDimitry Andric return ret;
48af732203SDimitry Andric ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
49af732203SDimitry Andric // we can get EINVAL if the architecture in question does not support
50af732203SDimitry Andric // hardware single-stepping -- that's fine, we have nothing to clear
51af732203SDimitry Andric // then
52af732203SDimitry Andric if (ret.GetError() == EINVAL)
53af732203SDimitry Andric ret.Clear();
54af732203SDimitry Andric if (ret.Success())
55af732203SDimitry Andric SetRunning();
56af732203SDimitry Andric return ret;
57af732203SDimitry Andric }
58af732203SDimitry Andric
SingleStep()59af732203SDimitry Andric Status NativeThreadFreeBSD::SingleStep() {
60af732203SDimitry Andric Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
61af732203SDimitry Andric if (!ret.Success())
62af732203SDimitry Andric return ret;
63af732203SDimitry Andric ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());
64af732203SDimitry Andric if (ret.Success())
65af732203SDimitry Andric SetStepping();
66af732203SDimitry Andric return ret;
67af732203SDimitry Andric }
68af732203SDimitry Andric
Suspend()69af732203SDimitry Andric Status NativeThreadFreeBSD::Suspend() {
70af732203SDimitry Andric Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());
71af732203SDimitry Andric if (ret.Success())
72af732203SDimitry Andric SetStopped();
73af732203SDimitry Andric return ret;
74af732203SDimitry Andric }
75af732203SDimitry Andric
SetStoppedBySignal(uint32_t signo,const siginfo_t * info)76af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo,
77af732203SDimitry Andric const siginfo_t *info) {
78af732203SDimitry Andric Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
79af732203SDimitry Andric LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
80af732203SDimitry Andric
81af732203SDimitry Andric SetStopped();
82af732203SDimitry Andric
83af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonSignal;
84af732203SDimitry Andric m_stop_info.details.signal.signo = signo;
85af732203SDimitry Andric
86af732203SDimitry Andric m_stop_description.clear();
87af732203SDimitry Andric if (info) {
88af732203SDimitry Andric switch (signo) {
89af732203SDimitry Andric case SIGSEGV:
90af732203SDimitry Andric case SIGBUS:
91af732203SDimitry Andric case SIGFPE:
92af732203SDimitry Andric case SIGILL:
93af732203SDimitry Andric const auto reason = GetCrashReason(*info);
94af732203SDimitry Andric m_stop_description = GetCrashReasonString(reason, *info);
95af732203SDimitry Andric break;
96af732203SDimitry Andric }
97af732203SDimitry Andric }
98af732203SDimitry Andric }
99af732203SDimitry Andric
SetStoppedByBreakpoint()100af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedByBreakpoint() {
101af732203SDimitry Andric SetStopped();
102af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonBreakpoint;
103af732203SDimitry Andric m_stop_info.details.signal.signo = SIGTRAP;
104af732203SDimitry Andric }
105af732203SDimitry Andric
SetStoppedByTrace()106af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedByTrace() {
107af732203SDimitry Andric SetStopped();
108af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonTrace;
109af732203SDimitry Andric m_stop_info.details.signal.signo = SIGTRAP;
110af732203SDimitry Andric }
111af732203SDimitry Andric
SetStoppedByExec()112af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedByExec() {
113af732203SDimitry Andric SetStopped();
114af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonExec;
115af732203SDimitry Andric m_stop_info.details.signal.signo = SIGTRAP;
116af732203SDimitry Andric }
117af732203SDimitry Andric
SetStoppedByWatchpoint(uint32_t wp_index)118af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
119af732203SDimitry Andric lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
120af732203SDimitry Andric
121af732203SDimitry Andric std::ostringstream ostr;
122af732203SDimitry Andric ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
123af732203SDimitry Andric ostr << wp_index;
124af732203SDimitry Andric
125af732203SDimitry Andric ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
126af732203SDimitry Andric
127af732203SDimitry Andric SetStopped();
128af732203SDimitry Andric m_stop_description = ostr.str();
129af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonWatchpoint;
130af732203SDimitry Andric m_stop_info.details.signal.signo = SIGTRAP;
131af732203SDimitry Andric }
132af732203SDimitry Andric
SetStoppedByFork(lldb::pid_t child_pid,lldb::tid_t child_tid)133*5f7ddb14SDimitry Andric void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid,
134*5f7ddb14SDimitry Andric lldb::tid_t child_tid) {
135*5f7ddb14SDimitry Andric SetStopped();
136*5f7ddb14SDimitry Andric
137*5f7ddb14SDimitry Andric m_stop_info.reason = StopReason::eStopReasonFork;
138*5f7ddb14SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
139*5f7ddb14SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
140*5f7ddb14SDimitry Andric }
141*5f7ddb14SDimitry Andric
SetStoppedByVFork(lldb::pid_t child_pid,lldb::tid_t child_tid)142*5f7ddb14SDimitry Andric void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid,
143*5f7ddb14SDimitry Andric lldb::tid_t child_tid) {
144*5f7ddb14SDimitry Andric SetStopped();
145*5f7ddb14SDimitry Andric
146*5f7ddb14SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVFork;
147*5f7ddb14SDimitry Andric m_stop_info.details.fork.child_pid = child_pid;
148*5f7ddb14SDimitry Andric m_stop_info.details.fork.child_tid = child_tid;
149*5f7ddb14SDimitry Andric }
150*5f7ddb14SDimitry Andric
SetStoppedByVForkDone()151*5f7ddb14SDimitry Andric void NativeThreadFreeBSD::SetStoppedByVForkDone() {
152*5f7ddb14SDimitry Andric SetStopped();
153*5f7ddb14SDimitry Andric
154*5f7ddb14SDimitry Andric m_stop_info.reason = StopReason::eStopReasonVForkDone;
155*5f7ddb14SDimitry Andric }
156*5f7ddb14SDimitry Andric
SetStoppedWithNoReason()157af732203SDimitry Andric void NativeThreadFreeBSD::SetStoppedWithNoReason() {
158af732203SDimitry Andric SetStopped();
159af732203SDimitry Andric
160af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
161af732203SDimitry Andric m_stop_info.details.signal.signo = 0;
162af732203SDimitry Andric }
163af732203SDimitry Andric
SetStopped()164af732203SDimitry Andric void NativeThreadFreeBSD::SetStopped() {
165af732203SDimitry Andric const StateType new_state = StateType::eStateStopped;
166af732203SDimitry Andric m_state = new_state;
167af732203SDimitry Andric m_stop_description.clear();
168af732203SDimitry Andric }
169af732203SDimitry Andric
SetRunning()170af732203SDimitry Andric void NativeThreadFreeBSD::SetRunning() {
171af732203SDimitry Andric m_state = StateType::eStateRunning;
172af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
173af732203SDimitry Andric }
174af732203SDimitry Andric
SetStepping()175af732203SDimitry Andric void NativeThreadFreeBSD::SetStepping() {
176af732203SDimitry Andric m_state = StateType::eStateStepping;
177af732203SDimitry Andric m_stop_info.reason = StopReason::eStopReasonNone;
178af732203SDimitry Andric }
179af732203SDimitry Andric
GetName()180af732203SDimitry Andric std::string NativeThreadFreeBSD::GetName() {
181af732203SDimitry Andric Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
182af732203SDimitry Andric
183af732203SDimitry Andric std::vector<struct kinfo_proc> kp;
184af732203SDimitry Andric int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
185af732203SDimitry Andric static_cast<int>(GetProcess().GetID())};
186af732203SDimitry Andric
187af732203SDimitry Andric while (1) {
188af732203SDimitry Andric size_t len = kp.size() * sizeof(struct kinfo_proc);
189af732203SDimitry Andric void *ptr = len == 0 ? nullptr : kp.data();
190af732203SDimitry Andric int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0);
191af732203SDimitry Andric if (ptr == nullptr || (error != 0 && errno == ENOMEM)) {
192af732203SDimitry Andric kp.resize(len / sizeof(struct kinfo_proc));
193af732203SDimitry Andric continue;
194af732203SDimitry Andric }
195af732203SDimitry Andric if (error != 0) {
196af732203SDimitry Andric len = 0;
197af732203SDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}",
198af732203SDimitry Andric GetID(), m_state, strerror(errno));
199af732203SDimitry Andric }
200af732203SDimitry Andric kp.resize(len / sizeof(struct kinfo_proc));
201af732203SDimitry Andric break;
202af732203SDimitry Andric }
203af732203SDimitry Andric
204af732203SDimitry Andric for (auto &procinfo : kp) {
205af732203SDimitry Andric if (procinfo.ki_tid == static_cast<lwpid_t>(GetID()))
206af732203SDimitry Andric return procinfo.ki_tdname;
207af732203SDimitry Andric }
208af732203SDimitry Andric
209af732203SDimitry Andric return "";
210af732203SDimitry Andric }
211af732203SDimitry Andric
GetState()212af732203SDimitry Andric lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }
213af732203SDimitry Andric
GetStopReason(ThreadStopInfo & stop_info,std::string & description)214af732203SDimitry Andric bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info,
215af732203SDimitry Andric std::string &description) {
216af732203SDimitry Andric Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
217af732203SDimitry Andric description.clear();
218af732203SDimitry Andric
219af732203SDimitry Andric switch (m_state) {
220af732203SDimitry Andric case eStateStopped:
221af732203SDimitry Andric case eStateCrashed:
222af732203SDimitry Andric case eStateExited:
223af732203SDimitry Andric case eStateSuspended:
224af732203SDimitry Andric case eStateUnloaded:
225af732203SDimitry Andric stop_info = m_stop_info;
226af732203SDimitry Andric description = m_stop_description;
227af732203SDimitry Andric
228af732203SDimitry Andric return true;
229af732203SDimitry Andric
230af732203SDimitry Andric case eStateInvalid:
231af732203SDimitry Andric case eStateConnected:
232af732203SDimitry Andric case eStateAttaching:
233af732203SDimitry Andric case eStateLaunching:
234af732203SDimitry Andric case eStateRunning:
235af732203SDimitry Andric case eStateStepping:
236af732203SDimitry Andric case eStateDetached:
237af732203SDimitry Andric LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
238af732203SDimitry Andric StateAsCString(m_state));
239af732203SDimitry Andric return false;
240af732203SDimitry Andric }
241af732203SDimitry Andric llvm_unreachable("unhandled StateType!");
242af732203SDimitry Andric }
243af732203SDimitry Andric
GetRegisterContext()244af732203SDimitry Andric NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {
245af732203SDimitry Andric assert(m_reg_context_up);
246af732203SDimitry Andric return *m_reg_context_up;
247af732203SDimitry Andric }
248af732203SDimitry Andric
SetWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags,bool hardware)249af732203SDimitry Andric Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
250af732203SDimitry Andric uint32_t watch_flags, bool hardware) {
251af732203SDimitry Andric assert(m_state == eStateStopped);
252af732203SDimitry Andric if (!hardware)
253af732203SDimitry Andric return Status("not implemented");
254af732203SDimitry Andric Status error = RemoveWatchpoint(addr);
255af732203SDimitry Andric if (error.Fail())
256af732203SDimitry Andric return error;
257af732203SDimitry Andric uint32_t wp_index =
258af732203SDimitry Andric GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
259af732203SDimitry Andric if (wp_index == LLDB_INVALID_INDEX32)
260af732203SDimitry Andric return Status("Setting hardware watchpoint failed.");
261af732203SDimitry Andric m_watchpoint_index_map.insert({addr, wp_index});
262af732203SDimitry Andric return Status();
263af732203SDimitry Andric }
264af732203SDimitry Andric
RemoveWatchpoint(lldb::addr_t addr)265af732203SDimitry Andric Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {
266af732203SDimitry Andric auto wp = m_watchpoint_index_map.find(addr);
267af732203SDimitry Andric if (wp == m_watchpoint_index_map.end())
268af732203SDimitry Andric return Status();
269af732203SDimitry Andric uint32_t wp_index = wp->second;
270af732203SDimitry Andric m_watchpoint_index_map.erase(wp);
271af732203SDimitry Andric if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
272af732203SDimitry Andric return Status();
273af732203SDimitry Andric return Status("Clearing hardware watchpoint failed.");
274af732203SDimitry Andric }
275af732203SDimitry Andric
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)276af732203SDimitry Andric Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,
277af732203SDimitry Andric size_t size) {
278af732203SDimitry Andric assert(m_state == eStateStopped);
279af732203SDimitry Andric Status error = RemoveHardwareBreakpoint(addr);
280af732203SDimitry Andric if (error.Fail())
281af732203SDimitry Andric return error;
282af732203SDimitry Andric
283af732203SDimitry Andric uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
284af732203SDimitry Andric
285af732203SDimitry Andric if (bp_index == LLDB_INVALID_INDEX32)
286af732203SDimitry Andric return Status("Setting hardware breakpoint failed.");
287af732203SDimitry Andric
288af732203SDimitry Andric m_hw_break_index_map.insert({addr, bp_index});
289af732203SDimitry Andric return Status();
290af732203SDimitry Andric }
291af732203SDimitry Andric
RemoveHardwareBreakpoint(lldb::addr_t addr)292af732203SDimitry Andric Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
293af732203SDimitry Andric auto bp = m_hw_break_index_map.find(addr);
294af732203SDimitry Andric if (bp == m_hw_break_index_map.end())
295af732203SDimitry Andric return Status();
296af732203SDimitry Andric
297af732203SDimitry Andric uint32_t bp_index = bp->second;
298af732203SDimitry Andric if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
299af732203SDimitry Andric m_hw_break_index_map.erase(bp);
300af732203SDimitry Andric return Status();
301af732203SDimitry Andric }
302af732203SDimitry Andric
303af732203SDimitry Andric return Status("Clearing hardware breakpoint failed.");
304af732203SDimitry Andric }
305af732203SDimitry Andric
306af732203SDimitry Andric llvm::Error
CopyWatchpointsFrom(NativeThreadFreeBSD & source)307af732203SDimitry Andric NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
308af732203SDimitry Andric llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
309af732203SDimitry Andric source.GetRegisterContext());
310af732203SDimitry Andric if (!s) {
311af732203SDimitry Andric m_watchpoint_index_map = source.m_watchpoint_index_map;
312af732203SDimitry Andric m_hw_break_index_map = source.m_hw_break_index_map;
313af732203SDimitry Andric }
314af732203SDimitry Andric return s;
315af732203SDimitry Andric }
316