1dda28197Spatrick //===-- NativeProcessNetBSD.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "NativeProcessNetBSD.h"
10061da546Spatrick
11061da546Spatrick #include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
12061da546Spatrick #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
13061da546Spatrick #include "lldb/Host/HostProcess.h"
14061da546Spatrick #include "lldb/Host/common/NativeRegisterContext.h"
15061da546Spatrick #include "lldb/Host/posix/ProcessLauncherPosixFork.h"
16061da546Spatrick #include "lldb/Target/Process.h"
17061da546Spatrick #include "lldb/Utility/State.h"
18061da546Spatrick #include "llvm/Support/Errno.h"
19061da546Spatrick
20061da546Spatrick // System includes - They have to be included after framework includes because
21061da546Spatrick // they define some macros which collide with variable names in other modules
22061da546Spatrick // clang-format off
23061da546Spatrick #include <sys/types.h>
24061da546Spatrick #include <sys/ptrace.h>
25061da546Spatrick #include <sys/sysctl.h>
26061da546Spatrick #include <sys/wait.h>
27061da546Spatrick #include <uvm/uvm_prot.h>
28061da546Spatrick #include <elf.h>
29061da546Spatrick #include <util.h>
30061da546Spatrick // clang-format on
31061da546Spatrick
32061da546Spatrick using namespace lldb;
33061da546Spatrick using namespace lldb_private;
34061da546Spatrick using namespace lldb_private::process_netbsd;
35061da546Spatrick using namespace llvm;
36061da546Spatrick
37061da546Spatrick // Simple helper function to ensure flags are enabled on the given file
38061da546Spatrick // descriptor.
EnsureFDFlags(int fd,int flags)39061da546Spatrick static Status EnsureFDFlags(int fd, int flags) {
40061da546Spatrick Status error;
41061da546Spatrick
42061da546Spatrick int status = fcntl(fd, F_GETFL);
43061da546Spatrick if (status == -1) {
44061da546Spatrick error.SetErrorToErrno();
45061da546Spatrick return error;
46061da546Spatrick }
47061da546Spatrick
48061da546Spatrick if (fcntl(fd, F_SETFL, status | flags) == -1) {
49061da546Spatrick error.SetErrorToErrno();
50061da546Spatrick return error;
51061da546Spatrick }
52061da546Spatrick
53061da546Spatrick return error;
54061da546Spatrick }
55061da546Spatrick
56061da546Spatrick // Public Static Methods
57061da546Spatrick
58061da546Spatrick llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Launch(ProcessLaunchInfo & launch_info,NativeDelegate & native_delegate,MainLoop & mainloop) const59061da546Spatrick NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
60061da546Spatrick NativeDelegate &native_delegate,
61061da546Spatrick MainLoop &mainloop) const {
62*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
63061da546Spatrick
64061da546Spatrick Status status;
65061da546Spatrick ::pid_t pid = ProcessLauncherPosixFork()
66061da546Spatrick .LaunchProcess(launch_info, status)
67061da546Spatrick .GetProcessId();
68061da546Spatrick LLDB_LOG(log, "pid = {0:x}", pid);
69061da546Spatrick if (status.Fail()) {
70061da546Spatrick LLDB_LOG(log, "failed to launch process: {0}", status);
71061da546Spatrick return status.ToError();
72061da546Spatrick }
73061da546Spatrick
74061da546Spatrick // Wait for the child process to trap on its call to execve.
75061da546Spatrick int wstatus;
76061da546Spatrick ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
77061da546Spatrick assert(wpid == pid);
78061da546Spatrick (void)wpid;
79061da546Spatrick if (!WIFSTOPPED(wstatus)) {
80061da546Spatrick LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
81061da546Spatrick WaitStatus::Decode(wstatus));
82061da546Spatrick return llvm::make_error<StringError>("Could not sync with inferior process",
83061da546Spatrick llvm::inconvertibleErrorCode());
84061da546Spatrick }
85061da546Spatrick LLDB_LOG(log, "inferior started, now in stopped state");
86061da546Spatrick
87061da546Spatrick ProcessInstanceInfo Info;
88061da546Spatrick if (!Host::GetProcessInfo(pid, Info)) {
89061da546Spatrick return llvm::make_error<StringError>("Cannot get process architecture",
90061da546Spatrick llvm::inconvertibleErrorCode());
91061da546Spatrick }
92061da546Spatrick
93061da546Spatrick // Set the architecture to the exe architecture.
94061da546Spatrick LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
95061da546Spatrick Info.GetArchitecture().GetArchitectureName());
96061da546Spatrick
97061da546Spatrick std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
98dda28197Spatrick pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
99061da546Spatrick Info.GetArchitecture(), mainloop));
100061da546Spatrick
101be691f3bSpatrick status = process_up->SetupTrace();
102061da546Spatrick if (status.Fail())
103061da546Spatrick return status.ToError();
104061da546Spatrick
105061da546Spatrick for (const auto &thread : process_up->m_threads)
106061da546Spatrick static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
107061da546Spatrick process_up->SetState(StateType::eStateStopped, false);
108061da546Spatrick
109061da546Spatrick return std::move(process_up);
110061da546Spatrick }
111061da546Spatrick
112061da546Spatrick llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid,NativeProcessProtocol::NativeDelegate & native_delegate,MainLoop & mainloop) const113061da546Spatrick NativeProcessNetBSD::Factory::Attach(
114061da546Spatrick lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
115061da546Spatrick MainLoop &mainloop) const {
116*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
117061da546Spatrick LLDB_LOG(log, "pid = {0:x}", pid);
118061da546Spatrick
119061da546Spatrick // Retrieve the architecture for the running process.
120061da546Spatrick ProcessInstanceInfo Info;
121061da546Spatrick if (!Host::GetProcessInfo(pid, Info)) {
122061da546Spatrick return llvm::make_error<StringError>("Cannot get process architecture",
123061da546Spatrick llvm::inconvertibleErrorCode());
124061da546Spatrick }
125061da546Spatrick
126061da546Spatrick std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
127061da546Spatrick pid, -1, native_delegate, Info.GetArchitecture(), mainloop));
128061da546Spatrick
129061da546Spatrick Status status = process_up->Attach();
130061da546Spatrick if (!status.Success())
131061da546Spatrick return status.ToError();
132061da546Spatrick
133061da546Spatrick return std::move(process_up);
134061da546Spatrick }
135061da546Spatrick
136be691f3bSpatrick NativeProcessNetBSD::Extension
GetSupportedExtensions() const137be691f3bSpatrick NativeProcessNetBSD::Factory::GetSupportedExtensions() const {
138be691f3bSpatrick return Extension::multiprocess | Extension::fork | Extension::vfork |
139*f6aab3d8Srobert Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
140*f6aab3d8Srobert Extension::savecore;
141be691f3bSpatrick }
142be691f3bSpatrick
143061da546Spatrick // Public Instance Methods
144061da546Spatrick
NativeProcessNetBSD(::pid_t pid,int terminal_fd,NativeDelegate & delegate,const ArchSpec & arch,MainLoop & mainloop)145061da546Spatrick NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
146061da546Spatrick NativeDelegate &delegate,
147061da546Spatrick const ArchSpec &arch,
148061da546Spatrick MainLoop &mainloop)
149be691f3bSpatrick : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
150be691f3bSpatrick m_main_loop(mainloop) {
151061da546Spatrick if (m_terminal_fd != -1) {
152061da546Spatrick Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
153061da546Spatrick assert(status.Success());
154061da546Spatrick }
155061da546Spatrick
156061da546Spatrick Status status;
157061da546Spatrick m_sigchld_handle = mainloop.RegisterSignal(
158061da546Spatrick SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
159061da546Spatrick assert(m_sigchld_handle && status.Success());
160061da546Spatrick }
161061da546Spatrick
162061da546Spatrick // Handles all waitpid events from the inferior process.
MonitorCallback(lldb::pid_t pid,int signal)163061da546Spatrick void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
164061da546Spatrick switch (signal) {
165061da546Spatrick case SIGTRAP:
166061da546Spatrick return MonitorSIGTRAP(pid);
167061da546Spatrick case SIGSTOP:
168061da546Spatrick return MonitorSIGSTOP(pid);
169061da546Spatrick default:
170061da546Spatrick return MonitorSignal(pid, signal);
171061da546Spatrick }
172061da546Spatrick }
173061da546Spatrick
MonitorExited(lldb::pid_t pid,WaitStatus status)174061da546Spatrick void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
175*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
176061da546Spatrick
177061da546Spatrick LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
178061da546Spatrick
179061da546Spatrick /* Stop Tracking All Threads attached to Process */
180061da546Spatrick m_threads.clear();
181061da546Spatrick
182061da546Spatrick SetExitStatus(status, true);
183061da546Spatrick
184061da546Spatrick // Notify delegate that our process has exited.
185061da546Spatrick SetState(StateType::eStateExited, true);
186061da546Spatrick }
187061da546Spatrick
MonitorSIGSTOP(lldb::pid_t pid)188061da546Spatrick void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
189061da546Spatrick ptrace_siginfo_t info;
190061da546Spatrick
191061da546Spatrick const auto siginfo_err =
192061da546Spatrick PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
193061da546Spatrick
194061da546Spatrick // Get details on the signal raised.
195061da546Spatrick if (siginfo_err.Success()) {
196061da546Spatrick // Handle SIGSTOP from LLGS (LLDB GDB Server)
197061da546Spatrick if (info.psi_siginfo.si_code == SI_USER &&
198061da546Spatrick info.psi_siginfo.si_pid == ::getpid()) {
199061da546Spatrick /* Stop Tracking all Threads attached to Process */
200061da546Spatrick for (const auto &thread : m_threads) {
201061da546Spatrick static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
202061da546Spatrick SIGSTOP, &info.psi_siginfo);
203061da546Spatrick }
204061da546Spatrick }
205061da546Spatrick SetState(StateType::eStateStopped, true);
206061da546Spatrick }
207061da546Spatrick }
208061da546Spatrick
MonitorSIGTRAP(lldb::pid_t pid)209061da546Spatrick void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
210*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
211061da546Spatrick ptrace_siginfo_t info;
212061da546Spatrick
213061da546Spatrick const auto siginfo_err =
214061da546Spatrick PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
215061da546Spatrick
216061da546Spatrick // Get details on the signal raised.
217061da546Spatrick if (siginfo_err.Fail()) {
218be691f3bSpatrick LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
219061da546Spatrick return;
220061da546Spatrick }
221061da546Spatrick
222be691f3bSpatrick LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
223be691f3bSpatrick info.psi_lwpid, info.psi_siginfo.si_code);
224061da546Spatrick NativeThreadNetBSD *thread = nullptr;
225be691f3bSpatrick
226061da546Spatrick if (info.psi_lwpid > 0) {
227061da546Spatrick for (const auto &t : m_threads) {
228061da546Spatrick if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
229061da546Spatrick thread = static_cast<NativeThreadNetBSD *>(t.get());
230061da546Spatrick break;
231061da546Spatrick }
232061da546Spatrick static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
233061da546Spatrick }
234061da546Spatrick if (!thread)
235be691f3bSpatrick LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
236061da546Spatrick info.psi_lwpid);
237061da546Spatrick }
238061da546Spatrick
239061da546Spatrick switch (info.psi_siginfo.si_code) {
240061da546Spatrick case TRAP_BRKPT:
241061da546Spatrick if (thread) {
242061da546Spatrick thread->SetStoppedByBreakpoint();
243061da546Spatrick FixupBreakpointPCAsNeeded(*thread);
244061da546Spatrick }
245061da546Spatrick SetState(StateType::eStateStopped, true);
246be691f3bSpatrick return;
247061da546Spatrick case TRAP_TRACE:
248061da546Spatrick if (thread)
249061da546Spatrick thread->SetStoppedByTrace();
250061da546Spatrick SetState(StateType::eStateStopped, true);
251be691f3bSpatrick return;
252061da546Spatrick case TRAP_EXEC: {
253061da546Spatrick Status error = ReinitializeThreads();
254061da546Spatrick if (error.Fail()) {
255061da546Spatrick SetState(StateType::eStateInvalid);
256061da546Spatrick return;
257061da546Spatrick }
258061da546Spatrick
259061da546Spatrick // Let our delegate know we have just exec'd.
260061da546Spatrick NotifyDidExec();
261061da546Spatrick
262061da546Spatrick for (const auto &thread : m_threads)
263061da546Spatrick static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
264061da546Spatrick SetState(StateType::eStateStopped, true);
265be691f3bSpatrick return;
266be691f3bSpatrick }
267be691f3bSpatrick case TRAP_CHLD: {
268be691f3bSpatrick ptrace_state_t pst;
269be691f3bSpatrick Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
270be691f3bSpatrick if (error.Fail()) {
271be691f3bSpatrick SetState(StateType::eStateInvalid);
272be691f3bSpatrick return;
273be691f3bSpatrick }
274be691f3bSpatrick
275be691f3bSpatrick assert(thread);
276be691f3bSpatrick if (pst.pe_report_event == PTRACE_VFORK_DONE) {
277be691f3bSpatrick if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
278be691f3bSpatrick thread->SetStoppedByVForkDone();
279be691f3bSpatrick SetState(StateType::eStateStopped, true);
280be691f3bSpatrick } else {
281be691f3bSpatrick Status error =
282be691f3bSpatrick PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
283be691f3bSpatrick if (error.Fail())
284be691f3bSpatrick SetState(StateType::eStateInvalid);
285be691f3bSpatrick }
286be691f3bSpatrick } else {
287be691f3bSpatrick assert(pst.pe_report_event == PTRACE_FORK ||
288be691f3bSpatrick pst.pe_report_event == PTRACE_VFORK);
289be691f3bSpatrick MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,
290be691f3bSpatrick *thread);
291be691f3bSpatrick }
292be691f3bSpatrick return;
293be691f3bSpatrick }
294061da546Spatrick case TRAP_LWP: {
295061da546Spatrick ptrace_state_t pst;
296061da546Spatrick Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
297061da546Spatrick if (error.Fail()) {
298061da546Spatrick SetState(StateType::eStateInvalid);
299061da546Spatrick return;
300061da546Spatrick }
301061da546Spatrick
302061da546Spatrick switch (pst.pe_report_event) {
303061da546Spatrick case PTRACE_LWP_CREATE: {
304be691f3bSpatrick LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,
305061da546Spatrick pst.pe_lwp);
306061da546Spatrick NativeThreadNetBSD &t = AddThread(pst.pe_lwp);
307061da546Spatrick error = t.CopyWatchpointsFrom(
308061da546Spatrick static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
309061da546Spatrick if (error.Fail()) {
310be691f3bSpatrick LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
311061da546Spatrick pst.pe_lwp, error);
312061da546Spatrick SetState(StateType::eStateInvalid);
313061da546Spatrick return;
314061da546Spatrick }
315061da546Spatrick } break;
316061da546Spatrick case PTRACE_LWP_EXIT:
317be691f3bSpatrick LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,
318061da546Spatrick pst.pe_lwp);
319061da546Spatrick RemoveThread(pst.pe_lwp);
320061da546Spatrick break;
321061da546Spatrick }
322061da546Spatrick
323061da546Spatrick error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
324be691f3bSpatrick if (error.Fail())
325061da546Spatrick SetState(StateType::eStateInvalid);
326061da546Spatrick return;
327061da546Spatrick }
328061da546Spatrick case TRAP_DBREG: {
329061da546Spatrick if (!thread)
330061da546Spatrick break;
331061da546Spatrick
332061da546Spatrick auto ®ctx = static_cast<NativeRegisterContextNetBSD &>(
333061da546Spatrick thread->GetRegisterContext());
334061da546Spatrick uint32_t wp_index = LLDB_INVALID_INDEX32;
335be691f3bSpatrick Status error = regctx.GetWatchpointHitIndex(
336be691f3bSpatrick wp_index, (uintptr_t)info.psi_siginfo.si_addr);
337061da546Spatrick if (error.Fail())
338061da546Spatrick LLDB_LOG(log,
339061da546Spatrick "received error while checking for watchpoint hits, pid = "
340be691f3bSpatrick "{0}, LWP = {1}, error = {2}",
341be691f3bSpatrick pid, info.psi_lwpid, error);
342061da546Spatrick if (wp_index != LLDB_INVALID_INDEX32) {
343061da546Spatrick thread->SetStoppedByWatchpoint(wp_index);
344061da546Spatrick regctx.ClearWatchpointHit(wp_index);
345061da546Spatrick SetState(StateType::eStateStopped, true);
346be691f3bSpatrick return;
347061da546Spatrick }
348061da546Spatrick
349061da546Spatrick thread->SetStoppedByTrace();
350061da546Spatrick SetState(StateType::eStateStopped, true);
351be691f3bSpatrick return;
352061da546Spatrick }
353061da546Spatrick }
354061da546Spatrick
355be691f3bSpatrick // Either user-generated SIGTRAP or an unknown event that would
356be691f3bSpatrick // otherwise leave the debugger hanging.
357be691f3bSpatrick LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
358be691f3bSpatrick MonitorSignal(pid, SIGTRAP);
359be691f3bSpatrick }
360be691f3bSpatrick
MonitorSignal(lldb::pid_t pid,int signal)361061da546Spatrick void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
362*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
363061da546Spatrick ptrace_siginfo_t info;
364be691f3bSpatrick
365061da546Spatrick const auto siginfo_err =
366061da546Spatrick PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
367be691f3bSpatrick if (siginfo_err.Fail()) {
368be691f3bSpatrick LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
369be691f3bSpatrick return;
370be691f3bSpatrick }
371061da546Spatrick
372061da546Spatrick for (const auto &abs_thread : m_threads) {
373061da546Spatrick NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
374061da546Spatrick assert(info.psi_lwpid >= 0);
375061da546Spatrick if (info.psi_lwpid == 0 ||
376061da546Spatrick static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
377061da546Spatrick thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
378061da546Spatrick else
379061da546Spatrick thread.SetStoppedWithNoReason();
380061da546Spatrick }
381061da546Spatrick SetState(StateType::eStateStopped, true);
382061da546Spatrick }
383061da546Spatrick
PtraceWrapper(int req,lldb::pid_t pid,void * addr,int data,int * result)384061da546Spatrick Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
385061da546Spatrick int data, int *result) {
386*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Ptrace);
387061da546Spatrick Status error;
388061da546Spatrick int ret;
389061da546Spatrick
390061da546Spatrick errno = 0;
391061da546Spatrick ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
392061da546Spatrick
393061da546Spatrick if (ret == -1)
394061da546Spatrick error.SetErrorToErrno();
395061da546Spatrick
396061da546Spatrick if (result)
397061da546Spatrick *result = ret;
398061da546Spatrick
399061da546Spatrick LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
400061da546Spatrick
401061da546Spatrick if (error.Fail())
402061da546Spatrick LLDB_LOG(log, "ptrace() failed: {0}", error);
403061da546Spatrick
404061da546Spatrick return error;
405061da546Spatrick }
406061da546Spatrick
ComputeSignalInfo(const std::vector<std::unique_ptr<NativeThreadProtocol>> & threads,const ResumeActionList & resume_actions)407061da546Spatrick static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
408061da546Spatrick const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
409061da546Spatrick const ResumeActionList &resume_actions) {
410061da546Spatrick // We need to account for three possible scenarios:
411061da546Spatrick // 1. no signal being sent.
412061da546Spatrick // 2. a signal being sent to one thread.
413061da546Spatrick // 3. a signal being sent to the whole process.
414061da546Spatrick
415061da546Spatrick // Count signaled threads. While at it, determine which signal is being sent
416061da546Spatrick // and ensure there's only one.
417061da546Spatrick size_t signaled_threads = 0;
418061da546Spatrick int signal = LLDB_INVALID_SIGNAL_NUMBER;
419061da546Spatrick lldb::tid_t signaled_lwp;
420061da546Spatrick for (const auto &thread : threads) {
421061da546Spatrick assert(thread && "thread list should not contain NULL threads");
422061da546Spatrick const ResumeAction *action =
423061da546Spatrick resume_actions.GetActionForThread(thread->GetID(), true);
424061da546Spatrick if (action) {
425061da546Spatrick if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {
426061da546Spatrick signaled_threads++;
427061da546Spatrick if (action->signal != signal) {
428061da546Spatrick if (signal != LLDB_INVALID_SIGNAL_NUMBER)
429061da546Spatrick return Status("NetBSD does not support passing multiple signals "
430061da546Spatrick "simultaneously")
431061da546Spatrick .ToError();
432061da546Spatrick signal = action->signal;
433061da546Spatrick signaled_lwp = thread->GetID();
434061da546Spatrick }
435061da546Spatrick }
436061da546Spatrick }
437061da546Spatrick }
438061da546Spatrick
439061da546Spatrick if (signaled_threads == 0) {
440061da546Spatrick ptrace_siginfo_t siginfo;
441061da546Spatrick siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
442061da546Spatrick return siginfo;
443061da546Spatrick }
444061da546Spatrick
445061da546Spatrick if (signaled_threads > 1 && signaled_threads < threads.size())
446061da546Spatrick return Status("NetBSD does not support passing signal to 1<i<all threads")
447061da546Spatrick .ToError();
448061da546Spatrick
449061da546Spatrick ptrace_siginfo_t siginfo;
450061da546Spatrick siginfo.psi_siginfo.si_signo = signal;
451061da546Spatrick siginfo.psi_siginfo.si_code = SI_USER;
452061da546Spatrick siginfo.psi_siginfo.si_pid = getpid();
453061da546Spatrick siginfo.psi_siginfo.si_uid = getuid();
454061da546Spatrick if (signaled_threads == 1)
455061da546Spatrick siginfo.psi_lwpid = signaled_lwp;
456061da546Spatrick else // signal for the whole process
457061da546Spatrick siginfo.psi_lwpid = 0;
458061da546Spatrick return siginfo;
459061da546Spatrick }
460061da546Spatrick
Resume(const ResumeActionList & resume_actions)461061da546Spatrick Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
462*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
463061da546Spatrick LLDB_LOG(log, "pid {0}", GetID());
464061da546Spatrick
465061da546Spatrick Status ret;
466061da546Spatrick
467061da546Spatrick Expected<ptrace_siginfo_t> siginfo =
468061da546Spatrick ComputeSignalInfo(m_threads, resume_actions);
469061da546Spatrick if (!siginfo)
470061da546Spatrick return Status(siginfo.takeError());
471061da546Spatrick
472061da546Spatrick for (const auto &abs_thread : m_threads) {
473061da546Spatrick assert(abs_thread && "thread list should not contain NULL threads");
474061da546Spatrick NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
475061da546Spatrick
476061da546Spatrick const ResumeAction *action =
477061da546Spatrick resume_actions.GetActionForThread(thread.GetID(), true);
478061da546Spatrick // we need to explicit issue suspend requests, so it is simpler to map it
479061da546Spatrick // into proper action
480061da546Spatrick ResumeAction suspend_action{thread.GetID(), eStateSuspended,
481061da546Spatrick LLDB_INVALID_SIGNAL_NUMBER};
482061da546Spatrick
483061da546Spatrick if (action == nullptr) {
484061da546Spatrick LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
485061da546Spatrick thread.GetID());
486061da546Spatrick action = &suspend_action;
487061da546Spatrick }
488061da546Spatrick
489061da546Spatrick LLDB_LOG(
490061da546Spatrick log,
491061da546Spatrick "processing resume action state {0} signal {1} for pid {2} tid {3}",
492061da546Spatrick action->state, action->signal, GetID(), thread.GetID());
493061da546Spatrick
494061da546Spatrick switch (action->state) {
495061da546Spatrick case eStateRunning:
496061da546Spatrick ret = thread.Resume();
497061da546Spatrick break;
498061da546Spatrick case eStateStepping:
499061da546Spatrick ret = thread.SingleStep();
500061da546Spatrick break;
501061da546Spatrick case eStateSuspended:
502061da546Spatrick case eStateStopped:
503061da546Spatrick if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
504061da546Spatrick return Status("Passing signal to suspended thread unsupported");
505061da546Spatrick
506061da546Spatrick ret = thread.Suspend();
507061da546Spatrick break;
508061da546Spatrick
509061da546Spatrick default:
510061da546Spatrick return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
511061da546Spatrick "for pid %" PRIu64 ", tid %" PRIu64,
512061da546Spatrick __FUNCTION__, StateAsCString(action->state), GetID(),
513061da546Spatrick thread.GetID());
514061da546Spatrick }
515061da546Spatrick
516061da546Spatrick if (!ret.Success())
517061da546Spatrick return ret;
518061da546Spatrick }
519061da546Spatrick
520061da546Spatrick int signal = 0;
521061da546Spatrick if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
522061da546Spatrick ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
523061da546Spatrick sizeof(*siginfo));
524061da546Spatrick if (!ret.Success())
525061da546Spatrick return ret;
526061da546Spatrick signal = siginfo->psi_siginfo.si_signo;
527061da546Spatrick }
528061da546Spatrick
529be691f3bSpatrick ret =
530be691f3bSpatrick PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
531061da546Spatrick if (ret.Success())
532061da546Spatrick SetState(eStateRunning, true);
533061da546Spatrick return ret;
534061da546Spatrick }
535061da546Spatrick
Halt()536be691f3bSpatrick Status NativeProcessNetBSD::Halt() { return PtraceWrapper(PT_STOP, GetID()); }
537061da546Spatrick
Detach()538061da546Spatrick Status NativeProcessNetBSD::Detach() {
539061da546Spatrick Status error;
540061da546Spatrick
541061da546Spatrick // Stop monitoring the inferior.
542061da546Spatrick m_sigchld_handle.reset();
543061da546Spatrick
544061da546Spatrick // Tell ptrace to detach from the process.
545061da546Spatrick if (GetID() == LLDB_INVALID_PROCESS_ID)
546061da546Spatrick return error;
547061da546Spatrick
548be691f3bSpatrick return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
549061da546Spatrick }
550061da546Spatrick
Signal(int signo)551061da546Spatrick Status NativeProcessNetBSD::Signal(int signo) {
552061da546Spatrick Status error;
553061da546Spatrick
554061da546Spatrick if (kill(GetID(), signo))
555061da546Spatrick error.SetErrorToErrno();
556061da546Spatrick
557061da546Spatrick return error;
558061da546Spatrick }
559061da546Spatrick
Interrupt()560061da546Spatrick Status NativeProcessNetBSD::Interrupt() {
561061da546Spatrick return PtraceWrapper(PT_STOP, GetID());
562061da546Spatrick }
563061da546Spatrick
Kill()564061da546Spatrick Status NativeProcessNetBSD::Kill() {
565*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
566061da546Spatrick LLDB_LOG(log, "pid {0}", GetID());
567061da546Spatrick
568061da546Spatrick Status error;
569061da546Spatrick
570061da546Spatrick switch (m_state) {
571061da546Spatrick case StateType::eStateInvalid:
572061da546Spatrick case StateType::eStateExited:
573061da546Spatrick case StateType::eStateCrashed:
574061da546Spatrick case StateType::eStateDetached:
575061da546Spatrick case StateType::eStateUnloaded:
576061da546Spatrick // Nothing to do - the process is already dead.
577061da546Spatrick LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
578061da546Spatrick StateAsCString(m_state));
579061da546Spatrick return error;
580061da546Spatrick
581061da546Spatrick case StateType::eStateConnected:
582061da546Spatrick case StateType::eStateAttaching:
583061da546Spatrick case StateType::eStateLaunching:
584061da546Spatrick case StateType::eStateStopped:
585061da546Spatrick case StateType::eStateRunning:
586061da546Spatrick case StateType::eStateStepping:
587061da546Spatrick case StateType::eStateSuspended:
588061da546Spatrick // We can try to kill a process in these states.
589061da546Spatrick break;
590061da546Spatrick }
591061da546Spatrick
592061da546Spatrick if (kill(GetID(), SIGKILL) != 0) {
593061da546Spatrick error.SetErrorToErrno();
594061da546Spatrick return error;
595061da546Spatrick }
596061da546Spatrick
597061da546Spatrick return error;
598061da546Spatrick }
599061da546Spatrick
GetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & range_info)600061da546Spatrick Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
601061da546Spatrick MemoryRegionInfo &range_info) {
602061da546Spatrick
603061da546Spatrick if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
604061da546Spatrick // We're done.
605061da546Spatrick return Status("unsupported");
606061da546Spatrick }
607061da546Spatrick
608061da546Spatrick Status error = PopulateMemoryRegionCache();
609061da546Spatrick if (error.Fail()) {
610061da546Spatrick return error;
611061da546Spatrick }
612061da546Spatrick
613061da546Spatrick lldb::addr_t prev_base_address = 0;
614061da546Spatrick // FIXME start by finding the last region that is <= target address using
615061da546Spatrick // binary search. Data is sorted.
616061da546Spatrick // There can be a ton of regions on pthreads apps with lots of threads.
617061da546Spatrick for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
618061da546Spatrick ++it) {
619061da546Spatrick MemoryRegionInfo &proc_entry_info = it->first;
620061da546Spatrick // Sanity check assumption that memory map entries are ascending.
621061da546Spatrick assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
622061da546Spatrick "descending memory map entries detected, unexpected");
623061da546Spatrick prev_base_address = proc_entry_info.GetRange().GetRangeBase();
624061da546Spatrick UNUSED_IF_ASSERT_DISABLED(prev_base_address);
625061da546Spatrick // If the target address comes before this entry, indicate distance to next
626061da546Spatrick // region.
627061da546Spatrick if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
628061da546Spatrick range_info.GetRange().SetRangeBase(load_addr);
629061da546Spatrick range_info.GetRange().SetByteSize(
630061da546Spatrick proc_entry_info.GetRange().GetRangeBase() - load_addr);
631061da546Spatrick range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
632061da546Spatrick range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
633061da546Spatrick range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
634061da546Spatrick range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
635061da546Spatrick return error;
636061da546Spatrick } else if (proc_entry_info.GetRange().Contains(load_addr)) {
637061da546Spatrick // The target address is within the memory region we're processing here.
638061da546Spatrick range_info = proc_entry_info;
639061da546Spatrick return error;
640061da546Spatrick }
641061da546Spatrick // The target memory address comes somewhere after the region we just
642061da546Spatrick // parsed.
643061da546Spatrick }
644061da546Spatrick // If we made it here, we didn't find an entry that contained the given
645061da546Spatrick // address. Return the load_addr as start and the amount of bytes betwwen
646061da546Spatrick // load address and the end of the memory as size.
647061da546Spatrick range_info.GetRange().SetRangeBase(load_addr);
648061da546Spatrick range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
649061da546Spatrick range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
650061da546Spatrick range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
651061da546Spatrick range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
652061da546Spatrick range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
653061da546Spatrick return error;
654061da546Spatrick }
655061da546Spatrick
PopulateMemoryRegionCache()656061da546Spatrick Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
657*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
658061da546Spatrick // If our cache is empty, pull the latest. There should always be at least
659061da546Spatrick // one memory region if memory region handling is supported.
660061da546Spatrick if (!m_mem_region_cache.empty()) {
661061da546Spatrick LLDB_LOG(log, "reusing {0} cached memory region entries",
662061da546Spatrick m_mem_region_cache.size());
663061da546Spatrick return Status();
664061da546Spatrick }
665061da546Spatrick
666061da546Spatrick struct kinfo_vmentry *vm;
667061da546Spatrick size_t count, i;
668061da546Spatrick vm = kinfo_getvmmap(GetID(), &count);
669061da546Spatrick if (vm == NULL) {
670061da546Spatrick m_supports_mem_region = LazyBool::eLazyBoolNo;
671061da546Spatrick Status error;
672061da546Spatrick error.SetErrorString("not supported");
673061da546Spatrick return error;
674061da546Spatrick }
675061da546Spatrick for (i = 0; i < count; i++) {
676061da546Spatrick MemoryRegionInfo info;
677061da546Spatrick info.Clear();
678061da546Spatrick info.GetRange().SetRangeBase(vm[i].kve_start);
679061da546Spatrick info.GetRange().SetRangeEnd(vm[i].kve_end);
680061da546Spatrick info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
681061da546Spatrick
682061da546Spatrick if (vm[i].kve_protection & VM_PROT_READ)
683061da546Spatrick info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
684061da546Spatrick else
685061da546Spatrick info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
686061da546Spatrick
687061da546Spatrick if (vm[i].kve_protection & VM_PROT_WRITE)
688061da546Spatrick info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
689061da546Spatrick else
690061da546Spatrick info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
691061da546Spatrick
692061da546Spatrick if (vm[i].kve_protection & VM_PROT_EXECUTE)
693061da546Spatrick info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
694061da546Spatrick else
695061da546Spatrick info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
696061da546Spatrick
697061da546Spatrick if (vm[i].kve_path[0])
698061da546Spatrick info.SetName(vm[i].kve_path);
699061da546Spatrick
700be691f3bSpatrick m_mem_region_cache.emplace_back(info,
701be691f3bSpatrick FileSpec(info.GetName().GetCString()));
702061da546Spatrick }
703061da546Spatrick free(vm);
704061da546Spatrick
705061da546Spatrick if (m_mem_region_cache.empty()) {
706061da546Spatrick // No entries after attempting to read them. This shouldn't happen. Assume
707061da546Spatrick // we don't support map entries.
708061da546Spatrick LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
709061da546Spatrick "for memory region metadata retrieval");
710061da546Spatrick m_supports_mem_region = LazyBool::eLazyBoolNo;
711061da546Spatrick Status error;
712061da546Spatrick error.SetErrorString("not supported");
713061da546Spatrick return error;
714061da546Spatrick }
715061da546Spatrick LLDB_LOG(log, "read {0} memory region entries from process {1}",
716061da546Spatrick m_mem_region_cache.size(), GetID());
717061da546Spatrick // We support memory retrieval, remember that.
718061da546Spatrick m_supports_mem_region = LazyBool::eLazyBoolYes;
719061da546Spatrick return Status();
720061da546Spatrick }
721061da546Spatrick
GetSharedLibraryInfoAddress()722061da546Spatrick lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
723061da546Spatrick // punt on this for now
724061da546Spatrick return LLDB_INVALID_ADDRESS;
725061da546Spatrick }
726061da546Spatrick
UpdateThreads()727061da546Spatrick size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
728061da546Spatrick
SetBreakpoint(lldb::addr_t addr,uint32_t size,bool hardware)729061da546Spatrick Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
730061da546Spatrick bool hardware) {
731061da546Spatrick if (hardware)
732061da546Spatrick return Status("NativeProcessNetBSD does not support hardware breakpoints");
733061da546Spatrick else
734061da546Spatrick return SetSoftwareBreakpoint(addr, size);
735061da546Spatrick }
736061da546Spatrick
GetLoadedModuleFileSpec(const char * module_path,FileSpec & file_spec)737061da546Spatrick Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
738061da546Spatrick FileSpec &file_spec) {
739be691f3bSpatrick Status error = PopulateMemoryRegionCache();
740be691f3bSpatrick if (error.Fail())
741be691f3bSpatrick return error;
742be691f3bSpatrick
743be691f3bSpatrick FileSpec module_file_spec(module_path);
744be691f3bSpatrick FileSystem::Instance().Resolve(module_file_spec);
745be691f3bSpatrick
746be691f3bSpatrick file_spec.Clear();
747be691f3bSpatrick for (const auto &it : m_mem_region_cache) {
748be691f3bSpatrick if (it.second.GetFilename() == module_file_spec.GetFilename()) {
749be691f3bSpatrick file_spec = it.second;
750be691f3bSpatrick return Status();
751be691f3bSpatrick }
752be691f3bSpatrick }
753be691f3bSpatrick return Status("Module file (%s) not found in process' memory map!",
754be691f3bSpatrick module_file_spec.GetFilename().AsCString());
755061da546Spatrick }
756061da546Spatrick
GetFileLoadAddress(const llvm::StringRef & file_name,lldb::addr_t & load_addr)757061da546Spatrick Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
758061da546Spatrick lldb::addr_t &load_addr) {
759061da546Spatrick load_addr = LLDB_INVALID_ADDRESS;
760be691f3bSpatrick Status error = PopulateMemoryRegionCache();
761be691f3bSpatrick if (error.Fail())
762be691f3bSpatrick return error;
763be691f3bSpatrick
764be691f3bSpatrick FileSpec file(file_name);
765be691f3bSpatrick for (const auto &it : m_mem_region_cache) {
766be691f3bSpatrick if (it.second == file) {
767be691f3bSpatrick load_addr = it.first.GetRange().GetRangeBase();
768061da546Spatrick return Status();
769061da546Spatrick }
770be691f3bSpatrick }
771be691f3bSpatrick return Status("No load address found for file %s.", file_name.str().c_str());
772be691f3bSpatrick }
773061da546Spatrick
SigchldHandler()774061da546Spatrick void NativeProcessNetBSD::SigchldHandler() {
775*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
776061da546Spatrick int status;
777be691f3bSpatrick ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
778be691f3bSpatrick WALLSIG | WNOHANG);
779061da546Spatrick
780061da546Spatrick if (wait_pid == 0)
781be691f3bSpatrick return;
782061da546Spatrick
783061da546Spatrick if (wait_pid == -1) {
784061da546Spatrick Status error(errno, eErrorTypePOSIX);
785061da546Spatrick LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
786be691f3bSpatrick return;
787061da546Spatrick }
788061da546Spatrick
789061da546Spatrick WaitStatus wait_status = WaitStatus::Decode(status);
790061da546Spatrick bool exited = wait_status.type == WaitStatus::Exit ||
791061da546Spatrick (wait_status.type == WaitStatus::Signal &&
792061da546Spatrick wait_pid == static_cast<::pid_t>(GetID()));
793061da546Spatrick
794061da546Spatrick LLDB_LOG(log,
795061da546Spatrick "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
796061da546Spatrick GetID(), wait_pid, status, exited);
797061da546Spatrick
798061da546Spatrick if (exited)
799061da546Spatrick MonitorExited(wait_pid, wait_status);
800061da546Spatrick else {
801061da546Spatrick assert(wait_status.type == WaitStatus::Stop);
802061da546Spatrick MonitorCallback(wait_pid, wait_status.status);
803061da546Spatrick }
804061da546Spatrick }
805061da546Spatrick
HasThreadNoLock(lldb::tid_t thread_id)806061da546Spatrick bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
807061da546Spatrick for (const auto &thread : m_threads) {
808061da546Spatrick assert(thread && "thread list should not contain NULL threads");
809061da546Spatrick if (thread->GetID() == thread_id) {
810061da546Spatrick // We have this thread.
811061da546Spatrick return true;
812061da546Spatrick }
813061da546Spatrick }
814061da546Spatrick
815061da546Spatrick // We don't have this thread.
816061da546Spatrick return false;
817061da546Spatrick }
818061da546Spatrick
AddThread(lldb::tid_t thread_id)819061da546Spatrick NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
820*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Thread);
821061da546Spatrick LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
822061da546Spatrick
823061da546Spatrick assert(thread_id > 0);
824061da546Spatrick assert(!HasThreadNoLock(thread_id) &&
825061da546Spatrick "attempted to add a thread by id that already exists");
826061da546Spatrick
827061da546Spatrick // If this is the first thread, save it as the current thread
828061da546Spatrick if (m_threads.empty())
829061da546Spatrick SetCurrentThreadID(thread_id);
830061da546Spatrick
831061da546Spatrick m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));
832061da546Spatrick return static_cast<NativeThreadNetBSD &>(*m_threads.back());
833061da546Spatrick }
834061da546Spatrick
RemoveThread(lldb::tid_t thread_id)835061da546Spatrick void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
836*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Thread);
837061da546Spatrick LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
838061da546Spatrick
839061da546Spatrick assert(thread_id > 0);
840061da546Spatrick assert(HasThreadNoLock(thread_id) &&
841061da546Spatrick "attempted to remove a thread that does not exist");
842061da546Spatrick
843061da546Spatrick for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
844061da546Spatrick if ((*it)->GetID() == thread_id) {
845061da546Spatrick m_threads.erase(it);
846061da546Spatrick break;
847061da546Spatrick }
848061da546Spatrick }
849061da546Spatrick }
850061da546Spatrick
Attach()851061da546Spatrick Status NativeProcessNetBSD::Attach() {
852061da546Spatrick // Attach to the requested process.
853061da546Spatrick // An attach will cause the thread to stop with a SIGSTOP.
854061da546Spatrick Status status = PtraceWrapper(PT_ATTACH, m_pid);
855061da546Spatrick if (status.Fail())
856061da546Spatrick return status;
857061da546Spatrick
858061da546Spatrick int wstatus;
859061da546Spatrick // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
860061da546Spatrick // point we should have a thread stopped if waitpid succeeds.
861be691f3bSpatrick if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,
862be691f3bSpatrick WALLSIG)) < 0)
863061da546Spatrick return Status(errno, eErrorTypePOSIX);
864061da546Spatrick
865be691f3bSpatrick // Initialize threads and tracing status
866be691f3bSpatrick // NB: this needs to be called before we set thread state
867be691f3bSpatrick status = SetupTrace();
868061da546Spatrick if (status.Fail())
869061da546Spatrick return status;
870061da546Spatrick
871061da546Spatrick for (const auto &thread : m_threads)
872061da546Spatrick static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
873061da546Spatrick
874061da546Spatrick // Let our process instance know the thread has stopped.
875be691f3bSpatrick SetCurrentThreadID(m_threads.front()->GetID());
876be691f3bSpatrick SetState(StateType::eStateStopped, false);
877061da546Spatrick return Status();
878061da546Spatrick }
879061da546Spatrick
ReadMemory(lldb::addr_t addr,void * buf,size_t size,size_t & bytes_read)880061da546Spatrick Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
881061da546Spatrick size_t size, size_t &bytes_read) {
882061da546Spatrick unsigned char *dst = static_cast<unsigned char *>(buf);
883061da546Spatrick struct ptrace_io_desc io;
884061da546Spatrick
885*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Memory);
886061da546Spatrick LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
887061da546Spatrick
888061da546Spatrick bytes_read = 0;
889061da546Spatrick io.piod_op = PIOD_READ_D;
890061da546Spatrick io.piod_len = size;
891061da546Spatrick
892061da546Spatrick do {
893061da546Spatrick io.piod_offs = (void *)(addr + bytes_read);
894061da546Spatrick io.piod_addr = dst + bytes_read;
895061da546Spatrick
896061da546Spatrick Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
897061da546Spatrick if (error.Fail() || io.piod_len == 0)
898061da546Spatrick return error;
899061da546Spatrick
900061da546Spatrick bytes_read += io.piod_len;
901061da546Spatrick io.piod_len = size - bytes_read;
902061da546Spatrick } while (bytes_read < size);
903061da546Spatrick
904061da546Spatrick return Status();
905061da546Spatrick }
906061da546Spatrick
WriteMemory(lldb::addr_t addr,const void * buf,size_t size,size_t & bytes_written)907061da546Spatrick Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
908061da546Spatrick size_t size, size_t &bytes_written) {
909061da546Spatrick const unsigned char *src = static_cast<const unsigned char *>(buf);
910061da546Spatrick Status error;
911061da546Spatrick struct ptrace_io_desc io;
912061da546Spatrick
913*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Memory);
914061da546Spatrick LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
915061da546Spatrick
916061da546Spatrick bytes_written = 0;
917061da546Spatrick io.piod_op = PIOD_WRITE_D;
918061da546Spatrick io.piod_len = size;
919061da546Spatrick
920061da546Spatrick do {
921be691f3bSpatrick io.piod_addr =
922be691f3bSpatrick const_cast<void *>(static_cast<const void *>(src + bytes_written));
923061da546Spatrick io.piod_offs = (void *)(addr + bytes_written);
924061da546Spatrick
925061da546Spatrick Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
926061da546Spatrick if (error.Fail() || io.piod_len == 0)
927061da546Spatrick return error;
928061da546Spatrick
929061da546Spatrick bytes_written += io.piod_len;
930061da546Spatrick io.piod_len = size - bytes_written;
931061da546Spatrick } while (bytes_written < size);
932061da546Spatrick
933061da546Spatrick return error;
934061da546Spatrick }
935061da546Spatrick
936061da546Spatrick llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const937061da546Spatrick NativeProcessNetBSD::GetAuxvData() const {
938061da546Spatrick /*
939061da546Spatrick * ELF_AUX_ENTRIES is currently restricted to kernel
940061da546Spatrick * (<sys/exec_elf.h> r. 1.155 specifies 15)
941061da546Spatrick *
942061da546Spatrick * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
943061da546Spatrick * information isn't needed.
944061da546Spatrick */
945061da546Spatrick size_t auxv_size = 100 * sizeof(AuxInfo);
946061da546Spatrick
947061da546Spatrick ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
948061da546Spatrick llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
949061da546Spatrick
950061da546Spatrick struct ptrace_io_desc io;
951061da546Spatrick io.piod_op = PIOD_READ_AUXV;
952061da546Spatrick io.piod_offs = 0;
953061da546Spatrick io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());
954061da546Spatrick io.piod_len = auxv_size;
955061da546Spatrick
956061da546Spatrick Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
957061da546Spatrick
958061da546Spatrick if (error.Fail())
959061da546Spatrick return std::error_code(error.GetError(), std::generic_category());
960061da546Spatrick
961061da546Spatrick if (io.piod_len < 1)
962061da546Spatrick return std::error_code(ECANCELED, std::generic_category());
963061da546Spatrick
964061da546Spatrick return std::move(buf);
965061da546Spatrick }
966061da546Spatrick
SetupTrace()967be691f3bSpatrick Status NativeProcessNetBSD::SetupTrace() {
968be691f3bSpatrick // Enable event reporting
969be691f3bSpatrick ptrace_event_t events;
970be691f3bSpatrick Status status =
971be691f3bSpatrick PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
972be691f3bSpatrick if (status.Fail())
973be691f3bSpatrick return status;
974be691f3bSpatrick // TODO: PTRACE_POSIX_SPAWN?
975be691f3bSpatrick events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
976be691f3bSpatrick PTRACE_VFORK | PTRACE_VFORK_DONE;
977be691f3bSpatrick status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
978be691f3bSpatrick if (status.Fail())
979be691f3bSpatrick return status;
980be691f3bSpatrick
981be691f3bSpatrick return ReinitializeThreads();
982be691f3bSpatrick }
983be691f3bSpatrick
ReinitializeThreads()984061da546Spatrick Status NativeProcessNetBSD::ReinitializeThreads() {
985061da546Spatrick // Clear old threads
986061da546Spatrick m_threads.clear();
987061da546Spatrick
988061da546Spatrick // Initialize new thread
989061da546Spatrick #ifdef PT_LWPSTATUS
990061da546Spatrick struct ptrace_lwpstatus info = {};
991061da546Spatrick int op = PT_LWPNEXT;
992061da546Spatrick #else
993061da546Spatrick struct ptrace_lwpinfo info = {};
994061da546Spatrick int op = PT_LWPINFO;
995061da546Spatrick #endif
996061da546Spatrick
997061da546Spatrick Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));
998061da546Spatrick
999061da546Spatrick if (error.Fail()) {
1000061da546Spatrick return error;
1001061da546Spatrick }
1002061da546Spatrick // Reinitialize from scratch threads and register them in process
1003061da546Spatrick while (info.pl_lwpid != 0) {
1004061da546Spatrick AddThread(info.pl_lwpid);
1005061da546Spatrick error = PtraceWrapper(op, GetID(), &info, sizeof(info));
1006061da546Spatrick if (error.Fail()) {
1007061da546Spatrick return error;
1008061da546Spatrick }
1009061da546Spatrick }
1010061da546Spatrick
1011061da546Spatrick return error;
1012061da546Spatrick }
1013be691f3bSpatrick
MonitorClone(::pid_t child_pid,bool is_vfork,NativeThreadNetBSD & parent_thread)1014be691f3bSpatrick void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
1015be691f3bSpatrick NativeThreadNetBSD &parent_thread) {
1016*f6aab3d8Srobert Log *log = GetLog(POSIXLog::Process);
1017be691f3bSpatrick LLDB_LOG(log, "clone, child_pid={0}", child_pid);
1018be691f3bSpatrick
1019be691f3bSpatrick int status;
1020be691f3bSpatrick ::pid_t wait_pid =
1021be691f3bSpatrick llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
1022be691f3bSpatrick if (wait_pid != child_pid) {
1023be691f3bSpatrick LLDB_LOG(log,
1024be691f3bSpatrick "waiting for pid {0} failed. Assuming the pid has "
1025be691f3bSpatrick "disappeared in the meantime",
1026be691f3bSpatrick child_pid);
1027be691f3bSpatrick return;
1028be691f3bSpatrick }
1029be691f3bSpatrick if (WIFEXITED(status)) {
1030be691f3bSpatrick LLDB_LOG(log,
1031be691f3bSpatrick "waiting for pid {0} returned an 'exited' event. Not "
1032be691f3bSpatrick "tracking it.",
1033be691f3bSpatrick child_pid);
1034be691f3bSpatrick return;
1035be691f3bSpatrick }
1036be691f3bSpatrick
1037be691f3bSpatrick ptrace_siginfo_t info;
1038be691f3bSpatrick const auto siginfo_err =
1039be691f3bSpatrick PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));
1040be691f3bSpatrick if (siginfo_err.Fail()) {
1041be691f3bSpatrick LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
1042be691f3bSpatrick return;
1043be691f3bSpatrick }
1044be691f3bSpatrick assert(info.psi_lwpid >= 0);
1045be691f3bSpatrick lldb::tid_t child_tid = info.psi_lwpid;
1046be691f3bSpatrick
1047be691f3bSpatrick std::unique_ptr<NativeProcessNetBSD> child_process{
1048be691f3bSpatrick new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,
1049be691f3bSpatrick m_delegate, m_arch, m_main_loop)};
1050be691f3bSpatrick if (!is_vfork)
1051be691f3bSpatrick child_process->m_software_breakpoints = m_software_breakpoints;
1052be691f3bSpatrick
1053be691f3bSpatrick Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
1054be691f3bSpatrick if ((m_enabled_extensions & expected_ext) == expected_ext) {
1055be691f3bSpatrick child_process->SetupTrace();
1056be691f3bSpatrick for (const auto &thread : child_process->m_threads)
1057be691f3bSpatrick static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
1058be691f3bSpatrick child_process->SetState(StateType::eStateStopped, false);
1059be691f3bSpatrick
1060be691f3bSpatrick m_delegate.NewSubprocess(this, std::move(child_process));
1061be691f3bSpatrick if (is_vfork)
1062be691f3bSpatrick parent_thread.SetStoppedByVFork(child_pid, child_tid);
1063be691f3bSpatrick else
1064be691f3bSpatrick parent_thread.SetStoppedByFork(child_pid, child_tid);
1065be691f3bSpatrick SetState(StateType::eStateStopped, true);
1066be691f3bSpatrick } else {
1067be691f3bSpatrick child_process->Detach();
1068be691f3bSpatrick Status pt_error =
1069be691f3bSpatrick PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
1070be691f3bSpatrick if (pt_error.Fail()) {
1071be691f3bSpatrick LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),
1072be691f3bSpatrick "unable to resume parent process {1}: {0}", GetID());
1073be691f3bSpatrick SetState(StateType::eStateInvalid);
1074be691f3bSpatrick }
1075be691f3bSpatrick }
1076be691f3bSpatrick }
1077*f6aab3d8Srobert
1078*f6aab3d8Srobert llvm::Expected<std::string>
SaveCore(llvm::StringRef path_hint)1079*f6aab3d8Srobert NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
1080*f6aab3d8Srobert llvm::SmallString<128> path{path_hint};
1081*f6aab3d8Srobert Status error;
1082*f6aab3d8Srobert
1083*f6aab3d8Srobert // Try with the suggested path first.
1084*f6aab3d8Srobert if (!path.empty()) {
1085*f6aab3d8Srobert error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1086*f6aab3d8Srobert if (!error.Fail())
1087*f6aab3d8Srobert return path.str().str();
1088*f6aab3d8Srobert
1089*f6aab3d8Srobert // If the request errored, fall back to a generic temporary file.
1090*f6aab3d8Srobert }
1091*f6aab3d8Srobert
1092*f6aab3d8Srobert if (std::error_code errc =
1093*f6aab3d8Srobert llvm::sys::fs::createTemporaryFile("lldb", "core", path))
1094*f6aab3d8Srobert return llvm::createStringError(errc, "Unable to create a temporary file");
1095*f6aab3d8Srobert
1096*f6aab3d8Srobert error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1097*f6aab3d8Srobert if (error.Fail())
1098*f6aab3d8Srobert return error.ToError();
1099*f6aab3d8Srobert return path.str().str();
1100*f6aab3d8Srobert }
1101