1126 lines · cpp
1//===-- NativeProcessNetBSD.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "NativeProcessNetBSD.h"10 11#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"12#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"13#include "lldb/Host/HostProcess.h"14#include "lldb/Host/common/NativeRegisterContext.h"15#include "lldb/Host/posix/ProcessLauncherPosixFork.h"16#include "lldb/Target/Process.h"17#include "lldb/Utility/State.h"18#include "llvm/Support/Errno.h"19 20// System includes - They have to be included after framework includes because21// they define some macros which collide with variable names in other modules22// clang-format off23#include <sys/types.h>24#include <sys/ptrace.h>25#include <sys/sysctl.h>26#include <sys/wait.h>27#include <uvm/uvm_prot.h>28#include <elf.h>29#include <util.h>30// clang-format on31 32using namespace lldb;33using namespace lldb_private;34using namespace lldb_private::process_netbsd;35using namespace llvm;36 37// Simple helper function to ensure flags are enabled on the given file38// descriptor.39static Status EnsureFDFlags(int fd, int flags) {40 Status error;41 42 int status = fcntl(fd, F_GETFL);43 if (status == -1) {44 error = Status::FromErrno();45 return error;46 }47 48 if (fcntl(fd, F_SETFL, status | flags) == -1) {49 error = Status::FromErrno();50 return error;51 }52 53 return error;54}55 56// Public Static Methods57 58llvm::Expected<std::unique_ptr<NativeProcessProtocol>>59NativeProcessNetBSD::Manager::Launch(ProcessLaunchInfo &launch_info,60 NativeDelegate &native_delegate) {61 Log *log = GetLog(POSIXLog::Process);62 63 Status status;64 ::pid_t pid = ProcessLauncherPosixFork()65 .LaunchProcess(launch_info, status)66 .GetProcessId();67 LLDB_LOG(log, "pid = {0:x}", pid);68 if (status.Fail()) {69 LLDB_LOG(log, "failed to launch process: {0}", status);70 return status.ToError();71 }72 73 // Wait for the child process to trap on its call to execve.74 int wstatus;75 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);76 assert(wpid == pid);77 (void)wpid;78 if (!WIFSTOPPED(wstatus)) {79 LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",80 WaitStatus::Decode(wstatus));81 return llvm::make_error<StringError>("Could not sync with inferior process",82 llvm::inconvertibleErrorCode());83 }84 LLDB_LOG(log, "inferior started, now in stopped state");85 86 ProcessInstanceInfo Info;87 if (!Host::GetProcessInfo(pid, Info)) {88 return llvm::make_error<StringError>("Cannot get process architecture",89 llvm::inconvertibleErrorCode());90 }91 92 // Set the architecture to the exe architecture.93 LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,94 Info.GetArchitecture().GetArchitectureName());95 96 std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(97 pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,98 Info.GetArchitecture(), m_mainloop));99 100 status = process_up->SetupTrace();101 if (status.Fail())102 return status.ToError();103 104 for (const auto &thread : process_up->m_threads)105 static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);106 process_up->SetState(StateType::eStateStopped, false);107 108 return std::move(process_up);109}110 111llvm::Expected<std::unique_ptr<NativeProcessProtocol>>112NativeProcessNetBSD::Manager::Attach(113 lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {114 Log *log = GetLog(POSIXLog::Process);115 LLDB_LOG(log, "pid = {0:x}", pid);116 117 // Retrieve the architecture for the running process.118 ProcessInstanceInfo Info;119 if (!Host::GetProcessInfo(pid, Info)) {120 return llvm::make_error<StringError>("Cannot get process architecture",121 llvm::inconvertibleErrorCode());122 }123 124 std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(125 pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));126 127 Status status = process_up->Attach();128 if (!status.Success())129 return status.ToError();130 131 return std::move(process_up);132}133 134NativeProcessNetBSD::Extension135NativeProcessNetBSD::Manager::GetSupportedExtensions() const {136 return Extension::multiprocess | Extension::fork | Extension::vfork |137 Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |138 Extension::savecore;139}140 141// Public Instance Methods142 143NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,144 NativeDelegate &delegate,145 const ArchSpec &arch,146 MainLoop &mainloop)147 : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),148 m_main_loop(mainloop) {149 if (m_terminal_fd != -1) {150 Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);151 assert(status.Success());152 }153 154 Status status;155 m_sigchld_handle = mainloop.RegisterSignal(156 SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);157 assert(m_sigchld_handle && status.Success());158}159 160// Handles all waitpid events from the inferior process.161void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {162 switch (signal) {163 case SIGTRAP:164 return MonitorSIGTRAP(pid);165 case SIGSTOP:166 return MonitorSIGSTOP(pid);167 default:168 return MonitorSignal(pid, signal);169 }170}171 172void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {173 Log *log = GetLog(POSIXLog::Process);174 175 LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);176 177 /* Stop Tracking All Threads attached to Process */178 m_threads.clear();179 180 SetExitStatus(status, true);181 182 // Notify delegate that our process has exited.183 SetState(StateType::eStateExited, true);184}185 186void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {187 ptrace_siginfo_t info;188 189 const auto siginfo_err =190 PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));191 192 // Get details on the signal raised.193 if (siginfo_err.Success()) {194 // Handle SIGSTOP from LLGS (LLDB GDB Server)195 if (info.psi_siginfo.si_code == SI_USER &&196 info.psi_siginfo.si_pid == ::getpid()) {197 /* Stop Tracking all Threads attached to Process */198 for (const auto &thread : m_threads) {199 static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(200 SIGSTOP, &info.psi_siginfo);201 }202 }203 SetState(StateType::eStateStopped, true);204 }205}206 207void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {208 Log *log = GetLog(POSIXLog::Process);209 ptrace_siginfo_t info;210 211 const auto siginfo_err =212 PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));213 214 // Get details on the signal raised.215 if (siginfo_err.Fail()) {216 LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);217 return;218 }219 220 LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,221 info.psi_lwpid, info.psi_siginfo.si_code);222 NativeThreadNetBSD *thread = nullptr;223 224 if (info.psi_lwpid > 0) {225 for (const auto &t : m_threads) {226 if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {227 thread = static_cast<NativeThreadNetBSD *>(t.get());228 break;229 }230 static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();231 }232 if (!thread)233 LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,234 info.psi_lwpid);235 }236 237 switch (info.psi_siginfo.si_code) {238 case TRAP_BRKPT:239 if (thread) {240 thread->SetStoppedByBreakpoint();241 FixupBreakpointPCAsNeeded(*thread);242 }243 SetState(StateType::eStateStopped, true);244 return;245 case TRAP_TRACE:246 if (thread)247 thread->SetStoppedByTrace();248 SetState(StateType::eStateStopped, true);249 return;250 case TRAP_EXEC: {251 Status error = ReinitializeThreads();252 if (error.Fail()) {253 SetState(StateType::eStateInvalid);254 return;255 }256 257 // Let our delegate know we have just exec'd.258 NotifyDidExec();259 260 for (const auto &thread : m_threads)261 static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();262 SetState(StateType::eStateStopped, true);263 return;264 }265 case TRAP_CHLD: {266 ptrace_state_t pst;267 Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));268 if (error.Fail()) {269 SetState(StateType::eStateInvalid);270 return;271 }272 273 assert(thread);274 if (pst.pe_report_event == PTRACE_VFORK_DONE) {275 if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {276 thread->SetStoppedByVForkDone();277 SetState(StateType::eStateStopped, true);278 } else {279 Status error =280 PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);281 if (error.Fail())282 SetState(StateType::eStateInvalid);283 }284 } else {285 assert(pst.pe_report_event == PTRACE_FORK ||286 pst.pe_report_event == PTRACE_VFORK);287 MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,288 *thread);289 }290 return;291 }292 case TRAP_LWP: {293 ptrace_state_t pst;294 Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));295 if (error.Fail()) {296 SetState(StateType::eStateInvalid);297 return;298 }299 300 switch (pst.pe_report_event) {301 case PTRACE_LWP_CREATE: {302 LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,303 pst.pe_lwp);304 NativeThreadNetBSD &t = AddThread(pst.pe_lwp);305 error = t.CopyWatchpointsFrom(306 static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));307 if (error.Fail()) {308 LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",309 pst.pe_lwp, error);310 SetState(StateType::eStateInvalid);311 return;312 }313 } break;314 case PTRACE_LWP_EXIT:315 LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,316 pst.pe_lwp);317 RemoveThread(pst.pe_lwp);318 break;319 }320 321 error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);322 if (error.Fail())323 SetState(StateType::eStateInvalid);324 return;325 }326 case TRAP_DBREG: {327 if (!thread)328 break;329 330 auto ®ctx = static_cast<NativeRegisterContextNetBSD &>(331 thread->GetRegisterContext());332 uint32_t wp_index = LLDB_INVALID_INDEX32;333 Status error = regctx.GetWatchpointHitIndex(334 wp_index, (uintptr_t)info.psi_siginfo.si_addr);335 if (error.Fail())336 LLDB_LOG(log,337 "received error while checking for watchpoint hits, pid = "338 "{0}, LWP = {1}, error = {2}",339 pid, info.psi_lwpid, error);340 if (wp_index != LLDB_INVALID_INDEX32) {341 thread->SetStoppedByWatchpoint(wp_index);342 regctx.ClearWatchpointHit(wp_index);343 SetState(StateType::eStateStopped, true);344 return;345 }346 347 thread->SetStoppedByTrace();348 SetState(StateType::eStateStopped, true);349 return;350 }351 }352 353 // Either user-generated SIGTRAP or an unknown event that would354 // otherwise leave the debugger hanging.355 LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");356 MonitorSignal(pid, SIGTRAP);357}358 359void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {360 Log *log = GetLog(POSIXLog::Process);361 ptrace_siginfo_t info;362 363 const auto siginfo_err =364 PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));365 if (siginfo_err.Fail()) {366 LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);367 return;368 }369 370 for (const auto &abs_thread : m_threads) {371 NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);372 assert(info.psi_lwpid >= 0);373 if (info.psi_lwpid == 0 ||374 static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())375 thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);376 else377 thread.SetStoppedWithNoReason();378 }379 SetState(StateType::eStateStopped, true);380}381 382Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) {383#ifdef PT_STOP384 return PtraceWrapper(PT_STOP, pid);385#else386 Log *log = GetLog(POSIXLog::Ptrace);387 Status error;388 int ret;389 390 errno = 0;391 ret = kill(pid, SIGSTOP);392 393 if (ret == -1)394 error = Status::FromErrno();395 396 LLDB_LOG(log, "kill({0}, SIGSTOP)", pid);397 398 if (error.Fail())399 LLDB_LOG(log, "kill() failed: {0}", error);400 401 return error;402#endif403}404 405Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,406 int data, int *result) {407 Log *log = GetLog(POSIXLog::Ptrace);408 Status error;409 int ret;410 411 errno = 0;412 ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);413 414 if (ret == -1)415 error = Status::FromErrno();416 417 if (result)418 *result = ret;419 420 LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);421 422 if (error.Fail())423 LLDB_LOG(log, "ptrace() failed: {0}", error);424 425 return error;426}427 428static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(429 const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,430 const ResumeActionList &resume_actions) {431 // We need to account for three possible scenarios:432 // 1. no signal being sent.433 // 2. a signal being sent to one thread.434 // 3. a signal being sent to the whole process.435 436 // Count signaled threads. While at it, determine which signal is being sent437 // and ensure there's only one.438 size_t signaled_threads = 0;439 int signal = LLDB_INVALID_SIGNAL_NUMBER;440 lldb::tid_t signaled_lwp;441 for (const auto &thread : threads) {442 assert(thread && "thread list should not contain NULL threads");443 const ResumeAction *action =444 resume_actions.GetActionForThread(thread->GetID(), true);445 if (action) {446 if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {447 signaled_threads++;448 if (action->signal != signal) {449 if (signal != LLDB_INVALID_SIGNAL_NUMBER)450 return Status::FromErrorString(451 "NetBSD does not support passing multiple signals "452 "simultaneously")453 .ToError();454 signal = action->signal;455 signaled_lwp = thread->GetID();456 }457 }458 }459 }460 461 if (signaled_threads == 0) {462 ptrace_siginfo_t siginfo;463 siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;464 return siginfo;465 }466 467 if (signaled_threads > 1 && signaled_threads < threads.size())468 return Status::FromErrorString(469 "NetBSD does not support passing signal to 1<i<all threads")470 .ToError();471 472 ptrace_siginfo_t siginfo;473 siginfo.psi_siginfo.si_signo = signal;474 siginfo.psi_siginfo.si_code = SI_USER;475 siginfo.psi_siginfo.si_pid = getpid();476 siginfo.psi_siginfo.si_uid = getuid();477 if (signaled_threads == 1)478 siginfo.psi_lwpid = signaled_lwp;479 else // signal for the whole process480 siginfo.psi_lwpid = 0;481 return siginfo;482}483 484Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {485 Log *log = GetLog(POSIXLog::Process);486 LLDB_LOG(log, "pid {0}", GetID());487 488 Status ret;489 490 Expected<ptrace_siginfo_t> siginfo =491 ComputeSignalInfo(m_threads, resume_actions);492 if (!siginfo)493 return Status(siginfo.takeError());494 495 for (const auto &abs_thread : m_threads) {496 assert(abs_thread && "thread list should not contain NULL threads");497 NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);498 499 const ResumeAction *action =500 resume_actions.GetActionForThread(thread.GetID(), true);501 // we need to explicit issue suspend requests, so it is simpler to map it502 // into proper action503 ResumeAction suspend_action{thread.GetID(), eStateSuspended,504 LLDB_INVALID_SIGNAL_NUMBER};505 506 if (action == nullptr) {507 LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),508 thread.GetID());509 action = &suspend_action;510 }511 512 LLDB_LOG(513 log,514 "processing resume action state {0} signal {1} for pid {2} tid {3}",515 action->state, action->signal, GetID(), thread.GetID());516 517 switch (action->state) {518 case eStateRunning:519 ret = thread.Resume();520 break;521 case eStateStepping:522 ret = thread.SingleStep();523 break;524 case eStateSuspended:525 case eStateStopped:526 if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)527 return Status::FromErrorString(528 "Passing signal to suspended thread unsupported");529 530 ret = thread.Suspend();531 break;532 533 default:534 return Status::FromErrorStringWithFormat(535 "NativeProcessNetBSD::%s (): unexpected state %s specified "536 "for pid %" PRIu64 ", tid %" PRIu64,537 __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());538 }539 540 if (!ret.Success())541 return ret;542 }543 544 int signal = 0;545 if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {546 ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),547 sizeof(*siginfo));548 if (!ret.Success())549 return ret;550 signal = siginfo->psi_siginfo.si_signo;551 }552 553 ret =554 PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);555 if (ret.Success())556 SetState(eStateRunning, true);557 return ret;558}559 560Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); }561 562Status NativeProcessNetBSD::Detach() {563 Status error;564 565 // Stop monitoring the inferior.566 m_sigchld_handle.reset();567 568 // Tell ptrace to detach from the process.569 if (GetID() == LLDB_INVALID_PROCESS_ID)570 return error;571 572 return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));573}574 575Status NativeProcessNetBSD::Signal(int signo) {576 Status error;577 578 if (kill(GetID(), signo))579 error = Status::FromErrno();580 581 return error;582}583 584Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); }585 586Status NativeProcessNetBSD::Kill() {587 Log *log = GetLog(POSIXLog::Process);588 LLDB_LOG(log, "pid {0}", GetID());589 590 Status error;591 592 switch (m_state) {593 case StateType::eStateInvalid:594 case StateType::eStateExited:595 case StateType::eStateCrashed:596 case StateType::eStateDetached:597 case StateType::eStateUnloaded:598 // Nothing to do - the process is already dead.599 LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),600 StateAsCString(m_state));601 return error;602 603 case StateType::eStateConnected:604 case StateType::eStateAttaching:605 case StateType::eStateLaunching:606 case StateType::eStateStopped:607 case StateType::eStateRunning:608 case StateType::eStateStepping:609 case StateType::eStateSuspended:610 // We can try to kill a process in these states.611 break;612 }613 614 if (kill(GetID(), SIGKILL) != 0) {615 error = Status::FromErrno();616 return error;617 }618 619 return error;620}621 622Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,623 MemoryRegionInfo &range_info) {624 625 if (m_supports_mem_region == LazyBool::eLazyBoolNo) {626 // We're done.627 return Status::FromErrorString("unsupported");628 }629 630 Status error = PopulateMemoryRegionCache();631 if (error.Fail()) {632 return error;633 }634 635 lldb::addr_t prev_base_address = 0;636 // FIXME start by finding the last region that is <= target address using637 // binary search. Data is sorted.638 // There can be a ton of regions on pthreads apps with lots of threads.639 for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();640 ++it) {641 MemoryRegionInfo &proc_entry_info = it->first;642 // Sanity check assumption that memory map entries are ascending.643 assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&644 "descending memory map entries detected, unexpected");645 prev_base_address = proc_entry_info.GetRange().GetRangeBase();646 UNUSED_IF_ASSERT_DISABLED(prev_base_address);647 // If the target address comes before this entry, indicate distance to next648 // region.649 if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {650 range_info.GetRange().SetRangeBase(load_addr);651 range_info.GetRange().SetByteSize(652 proc_entry_info.GetRange().GetRangeBase() - load_addr);653 range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);654 range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);655 range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);656 range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);657 return error;658 } else if (proc_entry_info.GetRange().Contains(load_addr)) {659 // The target address is within the memory region we're processing here.660 range_info = proc_entry_info;661 return error;662 }663 // The target memory address comes somewhere after the region we just664 // parsed.665 }666 // If we made it here, we didn't find an entry that contained the given667 // address. Return the load_addr as start and the amount of bytes betwwen668 // load address and the end of the memory as size.669 range_info.GetRange().SetRangeBase(load_addr);670 range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);671 range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);672 range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);673 range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);674 range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);675 return error;676}677 678Status NativeProcessNetBSD::PopulateMemoryRegionCache() {679 Log *log = GetLog(POSIXLog::Process);680 // If our cache is empty, pull the latest. There should always be at least681 // one memory region if memory region handling is supported.682 if (!m_mem_region_cache.empty()) {683 LLDB_LOG(log, "reusing {0} cached memory region entries",684 m_mem_region_cache.size());685 return Status();686 }687 688 struct kinfo_vmentry *vm;689 size_t count, i;690 vm = kinfo_getvmmap(GetID(), &count);691 if (vm == NULL) {692 m_supports_mem_region = LazyBool::eLazyBoolNo;693 Status error;694 error = Status::FromErrorString("not supported");695 return error;696 }697 for (i = 0; i < count; i++) {698 MemoryRegionInfo info;699 info.Clear();700 info.GetRange().SetRangeBase(vm[i].kve_start);701 info.GetRange().SetRangeEnd(vm[i].kve_end);702 info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);703 704 if (vm[i].kve_protection & VM_PROT_READ)705 info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);706 else707 info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);708 709 if (vm[i].kve_protection & VM_PROT_WRITE)710 info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);711 else712 info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);713 714 if (vm[i].kve_protection & VM_PROT_EXECUTE)715 info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);716 else717 info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);718 719 if (vm[i].kve_path[0])720 info.SetName(vm[i].kve_path);721 722 m_mem_region_cache.emplace_back(info,723 FileSpec(info.GetName().GetCString()));724 }725 free(vm);726 727 if (m_mem_region_cache.empty()) {728 // No entries after attempting to read them. This shouldn't happen. Assume729 // we don't support map entries.730 LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "731 "for memory region metadata retrieval");732 m_supports_mem_region = LazyBool::eLazyBoolNo;733 Status error;734 error = Status::FromErrorString("not supported");735 return error;736 }737 LLDB_LOG(log, "read {0} memory region entries from process {1}",738 m_mem_region_cache.size(), GetID());739 // We support memory retrieval, remember that.740 m_supports_mem_region = LazyBool::eLazyBoolYes;741 return Status();742}743 744lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {745 // punt on this for now746 return LLDB_INVALID_ADDRESS;747}748 749size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }750 751Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,752 bool hardware) {753 if (hardware)754 return Status::FromErrorString(755 "NativeProcessNetBSD does not support hardware breakpoints");756 else757 return SetSoftwareBreakpoint(addr, size);758}759 760Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,761 FileSpec &file_spec) {762 Status error = PopulateMemoryRegionCache();763 if (error.Fail())764 return error;765 766 FileSpec module_file_spec(module_path);767 FileSystem::Instance().Resolve(module_file_spec);768 769 file_spec.Clear();770 for (const auto &it : m_mem_region_cache) {771 if (it.second.GetFilename() == module_file_spec.GetFilename()) {772 file_spec = it.second;773 return Status();774 }775 }776 return Status::FromErrorStringWithFormat(777 "Module file (%s) not found in process' memory map!",778 module_file_spec.GetFilename().AsCString());779}780 781Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,782 lldb::addr_t &load_addr) {783 load_addr = LLDB_INVALID_ADDRESS;784 Status error = PopulateMemoryRegionCache();785 if (error.Fail())786 return error;787 788 FileSpec file(file_name);789 for (const auto &it : m_mem_region_cache) {790 if (it.second == file) {791 load_addr = it.first.GetRange().GetRangeBase();792 return Status();793 }794 }795 return Status::FromErrorStringWithFormat("No load address found for file %s.",796 file_name.str().c_str());797}798 799void NativeProcessNetBSD::SigchldHandler() {800 Log *log = GetLog(POSIXLog::Process);801 int status;802 ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,803 WALLSIG | WNOHANG);804 805 if (wait_pid == 0)806 return;807 808 if (wait_pid == -1) {809 Status error(errno, eErrorTypePOSIX);810 LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);811 return;812 }813 814 WaitStatus wait_status = WaitStatus::Decode(status);815 bool exited = wait_status.type == WaitStatus::Exit ||816 (wait_status.type == WaitStatus::Signal &&817 wait_pid == static_cast<::pid_t>(GetID()));818 819 LLDB_LOG(log,820 "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",821 GetID(), wait_pid, status, exited);822 823 if (exited)824 MonitorExited(wait_pid, wait_status);825 else {826 assert(wait_status.type == WaitStatus::Stop);827 MonitorCallback(wait_pid, wait_status.status);828 }829}830 831bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {832 for (const auto &thread : m_threads) {833 assert(thread && "thread list should not contain NULL threads");834 if (thread->GetID() == thread_id) {835 // We have this thread.836 return true;837 }838 }839 840 // We don't have this thread.841 return false;842}843 844NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {845 Log *log = GetLog(POSIXLog::Thread);846 LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);847 848 assert(thread_id > 0);849 assert(!HasThreadNoLock(thread_id) &&850 "attempted to add a thread by id that already exists");851 852 // If this is the first thread, save it as the current thread853 if (m_threads.empty())854 SetCurrentThreadID(thread_id);855 856 m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));857 return static_cast<NativeThreadNetBSD &>(*m_threads.back());858}859 860void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {861 Log *log = GetLog(POSIXLog::Thread);862 LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);863 864 assert(thread_id > 0);865 assert(HasThreadNoLock(thread_id) &&866 "attempted to remove a thread that does not exist");867 868 for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {869 if ((*it)->GetID() == thread_id) {870 m_threads.erase(it);871 break;872 }873 }874}875 876Status NativeProcessNetBSD::Attach() {877 // Attach to the requested process.878 // An attach will cause the thread to stop with a SIGSTOP.879 Status status = PtraceWrapper(PT_ATTACH, m_pid);880 if (status.Fail())881 return status;882 883 int wstatus;884 // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this885 // point we should have a thread stopped if waitpid succeeds.886 if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,887 WALLSIG)) < 0)888 return Status(errno, eErrorTypePOSIX);889 890 // Initialize threads and tracing status891 // NB: this needs to be called before we set thread state892 status = SetupTrace();893 if (status.Fail())894 return status;895 896 for (const auto &thread : m_threads)897 static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);898 899 // Let our process instance know the thread has stopped.900 SetCurrentThreadID(m_threads.front()->GetID());901 SetState(StateType::eStateStopped, false);902 return Status();903}904 905Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,906 size_t size, size_t &bytes_read) {907 unsigned char *dst = static_cast<unsigned char *>(buf);908 struct ptrace_io_desc io;909 910 Log *log = GetLog(POSIXLog::Memory);911 LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);912 913 bytes_read = 0;914 io.piod_op = PIOD_READ_D;915 io.piod_len = size;916 917 do {918 io.piod_offs = (void *)(addr + bytes_read);919 io.piod_addr = dst + bytes_read;920 921 Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);922 if (error.Fail() || io.piod_len == 0)923 return error;924 925 bytes_read += io.piod_len;926 io.piod_len = size - bytes_read;927 } while (bytes_read < size);928 929 return Status();930}931 932Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,933 size_t size, size_t &bytes_written) {934 const unsigned char *src = static_cast<const unsigned char *>(buf);935 Status error;936 struct ptrace_io_desc io;937 938 Log *log = GetLog(POSIXLog::Memory);939 LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);940 941 bytes_written = 0;942 io.piod_op = PIOD_WRITE_D;943 io.piod_len = size;944 945 do {946 io.piod_addr =947 const_cast<void *>(static_cast<const void *>(src + bytes_written));948 io.piod_offs = (void *)(addr + bytes_written);949 950 Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);951 if (error.Fail() || io.piod_len == 0)952 return error;953 954 bytes_written += io.piod_len;955 io.piod_len = size - bytes_written;956 } while (bytes_written < size);957 958 return error;959}960 961llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>962NativeProcessNetBSD::GetAuxvData() const {963 /*964 * ELF_AUX_ENTRIES is currently restricted to kernel965 * (<sys/exec_elf.h> r. 1.155 specifies 15)966 *967 * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this968 * information isn't needed.969 */970 size_t auxv_size = 100 * sizeof(AuxInfo);971 972 ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =973 llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);974 975 struct ptrace_io_desc io;976 io.piod_op = PIOD_READ_AUXV;977 io.piod_offs = 0;978 io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());979 io.piod_len = auxv_size;980 981 Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);982 983 if (error.Fail())984 return std::error_code(error.GetError(), std::generic_category());985 986 if (io.piod_len < 1)987 return std::error_code(ECANCELED, std::generic_category());988 989 return std::move(buf);990}991 992Status NativeProcessNetBSD::SetupTrace() {993 // Enable event reporting994 ptrace_event_t events;995 Status status =996 PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));997 if (status.Fail())998 return status;999 // TODO: PTRACE_POSIX_SPAWN?1000 events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |1001 PTRACE_VFORK | PTRACE_VFORK_DONE;1002 status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));1003 if (status.Fail())1004 return status;1005 1006 return ReinitializeThreads();1007}1008 1009Status NativeProcessNetBSD::ReinitializeThreads() {1010 // Clear old threads1011 m_threads.clear();1012 1013 // Initialize new thread1014#ifdef PT_LWPSTATUS1015 struct ptrace_lwpstatus info = {};1016 int op = PT_LWPNEXT;1017#else1018 struct ptrace_lwpinfo info = {};1019 int op = PT_LWPINFO;1020#endif1021 1022 Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));1023 1024 if (error.Fail()) {1025 return error;1026 }1027 // Reinitialize from scratch threads and register them in process1028 while (info.pl_lwpid != 0) {1029 AddThread(info.pl_lwpid);1030 error = PtraceWrapper(op, GetID(), &info, sizeof(info));1031 if (error.Fail()) {1032 return error;1033 }1034 }1035 1036 return error;1037}1038 1039void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,1040 NativeThreadNetBSD &parent_thread) {1041 Log *log = GetLog(POSIXLog::Process);1042 LLDB_LOG(log, "clone, child_pid={0}", child_pid);1043 1044 int status;1045 ::pid_t wait_pid =1046 llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);1047 if (wait_pid != child_pid) {1048 LLDB_LOG(log,1049 "waiting for pid {0} failed. Assuming the pid has "1050 "disappeared in the meantime",1051 child_pid);1052 return;1053 }1054 if (WIFEXITED(status)) {1055 LLDB_LOG(log,1056 "waiting for pid {0} returned an 'exited' event. Not "1057 "tracking it.",1058 child_pid);1059 return;1060 }1061 1062 ptrace_siginfo_t info;1063 const auto siginfo_err =1064 PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));1065 if (siginfo_err.Fail()) {1066 LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);1067 return;1068 }1069 assert(info.psi_lwpid >= 0);1070 lldb::tid_t child_tid = info.psi_lwpid;1071 1072 std::unique_ptr<NativeProcessNetBSD> child_process{1073 new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,1074 m_delegate, m_arch, m_main_loop)};1075 if (!is_vfork)1076 child_process->m_software_breakpoints = m_software_breakpoints;1077 1078 Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;1079 if ((m_enabled_extensions & expected_ext) == expected_ext) {1080 child_process->SetupTrace();1081 for (const auto &thread : child_process->m_threads)1082 static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);1083 child_process->SetState(StateType::eStateStopped, false);1084 1085 m_delegate.NewSubprocess(this, std::move(child_process));1086 if (is_vfork)1087 parent_thread.SetStoppedByVFork(child_pid, child_tid);1088 else1089 parent_thread.SetStoppedByFork(child_pid, child_tid);1090 SetState(StateType::eStateStopped, true);1091 } else {1092 child_process->Detach();1093 Status pt_error =1094 PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);1095 if (pt_error.Fail()) {1096 LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),1097 "unable to resume parent process {1}: {0}", GetID());1098 SetState(StateType::eStateInvalid);1099 }1100 }1101}1102 1103llvm::Expected<std::string>1104NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {1105 llvm::SmallString<128> path{path_hint};1106 Status error;1107 1108 // Try with the suggested path first.1109 if (!path.empty()) {1110 error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());1111 if (!error.Fail())1112 return path.str().str();1113 1114 // If the request errored, fall back to a generic temporary file.1115 }1116 1117 if (std::error_code errc =1118 llvm::sys::fs::createTemporaryFile("lldb", "core", path))1119 return llvm::createStringError(errc, "Unable to create a temporary file");1120 1121 error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());1122 if (error.Fail())1123 return error.ToError();1124 return path.str().str();1125}1126