1 | //===-- NativeThreadNetBSD.cpp --------------------------------------------===// |
---|---|
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 | // clang-format off |
22 | #include <sys/types.h> |
23 | #include <sys/ptrace.h> |
24 | // clang-format on |
25 | |
26 | #include <sstream> |
27 | |
28 | // clang-format off |
29 | #include <sys/sysctl.h> |
30 | // clang-format on |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | using namespace lldb_private::process_netbsd; |
35 | |
36 | NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, |
37 | lldb::tid_t tid) |
38 | : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), |
39 | m_stop_info(), m_reg_context_up( |
40 | NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(target_arch: process.GetArchitecture(), native_thread&: *this) |
41 | ), m_stop_description() {} |
42 | |
43 | Status NativeThreadNetBSD::Resume() { |
44 | Status ret = NativeProcessNetBSD::PtraceWrapper(req: PT_RESUME, pid: m_process.GetID(), |
45 | addr: nullptr, data: GetID()); |
46 | if (!ret.Success()) |
47 | return ret; |
48 | ret = NativeProcessNetBSD::PtraceWrapper(req: PT_CLEARSTEP, pid: m_process.GetID(), |
49 | addr: nullptr, data: GetID()); |
50 | if (ret.Success()) |
51 | SetRunning(); |
52 | return ret; |
53 | } |
54 | |
55 | Status NativeThreadNetBSD::SingleStep() { |
56 | Status ret = NativeProcessNetBSD::PtraceWrapper(req: PT_RESUME, pid: m_process.GetID(), |
57 | addr: nullptr, data: GetID()); |
58 | if (!ret.Success()) |
59 | return ret; |
60 | ret = NativeProcessNetBSD::PtraceWrapper(req: PT_SETSTEP, pid: m_process.GetID(), |
61 | addr: nullptr, data: GetID()); |
62 | if (ret.Success()) |
63 | SetStepping(); |
64 | return ret; |
65 | } |
66 | |
67 | Status NativeThreadNetBSD::Suspend() { |
68 | Status ret = NativeProcessNetBSD::PtraceWrapper(req: PT_SUSPEND, pid: m_process.GetID(), |
69 | addr: nullptr, data: GetID()); |
70 | if (ret.Success()) |
71 | SetStopped(); |
72 | return ret; |
73 | } |
74 | |
75 | void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, |
76 | const siginfo_t *info) { |
77 | Log *log = GetLog(mask: POSIXLog::Thread); |
78 | LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); |
79 | |
80 | SetStopped(); |
81 | |
82 | m_stop_info.reason = StopReason::eStopReasonSignal; |
83 | m_stop_info.signo = signo; |
84 | |
85 | m_stop_description.clear(); |
86 | if (info) { |
87 | switch (signo) { |
88 | case SIGSEGV: |
89 | case SIGBUS: |
90 | case SIGFPE: |
91 | case SIGILL: |
92 | m_stop_description = GetCrashReasonString(info: *info); |
93 | break; |
94 | } |
95 | } |
96 | } |
97 | |
98 | void NativeThreadNetBSD::SetStoppedByBreakpoint() { |
99 | SetStopped(); |
100 | m_stop_info.reason = StopReason::eStopReasonBreakpoint; |
101 | m_stop_info.signo = SIGTRAP; |
102 | } |
103 | |
104 | void NativeThreadNetBSD::SetStoppedByTrace() { |
105 | SetStopped(); |
106 | m_stop_info.reason = StopReason::eStopReasonTrace; |
107 | m_stop_info.signo = SIGTRAP; |
108 | } |
109 | |
110 | void NativeThreadNetBSD::SetStoppedByExec() { |
111 | SetStopped(); |
112 | m_stop_info.reason = StopReason::eStopReasonExec; |
113 | m_stop_info.signo = SIGTRAP; |
114 | } |
115 | |
116 | void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { |
117 | lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); |
118 | |
119 | std::ostringstream ostr; |
120 | ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; |
121 | ostr << wp_index; |
122 | |
123 | ostr << " "<< GetRegisterContext().GetWatchpointHitAddress(wp_index); |
124 | |
125 | SetStopped(); |
126 | m_stop_description = ostr.str(); |
127 | m_stop_info.reason = StopReason::eStopReasonWatchpoint; |
128 | m_stop_info.signo = SIGTRAP; |
129 | } |
130 | |
131 | void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid, |
132 | lldb::tid_t child_tid) { |
133 | SetStopped(); |
134 | |
135 | m_stop_info.reason = StopReason::eStopReasonFork; |
136 | m_stop_info.signo = SIGTRAP; |
137 | m_stop_info.details.fork.child_pid = child_pid; |
138 | m_stop_info.details.fork.child_tid = child_tid; |
139 | } |
140 | |
141 | void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid, |
142 | lldb::tid_t child_tid) { |
143 | SetStopped(); |
144 | |
145 | m_stop_info.reason = StopReason::eStopReasonVFork; |
146 | m_stop_info.signo = SIGTRAP; |
147 | m_stop_info.details.fork.child_pid = child_pid; |
148 | m_stop_info.details.fork.child_tid = child_tid; |
149 | } |
150 | |
151 | void NativeThreadNetBSD::SetStoppedByVForkDone() { |
152 | SetStopped(); |
153 | |
154 | m_stop_info.reason = StopReason::eStopReasonVForkDone; |
155 | m_stop_info.signo = SIGTRAP; |
156 | } |
157 | |
158 | void NativeThreadNetBSD::SetStoppedWithNoReason() { |
159 | SetStopped(); |
160 | |
161 | m_stop_info.reason = StopReason::eStopReasonNone; |
162 | m_stop_info.signo = 0; |
163 | } |
164 | |
165 | void NativeThreadNetBSD::SetStopped() { |
166 | const StateType new_state = StateType::eStateStopped; |
167 | m_state = new_state; |
168 | m_stop_description.clear(); |
169 | } |
170 | |
171 | void NativeThreadNetBSD::SetRunning() { |
172 | m_state = StateType::eStateRunning; |
173 | m_stop_info.reason = StopReason::eStopReasonNone; |
174 | } |
175 | |
176 | void NativeThreadNetBSD::SetStepping() { |
177 | m_state = StateType::eStateStepping; |
178 | m_stop_info.reason = StopReason::eStopReasonNone; |
179 | } |
180 | |
181 | std::string NativeThreadNetBSD::GetName() { |
182 | #ifdef PT_LWPSTATUS |
183 | struct ptrace_lwpstatus info = {}; |
184 | info.pl_lwpid = m_tid; |
185 | Status error = NativeProcessNetBSD::PtraceWrapper( |
186 | PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); |
187 | if (error.Fail()) { |
188 | return ""; |
189 | } |
190 | return info.pl_name; |
191 | #else |
192 | std::vector<struct kinfo_lwp> infos; |
193 | Log *log = GetLog(mask: POSIXLog::Thread); |
194 | |
195 | int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), |
196 | sizeof(struct kinfo_lwp), 0}; |
197 | size_t size; |
198 | |
199 | if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { |
200 | LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", |
201 | llvm::sys::StrError()); |
202 | return ""; |
203 | } |
204 | |
205 | mib[4] = size / sizeof(size_t); |
206 | infos.resize(size / sizeof(struct kinfo_lwp)); |
207 | |
208 | if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { |
209 | LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); |
210 | return ""; |
211 | } |
212 | |
213 | size_t nlwps = size / sizeof(struct kinfo_lwp); |
214 | for (size_t i = 0; i < nlwps; i++) { |
215 | if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { |
216 | return infos[i].l_name; |
217 | } |
218 | } |
219 | |
220 | LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); |
221 | return ""; |
222 | #endif |
223 | } |
224 | |
225 | lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } |
226 | |
227 | bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, |
228 | std::string &description) { |
229 | Log *log = GetLog(mask: POSIXLog::Thread); |
230 | description.clear(); |
231 | |
232 | switch (m_state) { |
233 | case eStateStopped: |
234 | case eStateCrashed: |
235 | case eStateExited: |
236 | case eStateSuspended: |
237 | case eStateUnloaded: |
238 | stop_info = m_stop_info; |
239 | description = m_stop_description; |
240 | |
241 | return true; |
242 | |
243 | case eStateInvalid: |
244 | case eStateConnected: |
245 | case eStateAttaching: |
246 | case eStateLaunching: |
247 | case eStateRunning: |
248 | case eStateStepping: |
249 | case eStateDetached: |
250 | LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), |
251 | StateAsCString(m_state)); |
252 | return false; |
253 | } |
254 | llvm_unreachable("unhandled StateType!"); |
255 | } |
256 | |
257 | NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { |
258 | assert(m_reg_context_up); |
259 | return *m_reg_context_up; |
260 | } |
261 | |
262 | Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, |
263 | uint32_t watch_flags, bool hardware) { |
264 | assert(m_state == eStateStopped); |
265 | if (!hardware) |
266 | return Status::FromErrorString(str: "not implemented"); |
267 | Status error = RemoveWatchpoint(addr); |
268 | if (error.Fail()) |
269 | return error; |
270 | uint32_t wp_index = |
271 | GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); |
272 | if (wp_index == LLDB_INVALID_INDEX32) |
273 | return Status::FromErrorString(str: "Setting hardware watchpoint failed."); |
274 | m_watchpoint_index_map.insert(x: {addr, wp_index}); |
275 | return Status(); |
276 | } |
277 | |
278 | Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { |
279 | auto wp = m_watchpoint_index_map.find(x: addr); |
280 | if (wp == m_watchpoint_index_map.end()) |
281 | return Status(); |
282 | uint32_t wp_index = wp->second; |
283 | m_watchpoint_index_map.erase(position: wp); |
284 | if (GetRegisterContext().ClearHardwareWatchpoint(hw_index: wp_index)) |
285 | return Status(); |
286 | return Status::FromErrorString(str: "Clearing hardware watchpoint failed."); |
287 | } |
288 | |
289 | Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, |
290 | size_t size) { |
291 | assert(m_state == eStateStopped); |
292 | Status error = RemoveHardwareBreakpoint(addr); |
293 | if (error.Fail()) |
294 | return error; |
295 | |
296 | uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); |
297 | |
298 | if (bp_index == LLDB_INVALID_INDEX32) |
299 | return Status::FromErrorString(str: "Setting hardware breakpoint failed."); |
300 | |
301 | m_hw_break_index_map.insert(x: {addr, bp_index}); |
302 | return Status(); |
303 | } |
304 | |
305 | Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { |
306 | auto bp = m_hw_break_index_map.find(x: addr); |
307 | if (bp == m_hw_break_index_map.end()) |
308 | return Status(); |
309 | |
310 | uint32_t bp_index = bp->second; |
311 | if (GetRegisterContext().ClearHardwareBreakpoint(hw_idx: bp_index)) { |
312 | m_hw_break_index_map.erase(position: bp); |
313 | return Status(); |
314 | } |
315 | |
316 | return Status::FromErrorString(str: "Clearing hardware breakpoint failed."); |
317 | } |
318 | |
319 | llvm::Error |
320 | NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { |
321 | llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( |
322 | source&: source.GetRegisterContext()); |
323 | if (!s) { |
324 | m_watchpoint_index_map = source.m_watchpoint_index_map; |
325 | m_hw_break_index_map = source.m_hw_break_index_map; |
326 | } |
327 | return s; |
328 | } |
329 |
Definitions
- NativeThreadNetBSD
- Resume
- SingleStep
- Suspend
- SetStoppedBySignal
- SetStoppedByBreakpoint
- SetStoppedByTrace
- SetStoppedByExec
- SetStoppedByWatchpoint
- SetStoppedByFork
- SetStoppedByVFork
- SetStoppedByVForkDone
- SetStoppedWithNoReason
- SetStopped
- SetRunning
- SetStepping
- GetName
- GetState
- GetStopReason
- GetRegisterContext
- SetWatchpoint
- RemoveWatchpoint
- SetHardwareBreakpoint
- RemoveHardwareBreakpoint
Improve your Profiling and Debugging skills
Find out more