1bee4d6efSMichał Górny //===-- NativeProcessFreeBSD.cpp ------------------------------------------===// 2bee4d6efSMichał Górny // 3bee4d6efSMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bee4d6efSMichał Górny // See https://llvm.org/LICENSE.txt for license information. 5bee4d6efSMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bee4d6efSMichał Górny // 7bee4d6efSMichał Górny //===----------------------------------------------------------------------===// 8bee4d6efSMichał Górny 9bee4d6efSMichał Górny #include "NativeProcessFreeBSD.h" 10bee4d6efSMichał Górny 11bee4d6efSMichał Górny // clang-format off 12bee4d6efSMichał Górny #include <sys/types.h> 13bee4d6efSMichał Górny #include <sys/ptrace.h> 14bee4d6efSMichał Górny #include <sys/sysctl.h> 15bee4d6efSMichał Górny #include <sys/user.h> 16bee4d6efSMichał Górny #include <sys/wait.h> 17bee4d6efSMichał Górny #include <machine/elf.h> 18bee4d6efSMichał Górny // clang-format on 19bee4d6efSMichał Górny 20bee4d6efSMichał Górny #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 21bee4d6efSMichał Górny #include "lldb/Host/HostProcess.h" 22bee4d6efSMichał Górny #include "lldb/Host/posix/ProcessLauncherPosixFork.h" 23bee4d6efSMichał Górny #include "lldb/Target/Process.h" 24bee4d6efSMichał Górny #include "lldb/Utility/State.h" 25bee4d6efSMichał Górny #include "llvm/Support/Errno.h" 26bee4d6efSMichał Górny 27bee4d6efSMichał Górny using namespace lldb; 28bee4d6efSMichał Górny using namespace lldb_private; 29bee4d6efSMichał Górny using namespace lldb_private::process_freebsd; 30bee4d6efSMichał Górny using namespace llvm; 31bee4d6efSMichał Górny 32bee4d6efSMichał Górny // Simple helper function to ensure flags are enabled on the given file 33bee4d6efSMichał Górny // descriptor. 34bee4d6efSMichał Górny static Status EnsureFDFlags(int fd, int flags) { 35bee4d6efSMichał Górny Status error; 36bee4d6efSMichał Górny 37bee4d6efSMichał Górny int status = fcntl(fd, F_GETFL); 38bee4d6efSMichał Górny if (status == -1) { 3947667ee2SAdrian Prantl error = Status::FromErrno(); 40bee4d6efSMichał Górny return error; 41bee4d6efSMichał Górny } 42bee4d6efSMichał Górny 43bee4d6efSMichał Górny if (fcntl(fd, F_SETFL, status | flags) == -1) { 4447667ee2SAdrian Prantl error = Status::FromErrno(); 45bee4d6efSMichał Górny return error; 46bee4d6efSMichał Górny } 47bee4d6efSMichał Górny 48bee4d6efSMichał Górny return error; 49bee4d6efSMichał Górny } 50bee4d6efSMichał Górny 51535da108SDavid CARLIER static Status CanTrace() { 52535da108SDavid CARLIER int proc_debug, ret; 53535da108SDavid CARLIER size_t len = sizeof(proc_debug); 54535da108SDavid CARLIER ret = ::sysctlbyname("security.bsd.unprivileged_proc_debug", &proc_debug, 55535da108SDavid CARLIER &len, nullptr, 0); 56535da108SDavid CARLIER if (ret != 0) 570642cd76SAdrian Prantl return Status::FromErrorString( 580642cd76SAdrian Prantl "sysctlbyname() security.bsd.unprivileged_proc_debug failed"); 59535da108SDavid CARLIER 60535da108SDavid CARLIER if (proc_debug < 1) 610642cd76SAdrian Prantl return Status::FromErrorString( 62535da108SDavid CARLIER "process debug disabled by security.bsd.unprivileged_proc_debug oid"); 63535da108SDavid CARLIER 64535da108SDavid CARLIER return {}; 65535da108SDavid CARLIER } 66535da108SDavid CARLIER 67bee4d6efSMichał Górny // Public Static Methods 68bee4d6efSMichał Górny 69bee4d6efSMichał Górny llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 70e64cc756SPavel Labath NativeProcessFreeBSD::Manager::Launch(ProcessLaunchInfo &launch_info, 71e64cc756SPavel Labath NativeDelegate &native_delegate) { 724fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 73bee4d6efSMichał Górny Status status; 74535da108SDavid CARLIER 75bee4d6efSMichał Górny ::pid_t pid = ProcessLauncherPosixFork() 76bee4d6efSMichał Górny .LaunchProcess(launch_info, status) 77bee4d6efSMichał Górny .GetProcessId(); 78bee4d6efSMichał Górny LLDB_LOG(log, "pid = {0:x}", pid); 79bee4d6efSMichał Górny if (status.Fail()) { 80bee4d6efSMichał Górny LLDB_LOG(log, "failed to launch process: {0}", status); 8173b2d672SDavid Spickett auto error = CanTrace(); 8273b2d672SDavid Spickett if (error.Fail()) 83535da108SDavid CARLIER return error.ToError(); 84bee4d6efSMichał Górny return status.ToError(); 85bee4d6efSMichał Górny } 86bee4d6efSMichał Górny 87bee4d6efSMichał Górny // Wait for the child process to trap on its call to execve. 88bee4d6efSMichał Górny int wstatus; 89bee4d6efSMichał Górny ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); 90bee4d6efSMichał Górny assert(wpid == pid); 9168fbc8eeSDavid Spickett UNUSED_IF_ASSERT_DISABLED(wpid); 92bee4d6efSMichał Górny if (!WIFSTOPPED(wstatus)) { 93bee4d6efSMichał Górny LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", 94bee4d6efSMichał Górny WaitStatus::Decode(wstatus)); 95bee4d6efSMichał Górny return llvm::make_error<StringError>("Could not sync with inferior process", 96bee4d6efSMichał Górny llvm::inconvertibleErrorCode()); 97bee4d6efSMichał Górny } 98bee4d6efSMichał Górny LLDB_LOG(log, "inferior started, now in stopped state"); 99bee4d6efSMichał Górny 100bee4d6efSMichał Górny ProcessInstanceInfo Info; 101bee4d6efSMichał Górny if (!Host::GetProcessInfo(pid, Info)) { 102bee4d6efSMichał Górny return llvm::make_error<StringError>("Cannot get process architecture", 103bee4d6efSMichał Górny llvm::inconvertibleErrorCode()); 104bee4d6efSMichał Górny } 105bee4d6efSMichał Górny 106bee4d6efSMichał Górny // Set the architecture to the exe architecture. 107bee4d6efSMichał Górny LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, 108bee4d6efSMichał Górny Info.GetArchitecture().GetArchitectureName()); 109bee4d6efSMichał Górny 110bee4d6efSMichał Górny std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD( 111bee4d6efSMichał Górny pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, 112e64cc756SPavel Labath Info.GetArchitecture(), m_mainloop)); 113bee4d6efSMichał Górny 114bee4d6efSMichał Górny status = process_up->SetupTrace(); 115bee4d6efSMichał Górny if (status.Fail()) 116bee4d6efSMichał Górny return status.ToError(); 117bee4d6efSMichał Górny 118bee4d6efSMichał Górny for (const auto &thread : process_up->m_threads) 119bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP); 120bee4d6efSMichał Górny process_up->SetState(StateType::eStateStopped, false); 121bee4d6efSMichał Górny 122bee4d6efSMichał Górny return std::move(process_up); 123bee4d6efSMichał Górny } 124bee4d6efSMichał Górny 125bee4d6efSMichał Górny llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 126e64cc756SPavel Labath NativeProcessFreeBSD::Manager::Attach( 127e64cc756SPavel Labath lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { 1284fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 129bee4d6efSMichał Górny LLDB_LOG(log, "pid = {0:x}", pid); 130bee4d6efSMichał Górny 131bee4d6efSMichał Górny // Retrieve the architecture for the running process. 132bee4d6efSMichał Górny ProcessInstanceInfo Info; 133bee4d6efSMichał Górny if (!Host::GetProcessInfo(pid, Info)) { 134bee4d6efSMichał Górny return llvm::make_error<StringError>("Cannot get process architecture", 135bee4d6efSMichał Górny llvm::inconvertibleErrorCode()); 136bee4d6efSMichał Górny } 137bee4d6efSMichał Górny 138bee4d6efSMichał Górny std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD( 139e64cc756SPavel Labath pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop)); 140bee4d6efSMichał Górny 141bee4d6efSMichał Górny Status status = process_up->Attach(); 142bee4d6efSMichał Górny if (!status.Success()) 143bee4d6efSMichał Górny return status.ToError(); 144bee4d6efSMichał Górny 145bee4d6efSMichał Górny return std::move(process_up); 146bee4d6efSMichał Górny } 147bee4d6efSMichał Górny 14865f2a757SMichał Górny NativeProcessFreeBSD::Extension 149e64cc756SPavel Labath NativeProcessFreeBSD::Manager::GetSupportedExtensions() const { 15002e690baSMichał Górny return 15102e690baSMichał Górny #if defined(PT_COREDUMP) 15202e690baSMichał Górny Extension::savecore | 15302e690baSMichał Górny #endif 15402e690baSMichał Górny Extension::multiprocess | Extension::fork | Extension::vfork | 1551e74e5e9SMichał Górny Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | 1561e74e5e9SMichał Górny Extension::siginfo_read; 15765f2a757SMichał Górny } 15865f2a757SMichał Górny 159bee4d6efSMichał Górny // Public Instance Methods 160bee4d6efSMichał Górny 161bee4d6efSMichał Górny NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd, 162bee4d6efSMichał Górny NativeDelegate &delegate, 163bee4d6efSMichał Górny const ArchSpec &arch, 164bee4d6efSMichał Górny MainLoop &mainloop) 16565f2a757SMichał Górny : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch), 16665f2a757SMichał Górny m_main_loop(mainloop) { 167bee4d6efSMichał Górny if (m_terminal_fd != -1) { 168bee4d6efSMichał Górny Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); 169bee4d6efSMichał Górny assert(status.Success()); 170bee4d6efSMichał Górny } 171bee4d6efSMichał Górny 172bee4d6efSMichał Górny Status status; 173bee4d6efSMichał Górny m_sigchld_handle = mainloop.RegisterSignal( 174bee4d6efSMichał Górny SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); 175bee4d6efSMichał Górny assert(m_sigchld_handle && status.Success()); 176bee4d6efSMichał Górny } 177bee4d6efSMichał Górny 178bee4d6efSMichał Górny // Handles all waitpid events from the inferior process. 179bee4d6efSMichał Górny void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) { 180bee4d6efSMichał Górny switch (signal) { 181bee4d6efSMichał Górny case SIGTRAP: 182bee4d6efSMichał Górny return MonitorSIGTRAP(pid); 183bee4d6efSMichał Górny case SIGSTOP: 184bee4d6efSMichał Górny return MonitorSIGSTOP(pid); 185bee4d6efSMichał Górny default: 186bee4d6efSMichał Górny return MonitorSignal(pid, signal); 187bee4d6efSMichał Górny } 188bee4d6efSMichał Górny } 189bee4d6efSMichał Górny 190bee4d6efSMichał Górny void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { 1914fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 192bee4d6efSMichał Górny 193bee4d6efSMichał Górny LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); 194bee4d6efSMichał Górny 195bee4d6efSMichał Górny /* Stop Tracking All Threads attached to Process */ 196bee4d6efSMichał Górny m_threads.clear(); 197bee4d6efSMichał Górny 198bee4d6efSMichał Górny SetExitStatus(status, true); 199bee4d6efSMichał Górny 200bee4d6efSMichał Górny // Notify delegate that our process has exited. 201bee4d6efSMichał Górny SetState(StateType::eStateExited, true); 202bee4d6efSMichał Górny } 203bee4d6efSMichał Górny 204bee4d6efSMichał Górny void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) { 205bee4d6efSMichał Górny /* Stop all Threads attached to Process */ 206bee4d6efSMichał Górny for (const auto &thread : m_threads) { 207bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP, 208bee4d6efSMichał Górny nullptr); 209bee4d6efSMichał Górny } 210bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 211bee4d6efSMichał Górny } 212bee4d6efSMichał Górny 213bee4d6efSMichał Górny void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { 2144fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 215bee4d6efSMichał Górny struct ptrace_lwpinfo info; 216bee4d6efSMichał Górny 217bee4d6efSMichał Górny const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); 218bee4d6efSMichał Górny if (siginfo_err.Fail()) { 219bee4d6efSMichał Górny LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); 220bee4d6efSMichał Górny return; 221bee4d6efSMichał Górny } 222bee4d6efSMichał Górny assert(info.pl_event == PL_EVENT_SIGNAL); 223bee4d6efSMichał Górny 224bee4d6efSMichał Górny LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid, 225bee4d6efSMichał Górny info.pl_lwpid, info.pl_flags); 226bee4d6efSMichał Górny NativeThreadFreeBSD *thread = nullptr; 227bee4d6efSMichał Górny 228bee4d6efSMichał Górny if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) { 229bee4d6efSMichał Górny if (info.pl_flags & PL_FLAG_BORN) { 230bee4d6efSMichał Górny LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid); 231bee4d6efSMichał Górny NativeThreadFreeBSD &t = AddThread(info.pl_lwpid); 232bee4d6efSMichał Górny 233bee4d6efSMichał Górny // Technically, the FreeBSD kernel copies the debug registers to new 234bee4d6efSMichał Górny // threads. However, there is a non-negligible delay between acquiring 235bee4d6efSMichał Górny // the DR values and reporting the new thread during which the user may 236bee4d6efSMichał Górny // establish a new watchpoint. In order to ensure that watchpoints 237bee4d6efSMichał Górny // established during this period are propagated to new threads, 238bee4d6efSMichał Górny // explicitly copy the DR value at the time the new thread is reported. 239bee4d6efSMichał Górny // 240bee4d6efSMichał Górny // See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954 241bee4d6efSMichał Górny 242bee4d6efSMichał Górny llvm::Error error = t.CopyWatchpointsFrom( 243bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*GetCurrentThread())); 244bee4d6efSMichał Górny if (error) { 2459f38001bSMichał Górny LLDB_LOG_ERROR(log, std::move(error), 2469f38001bSMichał Górny "failed to copy watchpoints to new thread {1}: {0}", 2479f38001bSMichał Górny info.pl_lwpid); 248bee4d6efSMichał Górny SetState(StateType::eStateInvalid); 249bee4d6efSMichał Górny return; 250bee4d6efSMichał Górny } 251bee4d6efSMichał Górny } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ { 252bee4d6efSMichał Górny LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid); 253bee4d6efSMichał Górny RemoveThread(info.pl_lwpid); 254bee4d6efSMichał Górny } 255bee4d6efSMichał Górny 256bee4d6efSMichał Górny Status error = 257bee4d6efSMichał Górny PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0); 258bee4d6efSMichał Górny if (error.Fail()) 259bee4d6efSMichał Górny SetState(StateType::eStateInvalid); 260bee4d6efSMichał Górny return; 261bee4d6efSMichał Górny } 262bee4d6efSMichał Górny 263bee4d6efSMichał Górny if (info.pl_flags & PL_FLAG_EXEC) { 264bee4d6efSMichał Górny Status error = ReinitializeThreads(); 265bee4d6efSMichał Górny if (error.Fail()) { 266bee4d6efSMichał Górny SetState(StateType::eStateInvalid); 267bee4d6efSMichał Górny return; 268bee4d6efSMichał Górny } 269bee4d6efSMichał Górny 270bee4d6efSMichał Górny // Let our delegate know we have just exec'd. 271bee4d6efSMichał Górny NotifyDidExec(); 272bee4d6efSMichał Górny 273bee4d6efSMichał Górny for (const auto &thread : m_threads) 274bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec(); 2759a1ce35dSMichał Górny SetCurrentThreadID(m_threads.front()->GetID()); 276bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 277bee4d6efSMichał Górny return; 278bee4d6efSMichał Górny } 279bee4d6efSMichał Górny 280bee4d6efSMichał Górny if (info.pl_lwpid > 0) { 281bee4d6efSMichał Górny for (const auto &t : m_threads) { 282bee4d6efSMichał Górny if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid)) 283bee4d6efSMichał Górny thread = static_cast<NativeThreadFreeBSD *>(t.get()); 284bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason(); 285bee4d6efSMichał Górny } 286bee4d6efSMichał Górny if (!thread) 287bee4d6efSMichał Górny LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid, 288bee4d6efSMichał Górny info.pl_lwpid); 289bee4d6efSMichał Górny } 290bee4d6efSMichał Górny 29165f2a757SMichał Górny if (info.pl_flags & PL_FLAG_FORKED) { 29265f2a757SMichał Górny assert(thread); 29365f2a757SMichał Górny MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread); 29465f2a757SMichał Górny return; 29565f2a757SMichał Górny } 29665f2a757SMichał Górny 29765f2a757SMichał Górny if (info.pl_flags & PL_FLAG_VFORK_DONE) { 29865f2a757SMichał Górny assert(thread); 29965f2a757SMichał Górny if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) { 30065f2a757SMichał Górny thread->SetStoppedByVForkDone(); 30165f2a757SMichał Górny SetState(StateType::eStateStopped, true); 30265f2a757SMichał Górny } else { 30365f2a757SMichał Górny Status error = 30465f2a757SMichał Górny PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0); 30565f2a757SMichał Górny if (error.Fail()) 30665f2a757SMichał Górny SetState(StateType::eStateInvalid); 30765f2a757SMichał Górny } 30865f2a757SMichał Górny return; 30965f2a757SMichał Górny } 31065f2a757SMichał Górny 311bee4d6efSMichał Górny if (info.pl_flags & PL_FLAG_SI) { 312bee4d6efSMichał Górny assert(info.pl_siginfo.si_signo == SIGTRAP); 313bee4d6efSMichał Górny LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}", 314bee4d6efSMichał Górny info.pl_siginfo.si_code, info.pl_siginfo.si_pid); 315bee4d6efSMichał Górny 316bee4d6efSMichał Górny switch (info.pl_siginfo.si_code) { 317bee4d6efSMichał Górny case TRAP_BRKPT: 318771c4c9cSMichał Górny LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}", 319771c4c9cSMichał Górny info.pl_siginfo.si_addr); 320771c4c9cSMichał Górny 321bee4d6efSMichał Górny if (thread) { 322213c59ddSJason Molenda auto ®ctx = static_cast<NativeRegisterContextFreeBSD &>( 323213c59ddSJason Molenda thread->GetRegisterContext()); 324bee4d6efSMichał Górny auto thread_info = 325bee4d6efSMichał Górny m_threads_stepping_with_breakpoint.find(thread->GetID()); 326213c59ddSJason Molenda if (thread_info != m_threads_stepping_with_breakpoint.end() && 327*85220a0cSKelvin Lee thread_info->second == regctx.GetPC()) { 328bee4d6efSMichał Górny thread->SetStoppedByTrace(); 329bee4d6efSMichał Górny Status brkpt_error = RemoveBreakpoint(thread_info->second); 330bee4d6efSMichał Górny if (brkpt_error.Fail()) 331bee4d6efSMichał Górny LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", 332bee4d6efSMichał Górny thread_info->first, brkpt_error); 333bee4d6efSMichał Górny m_threads_stepping_with_breakpoint.erase(thread_info); 334bee4d6efSMichał Górny } else 335bee4d6efSMichał Górny thread->SetStoppedByBreakpoint(); 336bee4d6efSMichał Górny FixupBreakpointPCAsNeeded(*thread); 3379a1ce35dSMichał Górny SetCurrentThreadID(thread->GetID()); 338bee4d6efSMichał Górny } 339bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 340bee4d6efSMichał Górny return; 341bee4d6efSMichał Górny case TRAP_TRACE: 342771c4c9cSMichał Górny LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}", 343771c4c9cSMichał Górny info.pl_siginfo.si_addr); 344771c4c9cSMichał Górny 345bee4d6efSMichał Górny if (thread) { 346bee4d6efSMichał Górny auto ®ctx = static_cast<NativeRegisterContextFreeBSD &>( 347bee4d6efSMichał Górny thread->GetRegisterContext()); 348bee4d6efSMichał Górny uint32_t wp_index = LLDB_INVALID_INDEX32; 349771c4c9cSMichał Górny Status error = regctx.GetWatchpointHitIndex( 350771c4c9cSMichał Górny wp_index, reinterpret_cast<uintptr_t>(info.pl_siginfo.si_addr)); 351bee4d6efSMichał Górny if (error.Fail()) 352bee4d6efSMichał Górny LLDB_LOG(log, 353bee4d6efSMichał Górny "received error while checking for watchpoint hits, pid = " 354bee4d6efSMichał Górny "{0}, LWP = {1}, error = {2}", 355bee4d6efSMichał Górny pid, info.pl_lwpid, error); 356bee4d6efSMichał Górny if (wp_index != LLDB_INVALID_INDEX32) { 357bee4d6efSMichał Górny regctx.ClearWatchpointHit(wp_index); 358bee4d6efSMichał Górny thread->SetStoppedByWatchpoint(wp_index); 3599a1ce35dSMichał Górny SetCurrentThreadID(thread->GetID()); 360bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 361bee4d6efSMichał Górny break; 362bee4d6efSMichał Górny } 363bee4d6efSMichał Górny 364bee4d6efSMichał Górny thread->SetStoppedByTrace(); 3659a1ce35dSMichał Górny SetCurrentThreadID(thread->GetID()); 366bee4d6efSMichał Górny } 367bee4d6efSMichał Górny 368bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 369bee4d6efSMichał Górny return; 370bee4d6efSMichał Górny } 371bee4d6efSMichał Górny } 372bee4d6efSMichał Górny 373bee4d6efSMichał Górny // Either user-generated SIGTRAP or an unknown event that would 374bee4d6efSMichał Górny // otherwise leave the debugger hanging. 375bee4d6efSMichał Górny LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler"); 376bee4d6efSMichał Górny MonitorSignal(pid, SIGTRAP); 377bee4d6efSMichał Górny } 378bee4d6efSMichał Górny 379bee4d6efSMichał Górny void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { 3804fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 381bee4d6efSMichał Górny struct ptrace_lwpinfo info; 382bee4d6efSMichał Górny 383bee4d6efSMichał Górny const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); 384bee4d6efSMichał Górny if (siginfo_err.Fail()) { 385bee4d6efSMichał Górny LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); 386bee4d6efSMichał Górny return; 387bee4d6efSMichał Górny } 388bee4d6efSMichał Górny assert(info.pl_event == PL_EVENT_SIGNAL); 389bee4d6efSMichał Górny // TODO: do we need to handle !PL_FLAG_SI? 390bee4d6efSMichał Górny assert(info.pl_flags & PL_FLAG_SI); 391bee4d6efSMichał Górny assert(info.pl_siginfo.si_signo == signal); 392bee4d6efSMichał Górny 393bee4d6efSMichał Górny for (const auto &abs_thread : m_threads) { 394bee4d6efSMichał Górny NativeThreadFreeBSD &thread = 395bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*abs_thread); 396bee4d6efSMichał Górny assert(info.pl_lwpid >= 0); 397bee4d6efSMichał Górny if (info.pl_lwpid == 0 || 3989a1ce35dSMichał Górny static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) { 399bee4d6efSMichał Górny thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo); 4009a1ce35dSMichał Górny SetCurrentThreadID(thread.GetID()); 4019a1ce35dSMichał Górny } else 402bee4d6efSMichał Górny thread.SetStoppedWithNoReason(); 403bee4d6efSMichał Górny } 404bee4d6efSMichał Górny SetState(StateType::eStateStopped, true); 405bee4d6efSMichał Górny } 406bee4d6efSMichał Górny 407bee4d6efSMichał Górny Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, 408bee4d6efSMichał Górny int data, int *result) { 4094fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Ptrace); 410bee4d6efSMichał Górny Status error; 411bee4d6efSMichał Górny int ret; 412bee4d6efSMichał Górny 413bee4d6efSMichał Górny errno = 0; 414bee4d6efSMichał Górny ret = 415bee4d6efSMichał Górny ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data); 416bee4d6efSMichał Górny 417535da108SDavid CARLIER if (ret == -1) { 418535da108SDavid CARLIER error = CanTrace(); 419535da108SDavid CARLIER if (error.Success()) 42047667ee2SAdrian Prantl error = Status::FromErrno(); 421535da108SDavid CARLIER } 422bee4d6efSMichał Górny 423bee4d6efSMichał Górny if (result) 424bee4d6efSMichał Górny *result = ret; 425bee4d6efSMichał Górny 426bee4d6efSMichał Górny LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret); 427bee4d6efSMichał Górny 428bee4d6efSMichał Górny if (error.Fail()) 429bee4d6efSMichał Górny LLDB_LOG(log, "ptrace() failed: {0}", error); 430bee4d6efSMichał Górny 431bee4d6efSMichał Górny return error; 432bee4d6efSMichał Górny } 433bee4d6efSMichał Górny 434bee4d6efSMichał Górny llvm::Expected<llvm::ArrayRef<uint8_t>> 435bee4d6efSMichał Górny NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { 436bee4d6efSMichał Górny static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7}; 437bee4d6efSMichał Górny static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; 438bee4d6efSMichał Górny 439bee4d6efSMichał Górny switch (GetArchitecture().GetMachine()) { 440bee4d6efSMichał Górny case llvm::Triple::arm: 441bee4d6efSMichał Górny switch (size_hint) { 442bee4d6efSMichał Górny case 2: 443984b800aSserge-sans-paille return llvm::ArrayRef(g_thumb_opcode); 444bee4d6efSMichał Górny case 4: 445984b800aSserge-sans-paille return llvm::ArrayRef(g_arm_opcode); 446bee4d6efSMichał Górny default: 447bee4d6efSMichał Górny return llvm::createStringError(llvm::inconvertibleErrorCode(), 448bee4d6efSMichał Górny "Unrecognised trap opcode size hint!"); 449bee4d6efSMichał Górny } 450bee4d6efSMichał Górny default: 451bee4d6efSMichał Górny return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); 452bee4d6efSMichał Górny } 453bee4d6efSMichał Górny } 454bee4d6efSMichał Górny 455bee4d6efSMichał Górny Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) { 4564fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 457bee4d6efSMichał Górny LLDB_LOG(log, "pid {0}", GetID()); 458bee4d6efSMichał Górny 459bee4d6efSMichał Górny Status ret; 460bee4d6efSMichał Górny 461bee4d6efSMichał Górny int signal = 0; 462bee4d6efSMichał Górny for (const auto &abs_thread : m_threads) { 463bee4d6efSMichał Górny assert(abs_thread && "thread list should not contain NULL threads"); 464bee4d6efSMichał Górny NativeThreadFreeBSD &thread = 465bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*abs_thread); 466bee4d6efSMichał Górny 467bee4d6efSMichał Górny const ResumeAction *action = 468bee4d6efSMichał Górny resume_actions.GetActionForThread(thread.GetID(), true); 469bee4d6efSMichał Górny // we need to explicit issue suspend requests, so it is simpler to map it 470bee4d6efSMichał Górny // into proper action 471bee4d6efSMichał Górny ResumeAction suspend_action{thread.GetID(), eStateSuspended, 472bee4d6efSMichał Górny LLDB_INVALID_SIGNAL_NUMBER}; 473bee4d6efSMichał Górny 474bee4d6efSMichał Górny if (action == nullptr) { 475bee4d6efSMichał Górny LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), 476bee4d6efSMichał Górny thread.GetID()); 477bee4d6efSMichał Górny action = &suspend_action; 478bee4d6efSMichał Górny } 479bee4d6efSMichał Górny 480bee4d6efSMichał Górny LLDB_LOG( 481bee4d6efSMichał Górny log, 482bee4d6efSMichał Górny "processing resume action state {0} signal {1} for pid {2} tid {3}", 483bee4d6efSMichał Górny action->state, action->signal, GetID(), thread.GetID()); 484bee4d6efSMichał Górny 485bee4d6efSMichał Górny switch (action->state) { 486bee4d6efSMichał Górny case eStateRunning: 487bee4d6efSMichał Górny ret = thread.Resume(); 488bee4d6efSMichał Górny break; 489bee4d6efSMichał Górny case eStateStepping: 490bee4d6efSMichał Górny ret = thread.SingleStep(); 491bee4d6efSMichał Górny break; 492bee4d6efSMichał Górny case eStateSuspended: 493bee4d6efSMichał Górny case eStateStopped: 494bee4d6efSMichał Górny if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) 4950642cd76SAdrian Prantl return Status::FromErrorString( 4960642cd76SAdrian Prantl "Passing signal to suspended thread unsupported"); 497bee4d6efSMichał Górny 498bee4d6efSMichał Górny ret = thread.Suspend(); 499bee4d6efSMichał Górny break; 500bee4d6efSMichał Górny 501bee4d6efSMichał Górny default: 5020642cd76SAdrian Prantl return Status::FromErrorStringWithFormat( 503bee4d6efSMichał Górny "NativeProcessFreeBSD::%s (): unexpected state %s specified " 504bee4d6efSMichał Górny "for pid %" PRIu64 ", tid %" PRIu64, 505bee4d6efSMichał Górny __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID()); 506bee4d6efSMichał Górny } 507bee4d6efSMichał Górny 508bee4d6efSMichał Górny if (!ret.Success()) 509bee4d6efSMichał Górny return ret; 510bee4d6efSMichał Górny if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) 511bee4d6efSMichał Górny signal = action->signal; 512bee4d6efSMichał Górny } 513bee4d6efSMichał Górny 514bee4d6efSMichał Górny ret = 515bee4d6efSMichał Górny PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal); 516bee4d6efSMichał Górny if (ret.Success()) 517bee4d6efSMichał Górny SetState(eStateRunning, true); 518bee4d6efSMichał Górny return ret; 519bee4d6efSMichał Górny } 520bee4d6efSMichał Górny 521bee4d6efSMichał Górny Status NativeProcessFreeBSD::Halt() { 522bee4d6efSMichał Górny Status error; 523bee4d6efSMichał Górny 524aed179f5SMichał Górny // Do not try to stop a process that's already stopped, this may cause 525aed179f5SMichał Górny // the SIGSTOP to get queued and stop the process again once resumed. 526aed179f5SMichał Górny if (StateIsStoppedState(m_state, false)) 527aed179f5SMichał Górny return error; 528bee4d6efSMichał Górny if (kill(GetID(), SIGSTOP) != 0) 52947667ee2SAdrian Prantl error = Status::FromErrno(); 530bee4d6efSMichał Górny return error; 531bee4d6efSMichał Górny } 532bee4d6efSMichał Górny 533bee4d6efSMichał Górny Status NativeProcessFreeBSD::Detach() { 534bee4d6efSMichał Górny Status error; 535bee4d6efSMichał Górny 536bee4d6efSMichał Górny // Stop monitoring the inferior. 537bee4d6efSMichał Górny m_sigchld_handle.reset(); 538bee4d6efSMichał Górny 539bee4d6efSMichał Górny // Tell ptrace to detach from the process. 540bee4d6efSMichał Górny if (GetID() == LLDB_INVALID_PROCESS_ID) 541bee4d6efSMichał Górny return error; 542bee4d6efSMichał Górny 543bee4d6efSMichał Górny return PtraceWrapper(PT_DETACH, GetID()); 544bee4d6efSMichał Górny } 545bee4d6efSMichał Górny 546bee4d6efSMichał Górny Status NativeProcessFreeBSD::Signal(int signo) { 547bee4d6efSMichał Górny Status error; 548bee4d6efSMichał Górny 549bee4d6efSMichał Górny if (kill(GetID(), signo)) 55047667ee2SAdrian Prantl error = Status::FromErrno(); 551bee4d6efSMichał Górny 552bee4d6efSMichał Górny return error; 553bee4d6efSMichał Górny } 554bee4d6efSMichał Górny 555bee4d6efSMichał Górny Status NativeProcessFreeBSD::Interrupt() { return Halt(); } 556bee4d6efSMichał Górny 557bee4d6efSMichał Górny Status NativeProcessFreeBSD::Kill() { 5584fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 559bee4d6efSMichał Górny LLDB_LOG(log, "pid {0}", GetID()); 560bee4d6efSMichał Górny 561bee4d6efSMichał Górny Status error; 562bee4d6efSMichał Górny 563bee4d6efSMichał Górny switch (m_state) { 564bee4d6efSMichał Górny case StateType::eStateInvalid: 565bee4d6efSMichał Górny case StateType::eStateExited: 566bee4d6efSMichał Górny case StateType::eStateCrashed: 567bee4d6efSMichał Górny case StateType::eStateDetached: 568bee4d6efSMichał Górny case StateType::eStateUnloaded: 569bee4d6efSMichał Górny // Nothing to do - the process is already dead. 570bee4d6efSMichał Górny LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), 571bee4d6efSMichał Górny StateAsCString(m_state)); 572bee4d6efSMichał Górny return error; 573bee4d6efSMichał Górny 574bee4d6efSMichał Górny case StateType::eStateConnected: 575bee4d6efSMichał Górny case StateType::eStateAttaching: 576bee4d6efSMichał Górny case StateType::eStateLaunching: 577bee4d6efSMichał Górny case StateType::eStateStopped: 578bee4d6efSMichał Górny case StateType::eStateRunning: 579bee4d6efSMichał Górny case StateType::eStateStepping: 580bee4d6efSMichał Górny case StateType::eStateSuspended: 581bee4d6efSMichał Górny // We can try to kill a process in these states. 582bee4d6efSMichał Górny break; 583bee4d6efSMichał Górny } 584bee4d6efSMichał Górny 585bee4d6efSMichał Górny return PtraceWrapper(PT_KILL, m_pid); 586bee4d6efSMichał Górny } 587bee4d6efSMichał Górny 588bee4d6efSMichał Górny Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, 589bee4d6efSMichał Górny MemoryRegionInfo &range_info) { 590bee4d6efSMichał Górny 591bee4d6efSMichał Górny if (m_supports_mem_region == LazyBool::eLazyBoolNo) { 592bee4d6efSMichał Górny // We're done. 5930642cd76SAdrian Prantl return Status::FromErrorString("unsupported"); 594bee4d6efSMichał Górny } 595bee4d6efSMichał Górny 596bee4d6efSMichał Górny Status error = PopulateMemoryRegionCache(); 597bee4d6efSMichał Górny if (error.Fail()) { 598bee4d6efSMichał Górny return error; 599bee4d6efSMichał Górny } 600bee4d6efSMichał Górny 601bee4d6efSMichał Górny lldb::addr_t prev_base_address = 0; 602bee4d6efSMichał Górny // FIXME start by finding the last region that is <= target address using 603bee4d6efSMichał Górny // binary search. Data is sorted. 604bee4d6efSMichał Górny // There can be a ton of regions on pthreads apps with lots of threads. 605bee4d6efSMichał Górny for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); 606bee4d6efSMichał Górny ++it) { 607bee4d6efSMichał Górny MemoryRegionInfo &proc_entry_info = it->first; 608bee4d6efSMichał Górny // Sanity check assumption that memory map entries are ascending. 609bee4d6efSMichał Górny assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && 610bee4d6efSMichał Górny "descending memory map entries detected, unexpected"); 611bee4d6efSMichał Górny prev_base_address = proc_entry_info.GetRange().GetRangeBase(); 612bee4d6efSMichał Górny UNUSED_IF_ASSERT_DISABLED(prev_base_address); 613bee4d6efSMichał Górny // If the target address comes before this entry, indicate distance to next 614bee4d6efSMichał Górny // region. 615bee4d6efSMichał Górny if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { 616bee4d6efSMichał Górny range_info.GetRange().SetRangeBase(load_addr); 617bee4d6efSMichał Górny range_info.GetRange().SetByteSize( 618bee4d6efSMichał Górny proc_entry_info.GetRange().GetRangeBase() - load_addr); 619bee4d6efSMichał Górny range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 620bee4d6efSMichał Górny range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 621bee4d6efSMichał Górny range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 622bee4d6efSMichał Górny range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); 623bee4d6efSMichał Górny return error; 624bee4d6efSMichał Górny } else if (proc_entry_info.GetRange().Contains(load_addr)) { 625bee4d6efSMichał Górny // The target address is within the memory region we're processing here. 626bee4d6efSMichał Górny range_info = proc_entry_info; 627bee4d6efSMichał Górny return error; 628bee4d6efSMichał Górny } 629bee4d6efSMichał Górny // The target memory address comes somewhere after the region we just 630bee4d6efSMichał Górny // parsed. 631bee4d6efSMichał Górny } 632bee4d6efSMichał Górny // If we made it here, we didn't find an entry that contained the given 633bee4d6efSMichał Górny // address. Return the load_addr as start and the amount of bytes betwwen 634bee4d6efSMichał Górny // load address and the end of the memory as size. 635bee4d6efSMichał Górny range_info.GetRange().SetRangeBase(load_addr); 636bee4d6efSMichał Górny range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); 637bee4d6efSMichał Górny range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 638bee4d6efSMichał Górny range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 639bee4d6efSMichał Górny range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 640bee4d6efSMichał Górny range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); 641bee4d6efSMichał Górny return error; 642bee4d6efSMichał Górny } 643bee4d6efSMichał Górny 644bee4d6efSMichał Górny Status NativeProcessFreeBSD::PopulateMemoryRegionCache() { 6454fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 646bee4d6efSMichał Górny // If our cache is empty, pull the latest. There should always be at least 647bee4d6efSMichał Górny // one memory region if memory region handling is supported. 648bee4d6efSMichał Górny if (!m_mem_region_cache.empty()) { 649bee4d6efSMichał Górny LLDB_LOG(log, "reusing {0} cached memory region entries", 650bee4d6efSMichał Górny m_mem_region_cache.size()); 651bee4d6efSMichał Górny return Status(); 652bee4d6efSMichał Górny } 653bee4d6efSMichał Górny 654bee4d6efSMichał Górny int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)}; 655bee4d6efSMichał Górny int ret; 656bee4d6efSMichał Górny size_t len; 657bee4d6efSMichał Górny 658bee4d6efSMichał Górny ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0); 659bee4d6efSMichał Górny if (ret != 0) { 660bee4d6efSMichał Górny m_supports_mem_region = LazyBool::eLazyBoolNo; 6610642cd76SAdrian Prantl return Status::FromErrorString("sysctl() for KERN_PROC_VMMAP failed"); 662bee4d6efSMichał Górny } 663bee4d6efSMichał Górny 664bee4d6efSMichał Górny std::unique_ptr<WritableMemoryBuffer> buf = 665bee4d6efSMichał Górny llvm::WritableMemoryBuffer::getNewMemBuffer(len); 666bee4d6efSMichał Górny ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0); 667bee4d6efSMichał Górny if (ret != 0) { 668bee4d6efSMichał Górny m_supports_mem_region = LazyBool::eLazyBoolNo; 6690642cd76SAdrian Prantl return Status::FromErrorString("sysctl() for KERN_PROC_VMMAP failed"); 670bee4d6efSMichał Górny } 671bee4d6efSMichał Górny 672bee4d6efSMichał Górny char *bp = buf->getBufferStart(); 673bee4d6efSMichał Górny char *end = bp + len; 674bee4d6efSMichał Górny while (bp < end) { 675bee4d6efSMichał Górny auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp); 676bee4d6efSMichał Górny if (kv->kve_structsize == 0) 677bee4d6efSMichał Górny break; 678bee4d6efSMichał Górny bp += kv->kve_structsize; 679bee4d6efSMichał Górny 680bee4d6efSMichał Górny MemoryRegionInfo info; 681bee4d6efSMichał Górny info.Clear(); 682bee4d6efSMichał Górny info.GetRange().SetRangeBase(kv->kve_start); 683bee4d6efSMichał Górny info.GetRange().SetRangeEnd(kv->kve_end); 684bee4d6efSMichał Górny info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); 685bee4d6efSMichał Górny 686bee4d6efSMichał Górny if (kv->kve_protection & VM_PROT_READ) 687bee4d6efSMichał Górny info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); 688bee4d6efSMichał Górny else 689bee4d6efSMichał Górny info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 690bee4d6efSMichał Górny 691bee4d6efSMichał Górny if (kv->kve_protection & VM_PROT_WRITE) 692bee4d6efSMichał Górny info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); 693bee4d6efSMichał Górny else 694bee4d6efSMichał Górny info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 695bee4d6efSMichał Górny 696bee4d6efSMichał Górny if (kv->kve_protection & VM_PROT_EXECUTE) 697bee4d6efSMichał Górny info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); 698bee4d6efSMichał Górny else 699bee4d6efSMichał Górny info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 700bee4d6efSMichał Górny 701bee4d6efSMichał Górny if (kv->kve_path[0]) 702bee4d6efSMichał Górny info.SetName(kv->kve_path); 703bee4d6efSMichał Górny 704bee4d6efSMichał Górny m_mem_region_cache.emplace_back(info, 705bee4d6efSMichał Górny FileSpec(info.GetName().GetCString())); 706bee4d6efSMichał Górny } 707bee4d6efSMichał Górny 708bee4d6efSMichał Górny if (m_mem_region_cache.empty()) { 709bee4d6efSMichał Górny // No entries after attempting to read them. This shouldn't happen. Assume 710bee4d6efSMichał Górny // we don't support map entries. 711bee4d6efSMichał Górny LLDB_LOG(log, "failed to find any vmmap entries, assuming no support " 712bee4d6efSMichał Górny "for memory region metadata retrieval"); 713bee4d6efSMichał Górny m_supports_mem_region = LazyBool::eLazyBoolNo; 7140642cd76SAdrian Prantl return Status::FromErrorString("not supported"); 715bee4d6efSMichał Górny } 716bee4d6efSMichał Górny LLDB_LOG(log, "read {0} memory region entries from process {1}", 717bee4d6efSMichał Górny m_mem_region_cache.size(), GetID()); 718bee4d6efSMichał Górny // We support memory retrieval, remember that. 719bee4d6efSMichał Górny m_supports_mem_region = LazyBool::eLazyBoolYes; 720bee4d6efSMichał Górny 721bee4d6efSMichał Górny return Status(); 722bee4d6efSMichał Górny } 723bee4d6efSMichał Górny 724bee4d6efSMichał Górny size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); } 725bee4d6efSMichał Górny 726bee4d6efSMichał Górny Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, 727bee4d6efSMichał Górny bool hardware) { 728bee4d6efSMichał Górny if (hardware) 729771c4c9cSMichał Górny return SetHardwareBreakpoint(addr, size); 730bee4d6efSMichał Górny return SetSoftwareBreakpoint(addr, size); 731bee4d6efSMichał Górny } 732bee4d6efSMichał Górny 733bee4d6efSMichał Górny Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path, 734bee4d6efSMichał Górny FileSpec &file_spec) { 735bee4d6efSMichał Górny Status error = PopulateMemoryRegionCache(); 736535da108SDavid CARLIER if (error.Fail()) { 737535da108SDavid CARLIER auto status = CanTrace(); 738535da108SDavid CARLIER if (status.Fail()) 739535da108SDavid CARLIER return status; 740bee4d6efSMichał Górny return error; 741535da108SDavid CARLIER } 742bee4d6efSMichał Górny 743bee4d6efSMichał Górny FileSpec module_file_spec(module_path); 744bee4d6efSMichał Górny FileSystem::Instance().Resolve(module_file_spec); 745bee4d6efSMichał Górny 746bee4d6efSMichał Górny file_spec.Clear(); 747bee4d6efSMichał Górny for (const auto &it : m_mem_region_cache) { 748bee4d6efSMichał Górny if (it.second.GetFilename() == module_file_spec.GetFilename()) { 749bee4d6efSMichał Górny file_spec = it.second; 750bee4d6efSMichał Górny return Status(); 751bee4d6efSMichał Górny } 752bee4d6efSMichał Górny } 7530642cd76SAdrian Prantl return Status::FromErrorStringWithFormat( 7540642cd76SAdrian Prantl "Module file (%s) not found in process' memory map!", 755bee4d6efSMichał Górny module_file_spec.GetFilename().AsCString()); 756bee4d6efSMichał Górny } 757bee4d6efSMichał Górny 758bee4d6efSMichał Górny Status 759bee4d6efSMichał Górny NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name, 760bee4d6efSMichał Górny lldb::addr_t &load_addr) { 761bee4d6efSMichał Górny load_addr = LLDB_INVALID_ADDRESS; 762bee4d6efSMichał Górny Status error = PopulateMemoryRegionCache(); 763535da108SDavid CARLIER if (error.Fail()) { 764535da108SDavid CARLIER auto status = CanTrace(); 765535da108SDavid CARLIER if (status.Fail()) 766535da108SDavid CARLIER return status; 767bee4d6efSMichał Górny return error; 768535da108SDavid CARLIER } 769bee4d6efSMichał Górny 770bee4d6efSMichał Górny FileSpec file(file_name); 771bee4d6efSMichał Górny for (const auto &it : m_mem_region_cache) { 772bee4d6efSMichał Górny if (it.second == file) { 773bee4d6efSMichał Górny load_addr = it.first.GetRange().GetRangeBase(); 774bee4d6efSMichał Górny return Status(); 775bee4d6efSMichał Górny } 776bee4d6efSMichał Górny } 7770642cd76SAdrian Prantl return Status::FromErrorStringWithFormat("No load address found for file %s.", 7780642cd76SAdrian Prantl file_name.str().c_str()); 779bee4d6efSMichał Górny } 780bee4d6efSMichał Górny 781bee4d6efSMichał Górny void NativeProcessFreeBSD::SigchldHandler() { 7824fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 783bee4d6efSMichał Górny int status; 784bee4d6efSMichał Górny ::pid_t wait_pid = 785bee4d6efSMichał Górny llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG); 786bee4d6efSMichał Górny 787bee4d6efSMichał Górny if (wait_pid == 0) 78863d75641SMichał Górny return; 789bee4d6efSMichał Górny 790bee4d6efSMichał Górny if (wait_pid == -1) { 791bee4d6efSMichał Górny Status error(errno, eErrorTypePOSIX); 792bee4d6efSMichał Górny LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); 79363d75641SMichał Górny return; 794bee4d6efSMichał Górny } 795bee4d6efSMichał Górny 796bee4d6efSMichał Górny WaitStatus wait_status = WaitStatus::Decode(status); 797bee4d6efSMichał Górny bool exited = wait_status.type == WaitStatus::Exit || 798bee4d6efSMichał Górny (wait_status.type == WaitStatus::Signal && 799bee4d6efSMichał Górny wait_pid == static_cast<::pid_t>(GetID())); 800bee4d6efSMichał Górny 801bee4d6efSMichał Górny LLDB_LOG(log, 802bee4d6efSMichał Górny "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}", 803bee4d6efSMichał Górny GetID(), wait_pid, status, exited); 804bee4d6efSMichał Górny 805bee4d6efSMichał Górny if (exited) 806bee4d6efSMichał Górny MonitorExited(wait_pid, wait_status); 807bee4d6efSMichał Górny else { 808bee4d6efSMichał Górny assert(wait_status.type == WaitStatus::Stop); 809bee4d6efSMichał Górny MonitorCallback(wait_pid, wait_status.status); 810bee4d6efSMichał Górny } 811bee4d6efSMichał Górny } 812bee4d6efSMichał Górny 813bee4d6efSMichał Górny bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) { 814bee4d6efSMichał Górny for (const auto &thread : m_threads) { 815bee4d6efSMichał Górny assert(thread && "thread list should not contain NULL threads"); 816bee4d6efSMichał Górny if (thread->GetID() == thread_id) { 817bee4d6efSMichał Górny // We have this thread. 818bee4d6efSMichał Górny return true; 819bee4d6efSMichał Górny } 820bee4d6efSMichał Górny } 821bee4d6efSMichał Górny 822bee4d6efSMichał Górny // We don't have this thread. 823bee4d6efSMichał Górny return false; 824bee4d6efSMichał Górny } 825bee4d6efSMichał Górny 826bee4d6efSMichał Górny NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) { 8274fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Thread); 828bee4d6efSMichał Górny LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); 829bee4d6efSMichał Górny 830bee4d6efSMichał Górny assert(thread_id > 0); 831bee4d6efSMichał Górny assert(!HasThreadNoLock(thread_id) && 832bee4d6efSMichał Górny "attempted to add a thread by id that already exists"); 833bee4d6efSMichał Górny 834bee4d6efSMichał Górny // If this is the first thread, save it as the current thread 835bee4d6efSMichał Górny if (m_threads.empty()) 836bee4d6efSMichał Górny SetCurrentThreadID(thread_id); 837bee4d6efSMichał Górny 838bee4d6efSMichał Górny m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id)); 839bee4d6efSMichał Górny return static_cast<NativeThreadFreeBSD &>(*m_threads.back()); 840bee4d6efSMichał Górny } 841bee4d6efSMichał Górny 842bee4d6efSMichał Górny void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) { 8434fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Thread); 844bee4d6efSMichał Górny LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); 845bee4d6efSMichał Górny 846bee4d6efSMichał Górny assert(thread_id > 0); 847bee4d6efSMichał Górny assert(HasThreadNoLock(thread_id) && 848bee4d6efSMichał Górny "attempted to remove a thread that does not exist"); 849bee4d6efSMichał Górny 850bee4d6efSMichał Górny for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { 851bee4d6efSMichał Górny if ((*it)->GetID() == thread_id) { 852bee4d6efSMichał Górny m_threads.erase(it); 853bee4d6efSMichał Górny break; 854bee4d6efSMichał Górny } 855bee4d6efSMichał Górny } 8569a1ce35dSMichał Górny 8579a1ce35dSMichał Górny if (GetCurrentThreadID() == thread_id) 8589a1ce35dSMichał Górny SetCurrentThreadID(m_threads.front()->GetID()); 859bee4d6efSMichał Górny } 860bee4d6efSMichał Górny 861bee4d6efSMichał Górny Status NativeProcessFreeBSD::Attach() { 862bee4d6efSMichał Górny // Attach to the requested process. 863bee4d6efSMichał Górny // An attach will cause the thread to stop with a SIGSTOP. 864bee4d6efSMichał Górny Status status = PtraceWrapper(PT_ATTACH, m_pid); 865bee4d6efSMichał Górny if (status.Fail()) 866bee4d6efSMichał Górny return status; 867bee4d6efSMichał Górny 868bee4d6efSMichał Górny int wstatus; 869bee4d6efSMichał Górny // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this 870bee4d6efSMichał Górny // point we should have a thread stopped if waitpid succeeds. 871bee4d6efSMichał Górny if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) < 872bee4d6efSMichał Górny 0) 873bee4d6efSMichał Górny return Status(errno, eErrorTypePOSIX); 874bee4d6efSMichał Górny 875bee4d6efSMichał Górny // Initialize threads and tracing status 876bee4d6efSMichał Górny // NB: this needs to be called before we set thread state 877bee4d6efSMichał Górny status = SetupTrace(); 878bee4d6efSMichał Górny if (status.Fail()) 879bee4d6efSMichał Górny return status; 880bee4d6efSMichał Górny 881bee4d6efSMichał Górny for (const auto &thread : m_threads) 882bee4d6efSMichał Górny static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP); 883bee4d6efSMichał Górny 884bee4d6efSMichał Górny // Let our process instance know the thread has stopped. 885bee4d6efSMichał Górny SetCurrentThreadID(m_threads.front()->GetID()); 886bee4d6efSMichał Górny SetState(StateType::eStateStopped, false); 887bee4d6efSMichał Górny return Status(); 888bee4d6efSMichał Górny } 889bee4d6efSMichał Górny 890bee4d6efSMichał Górny Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf, 891bee4d6efSMichał Górny size_t size, size_t &bytes_read) { 892bee4d6efSMichał Górny unsigned char *dst = static_cast<unsigned char *>(buf); 893bee4d6efSMichał Górny struct ptrace_io_desc io; 894bee4d6efSMichał Górny 8954fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Memory); 896bee4d6efSMichał Górny LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); 897bee4d6efSMichał Górny 898bee4d6efSMichał Górny bytes_read = 0; 899bee4d6efSMichał Górny io.piod_op = PIOD_READ_D; 900bee4d6efSMichał Górny io.piod_len = size; 901bee4d6efSMichał Górny 902bee4d6efSMichał Górny do { 903bee4d6efSMichał Górny io.piod_offs = (void *)(addr + bytes_read); 904bee4d6efSMichał Górny io.piod_addr = dst + bytes_read; 905bee4d6efSMichał Górny 906bee4d6efSMichał Górny Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); 907bee4d6efSMichał Górny if (error.Fail() || io.piod_len == 0) 908bee4d6efSMichał Górny return error; 909bee4d6efSMichał Górny 910bee4d6efSMichał Górny bytes_read += io.piod_len; 911bee4d6efSMichał Górny io.piod_len = size - bytes_read; 912bee4d6efSMichał Górny } while (bytes_read < size); 913bee4d6efSMichał Górny 914bee4d6efSMichał Górny return Status(); 915bee4d6efSMichał Górny } 916bee4d6efSMichał Górny 917bee4d6efSMichał Górny Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf, 918bee4d6efSMichał Górny size_t size, size_t &bytes_written) { 919bee4d6efSMichał Górny const unsigned char *src = static_cast<const unsigned char *>(buf); 920bee4d6efSMichał Górny Status error; 921bee4d6efSMichał Górny struct ptrace_io_desc io; 922bee4d6efSMichał Górny 9234fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Memory); 924bee4d6efSMichał Górny LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); 925bee4d6efSMichał Górny 926bee4d6efSMichał Górny bytes_written = 0; 927bee4d6efSMichał Górny io.piod_op = PIOD_WRITE_D; 928bee4d6efSMichał Górny io.piod_len = size; 929bee4d6efSMichał Górny 930bee4d6efSMichał Górny do { 931bee4d6efSMichał Górny io.piod_addr = 932bee4d6efSMichał Górny const_cast<void *>(static_cast<const void *>(src + bytes_written)); 933bee4d6efSMichał Górny io.piod_offs = (void *)(addr + bytes_written); 934bee4d6efSMichał Górny 935bee4d6efSMichał Górny Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); 936bee4d6efSMichał Górny if (error.Fail() || io.piod_len == 0) 937bee4d6efSMichał Górny return error; 938bee4d6efSMichał Górny 939bee4d6efSMichał Górny bytes_written += io.piod_len; 940bee4d6efSMichał Górny io.piod_len = size - bytes_written; 941bee4d6efSMichał Górny } while (bytes_written < size); 942bee4d6efSMichał Górny 943bee4d6efSMichał Górny return error; 944bee4d6efSMichał Górny } 945bee4d6efSMichał Górny 946bee4d6efSMichał Górny llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 947bee4d6efSMichał Górny NativeProcessFreeBSD::GetAuxvData() const { 948bee4d6efSMichał Górny int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())}; 949bee4d6efSMichał Górny size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo); 950bee4d6efSMichał Górny std::unique_ptr<WritableMemoryBuffer> buf = 951bee4d6efSMichał Górny llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size); 952bee4d6efSMichał Górny 953bee4d6efSMichał Górny if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0) 954bee4d6efSMichał Górny return std::error_code(errno, std::generic_category()); 955bee4d6efSMichał Górny 956bee4d6efSMichał Górny return buf; 957bee4d6efSMichał Górny } 958bee4d6efSMichał Górny 959bee4d6efSMichał Górny Status NativeProcessFreeBSD::SetupTrace() { 960bee4d6efSMichał Górny // Enable event reporting 961bee4d6efSMichał Górny int events; 962bee4d6efSMichał Górny Status status = 963bee4d6efSMichał Górny PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events)); 964bee4d6efSMichał Górny if (status.Fail()) 965bee4d6efSMichał Górny return status; 96663d75641SMichał Górny events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK; 967bee4d6efSMichał Górny status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events)); 968bee4d6efSMichał Górny if (status.Fail()) 969bee4d6efSMichał Górny return status; 970bee4d6efSMichał Górny 971bee4d6efSMichał Górny return ReinitializeThreads(); 972bee4d6efSMichał Górny } 973bee4d6efSMichał Górny 974bee4d6efSMichał Górny Status NativeProcessFreeBSD::ReinitializeThreads() { 975bee4d6efSMichał Górny // Clear old threads 976bee4d6efSMichał Górny m_threads.clear(); 977bee4d6efSMichał Górny 978bee4d6efSMichał Górny int num_lwps; 979bee4d6efSMichał Górny Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps); 980bee4d6efSMichał Górny if (error.Fail()) 981bee4d6efSMichał Górny return error; 982bee4d6efSMichał Górny 983bee4d6efSMichał Górny std::vector<lwpid_t> lwp_ids; 984bee4d6efSMichał Górny lwp_ids.resize(num_lwps); 985bee4d6efSMichał Górny error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(), 986bee4d6efSMichał Górny lwp_ids.size() * sizeof(lwpid_t), &num_lwps); 987bee4d6efSMichał Górny if (error.Fail()) 988bee4d6efSMichał Górny return error; 989bee4d6efSMichał Górny 990bee4d6efSMichał Górny // Reinitialize from scratch threads and register them in process 991bee4d6efSMichał Górny for (lwpid_t lwp : lwp_ids) 992bee4d6efSMichał Górny AddThread(lwp); 993bee4d6efSMichał Górny 994bee4d6efSMichał Górny return error; 995bee4d6efSMichał Górny } 996bee4d6efSMichał Górny 997bee4d6efSMichał Górny bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const { 998bee4d6efSMichał Górny return !m_arch.IsMIPS(); 999bee4d6efSMichał Górny } 100063d75641SMichał Górny 100165f2a757SMichał Górny void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork, 100265f2a757SMichał Górny NativeThreadFreeBSD &parent_thread) { 10034fa1ad05SPavel Labath Log *log = GetLog(POSIXLog::Process); 100463d75641SMichał Górny LLDB_LOG(log, "fork, child_pid={0}", child_pid); 100563d75641SMichał Górny 100663d75641SMichał Górny int status; 100763d75641SMichał Górny ::pid_t wait_pid = 100863d75641SMichał Górny llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0); 100963d75641SMichał Górny if (wait_pid != child_pid) { 101063d75641SMichał Górny LLDB_LOG(log, 101163d75641SMichał Górny "waiting for pid {0} failed. Assuming the pid has " 101263d75641SMichał Górny "disappeared in the meantime", 101363d75641SMichał Górny child_pid); 101463d75641SMichał Górny return; 101563d75641SMichał Górny } 101663d75641SMichał Górny if (WIFEXITED(status)) { 101763d75641SMichał Górny LLDB_LOG(log, 101863d75641SMichał Górny "waiting for pid {0} returned an 'exited' event. Not " 101963d75641SMichał Górny "tracking it.", 102063d75641SMichał Górny child_pid); 102163d75641SMichał Górny return; 102263d75641SMichał Górny } 102363d75641SMichał Górny 102465f2a757SMichał Górny struct ptrace_lwpinfo info; 102565f2a757SMichał Górny const auto siginfo_err = PtraceWrapper(PT_LWPINFO, child_pid, &info, sizeof(info)); 102665f2a757SMichał Górny if (siginfo_err.Fail()) { 102765f2a757SMichał Górny LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); 102865f2a757SMichał Górny return; 102965f2a757SMichał Górny } 103065f2a757SMichał Górny assert(info.pl_event == PL_EVENT_SIGNAL); 103165f2a757SMichał Górny lldb::tid_t child_tid = info.pl_lwpid; 103265f2a757SMichał Górny 103365f2a757SMichał Górny std::unique_ptr<NativeProcessFreeBSD> child_process{ 103465f2a757SMichał Górny new NativeProcessFreeBSD(static_cast<::pid_t>(child_pid), m_terminal_fd, 103565f2a757SMichał Górny m_delegate, m_arch, m_main_loop)}; 103665f2a757SMichał Górny if (!is_vfork) 103765f2a757SMichał Górny child_process->m_software_breakpoints = m_software_breakpoints; 103865f2a757SMichał Górny 103965f2a757SMichał Górny Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; 104065f2a757SMichał Górny if ((m_enabled_extensions & expected_ext) == expected_ext) { 104165f2a757SMichał Górny child_process->SetupTrace(); 104265f2a757SMichał Górny for (const auto &thread : child_process->m_threads) 104365f2a757SMichał Górny static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP); 104465f2a757SMichał Górny child_process->SetState(StateType::eStateStopped, false); 104565f2a757SMichał Górny 104665f2a757SMichał Górny m_delegate.NewSubprocess(this, std::move(child_process)); 104765f2a757SMichał Górny if (is_vfork) 104865f2a757SMichał Górny parent_thread.SetStoppedByVFork(child_pid, child_tid); 104965f2a757SMichał Górny else 105065f2a757SMichał Górny parent_thread.SetStoppedByFork(child_pid, child_tid); 105165f2a757SMichał Górny SetState(StateType::eStateStopped, true); 105265f2a757SMichał Górny } else { 105365f2a757SMichał Górny child_process->Detach(); 105463d75641SMichał Górny Status pt_error = 105563d75641SMichał Górny PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0); 105663d75641SMichał Górny if (pt_error.Fail()) { 105763d75641SMichał Górny LLDB_LOG_ERROR(log, pt_error.ToError(), 105863d75641SMichał Górny "unable to resume parent process {1}: {0}", GetID()); 105963d75641SMichał Górny SetState(StateType::eStateInvalid); 106063d75641SMichał Górny } 106163d75641SMichał Górny } 106265f2a757SMichał Górny } 1063b07803eeSMichał Górny 1064b07803eeSMichał Górny llvm::Expected<std::string> 1065b07803eeSMichał Górny NativeProcessFreeBSD::SaveCore(llvm::StringRef path_hint) { 106602e690baSMichał Górny #if defined(PT_COREDUMP) 1067b07803eeSMichał Górny using namespace llvm::sys::fs; 1068b07803eeSMichał Górny 1069b07803eeSMichał Górny llvm::SmallString<128> path{path_hint}; 1070b07803eeSMichał Górny Status error; 1071b07803eeSMichał Górny struct ptrace_coredump pc = {}; 1072b07803eeSMichał Górny 1073b07803eeSMichał Górny // Try with the suggested path first. If there is no suggested path or it 1074b07803eeSMichał Górny // failed to open, use a temporary file. 1075b07803eeSMichał Górny if (path.empty() || 1076b07803eeSMichał Górny openFile(path, pc.pc_fd, CD_CreateNew, FA_Write, OF_None)) { 1077b07803eeSMichał Górny if (std::error_code errc = 1078b07803eeSMichał Górny createTemporaryFile("lldb", "core", pc.pc_fd, path)) 1079b07803eeSMichał Górny return llvm::createStringError(errc, "Unable to create a temporary file"); 1080b07803eeSMichał Górny } 1081b07803eeSMichał Górny error = PtraceWrapper(PT_COREDUMP, GetID(), &pc, sizeof(pc)); 1082b07803eeSMichał Górny 1083b07803eeSMichał Górny std::error_code close_err = closeFile(pc.pc_fd); 1084b07803eeSMichał Górny if (error.Fail()) 1085b07803eeSMichał Górny return error.ToError(); 1086b07803eeSMichał Górny if (close_err) 1087b07803eeSMichał Górny return llvm::createStringError( 1088b07803eeSMichał Górny close_err, "Unable to close the core dump after writing"); 1089b07803eeSMichał Górny return path.str().str(); 109002e690baSMichał Górny #else // !defined(PT_COREDUMP) 109102e690baSMichał Górny return llvm::createStringError( 109202e690baSMichał Górny llvm::inconvertibleErrorCode(), 109302e690baSMichał Górny "PT_COREDUMP not supported in the FreeBSD version used to build LLDB"); 109402e690baSMichał Górny #endif 1095b07803eeSMichał Górny } 1096