xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1cfca06d7SDimitry Andric //===-- NativeProcessNetBSD.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 "NativeProcessNetBSD.h"
1074a628f7SDimitry Andric 
11706b4fc4SDimitry Andric #include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
1274a628f7SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
1374a628f7SDimitry Andric #include "lldb/Host/HostProcess.h"
1474a628f7SDimitry Andric #include "lldb/Host/common/NativeRegisterContext.h"
1574a628f7SDimitry Andric #include "lldb/Host/posix/ProcessLauncherPosixFork.h"
1674a628f7SDimitry Andric #include "lldb/Target/Process.h"
1794994d37SDimitry Andric #include "lldb/Utility/State.h"
18e75e363cSDimitry Andric #include "llvm/Support/Errno.h"
1974a628f7SDimitry Andric 
2074a628f7SDimitry Andric // System includes - They have to be included after framework includes because
21f73363f1SDimitry Andric // they define some macros which collide with variable names in other modules
2274a628f7SDimitry Andric // clang-format off
2374a628f7SDimitry Andric #include <sys/types.h>
2474a628f7SDimitry Andric #include <sys/ptrace.h>
2574a628f7SDimitry Andric #include <sys/sysctl.h>
2674a628f7SDimitry Andric #include <sys/wait.h>
2774a628f7SDimitry Andric #include <uvm/uvm_prot.h>
2874a628f7SDimitry Andric #include <elf.h>
2974a628f7SDimitry Andric #include <util.h>
3074a628f7SDimitry Andric // clang-format on
3174a628f7SDimitry Andric 
3274a628f7SDimitry Andric using namespace lldb;
3374a628f7SDimitry Andric using namespace lldb_private;
3474a628f7SDimitry Andric using namespace lldb_private::process_netbsd;
3574a628f7SDimitry Andric using namespace llvm;
3674a628f7SDimitry Andric 
3774a628f7SDimitry Andric // Simple helper function to ensure flags are enabled on the given file
3874a628f7SDimitry Andric // descriptor.
EnsureFDFlags(int fd,int flags)39b76161e4SDimitry Andric static Status EnsureFDFlags(int fd, int flags) {
40b76161e4SDimitry Andric   Status error;
4174a628f7SDimitry Andric 
4274a628f7SDimitry Andric   int status = fcntl(fd, F_GETFL);
4374a628f7SDimitry Andric   if (status == -1) {
4474a628f7SDimitry Andric     error.SetErrorToErrno();
4574a628f7SDimitry Andric     return error;
4674a628f7SDimitry Andric   }
4774a628f7SDimitry Andric 
4874a628f7SDimitry Andric   if (fcntl(fd, F_SETFL, status | flags) == -1) {
4974a628f7SDimitry Andric     error.SetErrorToErrno();
5074a628f7SDimitry Andric     return error;
5174a628f7SDimitry Andric   }
5274a628f7SDimitry Andric 
5374a628f7SDimitry Andric   return error;
5474a628f7SDimitry Andric }
5574a628f7SDimitry Andric 
5674a628f7SDimitry Andric // Public Static Methods
5774a628f7SDimitry Andric 
58a884e649SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Launch(ProcessLaunchInfo & launch_info,NativeDelegate & native_delegate)597fa27ce4SDimitry Andric NativeProcessNetBSD::Manager::Launch(ProcessLaunchInfo &launch_info,
607fa27ce4SDimitry Andric                                      NativeDelegate &native_delegate) {
616f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
6274a628f7SDimitry Andric 
63e75e363cSDimitry Andric   Status status;
64e75e363cSDimitry Andric   ::pid_t pid = ProcessLauncherPosixFork()
65e75e363cSDimitry Andric                     .LaunchProcess(launch_info, status)
66e75e363cSDimitry Andric                     .GetProcessId();
67e75e363cSDimitry Andric   LLDB_LOG(log, "pid = {0:x}", pid);
68e75e363cSDimitry Andric   if (status.Fail()) {
69e75e363cSDimitry Andric     LLDB_LOG(log, "failed to launch process: {0}", status);
70e75e363cSDimitry Andric     return status.ToError();
7174a628f7SDimitry Andric   }
7274a628f7SDimitry Andric 
73e75e363cSDimitry Andric   // Wait for the child process to trap on its call to execve.
74e75e363cSDimitry Andric   int wstatus;
75e75e363cSDimitry Andric   ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
76e75e363cSDimitry Andric   assert(wpid == pid);
77e75e363cSDimitry Andric   (void)wpid;
78e75e363cSDimitry Andric   if (!WIFSTOPPED(wstatus)) {
79e75e363cSDimitry Andric     LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
80e75e363cSDimitry Andric              WaitStatus::Decode(wstatus));
81e75e363cSDimitry Andric     return llvm::make_error<StringError>("Could not sync with inferior process",
82e75e363cSDimitry Andric                                          llvm::inconvertibleErrorCode());
83e75e363cSDimitry Andric   }
84e75e363cSDimitry Andric   LLDB_LOG(log, "inferior started, now in stopped state");
8574a628f7SDimitry Andric 
86f73363f1SDimitry Andric   ProcessInstanceInfo Info;
87f73363f1SDimitry Andric   if (!Host::GetProcessInfo(pid, Info)) {
88f73363f1SDimitry Andric     return llvm::make_error<StringError>("Cannot get process architecture",
89f73363f1SDimitry Andric                                          llvm::inconvertibleErrorCode());
90f73363f1SDimitry Andric   }
91e75e363cSDimitry Andric 
92e75e363cSDimitry Andric   // Set the architecture to the exe architecture.
93e75e363cSDimitry Andric   LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
94f73363f1SDimitry Andric            Info.GetArchitecture().GetArchitectureName());
95e75e363cSDimitry Andric 
96a884e649SDimitry Andric   std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
97cfca06d7SDimitry Andric       pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
987fa27ce4SDimitry Andric       Info.GetArchitecture(), m_mainloop));
99e75e363cSDimitry Andric 
100b60736ecSDimitry Andric   status = process_up->SetupTrace();
101e75e363cSDimitry Andric   if (status.Fail())
102e75e363cSDimitry Andric     return status.ToError();
103e75e363cSDimitry Andric 
104ef5d0b5eSDimitry Andric   for (const auto &thread : process_up->m_threads)
105ef5d0b5eSDimitry Andric     static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
106f73363f1SDimitry Andric   process_up->SetState(StateType::eStateStopped, false);
107e75e363cSDimitry Andric 
108a884e649SDimitry Andric   return std::move(process_up);
10974a628f7SDimitry Andric }
11074a628f7SDimitry Andric 
111a884e649SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid,NativeProcessProtocol::NativeDelegate & native_delegate)1127fa27ce4SDimitry Andric NativeProcessNetBSD::Manager::Attach(
1137fa27ce4SDimitry Andric     lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
1146f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
11574a628f7SDimitry Andric   LLDB_LOG(log, "pid = {0:x}", pid);
11674a628f7SDimitry Andric 
11774a628f7SDimitry Andric   // Retrieve the architecture for the running process.
118f73363f1SDimitry Andric   ProcessInstanceInfo Info;
119f73363f1SDimitry Andric   if (!Host::GetProcessInfo(pid, Info)) {
120f73363f1SDimitry Andric     return llvm::make_error<StringError>("Cannot get process architecture",
121f73363f1SDimitry Andric                                          llvm::inconvertibleErrorCode());
122f73363f1SDimitry Andric   }
12374a628f7SDimitry Andric 
124f73363f1SDimitry Andric   std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
1257fa27ce4SDimitry Andric       pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));
12674a628f7SDimitry Andric 
127f73363f1SDimitry Andric   Status status = process_up->Attach();
128e75e363cSDimitry Andric   if (!status.Success())
129e75e363cSDimitry Andric     return status.ToError();
13074a628f7SDimitry Andric 
131a884e649SDimitry Andric   return std::move(process_up);
13274a628f7SDimitry Andric }
13374a628f7SDimitry Andric 
134344a3780SDimitry Andric NativeProcessNetBSD::Extension
GetSupportedExtensions() const1357fa27ce4SDimitry Andric NativeProcessNetBSD::Manager::GetSupportedExtensions() const {
136344a3780SDimitry Andric   return Extension::multiprocess | Extension::fork | Extension::vfork |
137c0981da4SDimitry Andric          Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
138c0981da4SDimitry Andric          Extension::savecore;
139344a3780SDimitry Andric }
140344a3780SDimitry Andric 
14174a628f7SDimitry Andric // Public Instance Methods
14274a628f7SDimitry Andric 
NativeProcessNetBSD(::pid_t pid,int terminal_fd,NativeDelegate & delegate,const ArchSpec & arch,MainLoop & mainloop)143e75e363cSDimitry Andric NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
144e75e363cSDimitry Andric                                          NativeDelegate &delegate,
145e75e363cSDimitry Andric                                          const ArchSpec &arch,
146e75e363cSDimitry Andric                                          MainLoop &mainloop)
147344a3780SDimitry Andric     : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
148344a3780SDimitry Andric       m_main_loop(mainloop) {
149e75e363cSDimitry Andric   if (m_terminal_fd != -1) {
150e75e363cSDimitry Andric     Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
151e75e363cSDimitry Andric     assert(status.Success());
152e75e363cSDimitry Andric   }
153e75e363cSDimitry Andric 
154e75e363cSDimitry Andric   Status status;
155e75e363cSDimitry Andric   m_sigchld_handle = mainloop.RegisterSignal(
156e75e363cSDimitry Andric       SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
157e75e363cSDimitry Andric   assert(m_sigchld_handle && status.Success());
158e75e363cSDimitry Andric }
15974a628f7SDimitry Andric 
16074a628f7SDimitry Andric // Handles all waitpid events from the inferior process.
MonitorCallback(lldb::pid_t pid,int signal)16174a628f7SDimitry Andric void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
16274a628f7SDimitry Andric   switch (signal) {
16374a628f7SDimitry Andric   case SIGTRAP:
16474a628f7SDimitry Andric     return MonitorSIGTRAP(pid);
16574a628f7SDimitry Andric   case SIGSTOP:
16674a628f7SDimitry Andric     return MonitorSIGSTOP(pid);
16774a628f7SDimitry Andric   default:
16874a628f7SDimitry Andric     return MonitorSignal(pid, signal);
16974a628f7SDimitry Andric   }
17074a628f7SDimitry Andric }
17174a628f7SDimitry Andric 
MonitorExited(lldb::pid_t pid,WaitStatus status)172fdea456aSDimitry Andric void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
1736f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
17474a628f7SDimitry Andric 
175fdea456aSDimitry Andric   LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
17674a628f7SDimitry Andric 
17774a628f7SDimitry Andric   /* Stop Tracking All Threads attached to Process */
17874a628f7SDimitry Andric   m_threads.clear();
17974a628f7SDimitry Andric 
180fdea456aSDimitry Andric   SetExitStatus(status, true);
18174a628f7SDimitry Andric 
18274a628f7SDimitry Andric   // Notify delegate that our process has exited.
18374a628f7SDimitry Andric   SetState(StateType::eStateExited, true);
18474a628f7SDimitry Andric }
18574a628f7SDimitry Andric 
MonitorSIGSTOP(lldb::pid_t pid)18674a628f7SDimitry Andric void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
18774a628f7SDimitry Andric   ptrace_siginfo_t info;
18874a628f7SDimitry Andric 
18974a628f7SDimitry Andric   const auto siginfo_err =
19074a628f7SDimitry Andric       PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
19174a628f7SDimitry Andric 
19274a628f7SDimitry Andric   // Get details on the signal raised.
19374a628f7SDimitry Andric   if (siginfo_err.Success()) {
19474a628f7SDimitry Andric     // Handle SIGSTOP from LLGS (LLDB GDB Server)
19574a628f7SDimitry Andric     if (info.psi_siginfo.si_code == SI_USER &&
19674a628f7SDimitry Andric         info.psi_siginfo.si_pid == ::getpid()) {
197ef5d0b5eSDimitry Andric       /* Stop Tracking all Threads attached to Process */
198ef5d0b5eSDimitry Andric       for (const auto &thread : m_threads) {
199ef5d0b5eSDimitry Andric         static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
20074a628f7SDimitry Andric             SIGSTOP, &info.psi_siginfo);
20174a628f7SDimitry Andric       }
20274a628f7SDimitry Andric     }
203ead24645SDimitry Andric     SetState(StateType::eStateStopped, true);
20474a628f7SDimitry Andric   }
20574a628f7SDimitry Andric }
20674a628f7SDimitry Andric 
MonitorSIGTRAP(lldb::pid_t pid)20774a628f7SDimitry Andric void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
2086f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
20974a628f7SDimitry Andric   ptrace_siginfo_t info;
21074a628f7SDimitry Andric 
21174a628f7SDimitry Andric   const auto siginfo_err =
21274a628f7SDimitry Andric       PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
21374a628f7SDimitry Andric 
21474a628f7SDimitry Andric   // Get details on the signal raised.
215d44a35e8SDimitry Andric   if (siginfo_err.Fail()) {
216b60736ecSDimitry Andric     LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
217d44a35e8SDimitry Andric     return;
218d44a35e8SDimitry Andric   }
219d44a35e8SDimitry Andric 
220b60736ecSDimitry Andric   LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
221b60736ecSDimitry Andric            info.psi_lwpid, info.psi_siginfo.si_code);
222706b4fc4SDimitry Andric   NativeThreadNetBSD *thread = nullptr;
223b60736ecSDimitry Andric 
224706b4fc4SDimitry Andric   if (info.psi_lwpid > 0) {
225706b4fc4SDimitry Andric     for (const auto &t : m_threads) {
226706b4fc4SDimitry Andric       if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
227706b4fc4SDimitry Andric         thread = static_cast<NativeThreadNetBSD *>(t.get());
228706b4fc4SDimitry Andric         break;
229706b4fc4SDimitry Andric       }
230706b4fc4SDimitry Andric       static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
231706b4fc4SDimitry Andric     }
232706b4fc4SDimitry Andric     if (!thread)
233b60736ecSDimitry Andric       LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
234706b4fc4SDimitry Andric                info.psi_lwpid);
235706b4fc4SDimitry Andric   }
236706b4fc4SDimitry Andric 
23774a628f7SDimitry Andric   switch (info.psi_siginfo.si_code) {
23874a628f7SDimitry Andric   case TRAP_BRKPT:
239706b4fc4SDimitry Andric     if (thread) {
240706b4fc4SDimitry Andric       thread->SetStoppedByBreakpoint();
241706b4fc4SDimitry Andric       FixupBreakpointPCAsNeeded(*thread);
24274a628f7SDimitry Andric     }
24374a628f7SDimitry Andric     SetState(StateType::eStateStopped, true);
244b60736ecSDimitry Andric     return;
24574a628f7SDimitry Andric   case TRAP_TRACE:
246706b4fc4SDimitry Andric     if (thread)
247706b4fc4SDimitry Andric       thread->SetStoppedByTrace();
24874a628f7SDimitry Andric     SetState(StateType::eStateStopped, true);
249b60736ecSDimitry Andric     return;
25074a628f7SDimitry Andric   case TRAP_EXEC: {
251b76161e4SDimitry Andric     Status error = ReinitializeThreads();
25274a628f7SDimitry Andric     if (error.Fail()) {
25374a628f7SDimitry Andric       SetState(StateType::eStateInvalid);
25474a628f7SDimitry Andric       return;
25574a628f7SDimitry Andric     }
25674a628f7SDimitry Andric 
25774a628f7SDimitry Andric     // Let our delegate know we have just exec'd.
25874a628f7SDimitry Andric     NotifyDidExec();
25974a628f7SDimitry Andric 
260ef5d0b5eSDimitry Andric     for (const auto &thread : m_threads)
261ef5d0b5eSDimitry Andric       static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
26274a628f7SDimitry Andric     SetState(StateType::eStateStopped, true);
263b60736ecSDimitry Andric     return;
264b60736ecSDimitry Andric   }
265344a3780SDimitry Andric   case TRAP_CHLD: {
266344a3780SDimitry Andric     ptrace_state_t pst;
267344a3780SDimitry Andric     Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
268344a3780SDimitry Andric     if (error.Fail()) {
269344a3780SDimitry Andric       SetState(StateType::eStateInvalid);
270344a3780SDimitry Andric       return;
271344a3780SDimitry Andric     }
272344a3780SDimitry Andric 
273344a3780SDimitry Andric     assert(thread);
274344a3780SDimitry Andric     if (pst.pe_report_event == PTRACE_VFORK_DONE) {
275344a3780SDimitry Andric       if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
276344a3780SDimitry Andric         thread->SetStoppedByVForkDone();
277344a3780SDimitry Andric         SetState(StateType::eStateStopped, true);
278344a3780SDimitry Andric       } else {
279344a3780SDimitry Andric         Status error =
280344a3780SDimitry Andric             PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
281344a3780SDimitry Andric         if (error.Fail())
282344a3780SDimitry Andric           SetState(StateType::eStateInvalid);
283344a3780SDimitry Andric       }
284344a3780SDimitry Andric     } else {
285344a3780SDimitry Andric       assert(pst.pe_report_event == PTRACE_FORK ||
286344a3780SDimitry Andric              pst.pe_report_event == PTRACE_VFORK);
287344a3780SDimitry Andric       MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,
288344a3780SDimitry Andric                    *thread);
289344a3780SDimitry Andric     }
290344a3780SDimitry Andric     return;
291344a3780SDimitry Andric   }
292706b4fc4SDimitry Andric   case TRAP_LWP: {
293706b4fc4SDimitry Andric     ptrace_state_t pst;
294706b4fc4SDimitry Andric     Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
295706b4fc4SDimitry Andric     if (error.Fail()) {
296706b4fc4SDimitry Andric       SetState(StateType::eStateInvalid);
297706b4fc4SDimitry Andric       return;
2985f29bb8aSDimitry Andric     }
299706b4fc4SDimitry Andric 
300706b4fc4SDimitry Andric     switch (pst.pe_report_event) {
301706b4fc4SDimitry Andric     case PTRACE_LWP_CREATE: {
302b60736ecSDimitry Andric       LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,
303706b4fc4SDimitry Andric                pst.pe_lwp);
304706b4fc4SDimitry Andric       NativeThreadNetBSD &t = AddThread(pst.pe_lwp);
305706b4fc4SDimitry Andric       error = t.CopyWatchpointsFrom(
306706b4fc4SDimitry Andric           static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
307706b4fc4SDimitry Andric       if (error.Fail()) {
308b60736ecSDimitry Andric         LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
309706b4fc4SDimitry Andric                  pst.pe_lwp, error);
310706b4fc4SDimitry Andric         SetState(StateType::eStateInvalid);
311706b4fc4SDimitry Andric         return;
312706b4fc4SDimitry Andric       }
313706b4fc4SDimitry Andric     } break;
314706b4fc4SDimitry Andric     case PTRACE_LWP_EXIT:
315b60736ecSDimitry Andric       LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,
316706b4fc4SDimitry Andric                pst.pe_lwp);
317706b4fc4SDimitry Andric       RemoveThread(pst.pe_lwp);
3185f29bb8aSDimitry Andric       break;
3195f29bb8aSDimitry Andric     }
3205f29bb8aSDimitry Andric 
321706b4fc4SDimitry Andric     error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
322b60736ecSDimitry Andric     if (error.Fail())
323706b4fc4SDimitry Andric       SetState(StateType::eStateInvalid);
324706b4fc4SDimitry Andric     return;
325706b4fc4SDimitry Andric   }
326706b4fc4SDimitry Andric   case TRAP_DBREG: {
327706b4fc4SDimitry Andric     if (!thread)
328706b4fc4SDimitry Andric       break;
329706b4fc4SDimitry Andric 
330706b4fc4SDimitry Andric     auto &regctx = static_cast<NativeRegisterContextNetBSD &>(
331706b4fc4SDimitry Andric         thread->GetRegisterContext());
3325f29bb8aSDimitry Andric     uint32_t wp_index = LLDB_INVALID_INDEX32;
333b60736ecSDimitry Andric     Status error = regctx.GetWatchpointHitIndex(
334b60736ecSDimitry Andric         wp_index, (uintptr_t)info.psi_siginfo.si_addr);
335d44a35e8SDimitry Andric     if (error.Fail())
336d44a35e8SDimitry Andric       LLDB_LOG(log,
337d44a35e8SDimitry Andric                "received error while checking for watchpoint hits, pid = "
338b60736ecSDimitry Andric                "{0}, LWP = {1}, error = {2}",
339b60736ecSDimitry Andric                pid, info.psi_lwpid, error);
340d44a35e8SDimitry Andric     if (wp_index != LLDB_INVALID_INDEX32) {
341706b4fc4SDimitry Andric       thread->SetStoppedByWatchpoint(wp_index);
342706b4fc4SDimitry Andric       regctx.ClearWatchpointHit(wp_index);
343d44a35e8SDimitry Andric       SetState(StateType::eStateStopped, true);
344b60736ecSDimitry Andric       return;
345d44a35e8SDimitry Andric     }
346d44a35e8SDimitry Andric 
347706b4fc4SDimitry Andric     thread->SetStoppedByTrace();
348d44a35e8SDimitry Andric     SetState(StateType::eStateStopped, true);
349b60736ecSDimitry Andric     return;
35074a628f7SDimitry Andric   }
35174a628f7SDimitry Andric   }
35274a628f7SDimitry Andric 
353b60736ecSDimitry Andric   // Either user-generated SIGTRAP or an unknown event that would
354b60736ecSDimitry Andric   // otherwise leave the debugger hanging.
355b60736ecSDimitry Andric   LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
356b60736ecSDimitry Andric   MonitorSignal(pid, SIGTRAP);
357b60736ecSDimitry Andric }
358b60736ecSDimitry Andric 
MonitorSignal(lldb::pid_t pid,int signal)35974a628f7SDimitry Andric void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
3606f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
36174a628f7SDimitry Andric   ptrace_siginfo_t info;
362b60736ecSDimitry Andric 
36374a628f7SDimitry Andric   const auto siginfo_err =
36474a628f7SDimitry Andric       PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
365b60736ecSDimitry Andric   if (siginfo_err.Fail()) {
366b60736ecSDimitry Andric     LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
367b60736ecSDimitry Andric     return;
368b60736ecSDimitry Andric   }
36974a628f7SDimitry Andric 
370706b4fc4SDimitry Andric   for (const auto &abs_thread : m_threads) {
371706b4fc4SDimitry Andric     NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
372706b4fc4SDimitry Andric     assert(info.psi_lwpid >= 0);
373706b4fc4SDimitry Andric     if (info.psi_lwpid == 0 ||
374706b4fc4SDimitry Andric         static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
375706b4fc4SDimitry Andric       thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
376706b4fc4SDimitry Andric     else
377706b4fc4SDimitry Andric       thread.SetStoppedWithNoReason();
37874a628f7SDimitry Andric   }
37974a628f7SDimitry Andric   SetState(StateType::eStateStopped, true);
38074a628f7SDimitry Andric }
38174a628f7SDimitry Andric 
StopProcess(lldb::pid_t pid)382b1c73532SDimitry Andric Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) {
383b1c73532SDimitry Andric #ifdef PT_STOP
384b1c73532SDimitry Andric   return PtraceWrapper(PT_STOP, pid);
385b1c73532SDimitry Andric #else
386b1c73532SDimitry Andric   Log *log = GetLog(POSIXLog::Ptrace);
387b1c73532SDimitry Andric   Status error;
388b1c73532SDimitry Andric   int ret;
389b1c73532SDimitry Andric 
390b1c73532SDimitry Andric   errno = 0;
391b1c73532SDimitry Andric   ret = kill(pid, SIGSTOP);
392b1c73532SDimitry Andric 
393b1c73532SDimitry Andric   if (ret == -1)
394b1c73532SDimitry Andric     error.SetErrorToErrno();
395b1c73532SDimitry Andric 
396b1c73532SDimitry Andric   LLDB_LOG(log, "kill({0}, SIGSTOP)", pid);
397b1c73532SDimitry Andric 
398b1c73532SDimitry Andric   if (error.Fail())
399b1c73532SDimitry Andric     LLDB_LOG(log, "kill() failed: {0}", error);
400b1c73532SDimitry Andric 
401b1c73532SDimitry Andric   return error;
402b1c73532SDimitry Andric #endif
403b1c73532SDimitry Andric }
404b1c73532SDimitry Andric 
PtraceWrapper(int req,lldb::pid_t pid,void * addr,int data,int * result)405b76161e4SDimitry Andric Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
40674a628f7SDimitry Andric                                           int data, int *result) {
4076f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Ptrace);
408b76161e4SDimitry Andric   Status error;
40974a628f7SDimitry Andric   int ret;
41074a628f7SDimitry Andric 
41174a628f7SDimitry Andric   errno = 0;
41274a628f7SDimitry Andric   ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
41374a628f7SDimitry Andric 
41474a628f7SDimitry Andric   if (ret == -1)
41574a628f7SDimitry Andric     error.SetErrorToErrno();
41674a628f7SDimitry Andric 
41774a628f7SDimitry Andric   if (result)
41874a628f7SDimitry Andric     *result = ret;
41974a628f7SDimitry Andric 
42074a628f7SDimitry Andric   LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
42174a628f7SDimitry Andric 
42274a628f7SDimitry Andric   if (error.Fail())
42374a628f7SDimitry Andric     LLDB_LOG(log, "ptrace() failed: {0}", error);
42474a628f7SDimitry Andric 
42574a628f7SDimitry Andric   return error;
42674a628f7SDimitry Andric }
42774a628f7SDimitry Andric 
ComputeSignalInfo(const std::vector<std::unique_ptr<NativeThreadProtocol>> & threads,const ResumeActionList & resume_actions)428706b4fc4SDimitry Andric static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
429706b4fc4SDimitry Andric     const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
430706b4fc4SDimitry Andric     const ResumeActionList &resume_actions) {
431706b4fc4SDimitry Andric   // We need to account for three possible scenarios:
432706b4fc4SDimitry Andric   // 1. no signal being sent.
433706b4fc4SDimitry Andric   // 2. a signal being sent to one thread.
434706b4fc4SDimitry Andric   // 3. a signal being sent to the whole process.
435706b4fc4SDimitry Andric 
436706b4fc4SDimitry Andric   // Count signaled threads.  While at it, determine which signal is being sent
437706b4fc4SDimitry Andric   // and ensure there's only one.
438706b4fc4SDimitry Andric   size_t signaled_threads = 0;
439706b4fc4SDimitry Andric   int signal = LLDB_INVALID_SIGNAL_NUMBER;
440706b4fc4SDimitry Andric   lldb::tid_t signaled_lwp;
441706b4fc4SDimitry Andric   for (const auto &thread : threads) {
442706b4fc4SDimitry Andric     assert(thread && "thread list should not contain NULL threads");
443706b4fc4SDimitry Andric     const ResumeAction *action =
444706b4fc4SDimitry Andric         resume_actions.GetActionForThread(thread->GetID(), true);
445706b4fc4SDimitry Andric     if (action) {
446706b4fc4SDimitry Andric       if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {
447706b4fc4SDimitry Andric         signaled_threads++;
448706b4fc4SDimitry Andric         if (action->signal != signal) {
449706b4fc4SDimitry Andric           if (signal != LLDB_INVALID_SIGNAL_NUMBER)
450706b4fc4SDimitry Andric             return Status("NetBSD does not support passing multiple signals "
451706b4fc4SDimitry Andric                           "simultaneously")
452706b4fc4SDimitry Andric                 .ToError();
453706b4fc4SDimitry Andric           signal = action->signal;
454706b4fc4SDimitry Andric           signaled_lwp = thread->GetID();
455706b4fc4SDimitry Andric         }
456706b4fc4SDimitry Andric       }
457706b4fc4SDimitry Andric     }
458706b4fc4SDimitry Andric   }
459706b4fc4SDimitry Andric 
460706b4fc4SDimitry Andric   if (signaled_threads == 0) {
461706b4fc4SDimitry Andric     ptrace_siginfo_t siginfo;
462706b4fc4SDimitry Andric     siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
463706b4fc4SDimitry Andric     return siginfo;
464706b4fc4SDimitry Andric   }
465706b4fc4SDimitry Andric 
466706b4fc4SDimitry Andric   if (signaled_threads > 1 && signaled_threads < threads.size())
467706b4fc4SDimitry Andric     return Status("NetBSD does not support passing signal to 1<i<all threads")
468706b4fc4SDimitry Andric         .ToError();
469706b4fc4SDimitry Andric 
470706b4fc4SDimitry Andric   ptrace_siginfo_t siginfo;
471706b4fc4SDimitry Andric   siginfo.psi_siginfo.si_signo = signal;
472706b4fc4SDimitry Andric   siginfo.psi_siginfo.si_code = SI_USER;
473706b4fc4SDimitry Andric   siginfo.psi_siginfo.si_pid = getpid();
474706b4fc4SDimitry Andric   siginfo.psi_siginfo.si_uid = getuid();
475706b4fc4SDimitry Andric   if (signaled_threads == 1)
476706b4fc4SDimitry Andric     siginfo.psi_lwpid = signaled_lwp;
477706b4fc4SDimitry Andric   else // signal for the whole process
478706b4fc4SDimitry Andric     siginfo.psi_lwpid = 0;
479706b4fc4SDimitry Andric   return siginfo;
480706b4fc4SDimitry Andric }
481706b4fc4SDimitry Andric 
Resume(const ResumeActionList & resume_actions)482b76161e4SDimitry Andric Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
4836f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
48474a628f7SDimitry Andric   LLDB_LOG(log, "pid {0}", GetID());
48574a628f7SDimitry Andric 
486706b4fc4SDimitry Andric   Status ret;
487706b4fc4SDimitry Andric 
488706b4fc4SDimitry Andric   Expected<ptrace_siginfo_t> siginfo =
489706b4fc4SDimitry Andric       ComputeSignalInfo(m_threads, resume_actions);
490706b4fc4SDimitry Andric   if (!siginfo)
491706b4fc4SDimitry Andric     return Status(siginfo.takeError());
492706b4fc4SDimitry Andric 
493706b4fc4SDimitry Andric   for (const auto &abs_thread : m_threads) {
494706b4fc4SDimitry Andric     assert(abs_thread && "thread list should not contain NULL threads");
495706b4fc4SDimitry Andric     NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
496706b4fc4SDimitry Andric 
497706b4fc4SDimitry Andric     const ResumeAction *action =
498706b4fc4SDimitry Andric         resume_actions.GetActionForThread(thread.GetID(), true);
499706b4fc4SDimitry Andric     // we need to explicit issue suspend requests, so it is simpler to map it
500706b4fc4SDimitry Andric     // into proper action
501706b4fc4SDimitry Andric     ResumeAction suspend_action{thread.GetID(), eStateSuspended,
502706b4fc4SDimitry Andric                                 LLDB_INVALID_SIGNAL_NUMBER};
50374a628f7SDimitry Andric 
50474a628f7SDimitry Andric     if (action == nullptr) {
50574a628f7SDimitry Andric       LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
506706b4fc4SDimitry Andric                thread.GetID());
507706b4fc4SDimitry Andric       action = &suspend_action;
50874a628f7SDimitry Andric     }
50974a628f7SDimitry Andric 
510706b4fc4SDimitry Andric     LLDB_LOG(
511706b4fc4SDimitry Andric         log,
512706b4fc4SDimitry Andric         "processing resume action state {0} signal {1} for pid {2} tid {3}",
513706b4fc4SDimitry Andric         action->state, action->signal, GetID(), thread.GetID());
51474a628f7SDimitry Andric 
51574a628f7SDimitry Andric     switch (action->state) {
516706b4fc4SDimitry Andric     case eStateRunning:
517706b4fc4SDimitry Andric       ret = thread.Resume();
51874a628f7SDimitry Andric       break;
51974a628f7SDimitry Andric     case eStateStepping:
520706b4fc4SDimitry Andric       ret = thread.SingleStep();
52174a628f7SDimitry Andric       break;
52274a628f7SDimitry Andric     case eStateSuspended:
52374a628f7SDimitry Andric     case eStateStopped:
524706b4fc4SDimitry Andric       if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
525706b4fc4SDimitry Andric         return Status("Passing signal to suspended thread unsupported");
526706b4fc4SDimitry Andric 
527706b4fc4SDimitry Andric       ret = thread.Suspend();
528706b4fc4SDimitry Andric       break;
52974a628f7SDimitry Andric 
53074a628f7SDimitry Andric     default:
531b76161e4SDimitry Andric       return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
53274a628f7SDimitry Andric                     "for pid %" PRIu64 ", tid %" PRIu64,
53374a628f7SDimitry Andric                     __FUNCTION__, StateAsCString(action->state), GetID(),
534706b4fc4SDimitry Andric                     thread.GetID());
53574a628f7SDimitry Andric     }
53674a628f7SDimitry Andric 
537706b4fc4SDimitry Andric     if (!ret.Success())
538706b4fc4SDimitry Andric       return ret;
539706b4fc4SDimitry Andric   }
540706b4fc4SDimitry Andric 
541706b4fc4SDimitry Andric   int signal = 0;
542706b4fc4SDimitry Andric   if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
543706b4fc4SDimitry Andric     ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
544706b4fc4SDimitry Andric                         sizeof(*siginfo));
545706b4fc4SDimitry Andric     if (!ret.Success())
546706b4fc4SDimitry Andric       return ret;
547706b4fc4SDimitry Andric     signal = siginfo->psi_siginfo.si_signo;
548706b4fc4SDimitry Andric   }
549706b4fc4SDimitry Andric 
550b60736ecSDimitry Andric   ret =
551b60736ecSDimitry Andric       PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
552706b4fc4SDimitry Andric   if (ret.Success())
553706b4fc4SDimitry Andric     SetState(eStateRunning, true);
554706b4fc4SDimitry Andric   return ret;
55574a628f7SDimitry Andric }
55674a628f7SDimitry Andric 
Halt()557b1c73532SDimitry Andric Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); }
55874a628f7SDimitry Andric 
Detach()559b76161e4SDimitry Andric Status NativeProcessNetBSD::Detach() {
560b76161e4SDimitry Andric   Status error;
56174a628f7SDimitry Andric 
56274a628f7SDimitry Andric   // Stop monitoring the inferior.
56374a628f7SDimitry Andric   m_sigchld_handle.reset();
56474a628f7SDimitry Andric 
56574a628f7SDimitry Andric   // Tell ptrace to detach from the process.
56674a628f7SDimitry Andric   if (GetID() == LLDB_INVALID_PROCESS_ID)
56774a628f7SDimitry Andric     return error;
56874a628f7SDimitry Andric 
569344a3780SDimitry Andric   return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
57074a628f7SDimitry Andric }
57174a628f7SDimitry Andric 
Signal(int signo)572b76161e4SDimitry Andric Status NativeProcessNetBSD::Signal(int signo) {
573b76161e4SDimitry Andric   Status error;
57474a628f7SDimitry Andric 
57574a628f7SDimitry Andric   if (kill(GetID(), signo))
57674a628f7SDimitry Andric     error.SetErrorToErrno();
57774a628f7SDimitry Andric 
57874a628f7SDimitry Andric   return error;
57974a628f7SDimitry Andric }
58074a628f7SDimitry Andric 
Interrupt()581b1c73532SDimitry Andric Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); }
582706b4fc4SDimitry Andric 
Kill()583b76161e4SDimitry Andric Status NativeProcessNetBSD::Kill() {
5846f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
58574a628f7SDimitry Andric   LLDB_LOG(log, "pid {0}", GetID());
58674a628f7SDimitry Andric 
587b76161e4SDimitry Andric   Status error;
58874a628f7SDimitry Andric 
58974a628f7SDimitry Andric   switch (m_state) {
59074a628f7SDimitry Andric   case StateType::eStateInvalid:
59174a628f7SDimitry Andric   case StateType::eStateExited:
59274a628f7SDimitry Andric   case StateType::eStateCrashed:
59374a628f7SDimitry Andric   case StateType::eStateDetached:
59474a628f7SDimitry Andric   case StateType::eStateUnloaded:
59574a628f7SDimitry Andric     // Nothing to do - the process is already dead.
59674a628f7SDimitry Andric     LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
59774a628f7SDimitry Andric              StateAsCString(m_state));
59874a628f7SDimitry Andric     return error;
59974a628f7SDimitry Andric 
60074a628f7SDimitry Andric   case StateType::eStateConnected:
60174a628f7SDimitry Andric   case StateType::eStateAttaching:
60274a628f7SDimitry Andric   case StateType::eStateLaunching:
60374a628f7SDimitry Andric   case StateType::eStateStopped:
60474a628f7SDimitry Andric   case StateType::eStateRunning:
60574a628f7SDimitry Andric   case StateType::eStateStepping:
60674a628f7SDimitry Andric   case StateType::eStateSuspended:
60774a628f7SDimitry Andric     // We can try to kill a process in these states.
60874a628f7SDimitry Andric     break;
60974a628f7SDimitry Andric   }
61074a628f7SDimitry Andric 
61174a628f7SDimitry Andric   if (kill(GetID(), SIGKILL) != 0) {
61274a628f7SDimitry Andric     error.SetErrorToErrno();
61374a628f7SDimitry Andric     return error;
61474a628f7SDimitry Andric   }
61574a628f7SDimitry Andric 
61674a628f7SDimitry Andric   return error;
61774a628f7SDimitry Andric }
61874a628f7SDimitry Andric 
GetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & range_info)619b76161e4SDimitry Andric Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
62074a628f7SDimitry Andric                                                 MemoryRegionInfo &range_info) {
62174a628f7SDimitry Andric 
62274a628f7SDimitry Andric   if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
62374a628f7SDimitry Andric     // We're done.
624b76161e4SDimitry Andric     return Status("unsupported");
62574a628f7SDimitry Andric   }
62674a628f7SDimitry Andric 
627b76161e4SDimitry Andric   Status error = PopulateMemoryRegionCache();
62874a628f7SDimitry Andric   if (error.Fail()) {
62974a628f7SDimitry Andric     return error;
63074a628f7SDimitry Andric   }
63174a628f7SDimitry Andric 
63274a628f7SDimitry Andric   lldb::addr_t prev_base_address = 0;
63374a628f7SDimitry Andric   // FIXME start by finding the last region that is <= target address using
63474a628f7SDimitry Andric   // binary search.  Data is sorted.
63574a628f7SDimitry Andric   // There can be a ton of regions on pthreads apps with lots of threads.
63674a628f7SDimitry Andric   for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
63774a628f7SDimitry Andric        ++it) {
63874a628f7SDimitry Andric     MemoryRegionInfo &proc_entry_info = it->first;
63974a628f7SDimitry Andric     // Sanity check assumption that memory map entries are ascending.
64074a628f7SDimitry Andric     assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
64174a628f7SDimitry Andric            "descending memory map entries detected, unexpected");
64274a628f7SDimitry Andric     prev_base_address = proc_entry_info.GetRange().GetRangeBase();
64374a628f7SDimitry Andric     UNUSED_IF_ASSERT_DISABLED(prev_base_address);
644f73363f1SDimitry Andric     // If the target address comes before this entry, indicate distance to next
645f73363f1SDimitry Andric     // region.
64674a628f7SDimitry Andric     if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
64774a628f7SDimitry Andric       range_info.GetRange().SetRangeBase(load_addr);
64874a628f7SDimitry Andric       range_info.GetRange().SetByteSize(
64974a628f7SDimitry Andric           proc_entry_info.GetRange().GetRangeBase() - load_addr);
65074a628f7SDimitry Andric       range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
65174a628f7SDimitry Andric       range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
65274a628f7SDimitry Andric       range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
65374a628f7SDimitry Andric       range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
65474a628f7SDimitry Andric       return error;
65574a628f7SDimitry Andric     } else if (proc_entry_info.GetRange().Contains(load_addr)) {
65674a628f7SDimitry Andric       // The target address is within the memory region we're processing here.
65774a628f7SDimitry Andric       range_info = proc_entry_info;
65874a628f7SDimitry Andric       return error;
65974a628f7SDimitry Andric     }
66074a628f7SDimitry Andric     // The target memory address comes somewhere after the region we just
66174a628f7SDimitry Andric     // parsed.
66274a628f7SDimitry Andric   }
66374a628f7SDimitry Andric   // If we made it here, we didn't find an entry that contained the given
664f73363f1SDimitry Andric   // address. Return the load_addr as start and the amount of bytes betwwen
665f73363f1SDimitry Andric   // load address and the end of the memory as size.
66674a628f7SDimitry Andric   range_info.GetRange().SetRangeBase(load_addr);
66774a628f7SDimitry Andric   range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
66874a628f7SDimitry Andric   range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
66974a628f7SDimitry Andric   range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
67074a628f7SDimitry Andric   range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
67174a628f7SDimitry Andric   range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
67274a628f7SDimitry Andric   return error;
67374a628f7SDimitry Andric }
67474a628f7SDimitry Andric 
PopulateMemoryRegionCache()675b76161e4SDimitry Andric Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
6766f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
67774a628f7SDimitry Andric   // If our cache is empty, pull the latest.  There should always be at least
67874a628f7SDimitry Andric   // one memory region if memory region handling is supported.
67974a628f7SDimitry Andric   if (!m_mem_region_cache.empty()) {
68074a628f7SDimitry Andric     LLDB_LOG(log, "reusing {0} cached memory region entries",
68174a628f7SDimitry Andric              m_mem_region_cache.size());
682b76161e4SDimitry Andric     return Status();
68374a628f7SDimitry Andric   }
68474a628f7SDimitry Andric 
68574a628f7SDimitry Andric   struct kinfo_vmentry *vm;
68674a628f7SDimitry Andric   size_t count, i;
68774a628f7SDimitry Andric   vm = kinfo_getvmmap(GetID(), &count);
68874a628f7SDimitry Andric   if (vm == NULL) {
68974a628f7SDimitry Andric     m_supports_mem_region = LazyBool::eLazyBoolNo;
690b76161e4SDimitry Andric     Status error;
69174a628f7SDimitry Andric     error.SetErrorString("not supported");
69274a628f7SDimitry Andric     return error;
69374a628f7SDimitry Andric   }
69474a628f7SDimitry Andric   for (i = 0; i < count; i++) {
69574a628f7SDimitry Andric     MemoryRegionInfo info;
69674a628f7SDimitry Andric     info.Clear();
69774a628f7SDimitry Andric     info.GetRange().SetRangeBase(vm[i].kve_start);
69874a628f7SDimitry Andric     info.GetRange().SetRangeEnd(vm[i].kve_end);
69974a628f7SDimitry Andric     info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
70074a628f7SDimitry Andric 
70174a628f7SDimitry Andric     if (vm[i].kve_protection & VM_PROT_READ)
70274a628f7SDimitry Andric       info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
70374a628f7SDimitry Andric     else
70474a628f7SDimitry Andric       info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
70574a628f7SDimitry Andric 
70674a628f7SDimitry Andric     if (vm[i].kve_protection & VM_PROT_WRITE)
70774a628f7SDimitry Andric       info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
70874a628f7SDimitry Andric     else
70974a628f7SDimitry Andric       info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
71074a628f7SDimitry Andric 
71174a628f7SDimitry Andric     if (vm[i].kve_protection & VM_PROT_EXECUTE)
71274a628f7SDimitry Andric       info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
71374a628f7SDimitry Andric     else
71474a628f7SDimitry Andric       info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
71574a628f7SDimitry Andric 
71674a628f7SDimitry Andric     if (vm[i].kve_path[0])
71774a628f7SDimitry Andric       info.SetName(vm[i].kve_path);
71874a628f7SDimitry Andric 
719b60736ecSDimitry Andric     m_mem_region_cache.emplace_back(info,
720b60736ecSDimitry Andric                                     FileSpec(info.GetName().GetCString()));
72174a628f7SDimitry Andric   }
72274a628f7SDimitry Andric   free(vm);
72374a628f7SDimitry Andric 
72474a628f7SDimitry Andric   if (m_mem_region_cache.empty()) {
725f73363f1SDimitry Andric     // No entries after attempting to read them.  This shouldn't happen. Assume
726f73363f1SDimitry Andric     // we don't support map entries.
72774a628f7SDimitry Andric     LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
72874a628f7SDimitry Andric                   "for memory region metadata retrieval");
72974a628f7SDimitry Andric     m_supports_mem_region = LazyBool::eLazyBoolNo;
730b76161e4SDimitry Andric     Status error;
73174a628f7SDimitry Andric     error.SetErrorString("not supported");
73274a628f7SDimitry Andric     return error;
73374a628f7SDimitry Andric   }
73474a628f7SDimitry Andric   LLDB_LOG(log, "read {0} memory region entries from process {1}",
73574a628f7SDimitry Andric            m_mem_region_cache.size(), GetID());
73674a628f7SDimitry Andric   // We support memory retrieval, remember that.
73774a628f7SDimitry Andric   m_supports_mem_region = LazyBool::eLazyBoolYes;
738b76161e4SDimitry Andric   return Status();
73974a628f7SDimitry Andric }
74074a628f7SDimitry Andric 
GetSharedLibraryInfoAddress()74174a628f7SDimitry Andric lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
74274a628f7SDimitry Andric   // punt on this for now
74374a628f7SDimitry Andric   return LLDB_INVALID_ADDRESS;
74474a628f7SDimitry Andric }
74574a628f7SDimitry Andric 
UpdateThreads()74674a628f7SDimitry Andric size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
74774a628f7SDimitry Andric 
SetBreakpoint(lldb::addr_t addr,uint32_t size,bool hardware)748b76161e4SDimitry Andric Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
74974a628f7SDimitry Andric                                           bool hardware) {
75074a628f7SDimitry Andric   if (hardware)
751b76161e4SDimitry Andric     return Status("NativeProcessNetBSD does not support hardware breakpoints");
75274a628f7SDimitry Andric   else
75374a628f7SDimitry Andric     return SetSoftwareBreakpoint(addr, size);
75474a628f7SDimitry Andric }
75574a628f7SDimitry Andric 
GetLoadedModuleFileSpec(const char * module_path,FileSpec & file_spec)756b76161e4SDimitry Andric Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
75774a628f7SDimitry Andric                                                     FileSpec &file_spec) {
758b60736ecSDimitry Andric   Status error = PopulateMemoryRegionCache();
759b60736ecSDimitry Andric   if (error.Fail())
760b60736ecSDimitry Andric     return error;
761b60736ecSDimitry Andric 
762b60736ecSDimitry Andric   FileSpec module_file_spec(module_path);
763b60736ecSDimitry Andric   FileSystem::Instance().Resolve(module_file_spec);
764b60736ecSDimitry Andric 
765b60736ecSDimitry Andric   file_spec.Clear();
766b60736ecSDimitry Andric   for (const auto &it : m_mem_region_cache) {
767b60736ecSDimitry Andric     if (it.second.GetFilename() == module_file_spec.GetFilename()) {
768b60736ecSDimitry Andric       file_spec = it.second;
769b60736ecSDimitry Andric       return Status();
770b60736ecSDimitry Andric     }
771b60736ecSDimitry Andric   }
772b60736ecSDimitry Andric   return Status("Module file (%s) not found in process' memory map!",
773b60736ecSDimitry Andric                 module_file_spec.GetFilename().AsCString());
77474a628f7SDimitry Andric }
77574a628f7SDimitry Andric 
GetFileLoadAddress(const llvm::StringRef & file_name,lldb::addr_t & load_addr)776b76161e4SDimitry Andric Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
77774a628f7SDimitry Andric                                                lldb::addr_t &load_addr) {
77874a628f7SDimitry Andric   load_addr = LLDB_INVALID_ADDRESS;
779b60736ecSDimitry Andric   Status error = PopulateMemoryRegionCache();
780b60736ecSDimitry Andric   if (error.Fail())
781b60736ecSDimitry Andric     return error;
782b60736ecSDimitry Andric 
783b60736ecSDimitry Andric   FileSpec file(file_name);
784b60736ecSDimitry Andric   for (const auto &it : m_mem_region_cache) {
785b60736ecSDimitry Andric     if (it.second == file) {
786b60736ecSDimitry Andric       load_addr = it.first.GetRange().GetRangeBase();
787b76161e4SDimitry Andric       return Status();
78874a628f7SDimitry Andric     }
789b60736ecSDimitry Andric   }
790b60736ecSDimitry Andric   return Status("No load address found for file %s.", file_name.str().c_str());
791b60736ecSDimitry Andric }
79274a628f7SDimitry Andric 
SigchldHandler()79374a628f7SDimitry Andric void NativeProcessNetBSD::SigchldHandler() {
7946f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
79574a628f7SDimitry Andric   int status;
796b60736ecSDimitry Andric   ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
797b60736ecSDimitry Andric                                                  WALLSIG | WNOHANG);
79874a628f7SDimitry Andric 
79974a628f7SDimitry Andric   if (wait_pid == 0)
800344a3780SDimitry Andric     return;
80174a628f7SDimitry Andric 
80274a628f7SDimitry Andric   if (wait_pid == -1) {
803b76161e4SDimitry Andric     Status error(errno, eErrorTypePOSIX);
80474a628f7SDimitry Andric     LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
805344a3780SDimitry Andric     return;
80674a628f7SDimitry Andric   }
80774a628f7SDimitry Andric 
808fdea456aSDimitry Andric   WaitStatus wait_status = WaitStatus::Decode(status);
809fdea456aSDimitry Andric   bool exited = wait_status.type == WaitStatus::Exit ||
810fdea456aSDimitry Andric                 (wait_status.type == WaitStatus::Signal &&
811fdea456aSDimitry Andric                  wait_pid == static_cast<::pid_t>(GetID()));
81274a628f7SDimitry Andric 
81374a628f7SDimitry Andric   LLDB_LOG(log,
814fdea456aSDimitry Andric            "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
815fdea456aSDimitry Andric            GetID(), wait_pid, status, exited);
81674a628f7SDimitry Andric 
81774a628f7SDimitry Andric   if (exited)
818fdea456aSDimitry Andric     MonitorExited(wait_pid, wait_status);
819fdea456aSDimitry Andric   else {
820fdea456aSDimitry Andric     assert(wait_status.type == WaitStatus::Stop);
821fdea456aSDimitry Andric     MonitorCallback(wait_pid, wait_status.status);
822fdea456aSDimitry Andric   }
82374a628f7SDimitry Andric }
82474a628f7SDimitry Andric 
HasThreadNoLock(lldb::tid_t thread_id)82561b440f5SDimitry Andric bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
826ef5d0b5eSDimitry Andric   for (const auto &thread : m_threads) {
827ef5d0b5eSDimitry Andric     assert(thread && "thread list should not contain NULL threads");
828ef5d0b5eSDimitry Andric     if (thread->GetID() == thread_id) {
82961b440f5SDimitry Andric       // We have this thread.
83061b440f5SDimitry Andric       return true;
83161b440f5SDimitry Andric     }
83261b440f5SDimitry Andric   }
83361b440f5SDimitry Andric 
83461b440f5SDimitry Andric   // We don't have this thread.
83561b440f5SDimitry Andric   return false;
83661b440f5SDimitry Andric }
83761b440f5SDimitry Andric 
AddThread(lldb::tid_t thread_id)838ef5d0b5eSDimitry Andric NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
8396f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
84074a628f7SDimitry Andric   LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
84174a628f7SDimitry Andric 
842706b4fc4SDimitry Andric   assert(thread_id > 0);
84374a628f7SDimitry Andric   assert(!HasThreadNoLock(thread_id) &&
84474a628f7SDimitry Andric          "attempted to add a thread by id that already exists");
84574a628f7SDimitry Andric 
84674a628f7SDimitry Andric   // If this is the first thread, save it as the current thread
84774a628f7SDimitry Andric   if (m_threads.empty())
84874a628f7SDimitry Andric     SetCurrentThreadID(thread_id);
84974a628f7SDimitry Andric 
850ead24645SDimitry Andric   m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));
851ef5d0b5eSDimitry Andric   return static_cast<NativeThreadNetBSD &>(*m_threads.back());
85274a628f7SDimitry Andric }
85374a628f7SDimitry Andric 
RemoveThread(lldb::tid_t thread_id)854706b4fc4SDimitry Andric void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
8556f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Thread);
856706b4fc4SDimitry Andric   LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
857706b4fc4SDimitry Andric 
858706b4fc4SDimitry Andric   assert(thread_id > 0);
859706b4fc4SDimitry Andric   assert(HasThreadNoLock(thread_id) &&
860706b4fc4SDimitry Andric          "attempted to remove a thread that does not exist");
861706b4fc4SDimitry Andric 
862706b4fc4SDimitry Andric   for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
863706b4fc4SDimitry Andric     if ((*it)->GetID() == thread_id) {
864706b4fc4SDimitry Andric       m_threads.erase(it);
865706b4fc4SDimitry Andric       break;
866706b4fc4SDimitry Andric     }
867706b4fc4SDimitry Andric   }
868706b4fc4SDimitry Andric }
869706b4fc4SDimitry Andric 
Attach()870e75e363cSDimitry Andric Status NativeProcessNetBSD::Attach() {
87174a628f7SDimitry Andric   // Attach to the requested process.
87274a628f7SDimitry Andric   // An attach will cause the thread to stop with a SIGSTOP.
873e75e363cSDimitry Andric   Status status = PtraceWrapper(PT_ATTACH, m_pid);
874e75e363cSDimitry Andric   if (status.Fail())
875e75e363cSDimitry Andric     return status;
87674a628f7SDimitry Andric 
877e75e363cSDimitry Andric   int wstatus;
878f73363f1SDimitry Andric   // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
879f73363f1SDimitry Andric   // point we should have a thread stopped if waitpid succeeds.
880b60736ecSDimitry Andric   if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,
881b60736ecSDimitry Andric                                              WALLSIG)) < 0)
882e75e363cSDimitry Andric     return Status(errno, eErrorTypePOSIX);
88374a628f7SDimitry Andric 
884b60736ecSDimitry Andric   // Initialize threads and tracing status
885b60736ecSDimitry Andric   // NB: this needs to be called before we set thread state
886b60736ecSDimitry Andric   status = SetupTrace();
887e75e363cSDimitry Andric   if (status.Fail())
888e75e363cSDimitry Andric     return status;
88974a628f7SDimitry Andric 
890ef5d0b5eSDimitry Andric   for (const auto &thread : m_threads)
891ef5d0b5eSDimitry Andric     static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
892d44a35e8SDimitry Andric 
89374a628f7SDimitry Andric   // Let our process instance know the thread has stopped.
894b60736ecSDimitry Andric   SetCurrentThreadID(m_threads.front()->GetID());
895b60736ecSDimitry Andric   SetState(StateType::eStateStopped, false);
896e75e363cSDimitry Andric   return Status();
89774a628f7SDimitry Andric }
89874a628f7SDimitry Andric 
ReadMemory(lldb::addr_t addr,void * buf,size_t size,size_t & bytes_read)899b76161e4SDimitry Andric Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
900b76161e4SDimitry Andric                                        size_t size, size_t &bytes_read) {
90174a628f7SDimitry Andric   unsigned char *dst = static_cast<unsigned char *>(buf);
90274a628f7SDimitry Andric   struct ptrace_io_desc io;
90374a628f7SDimitry Andric 
9046f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Memory);
90574a628f7SDimitry Andric   LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
90674a628f7SDimitry Andric 
90774a628f7SDimitry Andric   bytes_read = 0;
90874a628f7SDimitry Andric   io.piod_op = PIOD_READ_D;
90974a628f7SDimitry Andric   io.piod_len = size;
91074a628f7SDimitry Andric 
91174a628f7SDimitry Andric   do {
91274a628f7SDimitry Andric     io.piod_offs = (void *)(addr + bytes_read);
91374a628f7SDimitry Andric     io.piod_addr = dst + bytes_read;
91474a628f7SDimitry Andric 
915b76161e4SDimitry Andric     Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
9165f29bb8aSDimitry Andric     if (error.Fail() || io.piod_len == 0)
91774a628f7SDimitry Andric       return error;
91874a628f7SDimitry Andric 
9195f29bb8aSDimitry Andric     bytes_read += io.piod_len;
92074a628f7SDimitry Andric     io.piod_len = size - bytes_read;
92174a628f7SDimitry Andric   } while (bytes_read < size);
92274a628f7SDimitry Andric 
923b76161e4SDimitry Andric   return Status();
92474a628f7SDimitry Andric }
92574a628f7SDimitry Andric 
WriteMemory(lldb::addr_t addr,const void * buf,size_t size,size_t & bytes_written)926b76161e4SDimitry Andric Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
92774a628f7SDimitry Andric                                         size_t size, size_t &bytes_written) {
92874a628f7SDimitry Andric   const unsigned char *src = static_cast<const unsigned char *>(buf);
929b76161e4SDimitry Andric   Status error;
93074a628f7SDimitry Andric   struct ptrace_io_desc io;
93174a628f7SDimitry Andric 
9326f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Memory);
93374a628f7SDimitry Andric   LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
93474a628f7SDimitry Andric 
93574a628f7SDimitry Andric   bytes_written = 0;
93674a628f7SDimitry Andric   io.piod_op = PIOD_WRITE_D;
93774a628f7SDimitry Andric   io.piod_len = size;
93874a628f7SDimitry Andric 
93974a628f7SDimitry Andric   do {
940b60736ecSDimitry Andric     io.piod_addr =
941b60736ecSDimitry Andric         const_cast<void *>(static_cast<const void *>(src + bytes_written));
94274a628f7SDimitry Andric     io.piod_offs = (void *)(addr + bytes_written);
94374a628f7SDimitry Andric 
944b76161e4SDimitry Andric     Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
9455f29bb8aSDimitry Andric     if (error.Fail() || io.piod_len == 0)
94674a628f7SDimitry Andric       return error;
94774a628f7SDimitry Andric 
9485f29bb8aSDimitry Andric     bytes_written += io.piod_len;
94974a628f7SDimitry Andric     io.piod_len = size - bytes_written;
95074a628f7SDimitry Andric   } while (bytes_written < size);
95174a628f7SDimitry Andric 
95274a628f7SDimitry Andric   return error;
95374a628f7SDimitry Andric }
95474a628f7SDimitry Andric 
95574a628f7SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const95674a628f7SDimitry Andric NativeProcessNetBSD::GetAuxvData() const {
95774a628f7SDimitry Andric   /*
95874a628f7SDimitry Andric    * ELF_AUX_ENTRIES is currently restricted to kernel
95974a628f7SDimitry Andric    * (<sys/exec_elf.h> r. 1.155 specifies 15)
96074a628f7SDimitry Andric    *
96174a628f7SDimitry Andric    * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
96274a628f7SDimitry Andric    * information isn't needed.
96374a628f7SDimitry Andric    */
96474a628f7SDimitry Andric   size_t auxv_size = 100 * sizeof(AuxInfo);
96574a628f7SDimitry Andric 
966f73363f1SDimitry Andric   ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
967f73363f1SDimitry Andric       llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
96874a628f7SDimitry Andric 
96961b440f5SDimitry Andric   struct ptrace_io_desc io;
97061b440f5SDimitry Andric   io.piod_op = PIOD_READ_AUXV;
97161b440f5SDimitry Andric   io.piod_offs = 0;
972f73363f1SDimitry Andric   io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());
97361b440f5SDimitry Andric   io.piod_len = auxv_size;
97474a628f7SDimitry Andric 
975b76161e4SDimitry Andric   Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
97674a628f7SDimitry Andric 
97774a628f7SDimitry Andric   if (error.Fail())
97874a628f7SDimitry Andric     return std::error_code(error.GetError(), std::generic_category());
97974a628f7SDimitry Andric 
98074a628f7SDimitry Andric   if (io.piod_len < 1)
98174a628f7SDimitry Andric     return std::error_code(ECANCELED, std::generic_category());
98274a628f7SDimitry Andric 
983f73363f1SDimitry Andric   return std::move(buf);
98474a628f7SDimitry Andric }
98574a628f7SDimitry Andric 
SetupTrace()986b60736ecSDimitry Andric Status NativeProcessNetBSD::SetupTrace() {
987b60736ecSDimitry Andric   // Enable event reporting
988b60736ecSDimitry Andric   ptrace_event_t events;
989b60736ecSDimitry Andric   Status status =
990b60736ecSDimitry Andric       PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
991b60736ecSDimitry Andric   if (status.Fail())
992b60736ecSDimitry Andric     return status;
993344a3780SDimitry Andric   // TODO: PTRACE_POSIX_SPAWN?
994344a3780SDimitry Andric   events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
995344a3780SDimitry Andric                          PTRACE_VFORK | PTRACE_VFORK_DONE;
996b60736ecSDimitry Andric   status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
997b60736ecSDimitry Andric   if (status.Fail())
998b60736ecSDimitry Andric     return status;
999b60736ecSDimitry Andric 
1000b60736ecSDimitry Andric   return ReinitializeThreads();
1001b60736ecSDimitry Andric }
1002b60736ecSDimitry Andric 
ReinitializeThreads()1003b76161e4SDimitry Andric Status NativeProcessNetBSD::ReinitializeThreads() {
100474a628f7SDimitry Andric   // Clear old threads
100574a628f7SDimitry Andric   m_threads.clear();
100674a628f7SDimitry Andric 
100774a628f7SDimitry Andric   // Initialize new thread
1008706b4fc4SDimitry Andric #ifdef PT_LWPSTATUS
1009706b4fc4SDimitry Andric   struct ptrace_lwpstatus info = {};
1010706b4fc4SDimitry Andric   int op = PT_LWPNEXT;
1011706b4fc4SDimitry Andric #else
101274a628f7SDimitry Andric   struct ptrace_lwpinfo info = {};
1013706b4fc4SDimitry Andric   int op = PT_LWPINFO;
1014706b4fc4SDimitry Andric #endif
1015706b4fc4SDimitry Andric 
1016706b4fc4SDimitry Andric   Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));
1017706b4fc4SDimitry Andric 
101874a628f7SDimitry Andric   if (error.Fail()) {
101974a628f7SDimitry Andric     return error;
102074a628f7SDimitry Andric   }
102174a628f7SDimitry Andric   // Reinitialize from scratch threads and register them in process
102274a628f7SDimitry Andric   while (info.pl_lwpid != 0) {
1023ef5d0b5eSDimitry Andric     AddThread(info.pl_lwpid);
1024706b4fc4SDimitry Andric     error = PtraceWrapper(op, GetID(), &info, sizeof(info));
102574a628f7SDimitry Andric     if (error.Fail()) {
102674a628f7SDimitry Andric       return error;
102774a628f7SDimitry Andric     }
102874a628f7SDimitry Andric   }
102974a628f7SDimitry Andric 
103074a628f7SDimitry Andric   return error;
103174a628f7SDimitry Andric }
1032344a3780SDimitry Andric 
MonitorClone(::pid_t child_pid,bool is_vfork,NativeThreadNetBSD & parent_thread)1033344a3780SDimitry Andric void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
1034344a3780SDimitry Andric                                        NativeThreadNetBSD &parent_thread) {
10356f8fc217SDimitry Andric   Log *log = GetLog(POSIXLog::Process);
1036344a3780SDimitry Andric   LLDB_LOG(log, "clone, child_pid={0}", child_pid);
1037344a3780SDimitry Andric 
1038344a3780SDimitry Andric   int status;
1039344a3780SDimitry Andric   ::pid_t wait_pid =
1040344a3780SDimitry Andric       llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
1041344a3780SDimitry Andric   if (wait_pid != child_pid) {
1042344a3780SDimitry Andric     LLDB_LOG(log,
1043344a3780SDimitry Andric              "waiting for pid {0} failed. Assuming the pid has "
1044344a3780SDimitry Andric              "disappeared in the meantime",
1045344a3780SDimitry Andric              child_pid);
1046344a3780SDimitry Andric     return;
1047344a3780SDimitry Andric   }
1048344a3780SDimitry Andric   if (WIFEXITED(status)) {
1049344a3780SDimitry Andric     LLDB_LOG(log,
1050344a3780SDimitry Andric              "waiting for pid {0} returned an 'exited' event. Not "
1051344a3780SDimitry Andric              "tracking it.",
1052344a3780SDimitry Andric              child_pid);
1053344a3780SDimitry Andric     return;
1054344a3780SDimitry Andric   }
1055344a3780SDimitry Andric 
1056344a3780SDimitry Andric   ptrace_siginfo_t info;
1057344a3780SDimitry Andric   const auto siginfo_err =
1058344a3780SDimitry Andric       PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));
1059344a3780SDimitry Andric   if (siginfo_err.Fail()) {
1060344a3780SDimitry Andric     LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
1061344a3780SDimitry Andric     return;
1062344a3780SDimitry Andric   }
1063344a3780SDimitry Andric   assert(info.psi_lwpid >= 0);
1064344a3780SDimitry Andric   lldb::tid_t child_tid = info.psi_lwpid;
1065344a3780SDimitry Andric 
1066344a3780SDimitry Andric   std::unique_ptr<NativeProcessNetBSD> child_process{
1067344a3780SDimitry Andric       new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,
1068344a3780SDimitry Andric                               m_delegate, m_arch, m_main_loop)};
1069344a3780SDimitry Andric   if (!is_vfork)
1070344a3780SDimitry Andric     child_process->m_software_breakpoints = m_software_breakpoints;
1071344a3780SDimitry Andric 
1072344a3780SDimitry Andric   Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
1073344a3780SDimitry Andric   if ((m_enabled_extensions & expected_ext) == expected_ext) {
1074344a3780SDimitry Andric     child_process->SetupTrace();
1075344a3780SDimitry Andric     for (const auto &thread : child_process->m_threads)
1076344a3780SDimitry Andric       static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
1077344a3780SDimitry Andric     child_process->SetState(StateType::eStateStopped, false);
1078344a3780SDimitry Andric 
1079344a3780SDimitry Andric     m_delegate.NewSubprocess(this, std::move(child_process));
1080344a3780SDimitry Andric     if (is_vfork)
1081344a3780SDimitry Andric       parent_thread.SetStoppedByVFork(child_pid, child_tid);
1082344a3780SDimitry Andric     else
1083344a3780SDimitry Andric       parent_thread.SetStoppedByFork(child_pid, child_tid);
1084344a3780SDimitry Andric     SetState(StateType::eStateStopped, true);
1085344a3780SDimitry Andric   } else {
1086344a3780SDimitry Andric     child_process->Detach();
1087344a3780SDimitry Andric     Status pt_error =
1088344a3780SDimitry Andric         PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
1089344a3780SDimitry Andric     if (pt_error.Fail()) {
1090344a3780SDimitry Andric       LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),
1091344a3780SDimitry Andric                      "unable to resume parent process {1}: {0}", GetID());
1092344a3780SDimitry Andric       SetState(StateType::eStateInvalid);
1093344a3780SDimitry Andric     }
1094344a3780SDimitry Andric   }
1095344a3780SDimitry Andric }
1096c0981da4SDimitry Andric 
1097c0981da4SDimitry Andric llvm::Expected<std::string>
SaveCore(llvm::StringRef path_hint)1098c0981da4SDimitry Andric NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
1099c0981da4SDimitry Andric   llvm::SmallString<128> path{path_hint};
1100c0981da4SDimitry Andric   Status error;
1101c0981da4SDimitry Andric 
1102c0981da4SDimitry Andric   // Try with the suggested path first.
1103c0981da4SDimitry Andric   if (!path.empty()) {
1104c0981da4SDimitry Andric     error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1105c0981da4SDimitry Andric     if (!error.Fail())
1106c0981da4SDimitry Andric       return path.str().str();
1107c0981da4SDimitry Andric 
1108c0981da4SDimitry Andric     // If the request errored, fall back to a generic temporary file.
1109c0981da4SDimitry Andric   }
1110c0981da4SDimitry Andric 
1111c0981da4SDimitry Andric   if (std::error_code errc =
1112c0981da4SDimitry Andric           llvm::sys::fs::createTemporaryFile("lldb", "core", path))
1113c0981da4SDimitry Andric     return llvm::createStringError(errc, "Unable to create a temporary file");
1114c0981da4SDimitry Andric 
1115c0981da4SDimitry Andric   error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1116c0981da4SDimitry Andric   if (error.Fail())
1117c0981da4SDimitry Andric     return error.ToError();
1118c0981da4SDimitry Andric   return path.str().str();
1119c0981da4SDimitry Andric }
1120