15ffd83dbSDimitry Andric //===-- NativeProcessNetBSD.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "NativeProcessNetBSD.h"
100b57cec5SDimitry Andric
11480093f4SDimitry Andric #include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
120b57cec5SDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
130b57cec5SDimitry Andric #include "lldb/Host/HostProcess.h"
140b57cec5SDimitry Andric #include "lldb/Host/common/NativeRegisterContext.h"
150b57cec5SDimitry Andric #include "lldb/Host/posix/ProcessLauncherPosixFork.h"
160b57cec5SDimitry Andric #include "lldb/Target/Process.h"
170b57cec5SDimitry Andric #include "lldb/Utility/State.h"
180b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric // System includes - They have to be included after framework includes because
210b57cec5SDimitry Andric // they define some macros which collide with variable names in other modules
220b57cec5SDimitry Andric // clang-format off
230b57cec5SDimitry Andric #include <sys/types.h>
240b57cec5SDimitry Andric #include <sys/ptrace.h>
250b57cec5SDimitry Andric #include <sys/sysctl.h>
260b57cec5SDimitry Andric #include <sys/wait.h>
270b57cec5SDimitry Andric #include <uvm/uvm_prot.h>
280b57cec5SDimitry Andric #include <elf.h>
290b57cec5SDimitry Andric #include <util.h>
300b57cec5SDimitry Andric // clang-format on
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric using namespace lldb;
330b57cec5SDimitry Andric using namespace lldb_private;
340b57cec5SDimitry Andric using namespace lldb_private::process_netbsd;
350b57cec5SDimitry Andric using namespace llvm;
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric // Simple helper function to ensure flags are enabled on the given file
380b57cec5SDimitry Andric // descriptor.
EnsureFDFlags(int fd,int flags)390b57cec5SDimitry Andric static Status EnsureFDFlags(int fd, int flags) {
400b57cec5SDimitry Andric Status error;
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric int status = fcntl(fd, F_GETFL);
430b57cec5SDimitry Andric if (status == -1) {
440b57cec5SDimitry Andric error.SetErrorToErrno();
450b57cec5SDimitry Andric return error;
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric if (fcntl(fd, F_SETFL, status | flags) == -1) {
490b57cec5SDimitry Andric error.SetErrorToErrno();
500b57cec5SDimitry Andric return error;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric return error;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric // Public Static Methods
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Launch(ProcessLaunchInfo & launch_info,NativeDelegate & native_delegate)59fe013be4SDimitry Andric NativeProcessNetBSD::Manager::Launch(ProcessLaunchInfo &launch_info,
60fe013be4SDimitry Andric NativeDelegate &native_delegate) {
6104eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric Status status;
640b57cec5SDimitry Andric ::pid_t pid = ProcessLauncherPosixFork()
650b57cec5SDimitry Andric .LaunchProcess(launch_info, status)
660b57cec5SDimitry Andric .GetProcessId();
670b57cec5SDimitry Andric LLDB_LOG(log, "pid = {0:x}", pid);
680b57cec5SDimitry Andric if (status.Fail()) {
690b57cec5SDimitry Andric LLDB_LOG(log, "failed to launch process: {0}", status);
700b57cec5SDimitry Andric return status.ToError();
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric // Wait for the child process to trap on its call to execve.
740b57cec5SDimitry Andric int wstatus;
750b57cec5SDimitry Andric ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
760b57cec5SDimitry Andric assert(wpid == pid);
770b57cec5SDimitry Andric (void)wpid;
780b57cec5SDimitry Andric if (!WIFSTOPPED(wstatus)) {
790b57cec5SDimitry Andric LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
800b57cec5SDimitry Andric WaitStatus::Decode(wstatus));
810b57cec5SDimitry Andric return llvm::make_error<StringError>("Could not sync with inferior process",
820b57cec5SDimitry Andric llvm::inconvertibleErrorCode());
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric LLDB_LOG(log, "inferior started, now in stopped state");
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric ProcessInstanceInfo Info;
870b57cec5SDimitry Andric if (!Host::GetProcessInfo(pid, Info)) {
880b57cec5SDimitry Andric return llvm::make_error<StringError>("Cannot get process architecture",
890b57cec5SDimitry Andric llvm::inconvertibleErrorCode());
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric // Set the architecture to the exe architecture.
930b57cec5SDimitry Andric LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
940b57cec5SDimitry Andric Info.GetArchitecture().GetArchitectureName());
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
975ffd83dbSDimitry Andric pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
98fe013be4SDimitry Andric Info.GetArchitecture(), m_mainloop));
990b57cec5SDimitry Andric
100e8d8bef9SDimitry Andric status = process_up->SetupTrace();
1010b57cec5SDimitry Andric if (status.Fail())
1020b57cec5SDimitry Andric return status.ToError();
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric for (const auto &thread : process_up->m_threads)
1050b57cec5SDimitry Andric static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
1060b57cec5SDimitry Andric process_up->SetState(StateType::eStateStopped, false);
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric return std::move(process_up);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid,NativeProcessProtocol::NativeDelegate & native_delegate)112fe013be4SDimitry Andric NativeProcessNetBSD::Manager::Attach(
113fe013be4SDimitry Andric lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
11404eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
1150b57cec5SDimitry Andric LLDB_LOG(log, "pid = {0:x}", pid);
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric // Retrieve the architecture for the running process.
1180b57cec5SDimitry Andric ProcessInstanceInfo Info;
1190b57cec5SDimitry Andric if (!Host::GetProcessInfo(pid, Info)) {
1200b57cec5SDimitry Andric return llvm::make_error<StringError>("Cannot get process architecture",
1210b57cec5SDimitry Andric llvm::inconvertibleErrorCode());
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
125fe013be4SDimitry Andric pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric Status status = process_up->Attach();
1280b57cec5SDimitry Andric if (!status.Success())
1290b57cec5SDimitry Andric return status.ToError();
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric return std::move(process_up);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
134fe6060f1SDimitry Andric NativeProcessNetBSD::Extension
GetSupportedExtensions() const135fe013be4SDimitry Andric NativeProcessNetBSD::Manager::GetSupportedExtensions() const {
136fe6060f1SDimitry Andric return Extension::multiprocess | Extension::fork | Extension::vfork |
137349cc55cSDimitry Andric Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
138349cc55cSDimitry Andric Extension::savecore;
139fe6060f1SDimitry Andric }
140fe6060f1SDimitry Andric
1410b57cec5SDimitry Andric // Public Instance Methods
1420b57cec5SDimitry Andric
NativeProcessNetBSD(::pid_t pid,int terminal_fd,NativeDelegate & delegate,const ArchSpec & arch,MainLoop & mainloop)1430b57cec5SDimitry Andric NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
1440b57cec5SDimitry Andric NativeDelegate &delegate,
1450b57cec5SDimitry Andric const ArchSpec &arch,
1460b57cec5SDimitry Andric MainLoop &mainloop)
147fe6060f1SDimitry Andric : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
148fe6060f1SDimitry Andric m_main_loop(mainloop) {
1490b57cec5SDimitry Andric if (m_terminal_fd != -1) {
1500b57cec5SDimitry Andric Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
1510b57cec5SDimitry Andric assert(status.Success());
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric Status status;
1550b57cec5SDimitry Andric m_sigchld_handle = mainloop.RegisterSignal(
1560b57cec5SDimitry Andric SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
1570b57cec5SDimitry Andric assert(m_sigchld_handle && status.Success());
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric // Handles all waitpid events from the inferior process.
MonitorCallback(lldb::pid_t pid,int signal)1610b57cec5SDimitry Andric void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
1620b57cec5SDimitry Andric switch (signal) {
1630b57cec5SDimitry Andric case SIGTRAP:
1640b57cec5SDimitry Andric return MonitorSIGTRAP(pid);
1650b57cec5SDimitry Andric case SIGSTOP:
1660b57cec5SDimitry Andric return MonitorSIGSTOP(pid);
1670b57cec5SDimitry Andric default:
1680b57cec5SDimitry Andric return MonitorSignal(pid, signal);
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
MonitorExited(lldb::pid_t pid,WaitStatus status)1720b57cec5SDimitry Andric void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
17304eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric /* Stop Tracking All Threads attached to Process */
1780b57cec5SDimitry Andric m_threads.clear();
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric SetExitStatus(status, true);
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric // Notify delegate that our process has exited.
1830b57cec5SDimitry Andric SetState(StateType::eStateExited, true);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
MonitorSIGSTOP(lldb::pid_t pid)1860b57cec5SDimitry Andric void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
1870b57cec5SDimitry Andric ptrace_siginfo_t info;
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric const auto siginfo_err =
1900b57cec5SDimitry Andric PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric // Get details on the signal raised.
1930b57cec5SDimitry Andric if (siginfo_err.Success()) {
1940b57cec5SDimitry Andric // Handle SIGSTOP from LLGS (LLDB GDB Server)
1950b57cec5SDimitry Andric if (info.psi_siginfo.si_code == SI_USER &&
1960b57cec5SDimitry Andric info.psi_siginfo.si_pid == ::getpid()) {
1970b57cec5SDimitry Andric /* Stop Tracking all Threads attached to Process */
1980b57cec5SDimitry Andric for (const auto &thread : m_threads) {
1990b57cec5SDimitry Andric static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
2000b57cec5SDimitry Andric SIGSTOP, &info.psi_siginfo);
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric }
2039dba64beSDimitry Andric SetState(StateType::eStateStopped, true);
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric
MonitorSIGTRAP(lldb::pid_t pid)2070b57cec5SDimitry Andric void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
20804eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
2090b57cec5SDimitry Andric ptrace_siginfo_t info;
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric const auto siginfo_err =
2120b57cec5SDimitry Andric PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric // Get details on the signal raised.
2150b57cec5SDimitry Andric if (siginfo_err.Fail()) {
216e8d8bef9SDimitry Andric LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
2170b57cec5SDimitry Andric return;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric
220e8d8bef9SDimitry Andric LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
221e8d8bef9SDimitry Andric info.psi_lwpid, info.psi_siginfo.si_code);
222480093f4SDimitry Andric NativeThreadNetBSD *thread = nullptr;
223e8d8bef9SDimitry Andric
224480093f4SDimitry Andric if (info.psi_lwpid > 0) {
225480093f4SDimitry Andric for (const auto &t : m_threads) {
226480093f4SDimitry Andric if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
227480093f4SDimitry Andric thread = static_cast<NativeThreadNetBSD *>(t.get());
228480093f4SDimitry Andric break;
229480093f4SDimitry Andric }
230480093f4SDimitry Andric static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
231480093f4SDimitry Andric }
232480093f4SDimitry Andric if (!thread)
233e8d8bef9SDimitry Andric LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
234480093f4SDimitry Andric info.psi_lwpid);
235480093f4SDimitry Andric }
236480093f4SDimitry Andric
2370b57cec5SDimitry Andric switch (info.psi_siginfo.si_code) {
2380b57cec5SDimitry Andric case TRAP_BRKPT:
239480093f4SDimitry Andric if (thread) {
240480093f4SDimitry Andric thread->SetStoppedByBreakpoint();
241480093f4SDimitry Andric FixupBreakpointPCAsNeeded(*thread);
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
244e8d8bef9SDimitry Andric return;
2450b57cec5SDimitry Andric case TRAP_TRACE:
246480093f4SDimitry Andric if (thread)
247480093f4SDimitry Andric thread->SetStoppedByTrace();
2480b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
249e8d8bef9SDimitry Andric return;
2500b57cec5SDimitry Andric case TRAP_EXEC: {
2510b57cec5SDimitry Andric Status error = ReinitializeThreads();
2520b57cec5SDimitry Andric if (error.Fail()) {
2530b57cec5SDimitry Andric SetState(StateType::eStateInvalid);
2540b57cec5SDimitry Andric return;
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric // Let our delegate know we have just exec'd.
2580b57cec5SDimitry Andric NotifyDidExec();
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric for (const auto &thread : m_threads)
2610b57cec5SDimitry Andric static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
2620b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
263e8d8bef9SDimitry Andric return;
264e8d8bef9SDimitry Andric }
265fe6060f1SDimitry Andric case TRAP_CHLD: {
266fe6060f1SDimitry Andric ptrace_state_t pst;
267fe6060f1SDimitry Andric Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
268fe6060f1SDimitry Andric if (error.Fail()) {
269fe6060f1SDimitry Andric SetState(StateType::eStateInvalid);
270fe6060f1SDimitry Andric return;
271fe6060f1SDimitry Andric }
272fe6060f1SDimitry Andric
273fe6060f1SDimitry Andric assert(thread);
274fe6060f1SDimitry Andric if (pst.pe_report_event == PTRACE_VFORK_DONE) {
275fe6060f1SDimitry Andric if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
276fe6060f1SDimitry Andric thread->SetStoppedByVForkDone();
277fe6060f1SDimitry Andric SetState(StateType::eStateStopped, true);
278fe6060f1SDimitry Andric } else {
279fe6060f1SDimitry Andric Status error =
280fe6060f1SDimitry Andric PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
281fe6060f1SDimitry Andric if (error.Fail())
282fe6060f1SDimitry Andric SetState(StateType::eStateInvalid);
283fe6060f1SDimitry Andric }
284fe6060f1SDimitry Andric } else {
285fe6060f1SDimitry Andric assert(pst.pe_report_event == PTRACE_FORK ||
286fe6060f1SDimitry Andric pst.pe_report_event == PTRACE_VFORK);
287fe6060f1SDimitry Andric MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,
288fe6060f1SDimitry Andric *thread);
289fe6060f1SDimitry Andric }
290fe6060f1SDimitry Andric return;
291fe6060f1SDimitry Andric }
292480093f4SDimitry Andric case TRAP_LWP: {
293480093f4SDimitry Andric ptrace_state_t pst;
294480093f4SDimitry Andric Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
295480093f4SDimitry Andric if (error.Fail()) {
296480093f4SDimitry Andric SetState(StateType::eStateInvalid);
297480093f4SDimitry Andric return;
2980b57cec5SDimitry Andric }
299480093f4SDimitry Andric
300480093f4SDimitry Andric switch (pst.pe_report_event) {
301480093f4SDimitry Andric case PTRACE_LWP_CREATE: {
302e8d8bef9SDimitry Andric LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,
303480093f4SDimitry Andric pst.pe_lwp);
304480093f4SDimitry Andric NativeThreadNetBSD &t = AddThread(pst.pe_lwp);
305480093f4SDimitry Andric error = t.CopyWatchpointsFrom(
306480093f4SDimitry Andric static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
307480093f4SDimitry Andric if (error.Fail()) {
308e8d8bef9SDimitry Andric LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
309480093f4SDimitry Andric pst.pe_lwp, error);
310480093f4SDimitry Andric SetState(StateType::eStateInvalid);
311480093f4SDimitry Andric return;
312480093f4SDimitry Andric }
313480093f4SDimitry Andric } break;
314480093f4SDimitry Andric case PTRACE_LWP_EXIT:
315e8d8bef9SDimitry Andric LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,
316480093f4SDimitry Andric pst.pe_lwp);
317480093f4SDimitry Andric RemoveThread(pst.pe_lwp);
3180b57cec5SDimitry Andric break;
3190b57cec5SDimitry Andric }
3200b57cec5SDimitry Andric
321480093f4SDimitry Andric error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
322e8d8bef9SDimitry Andric if (error.Fail())
323480093f4SDimitry Andric SetState(StateType::eStateInvalid);
324480093f4SDimitry Andric return;
325480093f4SDimitry Andric }
326480093f4SDimitry Andric case TRAP_DBREG: {
327480093f4SDimitry Andric if (!thread)
328480093f4SDimitry Andric break;
329480093f4SDimitry Andric
330480093f4SDimitry Andric auto ®ctx = static_cast<NativeRegisterContextNetBSD &>(
331480093f4SDimitry Andric thread->GetRegisterContext());
3320b57cec5SDimitry Andric uint32_t wp_index = LLDB_INVALID_INDEX32;
333e8d8bef9SDimitry Andric Status error = regctx.GetWatchpointHitIndex(
334e8d8bef9SDimitry Andric wp_index, (uintptr_t)info.psi_siginfo.si_addr);
3350b57cec5SDimitry Andric if (error.Fail())
3360b57cec5SDimitry Andric LLDB_LOG(log,
3370b57cec5SDimitry Andric "received error while checking for watchpoint hits, pid = "
338e8d8bef9SDimitry Andric "{0}, LWP = {1}, error = {2}",
339e8d8bef9SDimitry Andric pid, info.psi_lwpid, error);
3400b57cec5SDimitry Andric if (wp_index != LLDB_INVALID_INDEX32) {
341480093f4SDimitry Andric thread->SetStoppedByWatchpoint(wp_index);
342480093f4SDimitry Andric regctx.ClearWatchpointHit(wp_index);
3430b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
344e8d8bef9SDimitry Andric return;
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric
347480093f4SDimitry Andric thread->SetStoppedByTrace();
3480b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
349e8d8bef9SDimitry Andric return;
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric
353e8d8bef9SDimitry Andric // Either user-generated SIGTRAP or an unknown event that would
354e8d8bef9SDimitry Andric // otherwise leave the debugger hanging.
355e8d8bef9SDimitry Andric LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
356e8d8bef9SDimitry Andric MonitorSignal(pid, SIGTRAP);
357e8d8bef9SDimitry Andric }
358e8d8bef9SDimitry Andric
MonitorSignal(lldb::pid_t pid,int signal)3590b57cec5SDimitry Andric void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
36004eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
3610b57cec5SDimitry Andric ptrace_siginfo_t info;
362e8d8bef9SDimitry Andric
3630b57cec5SDimitry Andric const auto siginfo_err =
3640b57cec5SDimitry Andric PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
365e8d8bef9SDimitry Andric if (siginfo_err.Fail()) {
366e8d8bef9SDimitry Andric LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
367e8d8bef9SDimitry Andric return;
368e8d8bef9SDimitry Andric }
3690b57cec5SDimitry Andric
370480093f4SDimitry Andric for (const auto &abs_thread : m_threads) {
371480093f4SDimitry Andric NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
372480093f4SDimitry Andric assert(info.psi_lwpid >= 0);
373480093f4SDimitry Andric if (info.psi_lwpid == 0 ||
374480093f4SDimitry Andric static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
375480093f4SDimitry Andric thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
376480093f4SDimitry Andric else
377480093f4SDimitry Andric thread.SetStoppedWithNoReason();
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric SetState(StateType::eStateStopped, true);
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric
StopProcess(lldb::pid_t pid)382*c9157d92SDimitry Andric Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) {
383*c9157d92SDimitry Andric #ifdef PT_STOP
384*c9157d92SDimitry Andric return PtraceWrapper(PT_STOP, pid);
385*c9157d92SDimitry Andric #else
386*c9157d92SDimitry Andric Log *log = GetLog(POSIXLog::Ptrace);
387*c9157d92SDimitry Andric Status error;
388*c9157d92SDimitry Andric int ret;
389*c9157d92SDimitry Andric
390*c9157d92SDimitry Andric errno = 0;
391*c9157d92SDimitry Andric ret = kill(pid, SIGSTOP);
392*c9157d92SDimitry Andric
393*c9157d92SDimitry Andric if (ret == -1)
394*c9157d92SDimitry Andric error.SetErrorToErrno();
395*c9157d92SDimitry Andric
396*c9157d92SDimitry Andric LLDB_LOG(log, "kill({0}, SIGSTOP)", pid);
397*c9157d92SDimitry Andric
398*c9157d92SDimitry Andric if (error.Fail())
399*c9157d92SDimitry Andric LLDB_LOG(log, "kill() failed: {0}", error);
400*c9157d92SDimitry Andric
401*c9157d92SDimitry Andric return error;
402*c9157d92SDimitry Andric #endif
403*c9157d92SDimitry Andric }
404*c9157d92SDimitry Andric
PtraceWrapper(int req,lldb::pid_t pid,void * addr,int data,int * result)4050b57cec5SDimitry Andric Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
4060b57cec5SDimitry Andric int data, int *result) {
40704eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Ptrace);
4080b57cec5SDimitry Andric Status error;
4090b57cec5SDimitry Andric int ret;
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric errno = 0;
4120b57cec5SDimitry Andric ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
4130b57cec5SDimitry Andric
4140b57cec5SDimitry Andric if (ret == -1)
4150b57cec5SDimitry Andric error.SetErrorToErrno();
4160b57cec5SDimitry Andric
4170b57cec5SDimitry Andric if (result)
4180b57cec5SDimitry Andric *result = ret;
4190b57cec5SDimitry Andric
4200b57cec5SDimitry Andric LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
4210b57cec5SDimitry Andric
4220b57cec5SDimitry Andric if (error.Fail())
4230b57cec5SDimitry Andric LLDB_LOG(log, "ptrace() failed: {0}", error);
4240b57cec5SDimitry Andric
4250b57cec5SDimitry Andric return error;
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric
ComputeSignalInfo(const std::vector<std::unique_ptr<NativeThreadProtocol>> & threads,const ResumeActionList & resume_actions)428480093f4SDimitry Andric static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
429480093f4SDimitry Andric const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
430480093f4SDimitry Andric const ResumeActionList &resume_actions) {
431480093f4SDimitry Andric // We need to account for three possible scenarios:
432480093f4SDimitry Andric // 1. no signal being sent.
433480093f4SDimitry Andric // 2. a signal being sent to one thread.
434480093f4SDimitry Andric // 3. a signal being sent to the whole process.
435480093f4SDimitry Andric
436480093f4SDimitry Andric // Count signaled threads. While at it, determine which signal is being sent
437480093f4SDimitry Andric // and ensure there's only one.
438480093f4SDimitry Andric size_t signaled_threads = 0;
439480093f4SDimitry Andric int signal = LLDB_INVALID_SIGNAL_NUMBER;
440480093f4SDimitry Andric lldb::tid_t signaled_lwp;
441480093f4SDimitry Andric for (const auto &thread : threads) {
442480093f4SDimitry Andric assert(thread && "thread list should not contain NULL threads");
443480093f4SDimitry Andric const ResumeAction *action =
444480093f4SDimitry Andric resume_actions.GetActionForThread(thread->GetID(), true);
445480093f4SDimitry Andric if (action) {
446480093f4SDimitry Andric if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {
447480093f4SDimitry Andric signaled_threads++;
448480093f4SDimitry Andric if (action->signal != signal) {
449480093f4SDimitry Andric if (signal != LLDB_INVALID_SIGNAL_NUMBER)
450480093f4SDimitry Andric return Status("NetBSD does not support passing multiple signals "
451480093f4SDimitry Andric "simultaneously")
452480093f4SDimitry Andric .ToError();
453480093f4SDimitry Andric signal = action->signal;
454480093f4SDimitry Andric signaled_lwp = thread->GetID();
455480093f4SDimitry Andric }
456480093f4SDimitry Andric }
457480093f4SDimitry Andric }
458480093f4SDimitry Andric }
459480093f4SDimitry Andric
460480093f4SDimitry Andric if (signaled_threads == 0) {
461480093f4SDimitry Andric ptrace_siginfo_t siginfo;
462480093f4SDimitry Andric siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
463480093f4SDimitry Andric return siginfo;
464480093f4SDimitry Andric }
465480093f4SDimitry Andric
466480093f4SDimitry Andric if (signaled_threads > 1 && signaled_threads < threads.size())
467480093f4SDimitry Andric return Status("NetBSD does not support passing signal to 1<i<all threads")
468480093f4SDimitry Andric .ToError();
469480093f4SDimitry Andric
470480093f4SDimitry Andric ptrace_siginfo_t siginfo;
471480093f4SDimitry Andric siginfo.psi_siginfo.si_signo = signal;
472480093f4SDimitry Andric siginfo.psi_siginfo.si_code = SI_USER;
473480093f4SDimitry Andric siginfo.psi_siginfo.si_pid = getpid();
474480093f4SDimitry Andric siginfo.psi_siginfo.si_uid = getuid();
475480093f4SDimitry Andric if (signaled_threads == 1)
476480093f4SDimitry Andric siginfo.psi_lwpid = signaled_lwp;
477480093f4SDimitry Andric else // signal for the whole process
478480093f4SDimitry Andric siginfo.psi_lwpid = 0;
479480093f4SDimitry Andric return siginfo;
480480093f4SDimitry Andric }
481480093f4SDimitry Andric
Resume(const ResumeActionList & resume_actions)4820b57cec5SDimitry Andric Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
48304eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
4840b57cec5SDimitry Andric LLDB_LOG(log, "pid {0}", GetID());
4850b57cec5SDimitry Andric
486480093f4SDimitry Andric Status ret;
487480093f4SDimitry Andric
488480093f4SDimitry Andric Expected<ptrace_siginfo_t> siginfo =
489480093f4SDimitry Andric ComputeSignalInfo(m_threads, resume_actions);
490480093f4SDimitry Andric if (!siginfo)
491480093f4SDimitry Andric return Status(siginfo.takeError());
492480093f4SDimitry Andric
493480093f4SDimitry Andric for (const auto &abs_thread : m_threads) {
494480093f4SDimitry Andric assert(abs_thread && "thread list should not contain NULL threads");
495480093f4SDimitry Andric NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
496480093f4SDimitry Andric
497480093f4SDimitry Andric const ResumeAction *action =
498480093f4SDimitry Andric resume_actions.GetActionForThread(thread.GetID(), true);
499480093f4SDimitry Andric // we need to explicit issue suspend requests, so it is simpler to map it
500480093f4SDimitry Andric // into proper action
501480093f4SDimitry Andric ResumeAction suspend_action{thread.GetID(), eStateSuspended,
502480093f4SDimitry Andric LLDB_INVALID_SIGNAL_NUMBER};
5030b57cec5SDimitry Andric
5040b57cec5SDimitry Andric if (action == nullptr) {
5050b57cec5SDimitry Andric LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
506480093f4SDimitry Andric thread.GetID());
507480093f4SDimitry Andric action = &suspend_action;
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric
510480093f4SDimitry Andric LLDB_LOG(
511480093f4SDimitry Andric log,
512480093f4SDimitry Andric "processing resume action state {0} signal {1} for pid {2} tid {3}",
513480093f4SDimitry Andric action->state, action->signal, GetID(), thread.GetID());
5140b57cec5SDimitry Andric
5150b57cec5SDimitry Andric switch (action->state) {
516480093f4SDimitry Andric case eStateRunning:
517480093f4SDimitry Andric ret = thread.Resume();
5180b57cec5SDimitry Andric break;
5190b57cec5SDimitry Andric case eStateStepping:
520480093f4SDimitry Andric ret = thread.SingleStep();
5210b57cec5SDimitry Andric break;
5220b57cec5SDimitry Andric case eStateSuspended:
5230b57cec5SDimitry Andric case eStateStopped:
524480093f4SDimitry Andric if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
525480093f4SDimitry Andric return Status("Passing signal to suspended thread unsupported");
526480093f4SDimitry Andric
527480093f4SDimitry Andric ret = thread.Suspend();
528480093f4SDimitry Andric break;
5290b57cec5SDimitry Andric
5300b57cec5SDimitry Andric default:
5310b57cec5SDimitry Andric return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
5320b57cec5SDimitry Andric "for pid %" PRIu64 ", tid %" PRIu64,
5330b57cec5SDimitry Andric __FUNCTION__, StateAsCString(action->state), GetID(),
534480093f4SDimitry Andric thread.GetID());
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric
537480093f4SDimitry Andric if (!ret.Success())
538480093f4SDimitry Andric return ret;
539480093f4SDimitry Andric }
540480093f4SDimitry Andric
541480093f4SDimitry Andric int signal = 0;
542480093f4SDimitry Andric if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
543480093f4SDimitry Andric ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
544480093f4SDimitry Andric sizeof(*siginfo));
545480093f4SDimitry Andric if (!ret.Success())
546480093f4SDimitry Andric return ret;
547480093f4SDimitry Andric signal = siginfo->psi_siginfo.si_signo;
548480093f4SDimitry Andric }
549480093f4SDimitry Andric
550e8d8bef9SDimitry Andric ret =
551e8d8bef9SDimitry Andric PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
552480093f4SDimitry Andric if (ret.Success())
553480093f4SDimitry Andric SetState(eStateRunning, true);
554480093f4SDimitry Andric return ret;
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
Halt()557*c9157d92SDimitry Andric Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); }
5580b57cec5SDimitry Andric
Detach()5590b57cec5SDimitry Andric Status NativeProcessNetBSD::Detach() {
5600b57cec5SDimitry Andric Status error;
5610b57cec5SDimitry Andric
5620b57cec5SDimitry Andric // Stop monitoring the inferior.
5630b57cec5SDimitry Andric m_sigchld_handle.reset();
5640b57cec5SDimitry Andric
5650b57cec5SDimitry Andric // Tell ptrace to detach from the process.
5660b57cec5SDimitry Andric if (GetID() == LLDB_INVALID_PROCESS_ID)
5670b57cec5SDimitry Andric return error;
5680b57cec5SDimitry Andric
569fe6060f1SDimitry Andric return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric
Signal(int signo)5720b57cec5SDimitry Andric Status NativeProcessNetBSD::Signal(int signo) {
5730b57cec5SDimitry Andric Status error;
5740b57cec5SDimitry Andric
5750b57cec5SDimitry Andric if (kill(GetID(), signo))
5760b57cec5SDimitry Andric error.SetErrorToErrno();
5770b57cec5SDimitry Andric
5780b57cec5SDimitry Andric return error;
5790b57cec5SDimitry Andric }
5800b57cec5SDimitry Andric
Interrupt()581*c9157d92SDimitry Andric Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); }
582480093f4SDimitry Andric
Kill()5830b57cec5SDimitry Andric Status NativeProcessNetBSD::Kill() {
58404eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
5850b57cec5SDimitry Andric LLDB_LOG(log, "pid {0}", GetID());
5860b57cec5SDimitry Andric
5870b57cec5SDimitry Andric Status error;
5880b57cec5SDimitry Andric
5890b57cec5SDimitry Andric switch (m_state) {
5900b57cec5SDimitry Andric case StateType::eStateInvalid:
5910b57cec5SDimitry Andric case StateType::eStateExited:
5920b57cec5SDimitry Andric case StateType::eStateCrashed:
5930b57cec5SDimitry Andric case StateType::eStateDetached:
5940b57cec5SDimitry Andric case StateType::eStateUnloaded:
5950b57cec5SDimitry Andric // Nothing to do - the process is already dead.
5960b57cec5SDimitry Andric LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
5970b57cec5SDimitry Andric StateAsCString(m_state));
5980b57cec5SDimitry Andric return error;
5990b57cec5SDimitry Andric
6000b57cec5SDimitry Andric case StateType::eStateConnected:
6010b57cec5SDimitry Andric case StateType::eStateAttaching:
6020b57cec5SDimitry Andric case StateType::eStateLaunching:
6030b57cec5SDimitry Andric case StateType::eStateStopped:
6040b57cec5SDimitry Andric case StateType::eStateRunning:
6050b57cec5SDimitry Andric case StateType::eStateStepping:
6060b57cec5SDimitry Andric case StateType::eStateSuspended:
6070b57cec5SDimitry Andric // We can try to kill a process in these states.
6080b57cec5SDimitry Andric break;
6090b57cec5SDimitry Andric }
6100b57cec5SDimitry Andric
6110b57cec5SDimitry Andric if (kill(GetID(), SIGKILL) != 0) {
6120b57cec5SDimitry Andric error.SetErrorToErrno();
6130b57cec5SDimitry Andric return error;
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric
6160b57cec5SDimitry Andric return error;
6170b57cec5SDimitry Andric }
6180b57cec5SDimitry Andric
GetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & range_info)6190b57cec5SDimitry Andric Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
6200b57cec5SDimitry Andric MemoryRegionInfo &range_info) {
6210b57cec5SDimitry Andric
6220b57cec5SDimitry Andric if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
6230b57cec5SDimitry Andric // We're done.
6240b57cec5SDimitry Andric return Status("unsupported");
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric
6270b57cec5SDimitry Andric Status error = PopulateMemoryRegionCache();
6280b57cec5SDimitry Andric if (error.Fail()) {
6290b57cec5SDimitry Andric return error;
6300b57cec5SDimitry Andric }
6310b57cec5SDimitry Andric
6320b57cec5SDimitry Andric lldb::addr_t prev_base_address = 0;
6330b57cec5SDimitry Andric // FIXME start by finding the last region that is <= target address using
6340b57cec5SDimitry Andric // binary search. Data is sorted.
6350b57cec5SDimitry Andric // There can be a ton of regions on pthreads apps with lots of threads.
6360b57cec5SDimitry Andric for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
6370b57cec5SDimitry Andric ++it) {
6380b57cec5SDimitry Andric MemoryRegionInfo &proc_entry_info = it->first;
6390b57cec5SDimitry Andric // Sanity check assumption that memory map entries are ascending.
6400b57cec5SDimitry Andric assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
6410b57cec5SDimitry Andric "descending memory map entries detected, unexpected");
6420b57cec5SDimitry Andric prev_base_address = proc_entry_info.GetRange().GetRangeBase();
6430b57cec5SDimitry Andric UNUSED_IF_ASSERT_DISABLED(prev_base_address);
6440b57cec5SDimitry Andric // If the target address comes before this entry, indicate distance to next
6450b57cec5SDimitry Andric // region.
6460b57cec5SDimitry Andric if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
6470b57cec5SDimitry Andric range_info.GetRange().SetRangeBase(load_addr);
6480b57cec5SDimitry Andric range_info.GetRange().SetByteSize(
6490b57cec5SDimitry Andric proc_entry_info.GetRange().GetRangeBase() - load_addr);
6500b57cec5SDimitry Andric range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
6510b57cec5SDimitry Andric range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
6520b57cec5SDimitry Andric range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
6530b57cec5SDimitry Andric range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
6540b57cec5SDimitry Andric return error;
6550b57cec5SDimitry Andric } else if (proc_entry_info.GetRange().Contains(load_addr)) {
6560b57cec5SDimitry Andric // The target address is within the memory region we're processing here.
6570b57cec5SDimitry Andric range_info = proc_entry_info;
6580b57cec5SDimitry Andric return error;
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric // The target memory address comes somewhere after the region we just
6610b57cec5SDimitry Andric // parsed.
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric // If we made it here, we didn't find an entry that contained the given
6640b57cec5SDimitry Andric // address. Return the load_addr as start and the amount of bytes betwwen
6650b57cec5SDimitry Andric // load address and the end of the memory as size.
6660b57cec5SDimitry Andric range_info.GetRange().SetRangeBase(load_addr);
6670b57cec5SDimitry Andric range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
6680b57cec5SDimitry Andric range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
6690b57cec5SDimitry Andric range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
6700b57cec5SDimitry Andric range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
6710b57cec5SDimitry Andric range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
6720b57cec5SDimitry Andric return error;
6730b57cec5SDimitry Andric }
6740b57cec5SDimitry Andric
PopulateMemoryRegionCache()6750b57cec5SDimitry Andric Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
67604eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
6770b57cec5SDimitry Andric // If our cache is empty, pull the latest. There should always be at least
6780b57cec5SDimitry Andric // one memory region if memory region handling is supported.
6790b57cec5SDimitry Andric if (!m_mem_region_cache.empty()) {
6800b57cec5SDimitry Andric LLDB_LOG(log, "reusing {0} cached memory region entries",
6810b57cec5SDimitry Andric m_mem_region_cache.size());
6820b57cec5SDimitry Andric return Status();
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric
6850b57cec5SDimitry Andric struct kinfo_vmentry *vm;
6860b57cec5SDimitry Andric size_t count, i;
6870b57cec5SDimitry Andric vm = kinfo_getvmmap(GetID(), &count);
6880b57cec5SDimitry Andric if (vm == NULL) {
6890b57cec5SDimitry Andric m_supports_mem_region = LazyBool::eLazyBoolNo;
6900b57cec5SDimitry Andric Status error;
6910b57cec5SDimitry Andric error.SetErrorString("not supported");
6920b57cec5SDimitry Andric return error;
6930b57cec5SDimitry Andric }
6940b57cec5SDimitry Andric for (i = 0; i < count; i++) {
6950b57cec5SDimitry Andric MemoryRegionInfo info;
6960b57cec5SDimitry Andric info.Clear();
6970b57cec5SDimitry Andric info.GetRange().SetRangeBase(vm[i].kve_start);
6980b57cec5SDimitry Andric info.GetRange().SetRangeEnd(vm[i].kve_end);
6990b57cec5SDimitry Andric info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
7000b57cec5SDimitry Andric
7010b57cec5SDimitry Andric if (vm[i].kve_protection & VM_PROT_READ)
7020b57cec5SDimitry Andric info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
7030b57cec5SDimitry Andric else
7040b57cec5SDimitry Andric info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
7050b57cec5SDimitry Andric
7060b57cec5SDimitry Andric if (vm[i].kve_protection & VM_PROT_WRITE)
7070b57cec5SDimitry Andric info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
7080b57cec5SDimitry Andric else
7090b57cec5SDimitry Andric info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric if (vm[i].kve_protection & VM_PROT_EXECUTE)
7120b57cec5SDimitry Andric info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
7130b57cec5SDimitry Andric else
7140b57cec5SDimitry Andric info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
7150b57cec5SDimitry Andric
7160b57cec5SDimitry Andric if (vm[i].kve_path[0])
7170b57cec5SDimitry Andric info.SetName(vm[i].kve_path);
7180b57cec5SDimitry Andric
719e8d8bef9SDimitry Andric m_mem_region_cache.emplace_back(info,
720e8d8bef9SDimitry Andric FileSpec(info.GetName().GetCString()));
7210b57cec5SDimitry Andric }
7220b57cec5SDimitry Andric free(vm);
7230b57cec5SDimitry Andric
7240b57cec5SDimitry Andric if (m_mem_region_cache.empty()) {
7250b57cec5SDimitry Andric // No entries after attempting to read them. This shouldn't happen. Assume
7260b57cec5SDimitry Andric // we don't support map entries.
7270b57cec5SDimitry Andric LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
7280b57cec5SDimitry Andric "for memory region metadata retrieval");
7290b57cec5SDimitry Andric m_supports_mem_region = LazyBool::eLazyBoolNo;
7300b57cec5SDimitry Andric Status error;
7310b57cec5SDimitry Andric error.SetErrorString("not supported");
7320b57cec5SDimitry Andric return error;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric LLDB_LOG(log, "read {0} memory region entries from process {1}",
7350b57cec5SDimitry Andric m_mem_region_cache.size(), GetID());
7360b57cec5SDimitry Andric // We support memory retrieval, remember that.
7370b57cec5SDimitry Andric m_supports_mem_region = LazyBool::eLazyBoolYes;
7380b57cec5SDimitry Andric return Status();
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric
GetSharedLibraryInfoAddress()7410b57cec5SDimitry Andric lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
7420b57cec5SDimitry Andric // punt on this for now
7430b57cec5SDimitry Andric return LLDB_INVALID_ADDRESS;
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric
UpdateThreads()7460b57cec5SDimitry Andric size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
7470b57cec5SDimitry Andric
SetBreakpoint(lldb::addr_t addr,uint32_t size,bool hardware)7480b57cec5SDimitry Andric Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
7490b57cec5SDimitry Andric bool hardware) {
7500b57cec5SDimitry Andric if (hardware)
7510b57cec5SDimitry Andric return Status("NativeProcessNetBSD does not support hardware breakpoints");
7520b57cec5SDimitry Andric else
7530b57cec5SDimitry Andric return SetSoftwareBreakpoint(addr, size);
7540b57cec5SDimitry Andric }
7550b57cec5SDimitry Andric
GetLoadedModuleFileSpec(const char * module_path,FileSpec & file_spec)7560b57cec5SDimitry Andric Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
7570b57cec5SDimitry Andric FileSpec &file_spec) {
758e8d8bef9SDimitry Andric Status error = PopulateMemoryRegionCache();
759e8d8bef9SDimitry Andric if (error.Fail())
760e8d8bef9SDimitry Andric return error;
761e8d8bef9SDimitry Andric
762e8d8bef9SDimitry Andric FileSpec module_file_spec(module_path);
763e8d8bef9SDimitry Andric FileSystem::Instance().Resolve(module_file_spec);
764e8d8bef9SDimitry Andric
765e8d8bef9SDimitry Andric file_spec.Clear();
766e8d8bef9SDimitry Andric for (const auto &it : m_mem_region_cache) {
767e8d8bef9SDimitry Andric if (it.second.GetFilename() == module_file_spec.GetFilename()) {
768e8d8bef9SDimitry Andric file_spec = it.second;
769e8d8bef9SDimitry Andric return Status();
770e8d8bef9SDimitry Andric }
771e8d8bef9SDimitry Andric }
772e8d8bef9SDimitry Andric return Status("Module file (%s) not found in process' memory map!",
773e8d8bef9SDimitry Andric module_file_spec.GetFilename().AsCString());
7740b57cec5SDimitry Andric }
7750b57cec5SDimitry Andric
GetFileLoadAddress(const llvm::StringRef & file_name,lldb::addr_t & load_addr)7760b57cec5SDimitry Andric Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
7770b57cec5SDimitry Andric lldb::addr_t &load_addr) {
7780b57cec5SDimitry Andric load_addr = LLDB_INVALID_ADDRESS;
779e8d8bef9SDimitry Andric Status error = PopulateMemoryRegionCache();
780e8d8bef9SDimitry Andric if (error.Fail())
781e8d8bef9SDimitry Andric return error;
782e8d8bef9SDimitry Andric
783e8d8bef9SDimitry Andric FileSpec file(file_name);
784e8d8bef9SDimitry Andric for (const auto &it : m_mem_region_cache) {
785e8d8bef9SDimitry Andric if (it.second == file) {
786e8d8bef9SDimitry Andric load_addr = it.first.GetRange().GetRangeBase();
7870b57cec5SDimitry Andric return Status();
7880b57cec5SDimitry Andric }
789e8d8bef9SDimitry Andric }
790e8d8bef9SDimitry Andric return Status("No load address found for file %s.", file_name.str().c_str());
791e8d8bef9SDimitry Andric }
7920b57cec5SDimitry Andric
SigchldHandler()7930b57cec5SDimitry Andric void NativeProcessNetBSD::SigchldHandler() {
79404eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
7950b57cec5SDimitry Andric int status;
796e8d8bef9SDimitry Andric ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
797e8d8bef9SDimitry Andric WALLSIG | WNOHANG);
7980b57cec5SDimitry Andric
7990b57cec5SDimitry Andric if (wait_pid == 0)
800fe6060f1SDimitry Andric return;
8010b57cec5SDimitry Andric
8020b57cec5SDimitry Andric if (wait_pid == -1) {
8030b57cec5SDimitry Andric Status error(errno, eErrorTypePOSIX);
8040b57cec5SDimitry Andric LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
805fe6060f1SDimitry Andric return;
8060b57cec5SDimitry Andric }
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric WaitStatus wait_status = WaitStatus::Decode(status);
8090b57cec5SDimitry Andric bool exited = wait_status.type == WaitStatus::Exit ||
8100b57cec5SDimitry Andric (wait_status.type == WaitStatus::Signal &&
8110b57cec5SDimitry Andric wait_pid == static_cast<::pid_t>(GetID()));
8120b57cec5SDimitry Andric
8130b57cec5SDimitry Andric LLDB_LOG(log,
8140b57cec5SDimitry Andric "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
8150b57cec5SDimitry Andric GetID(), wait_pid, status, exited);
8160b57cec5SDimitry Andric
8170b57cec5SDimitry Andric if (exited)
8180b57cec5SDimitry Andric MonitorExited(wait_pid, wait_status);
8190b57cec5SDimitry Andric else {
8200b57cec5SDimitry Andric assert(wait_status.type == WaitStatus::Stop);
8210b57cec5SDimitry Andric MonitorCallback(wait_pid, wait_status.status);
8220b57cec5SDimitry Andric }
8230b57cec5SDimitry Andric }
8240b57cec5SDimitry Andric
HasThreadNoLock(lldb::tid_t thread_id)8250b57cec5SDimitry Andric bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
8260b57cec5SDimitry Andric for (const auto &thread : m_threads) {
8270b57cec5SDimitry Andric assert(thread && "thread list should not contain NULL threads");
8280b57cec5SDimitry Andric if (thread->GetID() == thread_id) {
8290b57cec5SDimitry Andric // We have this thread.
8300b57cec5SDimitry Andric return true;
8310b57cec5SDimitry Andric }
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric
8340b57cec5SDimitry Andric // We don't have this thread.
8350b57cec5SDimitry Andric return false;
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric
AddThread(lldb::tid_t thread_id)8380b57cec5SDimitry Andric NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
83904eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
8400b57cec5SDimitry Andric LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
8410b57cec5SDimitry Andric
842480093f4SDimitry Andric assert(thread_id > 0);
8430b57cec5SDimitry Andric assert(!HasThreadNoLock(thread_id) &&
8440b57cec5SDimitry Andric "attempted to add a thread by id that already exists");
8450b57cec5SDimitry Andric
8460b57cec5SDimitry Andric // If this is the first thread, save it as the current thread
8470b57cec5SDimitry Andric if (m_threads.empty())
8480b57cec5SDimitry Andric SetCurrentThreadID(thread_id);
8490b57cec5SDimitry Andric
8509dba64beSDimitry Andric m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));
8510b57cec5SDimitry Andric return static_cast<NativeThreadNetBSD &>(*m_threads.back());
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric
RemoveThread(lldb::tid_t thread_id)854480093f4SDimitry Andric void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
85504eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Thread);
856480093f4SDimitry Andric LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
857480093f4SDimitry Andric
858480093f4SDimitry Andric assert(thread_id > 0);
859480093f4SDimitry Andric assert(HasThreadNoLock(thread_id) &&
860480093f4SDimitry Andric "attempted to remove a thread that does not exist");
861480093f4SDimitry Andric
862480093f4SDimitry Andric for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
863480093f4SDimitry Andric if ((*it)->GetID() == thread_id) {
864480093f4SDimitry Andric m_threads.erase(it);
865480093f4SDimitry Andric break;
866480093f4SDimitry Andric }
867480093f4SDimitry Andric }
868480093f4SDimitry Andric }
869480093f4SDimitry Andric
Attach()8700b57cec5SDimitry Andric Status NativeProcessNetBSD::Attach() {
8710b57cec5SDimitry Andric // Attach to the requested process.
8720b57cec5SDimitry Andric // An attach will cause the thread to stop with a SIGSTOP.
8730b57cec5SDimitry Andric Status status = PtraceWrapper(PT_ATTACH, m_pid);
8740b57cec5SDimitry Andric if (status.Fail())
8750b57cec5SDimitry Andric return status;
8760b57cec5SDimitry Andric
8770b57cec5SDimitry Andric int wstatus;
8780b57cec5SDimitry Andric // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
8790b57cec5SDimitry Andric // point we should have a thread stopped if waitpid succeeds.
880e8d8bef9SDimitry Andric if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,
881e8d8bef9SDimitry Andric WALLSIG)) < 0)
8820b57cec5SDimitry Andric return Status(errno, eErrorTypePOSIX);
8830b57cec5SDimitry Andric
884e8d8bef9SDimitry Andric // Initialize threads and tracing status
885e8d8bef9SDimitry Andric // NB: this needs to be called before we set thread state
886e8d8bef9SDimitry Andric status = SetupTrace();
8870b57cec5SDimitry Andric if (status.Fail())
8880b57cec5SDimitry Andric return status;
8890b57cec5SDimitry Andric
8900b57cec5SDimitry Andric for (const auto &thread : m_threads)
8910b57cec5SDimitry Andric static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
8920b57cec5SDimitry Andric
8930b57cec5SDimitry Andric // Let our process instance know the thread has stopped.
894e8d8bef9SDimitry Andric SetCurrentThreadID(m_threads.front()->GetID());
895e8d8bef9SDimitry Andric SetState(StateType::eStateStopped, false);
8960b57cec5SDimitry Andric return Status();
8970b57cec5SDimitry Andric }
8980b57cec5SDimitry Andric
ReadMemory(lldb::addr_t addr,void * buf,size_t size,size_t & bytes_read)8990b57cec5SDimitry Andric Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
9000b57cec5SDimitry Andric size_t size, size_t &bytes_read) {
9010b57cec5SDimitry Andric unsigned char *dst = static_cast<unsigned char *>(buf);
9020b57cec5SDimitry Andric struct ptrace_io_desc io;
9030b57cec5SDimitry Andric
90404eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Memory);
9050b57cec5SDimitry Andric LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
9060b57cec5SDimitry Andric
9070b57cec5SDimitry Andric bytes_read = 0;
9080b57cec5SDimitry Andric io.piod_op = PIOD_READ_D;
9090b57cec5SDimitry Andric io.piod_len = size;
9100b57cec5SDimitry Andric
9110b57cec5SDimitry Andric do {
9120b57cec5SDimitry Andric io.piod_offs = (void *)(addr + bytes_read);
9130b57cec5SDimitry Andric io.piod_addr = dst + bytes_read;
9140b57cec5SDimitry Andric
9150b57cec5SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
9160b57cec5SDimitry Andric if (error.Fail() || io.piod_len == 0)
9170b57cec5SDimitry Andric return error;
9180b57cec5SDimitry Andric
9190b57cec5SDimitry Andric bytes_read += io.piod_len;
9200b57cec5SDimitry Andric io.piod_len = size - bytes_read;
9210b57cec5SDimitry Andric } while (bytes_read < size);
9220b57cec5SDimitry Andric
9230b57cec5SDimitry Andric return Status();
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric
WriteMemory(lldb::addr_t addr,const void * buf,size_t size,size_t & bytes_written)9260b57cec5SDimitry Andric Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
9270b57cec5SDimitry Andric size_t size, size_t &bytes_written) {
9280b57cec5SDimitry Andric const unsigned char *src = static_cast<const unsigned char *>(buf);
9290b57cec5SDimitry Andric Status error;
9300b57cec5SDimitry Andric struct ptrace_io_desc io;
9310b57cec5SDimitry Andric
93204eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Memory);
9330b57cec5SDimitry Andric LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
9340b57cec5SDimitry Andric
9350b57cec5SDimitry Andric bytes_written = 0;
9360b57cec5SDimitry Andric io.piod_op = PIOD_WRITE_D;
9370b57cec5SDimitry Andric io.piod_len = size;
9380b57cec5SDimitry Andric
9390b57cec5SDimitry Andric do {
940e8d8bef9SDimitry Andric io.piod_addr =
941e8d8bef9SDimitry Andric const_cast<void *>(static_cast<const void *>(src + bytes_written));
9420b57cec5SDimitry Andric io.piod_offs = (void *)(addr + bytes_written);
9430b57cec5SDimitry Andric
9440b57cec5SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
9450b57cec5SDimitry Andric if (error.Fail() || io.piod_len == 0)
9460b57cec5SDimitry Andric return error;
9470b57cec5SDimitry Andric
9480b57cec5SDimitry Andric bytes_written += io.piod_len;
9490b57cec5SDimitry Andric io.piod_len = size - bytes_written;
9500b57cec5SDimitry Andric } while (bytes_written < size);
9510b57cec5SDimitry Andric
9520b57cec5SDimitry Andric return error;
9530b57cec5SDimitry Andric }
9540b57cec5SDimitry Andric
9550b57cec5SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const9560b57cec5SDimitry Andric NativeProcessNetBSD::GetAuxvData() const {
9570b57cec5SDimitry Andric /*
9580b57cec5SDimitry Andric * ELF_AUX_ENTRIES is currently restricted to kernel
9590b57cec5SDimitry Andric * (<sys/exec_elf.h> r. 1.155 specifies 15)
9600b57cec5SDimitry Andric *
9610b57cec5SDimitry Andric * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
9620b57cec5SDimitry Andric * information isn't needed.
9630b57cec5SDimitry Andric */
9640b57cec5SDimitry Andric size_t auxv_size = 100 * sizeof(AuxInfo);
9650b57cec5SDimitry Andric
9660b57cec5SDimitry Andric ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
9670b57cec5SDimitry Andric llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
9680b57cec5SDimitry Andric
9690b57cec5SDimitry Andric struct ptrace_io_desc io;
9700b57cec5SDimitry Andric io.piod_op = PIOD_READ_AUXV;
9710b57cec5SDimitry Andric io.piod_offs = 0;
9720b57cec5SDimitry Andric io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());
9730b57cec5SDimitry Andric io.piod_len = auxv_size;
9740b57cec5SDimitry Andric
9750b57cec5SDimitry Andric Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
9760b57cec5SDimitry Andric
9770b57cec5SDimitry Andric if (error.Fail())
9780b57cec5SDimitry Andric return std::error_code(error.GetError(), std::generic_category());
9790b57cec5SDimitry Andric
9800b57cec5SDimitry Andric if (io.piod_len < 1)
9810b57cec5SDimitry Andric return std::error_code(ECANCELED, std::generic_category());
9820b57cec5SDimitry Andric
9830b57cec5SDimitry Andric return std::move(buf);
9840b57cec5SDimitry Andric }
9850b57cec5SDimitry Andric
SetupTrace()986e8d8bef9SDimitry Andric Status NativeProcessNetBSD::SetupTrace() {
987e8d8bef9SDimitry Andric // Enable event reporting
988e8d8bef9SDimitry Andric ptrace_event_t events;
989e8d8bef9SDimitry Andric Status status =
990e8d8bef9SDimitry Andric PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
991e8d8bef9SDimitry Andric if (status.Fail())
992e8d8bef9SDimitry Andric return status;
993fe6060f1SDimitry Andric // TODO: PTRACE_POSIX_SPAWN?
994fe6060f1SDimitry Andric events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
995fe6060f1SDimitry Andric PTRACE_VFORK | PTRACE_VFORK_DONE;
996e8d8bef9SDimitry Andric status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
997e8d8bef9SDimitry Andric if (status.Fail())
998e8d8bef9SDimitry Andric return status;
999e8d8bef9SDimitry Andric
1000e8d8bef9SDimitry Andric return ReinitializeThreads();
1001e8d8bef9SDimitry Andric }
1002e8d8bef9SDimitry Andric
ReinitializeThreads()10030b57cec5SDimitry Andric Status NativeProcessNetBSD::ReinitializeThreads() {
10040b57cec5SDimitry Andric // Clear old threads
10050b57cec5SDimitry Andric m_threads.clear();
10060b57cec5SDimitry Andric
10070b57cec5SDimitry Andric // Initialize new thread
1008480093f4SDimitry Andric #ifdef PT_LWPSTATUS
1009480093f4SDimitry Andric struct ptrace_lwpstatus info = {};
1010480093f4SDimitry Andric int op = PT_LWPNEXT;
1011480093f4SDimitry Andric #else
10120b57cec5SDimitry Andric struct ptrace_lwpinfo info = {};
1013480093f4SDimitry Andric int op = PT_LWPINFO;
1014480093f4SDimitry Andric #endif
1015480093f4SDimitry Andric
1016480093f4SDimitry Andric Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));
1017480093f4SDimitry Andric
10180b57cec5SDimitry Andric if (error.Fail()) {
10190b57cec5SDimitry Andric return error;
10200b57cec5SDimitry Andric }
10210b57cec5SDimitry Andric // Reinitialize from scratch threads and register them in process
10220b57cec5SDimitry Andric while (info.pl_lwpid != 0) {
10230b57cec5SDimitry Andric AddThread(info.pl_lwpid);
1024480093f4SDimitry Andric error = PtraceWrapper(op, GetID(), &info, sizeof(info));
10250b57cec5SDimitry Andric if (error.Fail()) {
10260b57cec5SDimitry Andric return error;
10270b57cec5SDimitry Andric }
10280b57cec5SDimitry Andric }
10290b57cec5SDimitry Andric
10300b57cec5SDimitry Andric return error;
10310b57cec5SDimitry Andric }
1032fe6060f1SDimitry Andric
MonitorClone(::pid_t child_pid,bool is_vfork,NativeThreadNetBSD & parent_thread)1033fe6060f1SDimitry Andric void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
1034fe6060f1SDimitry Andric NativeThreadNetBSD &parent_thread) {
103504eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Process);
1036fe6060f1SDimitry Andric LLDB_LOG(log, "clone, child_pid={0}", child_pid);
1037fe6060f1SDimitry Andric
1038fe6060f1SDimitry Andric int status;
1039fe6060f1SDimitry Andric ::pid_t wait_pid =
1040fe6060f1SDimitry Andric llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
1041fe6060f1SDimitry Andric if (wait_pid != child_pid) {
1042fe6060f1SDimitry Andric LLDB_LOG(log,
1043fe6060f1SDimitry Andric "waiting for pid {0} failed. Assuming the pid has "
1044fe6060f1SDimitry Andric "disappeared in the meantime",
1045fe6060f1SDimitry Andric child_pid);
1046fe6060f1SDimitry Andric return;
1047fe6060f1SDimitry Andric }
1048fe6060f1SDimitry Andric if (WIFEXITED(status)) {
1049fe6060f1SDimitry Andric LLDB_LOG(log,
1050fe6060f1SDimitry Andric "waiting for pid {0} returned an 'exited' event. Not "
1051fe6060f1SDimitry Andric "tracking it.",
1052fe6060f1SDimitry Andric child_pid);
1053fe6060f1SDimitry Andric return;
1054fe6060f1SDimitry Andric }
1055fe6060f1SDimitry Andric
1056fe6060f1SDimitry Andric ptrace_siginfo_t info;
1057fe6060f1SDimitry Andric const auto siginfo_err =
1058fe6060f1SDimitry Andric PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));
1059fe6060f1SDimitry Andric if (siginfo_err.Fail()) {
1060fe6060f1SDimitry Andric LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
1061fe6060f1SDimitry Andric return;
1062fe6060f1SDimitry Andric }
1063fe6060f1SDimitry Andric assert(info.psi_lwpid >= 0);
1064fe6060f1SDimitry Andric lldb::tid_t child_tid = info.psi_lwpid;
1065fe6060f1SDimitry Andric
1066fe6060f1SDimitry Andric std::unique_ptr<NativeProcessNetBSD> child_process{
1067fe6060f1SDimitry Andric new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,
1068fe6060f1SDimitry Andric m_delegate, m_arch, m_main_loop)};
1069fe6060f1SDimitry Andric if (!is_vfork)
1070fe6060f1SDimitry Andric child_process->m_software_breakpoints = m_software_breakpoints;
1071fe6060f1SDimitry Andric
1072fe6060f1SDimitry Andric Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
1073fe6060f1SDimitry Andric if ((m_enabled_extensions & expected_ext) == expected_ext) {
1074fe6060f1SDimitry Andric child_process->SetupTrace();
1075fe6060f1SDimitry Andric for (const auto &thread : child_process->m_threads)
1076fe6060f1SDimitry Andric static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
1077fe6060f1SDimitry Andric child_process->SetState(StateType::eStateStopped, false);
1078fe6060f1SDimitry Andric
1079fe6060f1SDimitry Andric m_delegate.NewSubprocess(this, std::move(child_process));
1080fe6060f1SDimitry Andric if (is_vfork)
1081fe6060f1SDimitry Andric parent_thread.SetStoppedByVFork(child_pid, child_tid);
1082fe6060f1SDimitry Andric else
1083fe6060f1SDimitry Andric parent_thread.SetStoppedByFork(child_pid, child_tid);
1084fe6060f1SDimitry Andric SetState(StateType::eStateStopped, true);
1085fe6060f1SDimitry Andric } else {
1086fe6060f1SDimitry Andric child_process->Detach();
1087fe6060f1SDimitry Andric Status pt_error =
1088fe6060f1SDimitry Andric PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
1089fe6060f1SDimitry Andric if (pt_error.Fail()) {
1090fe6060f1SDimitry Andric LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),
1091fe6060f1SDimitry Andric "unable to resume parent process {1}: {0}", GetID());
1092fe6060f1SDimitry Andric SetState(StateType::eStateInvalid);
1093fe6060f1SDimitry Andric }
1094fe6060f1SDimitry Andric }
1095fe6060f1SDimitry Andric }
1096349cc55cSDimitry Andric
1097349cc55cSDimitry Andric llvm::Expected<std::string>
SaveCore(llvm::StringRef path_hint)1098349cc55cSDimitry Andric NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
1099349cc55cSDimitry Andric llvm::SmallString<128> path{path_hint};
1100349cc55cSDimitry Andric Status error;
1101349cc55cSDimitry Andric
1102349cc55cSDimitry Andric // Try with the suggested path first.
1103349cc55cSDimitry Andric if (!path.empty()) {
1104349cc55cSDimitry Andric error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1105349cc55cSDimitry Andric if (!error.Fail())
1106349cc55cSDimitry Andric return path.str().str();
1107349cc55cSDimitry Andric
1108349cc55cSDimitry Andric // If the request errored, fall back to a generic temporary file.
1109349cc55cSDimitry Andric }
1110349cc55cSDimitry Andric
1111349cc55cSDimitry Andric if (std::error_code errc =
1112349cc55cSDimitry Andric llvm::sys::fs::createTemporaryFile("lldb", "core", path))
1113349cc55cSDimitry Andric return llvm::createStringError(errc, "Unable to create a temporary file");
1114349cc55cSDimitry Andric
1115349cc55cSDimitry Andric error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
1116349cc55cSDimitry Andric if (error.Fail())
1117349cc55cSDimitry Andric return error.ToError();
1118349cc55cSDimitry Andric return path.str().str();
1119349cc55cSDimitry Andric }
1120