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 ®ctx = 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